个人中心

前言

Uniboot 模板项目提供了两套针对个人中心(用户基本资料、绑定邮箱修改、登录历史查看、用户密码修改)的不同设计模式:Simple 模板(本地定制化模式)Auth 模板(核心插件注入模式)。两套设计完美兼顾了前端二次开发灵活性与核心模块的免维护高度整合。

个人设置简介

模板项目的个人中心基于大系统集成的维度,提供了不同的实现方式:

  • Simple 模板:为了让开发者能在当前应用中任意扩展或修改个人中心的表单项、安全策略及交互,页面源码直接实现并暴露在项目本地。
  • Auth 模板:为了让各子系统与统一用户中心(或 SSO 授权中心)在个人设置界面和交互接口上保持高度的一致性,系统不提供本地页面源码,而是通过引导生命周期中的核心插件动态拦截并无感知地注入路由和 UI 面板。

Simple 模板个人中心 (本地定制化模式)

Simple 模板项目直接将页面源码放置在本地:src/views/account/profile.vue

本地页面结构与内置面板

页面结构依托 uniboot-ui 组件库提供的 <ProfilePage> 进行网格架设,默认开启了 builtin-panels(内置面板):

vue
<template>
  <div class="user-center-page">
    <ProfilePage
      fill-container
      v-model:active-key="activeKey"
      v-model:basic-profile="basicProfile"
      builtin-panels
      :menus="menus"
      :nick-name="nickNameDisplay"
      :role-names="roleNamesDisplay"
      :login-meta="loginMetaDisplay"
      :security-email="maskedEmail"
      :change-email-current-email="currentEmail"
      :show-basic-edit-button="false"
      center-max-width="960px"
      :background="pageBackground"
      :on-back="handleBack"
      :on-send-old-email-code="onSendOldEmailCode"
      :on-send-new-email-code="onSendNewEmailCode"
      :on-verify-old-email-code="onVerifyOldEmailCode"
      :on-change-email-finish="onChangeEmailFinish"
      :on-change-password-finish="onChangePasswordFinish"
    />
  </div>
</template>

在前端脚本中,我们通过监听 Pinia store 中的 userInfo 响应式数据,处理并供给组件所需的各种展示字段:

  • 角色信息映射:使用辅助函数将角色标识(如 admin)利用多语言翻译映射后输出给 roleNamesDisplay
  • 登录记录:提取 loginIploginTime 作为 loginMetaDisplay
  • 安全脱敏:将原始邮箱地址脱敏处理(保留首尾字符,中间遮蔽为星号 ****)后赋给 maskedEmail 选项,以规避隐私泄露安全隐患。

交互事件绑定与本地方案 API 接入

个人中心的安全操作涉及到邮箱验证码的发送、旧邮箱验证、新邮箱保存和密码重设。这些复杂的异步交互流程通过组件的属性回调函数(Callback Props)直接绑定至本地 src/api/user.ts 所配置的 API 上:

ts
import {
  changePassword,
  checkEmailCode,
  sendEmailCode,
  sendNewEmailCode,
  updateEmail,
} from '@/api/user'

// 1. 获取验证老邮箱的验证码 Token
async function onSendOldEmailCode() {
  const data = (await sendEmailCode()) as { codeToken: string }
  return { codeToken: data.codeToken }
}

// 2. 发送验证码到新绑定的邮箱
async function onSendNewEmailCode(email: string) {
  const data = (await sendNewEmailCode(email)) as { codeToken: string }
  return { codeToken: data.codeToken }
}

// 3. 验证老邮箱验证码
async function onVerifyOldEmailCode(payload: {
  code: string
  codeToken: string
}) {
  await checkEmailCode({ codeToken: payload.codeToken, code: payload.code })
  return true
}

// 4. 完成新邮箱的持久化绑定并同步刷新前端用户信息
async function onChangeEmailFinish(payload: {
  email: string
  code: string
  codeToken: string
}) {
  await updateEmail({
    email: payload.email,
    code: payload.code,
    codeToken: payload.codeToken,
  })
  await userStore.getUserInfo() // 重新拉取用户信息
  return true
}

// 5. 修改当前账户的登录密码(组件内已对密码做 SHA-256 摘要后传入)
async function onChangePasswordFinish(payload: {
  oldPassword: string
  newPassword: string
}) {
  await changePassword({
    newPassword: payload.newPassword,
    oldPassword: payload.oldPassword,
  })
  return true
}

Auth 模板个人中心 (核心插件注入模式)

由于对接了 Java 后端统一授权服务中心(SSO),Auth 模板的前端源码目录 src/views/account不提供任何个人中心的页面代码文件。页面在运行时完全由核心插件代理装载。

插件装载与动态路由注册

在程序初始化和挂载前端路由之前,系统在 src/install/plugins/uniboot-admin.ts 中注册并执行 installUnibootAdmin。它通过 @uniboot/adminsetupUnibootAdmin,动态注册个人中心等账号域路由,并注入实时用户与 API 依赖:

ts
import { setupUnibootAdmin } from '@uniboot/admin'

setupUnibootAdmin(app, {
  router,
  i18n,
  layout: LAYOUT,
  adminApi,
  userApi,
  roleApi,
  liveUser: () => useUserStore().userInfo,
  paths: {
    forget: PageEnum.FORGET,
    initialPassword: PageEnum.MODIFY_INIT_PWD,
    profile: PageEnum.PROFILE,
  },
  user: {
    snapshot: () => useUserStore().userInfo,
    logout: () => useUserStore().logout(),
    refreshUser: () => useUserStore().getUserInfo(),
  },
  // ...
})

数据通信解耦与核心层代理

setupUnibootAdmin 内部会 provide(UNIBOOT_ADMIN_PROFILE_LIVE_USER, liveUser),使个人中心始终读取 Pinia Store 内当前实时更新的 userInfo,与路由 props 解耦。

当用户点击侧边栏头像下拉菜单的「个人中心」时,路由器会匹配由 setupUnibootAdmin 注册好的 /profile。底层组件通过注入的实时用户 getter 渲染数据;改密或换邮箱时直接使用 adminApi,表单布局和逻辑完全托管,无需业务侧重复编写胶水代码。