--- name: session-20260613-2 description: 2026-06-13 第2次会话 — UI移动端优化、登录跳转修复、操作人乱码修复、操作详情弹窗重设计、文件对象存储从DB迁移到磁盘、系统配置页、开放文件API metadata: type: session date: 2026-06-13 sessionNumber: 2 startTime: 2026-06-13T00:00:00+08:00 --- # 2026-06-13 第2次会话 ## 会话摘要 完成前两轮累积的全部需求:UI移动端适配、登录页跳转优化、操作人乱码BUG修复(Header URL编解码)、操作日志查看弹窗重新设计、文件存储从MySQL BLOB迁移到本地磁盘、系统配置管理页、文件对象储存列表重设计、开放API文件上传/下载接口、open-api-doc.md文档更新。 ## 关键操作 ### 一、前端UI优化 **登录页 (LoginView.vue)**: - 登录成功后按钮持续转圈(loading不关闭),显示"正在跳转..." - `navigating` 标志防重复跳转 - 支持二次点击(已登录成功卡住时重新触发跳转) - 8秒超时自动提示"网络较慢" **操作日志 (OperationLogList.vue)**: - 查看弹窗完全重设计:el-descriptions 展示操作人/时间/接口/方法/成功/耗时 - 深色代码块 + 折叠面板展示传入/返回报文 - 一键复制按钮 **移动端全局适配 (global.css)**: - 操作列按钮 480px 以上保留文字,480px 以下只显示图标 - 搜索卡片 inline 表单移动端垂直排列 - 分页移动端隐藏 sizes 和 jumper - 弹窗移动端 95vw **列表页移动端适配**: SystemList/UserList/RoleList/DictList/LoginLogList 全部更新 ### 二、操作人乱码BUG修复 **根因**: HeaderInjectFilter 将中文 realName(如"张三")注入 HTTP 头 `X-User-Name`。HTTP 头只支持 ASCII,跨服务转发时中文字符损坏。 **修复**: - `HeaderInjectFilter.java`: `X-User-Name` 值写入前 `URLEncoder.encode(realName, UTF_8)` - `OperationLogAspect.java`: 读取后 `URLDecoder.decode(value, UTF_8)` 还原 - 新增 `decodeHeader()` 辅助方法 ### 三、文件对象存储(DB BLOB → 本地磁盘) **核心原则**: 文件二进制数据一律存磁盘,sys_file 表只存元信息。 **数据库变更**: - 新建 `sys_config` 表(系统配置键值对) - `sys_file` 加 `storage_file_name`、`upload_user_name` 字段 - 保留 `file_data` 列用于存量 BLOB 向后兼容 **后端新增**: - `SysConfig.java` 实体 + `SysConfigMapper` + `ConfigService`(含 ConcurrentHashMap 缓存) + `ConfigController` - `FileServiceImpl.upload()` 改为写磁盘:`{basePath}/{yyyy-MM}/{uuid}.{ext}` - `FileController.view()` 优先读磁盘,兜底读 BLOB(存量兼容) - `FileController.download()` 新增下载端点(Content-Disposition: attachment) - `uploadUserName` 逻辑:管理后台上传→用户姓名,API上传→系统名称 **开放 API(OpenApiController)**: - `POST /zgapi/v1/open/file/upload` — form 字段传 token,上传成功消费 - `GET /zgapi/v1/open/file/{id}/download?token=xxx` — query 参数传 token,下载成功消费 - 新增 `validateOpenTokenFromValue(String)` 支持非 Header 传 token **网关 (TokenAuthFilter)**: - `authenticateOpenApi()` 无 Bearer Header 时从 `request.getParameter("token")` 兜底 **前端**: - `SystemConfig.vue` — 系统配置页(存储磁盘路径输入框 + 保存) - `FileList.vue` — 完全重写:卡片网格、缩略图点击预览、储存文件名、上传者、下载/复制链接/删除 - 菜单"文件管理"→"文件对象储存" - 新增"系统配置"菜单(Setting 图标) **菜单 SQL**: - `add_file_storage.sql`: sys_config DDL + sys_file ALTER + 菜单改名+新增 - `add_file_menu.sql`: 菜单名更新 ### 四、文档更新 `docs/open-api-doc.md` 新增: - §4 上传文件(multipart/form-data 示例、响应字段说明) - §5 下载文件(query param token 示例) - Java 调用示例增加文件上传 - 附录重新编号为 §7 ## 修改文件清单 | 文件 | 操作 | |------|------| | `LoginView.vue` | 修改 | | `OperationLogList.vue` | 修改 | | `global.css` | 修改 | | `SystemList.vue` | 修改 | | `UserList.vue` | 修改 | | `RoleList.vue` | 修改 | | `DictList.vue` | 修改 | | `LoginLogList.vue` | 修改 | | `HeaderInjectFilter.java` | 修改(URL编码) | | `OperationLogAspect.java` | 修改(URL解码) | | `SysConfig.java` | **新增** | | `SysConfigMapper.java` | **新增** | | `ConfigService.java` | **新增** | | `ConfigServiceImpl.java` | **新增** | | `ConfigController.java` | **新增** | | `SysFile.java` | 修改(+2字段) | | `FileService.java` | 修改(接口更新) | | `FileServiceImpl.java` | 重写(磁盘存储) | | `FileController.java` | 重写(+download,view改磁盘优先) | | `OpenApiController.java` | 修改(+2文件端点) | | `TokenAuthFilter.java` | 修改(query param token) | | `SystemConfig.vue` | **新增** | | `FileList.vue` | 重写 | | `router/index.ts` | 修改 | | `AdminLayout.vue` | 修改 | | `open-api-doc.md` | 修改 | | `add_file_storage.sql` | **新增** | | `add_file_menu.sql` | 修改 | ## 重要信息 - 文件存储路径: 默认 `/data/mokee/gw/file`,可在系统配置页修改 - 磁盘文件结构: `{basePath}/{yyyy-MM}/{uuid}.{ext}` - 存量 BLOB 文件仍可正常读取(view/download 兜底逻辑) - 开放 API Token 消费规则: 上传/下载成功后消费,失败不消费 - Token 在 download 通过 query 参数传递(浏览器 `` 标签无法设 Header) ## 待处理 - [ ] 执行 `add_file_storage.sql` 到 QA/PROD 数据库 - [ ] 服务器上创建存储目录 `/data/mokee/gw/file` 并设置写权限 - [ ] 执行 QA/PROD 菜单更新(文件管理→文件对象储存 + 系统配置菜单) - [ ] 构建部署:`mvn clean package` + `npm run build:prod` - [ ] 原有迁移建议:现有文件数据过大时,可编写迁移脚本将 `file_data` BLOB 导出到磁盘