feat(@vben/common-ui): 添加个人中心功能- 新增个人中心页面,包含用户信息展示和修改、密码修改等功能
This commit is contained in:
parent
5026ae0bbd
commit
d3c25dd899
@ -93,6 +93,14 @@ export namespace UserApi {
|
||||
permissions?: string[] | undefined;
|
||||
authorities?: string[];
|
||||
}
|
||||
|
||||
export interface UserUpdateRecord {
|
||||
username?: string;
|
||||
email?: string;
|
||||
phone?: string;
|
||||
address?: string;
|
||||
avatar?: string;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -147,7 +155,7 @@ export function updateUser(id: any, data: UserApi.UserRecord) {
|
||||
return requestClient.patch<UserApi.Res>(`/rest/user/${id}`, data);
|
||||
}
|
||||
|
||||
export function selfUpdate(data: UserApi.User) {
|
||||
export function selfUpdate(data: UserApi.UserUpdateRecord) {
|
||||
return requestClient.patch<UserApi.Res>(`/rest/user/self`, data);
|
||||
}
|
||||
|
||||
|
19
apps/web-antd/src/router/routes/modules/person.ts
Normal file
19
apps/web-antd/src/router/routes/modules/person.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import type { RouteRecordRaw } from 'vue-router';
|
||||
|
||||
import { MaterPerson } from '@vben/icons';
|
||||
|
||||
const routes: RouteRecordRaw[] = [
|
||||
{
|
||||
name: 'Person',
|
||||
path: '/person',
|
||||
component: () => import('#/views/person/list.vue'),
|
||||
meta: {
|
||||
icon: MaterPerson,
|
||||
title: '个人',
|
||||
order: 5,
|
||||
authority: ['dashboard'],
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export default routes;
|
47
apps/web-antd/src/views/person/list.vue
Normal file
47
apps/web-antd/src/views/person/list.vue
Normal file
@ -0,0 +1,47 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
|
||||
import { Card, Tabs } from 'ant-design-vue';
|
||||
|
||||
import { getUserInfo } from '#/api';
|
||||
import BasicForm from '#/views/person/modules/basic-form.vue';
|
||||
import PasswordForm from '#/views/person/modules/password-form.vue';
|
||||
import UserPanel from '#/views/person/modules/user-panel.vue';
|
||||
|
||||
const userInfo = ref();
|
||||
const permissions = ref();
|
||||
getUserInfo().then((res) => {
|
||||
userInfo.value = res.user;
|
||||
permissions.value = res.permissions;
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex flex-col gap-4 p-4" style="height: 75vh">
|
||||
<Card>
|
||||
<UserPanel :user-info="userInfo" :permissions="permissions" />
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<!-- 使用 Tabs 切换组件 -->
|
||||
<Tabs default-active-key="BasicForm" class="px-4">
|
||||
<Tabs.TabPane key="BasicForm" tab="用户信息">
|
||||
<BasicForm :user-info="userInfo" />
|
||||
</Tabs.TabPane>
|
||||
<Tabs.TabPane key="PasswordForm" tab="修改密码">
|
||||
<PasswordForm />
|
||||
</Tabs.TabPane>
|
||||
</Tabs>
|
||||
</Card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
:deep(.ant-card-body) {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
:deep(.ant-tabs-content) {
|
||||
padding: 16px;
|
||||
}
|
||||
</style>
|
67
apps/web-antd/src/views/person/modules/basic-form.vue
Normal file
67
apps/web-antd/src/views/person/modules/basic-form.vue
Normal file
@ -0,0 +1,67 @@
|
||||
<script setup lang="ts">
|
||||
import { toRefs } from 'vue';
|
||||
|
||||
import { Button, Form, Input, notification } from 'ant-design-vue';
|
||||
|
||||
import { selfUpdate } from '#/api';
|
||||
|
||||
const props = defineProps({
|
||||
// 这里可以定义父组件传递的属性
|
||||
userInfo: {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
username: '',
|
||||
email: '',
|
||||
phone: '',
|
||||
address: '',
|
||||
}),
|
||||
},
|
||||
});
|
||||
const { userInfo } = toRefs(props);
|
||||
|
||||
// 表单提交方法
|
||||
const handleSubmit = async () => {
|
||||
const res = await selfUpdate({
|
||||
username: userInfo.value.username,
|
||||
phone: userInfo.value.phone,
|
||||
email: userInfo.value.email,
|
||||
address: userInfo.value.address,
|
||||
});
|
||||
if (res.code === 200) {
|
||||
notification.success({
|
||||
message: '修改成功',
|
||||
description: '用户信息已更新',
|
||||
duration: 3,
|
||||
});
|
||||
} else {
|
||||
notification.error({
|
||||
message: '修改失败',
|
||||
description: res.msg,
|
||||
});
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Form
|
||||
:model="userInfo"
|
||||
layout="vertical"
|
||||
@finish="handleSubmit"
|
||||
class="p-4"
|
||||
style="max-width: 500px; margin: 0 auto"
|
||||
>
|
||||
<Form.Item label="用户名">
|
||||
<Input v-model:value="userInfo.username" />
|
||||
</Form.Item>
|
||||
<Form.Item label="邮箱" name="email">
|
||||
<Input v-model:value="userInfo.email" />
|
||||
</Form.Item>
|
||||
<Form.Item label="联系电话">
|
||||
<Input v-model:value="userInfo.phone" />
|
||||
</Form.Item>
|
||||
<Form.Item label="地址">
|
||||
<Input v-model:value="userInfo.address" />
|
||||
</Form.Item>
|
||||
<Button type="primary" html-type="submit">保存修改</Button>
|
||||
</Form>
|
||||
</template>
|
83
apps/web-antd/src/views/person/modules/password-form.vue
Normal file
83
apps/web-antd/src/views/person/modules/password-form.vue
Normal file
@ -0,0 +1,83 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
|
||||
import { Button, Form, Input, notification } from 'ant-design-vue';
|
||||
|
||||
import { resetPassword } from '#/api';
|
||||
|
||||
// 密码表单数据
|
||||
const passwordForm = ref({
|
||||
oldPassword: '',
|
||||
password: '',
|
||||
confirmPassword: '',
|
||||
});
|
||||
|
||||
// 提交修改密码的方法
|
||||
const handleSubmit = async () => {
|
||||
if (passwordForm.value.password !== passwordForm.value.confirmPassword) {
|
||||
notification.success({
|
||||
message: '两次输入的新密码不一致',
|
||||
duration: 3,
|
||||
});
|
||||
return;
|
||||
}
|
||||
// 调用API进行密码修改
|
||||
const res = await resetPassword(passwordForm.value);
|
||||
if (res === true) {
|
||||
notification.success({
|
||||
message: '密码修改成功',
|
||||
description: '密码已修改',
|
||||
duration: 3,
|
||||
});
|
||||
passwordForm.value = {
|
||||
oldPassword: '',
|
||||
password: '',
|
||||
confirmPassword: '',
|
||||
};
|
||||
} else {
|
||||
notification.error({
|
||||
message: '密码修改失败',
|
||||
description: res.msg,
|
||||
});
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Form
|
||||
:model="passwordForm"
|
||||
layout="vertical"
|
||||
@finish="handleSubmit"
|
||||
class="p-4"
|
||||
style="max-width: 500px; margin: 0 auto"
|
||||
>
|
||||
<Form.Item
|
||||
label="原密码"
|
||||
name="oldPassword"
|
||||
:rules="[{ required: true, message: '请输入原密码' }]"
|
||||
>
|
||||
<Input.Password v-model:value="passwordForm.oldPassword" />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="新密码"
|
||||
name="password"
|
||||
:rules="[{ required: true, message: '请输入新密码' }]"
|
||||
>
|
||||
<Input.Password v-model:value="passwordForm.password" />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="确认新密码"
|
||||
name="confirmPassword"
|
||||
:rules="[{ required: true, message: '请确认新密码' }]"
|
||||
>
|
||||
<Input.Password v-model:value="passwordForm.confirmPassword" />
|
||||
</Form.Item>
|
||||
<Button type="primary" html-type="submit">保存密码</Button>
|
||||
</Form>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
:deep(.ant-form) {
|
||||
max-width: 500px;
|
||||
}
|
||||
</style>
|
@ -1,37 +1,43 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { toRefs } from 'vue';
|
||||
|
||||
import { Descriptions, Space, Upload } from 'ant-design-vue';
|
||||
import { Avatar, Descriptions, Space } from 'ant-design-vue';
|
||||
|
||||
const fileList = ref([
|
||||
{
|
||||
uid: '-1',
|
||||
name: 'image.png',
|
||||
status: 'done',
|
||||
url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
|
||||
// const fileList = ref([
|
||||
// {
|
||||
// uid: '-1',
|
||||
// name: 'image.png',
|
||||
// status: 'done',
|
||||
// url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
|
||||
// },
|
||||
// ]);
|
||||
|
||||
const props = defineProps({
|
||||
userInfo: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
]);
|
||||
|
||||
// 模拟用户信息数据
|
||||
const userInfo = {
|
||||
username: '张三',
|
||||
email: 'zhangsan@example.com',
|
||||
role: '管理员',
|
||||
department: '技术部',
|
||||
phone: '123-456-7890',
|
||||
};
|
||||
permissions: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
});
|
||||
const { userInfo, permissions } = toRefs(props);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Space :size="54">
|
||||
<Space :size="64" class="p-4">
|
||||
<!-- 用户头像上传组件 -->
|
||||
<Upload
|
||||
list-type="picture-card"
|
||||
:file-list="fileList"
|
||||
:show-upload-button="false"
|
||||
>
|
||||
<!-- 自定义显示头像 -->
|
||||
</Upload>
|
||||
<!-- <Upload-->
|
||||
<!-- list-type="picture-card"-->
|
||||
<!-- :file-list="fileList"-->
|
||||
<!-- :show-upload-button="false"-->
|
||||
<!-- >-->
|
||||
<!-- <!– 自定义显示头像 –>-->
|
||||
<!-- </Upload>-->
|
||||
<Avatar :size="64">
|
||||
{{ userInfo.username }}
|
||||
</Avatar>
|
||||
|
||||
<!-- 用户信息展示 -->
|
||||
<Descriptions title="" size="middle">
|
||||
@ -39,9 +45,9 @@ const userInfo = {
|
||||
{{ userInfo.username }}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="邮箱">{{ userInfo.email }}</Descriptions.Item>
|
||||
<Descriptions.Item label="角色">{{ userInfo.role }}</Descriptions.Item>
|
||||
<Descriptions.Item label="角色">{{ permissions }}</Descriptions.Item>
|
||||
<Descriptions.Item label="部门">
|
||||
{{ userInfo.department }}
|
||||
{{ userInfo.dept?.name }}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="联系电话">
|
||||
{{ userInfo.phone }}
|
||||
|
@ -97,7 +97,7 @@ export function useFormSchema(): VbenFormSchema[] {
|
||||
labelField: 'name',
|
||||
valueField: 'id',
|
||||
},
|
||||
fieldName: 'roleIds',
|
||||
fieldName: 'roleId',
|
||||
label: '所属角色',
|
||||
},
|
||||
{
|
||||
|
@ -36,6 +36,8 @@ const [Drawer, drawerApi] = useVbenDrawer({
|
||||
const { valid } = await formApi.validate();
|
||||
if (!valid) return;
|
||||
const values = await formApi.getValues();
|
||||
values.roleIds = values.roleId;
|
||||
delete values.roleId;
|
||||
drawerApi.lock();
|
||||
(id.value ? updateUser(id.value, values) : createUser(values))
|
||||
.then(() => {
|
||||
|
Loading…
Reference in New Issue
Block a user