diff --git a/apps/vben5/apps/app-antd/src/layouts/basic.vue b/apps/vben5/apps/app-antd/src/layouts/basic.vue index 51412956a..bc20b84e5 100644 --- a/apps/vben5/apps/app-antd/src/layouts/basic.vue +++ b/apps/vben5/apps/app-antd/src/layouts/basic.vue @@ -2,11 +2,17 @@ import type { NotificationItem } from '@vben/layouts'; import { computed, ref, watch } from 'vue'; +import { useRouter } from 'vue-router'; import { AuthenticationLoginExpiredModal } from '@vben/common-ui'; import { VBEN_DOC_URL, VBEN_GITHUB_URL } from '@vben/constants'; import { useWatermark } from '@vben/hooks'; -import { BookOpenText, CircleHelp, MdiGithub } from '@vben/icons'; +import { + BookOpenText, + CircleHelp, + createIconifyIcon, + MdiGithub, +} from '@vben/icons'; import { BasicLayout, LockScreen, @@ -21,6 +27,8 @@ import { $t } from '#/locales'; import { useAuthStore } from '#/store'; import LoginForm from '#/views/_core/authentication/login.vue'; +const UserSettingsIcon = createIconifyIcon('tdesign:user-setting'); + const notifications = ref([ { avatar: 'https://avatar.vercel.sh/vercel.svg?text=VB', @@ -52,6 +60,7 @@ const notifications = ref([ }, ]); +const { replace } = useRouter(); const userStore = useUserStore(); const authStore = useAuthStore(); const accessStore = useAccessStore(); @@ -61,6 +70,13 @@ const showDot = computed(() => ); const menus = computed(() => [ + { + handler: () => { + replace('/account/my-settings'); + }, + icon: UserSettingsIcon, + text: $t('abp.account.settings.title'), + }, { handler: () => { openWindow(VBEN_DOC_URL, { @@ -127,10 +143,10 @@ watch( diff --git a/apps/vben5/apps/app-antd/src/locales/langs/en-US/abp.json b/apps/vben5/apps/app-antd/src/locales/langs/en-US/abp.json index 25ec69283..111ddf7c6 100644 --- a/apps/vben5/apps/app-antd/src/locales/langs/en-US/abp.json +++ b/apps/vben5/apps/app-antd/src/locales/langs/en-US/abp.json @@ -28,5 +28,28 @@ "authorizations": "Authorizations", "scopes": "Scopes", "tokens": "Tokens" + }, + "account": { + "title": "Account", + "settings": { + "title": "My Settings", + "basic": { + "title": "Basic Settings" + }, + "security": { + "title": "Security Settings", + "verified": "Verified", + "unVerified": "Not Verified", + "email": "Email", + "password": "Password", + "passwordDesc": "Reset My Password", + "phoneNumber": "PhoneNumber" + }, + "bindSettings": "Bind Settings", + "noticeSettings": "Notice Settings", + "authenticatorSettings": "Authenticator Settings", + "changeAvatar": "Change Avatar" + }, + "profile": "My Profile" } } diff --git a/apps/vben5/apps/app-antd/src/locales/langs/zh-CN/abp.json b/apps/vben5/apps/app-antd/src/locales/langs/zh-CN/abp.json index bd4920650..8d0a0f3ee 100644 --- a/apps/vben5/apps/app-antd/src/locales/langs/zh-CN/abp.json +++ b/apps/vben5/apps/app-antd/src/locales/langs/zh-CN/abp.json @@ -28,5 +28,28 @@ "authorizations": "授权管理", "scopes": "范围管理", "tokens": "授权令牌" + }, + "account": { + "title": "账户管理", + "settings": { + "title": "个人设置", + "basic": { + "title": "基本设置" + }, + "security": { + "title": "安全设置", + "verified": "已验证", + "unVerified": "未验证", + "email": "电子邮件", + "password": "密码", + "passwordDesc": "重置我的密码", + "phoneNumber": "手机号码" + }, + "bindSettings": "账号绑定", + "noticeSettings": "新消息通知", + "authenticatorSettings": "身份验证程序", + "changeAvatar": "更改头像" + }, + "profile": "个人中心" } } diff --git a/apps/vben5/apps/app-antd/src/router/routes/modules/abp.ts b/apps/vben5/apps/app-antd/src/router/routes/modules/abp.ts index 7fcd60a98..376a6f185 100644 --- a/apps/vben5/apps/app-antd/src/router/routes/modules/abp.ts +++ b/apps/vben5/apps/app-antd/src/router/routes/modules/abp.ts @@ -198,6 +198,26 @@ const routes: RouteRecordRaw[] = [ }, ], }, + { + name: 'Account', + path: '/account', + meta: { + title: $t('abp.account.title'), + icon: 'mdi:account-outline', + hideInMenu: true, + }, + children: [ + { + meta: { + title: $t('abp.account.settings.title'), + icon: 'tdesign:user-setting', + }, + name: 'MySettings', + path: '/account/my-settings', + component: () => import('#/views/account/my-settings/index.vue'), + }, + ], + }, ], }, ]; diff --git a/apps/vben5/apps/app-antd/src/store/auth.ts b/apps/vben5/apps/app-antd/src/store/auth.ts index 1953c88f0..407426e9a 100644 --- a/apps/vben5/apps/app-antd/src/store/auth.ts +++ b/apps/vben5/apps/app-antd/src/store/auth.ts @@ -99,12 +99,18 @@ export const useAuthStore = defineStore('auth', () => { const userInfoRes = await getUserInfoApi(); const abpConfig = await getConfigApi(); userInfo = { - userId: userInfoRes.sub, - username: userInfoRes.uniqueName, - realName: userInfoRes.name, + userId: userInfoRes.sub ?? abpConfig.currentUser.id, + username: userInfoRes.uniqueName ?? abpConfig.currentUser.userName, + realName: userInfoRes.name ?? abpConfig.currentUser.name, avatar: userInfoRes.avatarUrl ?? userInfoRes.picture, desc: userInfoRes.uniqueName ?? userInfoRes.name, email: userInfoRes.email ?? userInfoRes.email, + emailVerified: + userInfoRes.emailVerified ?? abpConfig.currentUser.emailVerified, + phoneNumber: userInfoRes.phoneNumber ?? abpConfig.currentUser.phoneNumber, + phoneNumberVerified: + userInfoRes.phoneNumberVerified ?? + abpConfig.currentUser.phoneNumberVerified, token: '', roles: abpConfig.currentUser.roles, homePath: '/', diff --git a/apps/vben5/apps/app-antd/src/views/account/my-profile/index.vue b/apps/vben5/apps/app-antd/src/views/account/my-profile/index.vue new file mode 100644 index 000000000..bb567c555 --- /dev/null +++ b/apps/vben5/apps/app-antd/src/views/account/my-profile/index.vue @@ -0,0 +1,15 @@ + + + diff --git a/apps/vben5/apps/app-antd/src/views/account/my-settings/index.vue b/apps/vben5/apps/app-antd/src/views/account/my-settings/index.vue new file mode 100644 index 000000000..0ce7db2d0 --- /dev/null +++ b/apps/vben5/apps/app-antd/src/views/account/my-settings/index.vue @@ -0,0 +1,15 @@ + + + diff --git a/apps/vben5/packages/@abp/account/package.json b/apps/vben5/packages/@abp/account/package.json index 64bb473bd..c0b1ddb0e 100644 --- a/apps/vben5/packages/@abp/account/package.json +++ b/apps/vben5/packages/@abp/account/package.json @@ -23,9 +23,16 @@ "@abp/core": "workspace:*", "@abp/request": "workspace:*", "@abp/ui": "workspace:*", + "@ant-design/icons-vue": "catalog:", + "@vben-core/shadcn-ui": "workspace:*", + "@vben/common-ui": "workspace:*", "@vben/hooks": "workspace:*", "@vben/layouts": "workspace:*", "@vben/locales": "workspace:*", + "@vben/preferences": "workspace:*", + "@vben/stores": "workspace:*", + "@vueuse/core": "catalog:", + "@vueuse/integrations": "catalog:", "ant-design-vue": "catalog:", "vue": "catalog:*" } diff --git a/apps/vben5/packages/@abp/account/src/api/index.ts b/apps/vben5/packages/@abp/account/src/api/index.ts index a082efc18..48ec78a52 100644 --- a/apps/vben5/packages/@abp/account/src/api/index.ts +++ b/apps/vben5/packages/@abp/account/src/api/index.ts @@ -1,2 +1,3 @@ +export { useProfileApi } from './useProfileApi'; export { useTokenApi } from './useTokenApi'; export { useUserInfoApi } from './useUserInfoApi'; diff --git a/apps/vben5/packages/@abp/account/src/api/useProfileApi.ts b/apps/vben5/packages/@abp/account/src/api/useProfileApi.ts new file mode 100644 index 000000000..53aaaf54a --- /dev/null +++ b/apps/vben5/packages/@abp/account/src/api/useProfileApi.ts @@ -0,0 +1,117 @@ +import type { + AuthenticatorDto, + AuthenticatorRecoveryCodeDto, + ChangePasswordInput, + ProfileDto, + TwoFactorEnabledDto, + UpdateProfileDto, + VerifyAuthenticatorCodeInput, +} from '../types/profile'; + +import { useRequest } from '@abp/request'; + +export function useProfileApi() { + const { cancel, request } = useRequest(); + + /** + * 查询个人信息 + * @returns 个人信息 + */ + function getApi(): Promise { + return request('/api/account/my-profile', { + method: 'GET', + }); + } + + /** + * 更新个人信息 + * @param input 参数 + * @returns 个人信息 + */ + function updateApi(input: UpdateProfileDto): Promise { + return request('/api/account/my-profile', { + data: input, + method: 'PUT', + }); + } + + /** + * 修改密码 + * @param input 参数 + */ + function changePasswordApi(input: ChangePasswordInput): Promise { + return request('/api/account/my-profile/change-password', { + data: input, + method: 'POST', + }); + } + + /** + * 获取二次认证启用状态 + */ + function getTwoFactorEnabledApi(): Promise { + return request('/api/account/my-profile/two-factor', { + method: 'GET', + }); + } + + /** + * 设置二次认证启用状态 + */ + function changeTwoFactorEnabledApi( + input: TwoFactorEnabledDto, + ): Promise { + return request('/api/account/my-profile/change-two-factor', { + data: input, + method: 'PUT', + }); + } + + /** + * 获取身份验证器配置 + * @returns 身份验证器 + */ + function getAuthenticatorApi(): Promise { + return request('/api/account/my-profile/authenticator', { + method: 'GET', + }); + } + + /** + * 验证身份验证代码 + * @param input 参数 + * @returns 重置代码 + */ + function verifyAuthenticatorCodeApi( + input: VerifyAuthenticatorCodeInput, + ): Promise { + return request( + '/api/account/my-profile/verify-authenticator-code', + { + data: input, + method: 'POST', + }, + ); + } + + /** + * 重置验证器 + */ + function resetAuthenticatorApi(): Promise { + return request('/api/account/my-profile/reset-authenticator', { + method: 'POST', + }); + } + + return { + cancel, + changePasswordApi, + changeTwoFactorEnabledApi, + getApi, + getAuthenticatorApi, + getTwoFactorEnabledApi, + resetAuthenticatorApi, + updateApi, + verifyAuthenticatorCodeApi, + }; +} diff --git a/apps/vben5/packages/@abp/account/src/components/MyProfile.vue b/apps/vben5/packages/@abp/account/src/components/MyProfile.vue new file mode 100644 index 000000000..a17f9b5eb --- /dev/null +++ b/apps/vben5/packages/@abp/account/src/components/MyProfile.vue @@ -0,0 +1,181 @@ + + + + + diff --git a/apps/vben5/packages/@abp/account/src/components/MySetting.vue b/apps/vben5/packages/@abp/account/src/components/MySetting.vue new file mode 100644 index 000000000..f014c90fa --- /dev/null +++ b/apps/vben5/packages/@abp/account/src/components/MySetting.vue @@ -0,0 +1,128 @@ + + + + + diff --git a/apps/vben5/packages/@abp/account/src/components/components/AuthenticatorSettings.vue b/apps/vben5/packages/@abp/account/src/components/components/AuthenticatorSettings.vue new file mode 100644 index 000000000..f23859c11 --- /dev/null +++ b/apps/vben5/packages/@abp/account/src/components/components/AuthenticatorSettings.vue @@ -0,0 +1,70 @@ + + + + + diff --git a/apps/vben5/packages/@abp/account/src/components/components/AuthenticatorSteps.vue b/apps/vben5/packages/@abp/account/src/components/components/AuthenticatorSteps.vue new file mode 100644 index 000000000..e337b11c9 --- /dev/null +++ b/apps/vben5/packages/@abp/account/src/components/components/AuthenticatorSteps.vue @@ -0,0 +1,210 @@ + + + + + diff --git a/apps/vben5/packages/@abp/account/src/components/components/BasicSettings.vue b/apps/vben5/packages/@abp/account/src/components/components/BasicSettings.vue new file mode 100644 index 000000000..f7c402b93 --- /dev/null +++ b/apps/vben5/packages/@abp/account/src/components/components/BasicSettings.vue @@ -0,0 +1,130 @@ + + + + + diff --git a/apps/vben5/packages/@abp/account/src/components/components/BindSettings.vue b/apps/vben5/packages/@abp/account/src/components/components/BindSettings.vue new file mode 100644 index 000000000..60ea57efc --- /dev/null +++ b/apps/vben5/packages/@abp/account/src/components/components/BindSettings.vue @@ -0,0 +1,11 @@ + + + + + diff --git a/apps/vben5/packages/@abp/account/src/components/components/NoticeSettings.vue b/apps/vben5/packages/@abp/account/src/components/components/NoticeSettings.vue new file mode 100644 index 000000000..80b2914e0 --- /dev/null +++ b/apps/vben5/packages/@abp/account/src/components/components/NoticeSettings.vue @@ -0,0 +1,11 @@ + + + + + diff --git a/apps/vben5/packages/@abp/account/src/components/components/SecuritySettings.vue b/apps/vben5/packages/@abp/account/src/components/components/SecuritySettings.vue new file mode 100644 index 000000000..bf5f5ebd6 --- /dev/null +++ b/apps/vben5/packages/@abp/account/src/components/components/SecuritySettings.vue @@ -0,0 +1,131 @@ + + + + + diff --git a/apps/vben5/packages/@abp/account/src/components/index.ts b/apps/vben5/packages/@abp/account/src/components/index.ts new file mode 100644 index 000000000..691de32ef --- /dev/null +++ b/apps/vben5/packages/@abp/account/src/components/index.ts @@ -0,0 +1,2 @@ +export { default as MyProfile } from './MyProfile.vue'; +export { default as MySetting } from './MySetting.vue'; diff --git a/apps/vben5/packages/@abp/account/src/index.ts b/apps/vben5/packages/@abp/account/src/index.ts index 4d4b4e299..314dad0cd 100644 --- a/apps/vben5/packages/@abp/account/src/index.ts +++ b/apps/vben5/packages/@abp/account/src/index.ts @@ -1,2 +1,3 @@ export * from './api'; +export * from './components'; export * from './types'; diff --git a/apps/vben5/packages/@abp/account/src/types/index.ts b/apps/vben5/packages/@abp/account/src/types/index.ts index 76ba2a014..8a346ac61 100644 --- a/apps/vben5/packages/@abp/account/src/types/index.ts +++ b/apps/vben5/packages/@abp/account/src/types/index.ts @@ -1,2 +1,3 @@ +export * from './profile'; export * from './token'; export * from './user'; diff --git a/apps/vben5/packages/@abp/account/src/types/profile.ts b/apps/vben5/packages/@abp/account/src/types/profile.ts new file mode 100644 index 000000000..3ce01df4f --- /dev/null +++ b/apps/vben5/packages/@abp/account/src/types/profile.ts @@ -0,0 +1,66 @@ +import type { ExtensibleObject, IHasConcurrencyStamp } from '@abp/core'; + +interface ProfileDto extends ExtensibleObject, IHasConcurrencyStamp { + /** 电子邮件 */ + email: string; + hasPassword: boolean; + /** 是否外部用户 */ + isExternal: boolean; + /** 名称 */ + name?: string; + /** 手机号码 */ + phoneNumber?: string; + /** 姓氏 */ + surname?: string; + /** 用户名 */ + userName: string; +} + +interface UpdateProfileDto extends ExtensibleObject, IHasConcurrencyStamp { + /** 电子邮件 */ + email: string; + /** 名称 */ + name?: string; + /** 手机号码 */ + phoneNumber?: string; + /** 姓氏 */ + surname?: string; + /** 用户名 */ + userName: string; +} + +interface ChangePasswordInput { + /** 当前密码 */ + currentPassword: string; + /** 新密码 */ + newPassword: string; +} + +interface TwoFactorEnabledDto { + /** 是否启用二次认证 */ + enabled: boolean; +} + +interface AuthenticatorDto { + authenticatorUri: string; + isAuthenticated: boolean; + sharedKey: string; +} + +interface VerifyAuthenticatorCodeInput { + authenticatorCode: string; +} + +interface AuthenticatorRecoveryCodeDto { + recoveryCodes: string[]; +} + +export type { + AuthenticatorDto, + AuthenticatorRecoveryCodeDto, + ChangePasswordInput, + ProfileDto, + TwoFactorEnabledDto, + UpdateProfileDto, + VerifyAuthenticatorCodeInput, +}; diff --git a/apps/vben5/packages/@abp/account/src/types/user.ts b/apps/vben5/packages/@abp/account/src/types/user.ts index b571e11a3..c0d40bf07 100644 --- a/apps/vben5/packages/@abp/account/src/types/user.ts +++ b/apps/vben5/packages/@abp/account/src/types/user.ts @@ -11,7 +11,7 @@ interface UserInfo { /** * 名称 */ - givenName: string; + givenName?: string; /** * 用户名 */