--- name: session-20260613-3 description: 2026-06-13 第3次会话 — 头像401、菜单check-strictly、移动端全面优化、token/info接口、唯一键校验、数据权限、文档更新 metadata: type: session date: 2026-06-13 sessionNumber: 3 startTime: 2026-06-13T00:00:00+08:00 --- # 2026-06-13 第3次会话 — 完整记录 ## 一、头像 401 修复 **根因**:文件服务 Token 一次一密,PersonalView.vue 上传和下载共用一个 Token,带 Token 的 URL 存入数据库 → 永久 401。 **修复**: - `auth.ts`:fetchUserInfo() 和 login() 先刷新 Token 再设 userInfo - `PersonalView.vue`:上传用 Token1(消费),下载用 Token2(新获取),DB 只存基础 URL ## 二、分配菜单 check-strictly **RoleList.vue**:el-tree 加 `check-strictly`,节点独立勾选,父子不联动。 - 可以只勾"系统列表"不给新增/编辑/删除 ## 三、移动端全面优化 ### 3.1 操作列 → 桌面按钮行 / 手机卡片按钮 不再使用 CSS dropdown hack,改用 `useIsMobile()` composable + `v-if` **composable**: `src/composables/useIsMobile.ts` — 响应式检测屏幕 ≤768px **已改造**:RoleList, UserList, SystemList, MenuList, DictList, ApiList, FileList, EmailList, LoginLogList, OperationLogList, OpenTokenLogList ### 3.2 表单按钮全局统一 `global.css`:移动端 `.form-footer { flex-direction: column }` 取消/保存按钮等宽上下排列 ### 3.3 分页滚动 `main.ts`:监听分页点击 → `window.scrollTo({ top: 0, behavior: 'smooth' })` ### 3.4 卡片样式 `global.css`:`.mobile-cards` / `.mobile-card` / `.card-field` / `.card-actions` ## 四、新增 GET /token/info 接口 - `OpenApiController.java`:`GET /zgapi/v1/open/token/info?token=xxx` - 不消费 Token,从 JWT 解析 systemId/systemCode/systemName - `TokenAuthFilter.java`:放行 `/zgapi/v1/open/token/info` - `open-api-doc.md`:新增 §4 ## 五、所有新增接口唯一键校验 | 接口 | 唯一约束 | 修复 | |------|----------|------| | 新增系统 | uk_system_code + uk_gateway_url | ✅ gatewayUrl 自动生成唯一值 | | 新增用户 | uk_username + uk_email | ✅ 空邮箱→null,重复提示中文 | | 新增角色 | uk_system_role_code | ✅ 系统+编码重复提示 | | 新增字典 | uk_type_value | ✅ 类型+值重复提示 | | 新增接口 | uk_system_path_method | ✅ 系统+路径+方法重复提示 | ## 六、全局数据权限 **架构**:`UserContextInterceptor` → `UserContextHolder`(ThreadLocal) → Service 层过滤 **规则**:roleCode=super_admin 看全部;其他角色只看绑定系统(sys_user_system)的数据 **新增文件**: - `config/UserContextHolder.java` — ThreadLocal - `config/UserContextInterceptor.java` — 拦截器,读 X-User-Roles 头 - `config/WebMvcConfig.java` — 注册拦截器 **修改的 Service**: - RoleServiceImpl.page() — in(systemIds) - SystemApiServiceImpl.page() — in(systemIds) - LogServiceImpl.loginLogPage() — in(systemIds) - UserServiceImpl.page() — 通过 sys_user_system 关联过滤 - SystemServiceImpl.page() — in(systemIds) - SystemServiceImpl.add() — gatewayUrl 唯一值 **不做过滤**: - 操作日志、Token日志(用户指定不要) - 字典、邮件(无 system_id) ## 七、FileList 系统筛选 - 搜索栏新增"所属系统"下拉(systemCode / systemName) - 表格新增"所属系统"列 - systemId 传给后端过滤 ## 八、接入文档更新 ### IntegrationDoc.vue(页面内文档) - **§9.3** 下载文件:Token 支持 Header 和 Query 参数两种方式 - **§10** 新增对外开放 API 章节(Token 获取 + 邮件发送) - **§3** 前端接入:localStorage → Cookie 读取 Token,说明跨域 Cookie 机制 - **§3.5** 登录回调:完整说明 Cookie Token 流程 ### open-api-doc.md(独立文档) - 下载文件 curl 示例增加 Query 参数方式 - 所有文档章节重新编号 ## 修改文件总清单 **后端新增**: - `config/UserContextHolder.java` - `config/UserContextInterceptor.java` - `config/WebMvcConfig.java` **后端修改**: - `OpenApiController.java` — +GET /token/info - `TokenAuthFilter.java` — 放行 /token/info - `UserServiceImpl.java` — 重复校验 + 数据权限 + 空邮箱→null - `SystemServiceImpl.java` — systemCode/gatewayUrl 唯一性 + 数据权限 - `RoleServiceImpl.java` — 角色编码唯一性 + 数据权限 - `DictServiceImpl.java` — 字典值唯一性 - `SystemApiServiceImpl.java` — 接口唯一性 + 数据权限 - `LogServiceImpl.java` — 登录日志数据权限(操作日志不过滤) - `FileController.java` — systemId 过滤已支持 **前端新增**: - `composables/useIsMobile.ts` **前端修改**: - `auth.ts` — 头像 Token 刷新 - `PersonalView.vue` — 头像双 Token - `global.css` — 移动端卡片 + 表单按钮 - `main.ts` — 分页滚动 - `RoleList.vue` — check-strictly + 手机卡片 - `UserList.vue` — 手机卡片 - `SystemList.vue` — 手机卡片 - `MenuList.vue` — 手机卡片 - `DictList.vue` — 手机卡片 - `ApiList.vue` — 手机卡片 - `FileList.vue` — 系统下拉过滤 - `EmailList.vue` — 手机卡片 + confirmDel - `LoginLogList.vue` — 手机卡片 - `OperationLogList.vue` — 手机卡片 - `OpenTokenLogList.vue` — 手机卡片 **文档修改**: - `docs/open-api-doc.md` — +token/info,下载 Query 参数 - `IntegrationDoc.vue` — Cookie Token + 邮件发送 + 下载方式