feat(@vben/common-ui): 添加个人中心功能- 新增个人中心页面,包含用户信息展示和修改、密码修改等功能
This commit is contained in:
parent
5026ae0bbd
commit
d3c25dd899
@ -93,6 +93,14 @@ export namespace UserApi {
|
|||||||
permissions?: string[] | undefined;
|
permissions?: string[] | undefined;
|
||||||
authorities?: string[];
|
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);
|
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);
|
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">
|
<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([
|
// const fileList = ref([
|
||||||
{
|
// {
|
||||||
uid: '-1',
|
// uid: '-1',
|
||||||
name: 'image.png',
|
// name: 'image.png',
|
||||||
status: 'done',
|
// status: 'done',
|
||||||
url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
|
// url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
|
||||||
|
// },
|
||||||
|
// ]);
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
userInfo: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({}),
|
||||||
},
|
},
|
||||||
]);
|
permissions: {
|
||||||
|
type: String,
|
||||||
// 模拟用户信息数据
|
default: '',
|
||||||
const userInfo = {
|
},
|
||||||
username: '张三',
|
});
|
||||||
email: 'zhangsan@example.com',
|
const { userInfo, permissions } = toRefs(props);
|
||||||
role: '管理员',
|
|
||||||
department: '技术部',
|
|
||||||
phone: '123-456-7890',
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Space :size="54">
|
<Space :size="64" class="p-4">
|
||||||
<!-- 用户头像上传组件 -->
|
<!-- 用户头像上传组件 -->
|
||||||
<Upload
|
<!-- <Upload-->
|
||||||
list-type="picture-card"
|
<!-- list-type="picture-card"-->
|
||||||
:file-list="fileList"
|
<!-- :file-list="fileList"-->
|
||||||
:show-upload-button="false"
|
<!-- :show-upload-button="false"-->
|
||||||
>
|
<!-- >-->
|
||||||
<!-- 自定义显示头像 -->
|
<!-- <!– 自定义显示头像 –>-->
|
||||||
</Upload>
|
<!-- </Upload>-->
|
||||||
|
<Avatar :size="64">
|
||||||
|
{{ userInfo.username }}
|
||||||
|
</Avatar>
|
||||||
|
|
||||||
<!-- 用户信息展示 -->
|
<!-- 用户信息展示 -->
|
||||||
<Descriptions title="" size="middle">
|
<Descriptions title="" size="middle">
|
||||||
@ -39,9 +45,9 @@ const userInfo = {
|
|||||||
{{ userInfo.username }}
|
{{ userInfo.username }}
|
||||||
</Descriptions.Item>
|
</Descriptions.Item>
|
||||||
<Descriptions.Item label="邮箱">{{ userInfo.email }}</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="部门">
|
<Descriptions.Item label="部门">
|
||||||
{{ userInfo.department }}
|
{{ userInfo.dept?.name }}
|
||||||
</Descriptions.Item>
|
</Descriptions.Item>
|
||||||
<Descriptions.Item label="联系电话">
|
<Descriptions.Item label="联系电话">
|
||||||
{{ userInfo.phone }}
|
{{ userInfo.phone }}
|
||||||
|
@ -97,7 +97,7 @@ export function useFormSchema(): VbenFormSchema[] {
|
|||||||
labelField: 'name',
|
labelField: 'name',
|
||||||
valueField: 'id',
|
valueField: 'id',
|
||||||
},
|
},
|
||||||
fieldName: 'roleIds',
|
fieldName: 'roleId',
|
||||||
label: '所属角色',
|
label: '所属角色',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -36,6 +36,8 @@ const [Drawer, drawerApi] = useVbenDrawer({
|
|||||||
const { valid } = await formApi.validate();
|
const { valid } = await formApi.validate();
|
||||||
if (!valid) return;
|
if (!valid) return;
|
||||||
const values = await formApi.getValues();
|
const values = await formApi.getValues();
|
||||||
|
values.roleIds = values.roleId;
|
||||||
|
delete values.roleId;
|
||||||
drawerApi.lock();
|
drawerApi.lock();
|
||||||
(id.value ? updateUser(id.value, values) : createUser(values))
|
(id.value ? updateUser(id.value, values) : createUser(values))
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
Loading…
Reference in New Issue
Block a user