# 6.15 首页与个人中心 :::tip 概述 index 模块(无表,聚合 user/menu)提供个人中心五接口:当前用户信息(超管返回通配权限)、菜单树、修改密码、更新个人信息。路由前缀 /api/index,登录即可(无 permission 节点)。 ::: ## 接口清单 | 方法 | 路由 | 权限 | 说明 | |------|------|------|------| | GET | /api/index/getUser | 登录即可 | 当前用户信息(超管返回 `*:*:*`) | | GET | /api/index/getMenus | 登录即可 | 当前用户菜单树(前端 common 菜单调用) | | GET | /api/index/getMenus/:id | 登录即可 | 同上(system/menu 页面调用) | | PUT | /api/index/updatePassword | 登录即可 | 修改个人密码(旧密码校验) | | PUT | /api/index/updateProfile | 登录即可 | 更新个人信息 | ## GetUser(当前用户信息) ```text 数据来源与安全边界: * 用户行经 dao.User.Ctx(自动过滤软删/租户);password/salt 永不返回 * Roles/Perms 优先取 JWT 中间件注入的 ctx(与鉴权同源),为空时回源 LoadIdentity * 超管强制 perms=["*:*:*"](前端据此放开全部按钮) * 头像经 upload.GetFileUrl 补域名 * 城市编码四列(province/city/district/street_code)组装为 city[] 数组; city_info 为空时用 ResolveCityNames 按编码回填名称 ``` ## GetMenus(菜单树) ```text 两条路由共用 getMenuTree: * 仅取 type=0(目录/菜单)且 status=0 且 hide=0 的节点 ——按钮权限节点不进菜单树,由 GetUser.permissions 下发 * 超管全量;其余 user→user_role→role_menu→menu.id IN(...) 授权过滤 * 无角色返回空树([] 非 null) * 挂树规则:父节点不在授权集合内(未授权/顶级)一律挂根,避免菜单丢失 * 排序 sort,id(根级再按 sort+id 兜底稳定排序) ``` ## UpdatePassword(修改密码) ```text 流程: 1) 只取 id/password/salt 三列 2) 旧密码 IsBcrypt + VerifyPassword 校验(错误 1012 原密码错误) 3) 事务外 GenerateSalt + HashPassword(CPU 密集预计算) 4) Update 覆盖 password/salt(update_user/time 由 hooks 盖章) 注意:改密后未强制下线(令牌仍有效至过期); 如需立即失效可配合在线用户强退(见 6.16 在线用户监控) ``` ## UpdateProfile(更新个人信息) ```text 流程: * 头像 SaveFileField(avatar, "user") 临时转正 * 城市优先由编码数组经 ResolveCityNames 解析名称覆盖 city_info * 四列编码经 cityCodeAt(req.City, i) 取值写入 安全边界:不触达 username/password/tenant 等敏感列 ``` ## 前端消费 ```text 登录后首页 dashboard:调 getUser(头像/名称/权限)+ getMenus(侧边菜单) 路由守卫:动态路由由 getMenus 生成(见 9.5 路由与动态菜单) 个人中心页:updateProfile(资料)/ updatePassword(改密) ``` ## 排障 | 症状 | 原因 | |------|------| | 菜单为空 | 无角色或角色未勾选菜单;超管应返回全量 | | getUser 权限缺失 | 身份缓存异常;超管应返回 `*:*:*` | | 改密后旧令牌仍可用 | 设计预期(不强制下线);配合在线用户强退 | | 头像不显示 | upload.GetFileUrl 域名配置(file.domainUrl)与静态服务根 |