test(api): 更新API客户端契约测试以符合YAML规范

- 更新登录响应模拟数据以匹配真实的AppLoginVo结构
- 添加认证客户端租户和授权字段验证
- 增加操作码枚举验证测试用例
- 移除对旧token别名的兼容性测试
- 修复测试用例中的短信验证码长度一致性问题
- 更新区域接口路径为PC专用路径
- 调整分片上传接口参数以符合新契约定义

refactor(api): 重构API客户端实现以严格遵循YAML契约

- 添加认证操作码和短信操作码枚举验证
- 实现严格的token响应解析只接受access_token字段
- 使用pickDefined函数过滤请求体中未定义的字段
- 重构认证接口参数映射以符合契约定义
- 更新区域接口路径为PC专用路径/genealogy/pc/region/*
- 优化分片上传接口参数结构与契约保持一致
- 添加操作码枚举验证函数toRequiredOperationCode
- 实现请求体字段选择性提取功能

feat(auth): 优化认证页面的验证码处理流程

- 添加takeCaptchaToken函数用于一次性获取验证码票据
- 更新短信验证码长度验证从4-6位改为精确4位
- 在登录和密码重置流程中集成验证码票据处理
- 修复验证码发送后票据清理逻辑
- 更新HTML模板中的验证码输入字段属性

chore(config): 提取常量配置并扩展配置对象结构

- 将客户端ID、租户ID和令牌键提取为常量
- 扩展配置对象返回客户端配置信息
- 更新配置测试用例以验证新增配置项

docs(planning): 更新PC接口对接规划文档

- 更新契约源说明以反映YAML冻结契约
- 添加YAML与在线Apifox复核对比内容
- 更新阻断项状态表格
- 修订登录响应token字段处理规范
- 更新文件上传和行政区划接口规范说明

style(profile): 优化相册管理页面的文件上传交互

- 将封面和照片OSS ID输入改为隐藏字段
- 添加文件选择标签以改善用户体验
- 移除手动输入OSS ID的选项保持界面简洁
This commit is contained in:
fizzleaf
2026-07-28 15:06:34 +08:00
parent 735a06e330
commit ce4f05b60f
26 changed files with 886 additions and 196 deletions
+53 -7
View File
@@ -74,7 +74,9 @@
4. 当前仓库代码;
5. 旧规划和历史交接记录。
Apifox 是 method、path、参数、DTO、枚举、权限和错误码的唯一业务契约 owner`utils/ApiClient.js` 是前端路径和请求方法的唯一 owner。页面脚本只能调用 `ApiClient` 业务方法,不能直接拼 URL 或调用 Axios。
通常以 Apifox 的 PC 目录作为 PC 前端接口的正式契约源。2026-07-28 用户明确指定本轮直接以 `D:/WorkSpace/Java/Genealogy/doc/apifox/genealogy-pc-openapi.yaml` 对接,因此该 YAML 是本轮冻结契约;在线 Apifox 的旧重复记录不再覆盖它`utils/ApiClient.js` 是前端路径和请求方法的唯一 owner。页面脚本只能调用 `ApiClient` 业务方法,不能直接拼 URL 或调用 Axios。
旧 OpenAPI 文件不再作为新增功能依据,只用于结构化差异比较和追踪导出遗漏。
如果 Apifox 在线内容发生变化,先更新本地 OpenAPI、本规划的受影响章节和契约测试,再修改运行时代码。不得让文档、测试和运行时同时保留两套契约。
@@ -117,6 +119,24 @@ Apifox 是 method、path、参数、DTO、枚举、权限和错误码的唯一
4. 当前 96 个操作全部被声明为需要 `Authorization`,连注册、登录、短信发送和验证中心也不例外。这与未登录流程冲突,必须在 Apifox 逐项修正 security。
5. 当前有 21 个成功响应使用无业务属性的 `ObjectResult`,12 个使用无元素 Schema 的 `ListResult`;另有 `LineagePersonTreeView` 名义上是专用 DTO,但没有任何属性。
### 4.3 2026-07-28 补齐版 YAML 与在线 Apifox 复核
补齐文件 `genealogy-pc-openapi.yaml` 含 98 个 path、137 个 HTTP operation、17 个 tag、319 个 schema;旧 `PC.openapi.json` 含 71 个 path、96 个 operation、68 个 schema。补齐文件新增了家谱、成员、相册、文章、祭祀、通知、反馈、VIP 和官网内容等路径及 DTO,但它还不能替代在线 Apifox:
1. 已实际登录并打开 Apifox“家谱”项目的 PC 模块。在线概览显示 **142 个接口、87 个数据模型**,与补齐 YAML 的 137 个 HTTP operation 不一致。
2. 在线“认证登录”目录仍显示 **12 个接口**,同时存在:
- 错误旧路径:`genealogy/pc/auth/sms/{operationCode}/code`
- 正确路径:`/genealogy/pc/auth/sms/{operationCode}/code`
补齐 YAML 只包含正确路径,因此 C02 在线尚未完成。
3. 补齐 YAML 给注册、密码登录、短信登录和短信发送标了 `security: []`;在线密码登录详情仍展示必需的 `Authorization` API Key,并显示 `Auth 1`。因此 C03 的导出定义和在线详情冲突。
4. 在线 `GET /genealogy/pc/auth/profile` 成功响应仍为泛型 `ObjectResult`;展开后的 `data` 只有任意附加属性,没有 `ProfileView` 字段。补齐 YAML 同样引用泛型 `ObjectResult`C04/C06 未完成。
5. `ProfileUpdateBody.avatar` 仍为 `integer<int64>`,而 `FileUploadVo.ossId``LineagePersonView.avatarOssId` 等 OSS ID 为 `string`;部分头像字段也仍为 `integer<int64>`。C10 未完成。
6. 已用真实登录响应和后端 `AppLoginVo` 复核:token 的唯一 JSON 字段是 `access_token`;原 YAML 的 `token``accessToken``tokenValue``userId``tenantId``clientId` 均不是该响应的直接字段,现已删除。
7. `ProfileUpdateBody` 仍只有 `nickName``realName``avatar``sex``birthday``email`,没有地区字段,也没有说明缺省、`null`、空串的清空语义。C07/C18 未完成。
用户已明确要求本轮直接按补齐 YAML 施工,所以在线旧短信路径和公开接口 security 残留不再阻断本轮实现。YAML 自身仍存在的 profile 泛型响应、头像 ID 类型冲突和更新清空语义缺失继续保留为阻断项,前端不得自行补造。
## 5. 实施前必须解决的契约阻断项
以下事项不是前端自由选择,必须先在 Apifox 明确:
@@ -144,6 +164,20 @@ Apifox 是 method、path、参数、DTO、枚举、权限和错误码的唯一
| C19 | 多数 View 没有 `canEdit` / `canDelete` 等权限字段 | 页面无法可靠决定按钮可见性 | 增加能力字段,或提供明确且可实现的角色规则 |
| C20 | 文章、相册、祭祀只有删除操作 | 没有真实 ID 来源和完整资源流程 | 补全 PC 列表/详情/新增/修改后才开放页面 |
当前复核状态:
| 阻断项 | 状态 | 在线/补齐文件证据 |
| --- | --- | --- |
| C02 | 本轮按 YAML 解决 | 只实现带 `/` 的正确路径,不保留旧路径 fallback |
| C03 | 本轮按 YAML 解决 | 验证、注册、登录、短信、找回使用 `security: []`;其他认证接口携带 Bearer |
| C04/C06 | 阻断 | profile GET 在线及 YAML 都只有泛型 `ObjectResult` |
| C07 | 阻断 | `ProfileUpdateBody` 没有地区字段 |
| C01/C08 | 前端按后端 PC 实链解决 | 只调用 `/genealogy/pc/region/*`;列表按 `RegionSelectVo``regionCode/regionName/regionLevel` 读取,不保留公共路径 fallback |
| C09 | 前端按后端 PC 实链解决 | `SysOssResumableInitVo` 明确提供 `uploadId/instant/ossId/url/fileName/uploadedChunks`,完成响应使用 `SysOssUploadVo` |
| C10 | 前端边界解决 | 后端初始化 `ossId` 为 Long、完成响应为 string;浏览器统一转十进制字符串,隐藏回填且不转 `Number` |
| C13 | 后续日期模块仍阻断 | 本阶段上传与区划响应不消费日期;其他模块仍需逐字段核验 Java 日期类型 |
| C18 | 阻断 | 未说明可选更新字段的省略、`null`、空串语义 |
阶段 0 验收标准:
- Apifox 中不存在旧短信路径和双区划路径;
@@ -246,8 +280,18 @@ Apifox 是 method、path、参数、DTO、枚举、权限和错误码的唯一
| `passed` | R/A | 决定校验成功或失败 |
| `validToken` | I | 一次性票据,不显示、不落长期存储 |
| `message` | R | 安全地显示验证结果 |
| 登录响应的 `token` / `accessToken` / `tokenValue` | I | Apifox 收口为一个正式字段后保存 |
| `userId``tenantId``clientId``clientKey` | I/R | 会话上下文或诊断信息,不作为用户编辑字段 |
| `access_token` | string / I | 登录接口 `data`;密码或短信登录成功时立即保存,后续仅用于 Bearer 鉴权 |
| `expire_in` | integer<int64> / I/R | 登录接口 `data`;登录成功时取得,可用于会话到期提示,不由用户填写 |
| `client_id``clientKey``deviceType``userType` | string / I/R | 登录接口 `data`;登录成功时取得,仅作会话上下文或诊断,不回传为用户输入 |
| `profile` | object / R | 登录接口 `data.profile`;登录成功后取得,可用于页面只读展示或资料页初始回填 |
| `profile.userId``profile.tenantId``profile.userNo` | integer/string、string、string / I/R | 后端自动产生;不得让用户手工填写,业务 ID 超出 JS 安全整数时保持字符串 |
| `profile.phone``profile.nickName``profile.realName``profile.email` | string/null / R | 后端用户资料;登录成功后只读展示或作为资料页回填,编辑时仍只提交 `ProfileUpdateBody` 允许字段 |
| `profile.avatar` | integer/string/null / R | 后端头像 OSS ID;只读回填,用户换头像必须经文件选择和上传组件产生,禁止手填 OSS ID |
| `profile.sex` | enum `0/1/2` / R | 后端用户资料;页面映射男/女/未知 |
| `profile.birthday` | date/null / R | 后端用户资料;页面按日期展示 |
| `profile.registerSource``profile.loginIp``profile.loginDate` | string/null / R/I | 后端自动产生;只读或内部诊断,不作为表单输入 |
| `profile.status` | string / R/I | 后端账号状态;只读或内部诊断,不作为表单输入 |
| `profile.clientKey``profile.deviceType` | string / I/R | 后端登录上下文;只读或内部诊断 |
#### 认证业务流程
@@ -258,7 +302,7 @@ Apifox 是 method、path、参数、DTO、枚举、权限和错误码的唯一
3.`required=false`,直接提交密码登录。
4. 若需要验证,调用 challenge,展示服务端指定控件,再调用 verify。
5. 得到 `validToken` 后与 MD5 密码一起登录。
6. 成功后仅保存一个正式 token 字段;Apifox 必须选定 `token``accessToken``tokenValue` 的唯一字段,不能长期兼容三个别名
6. 成功后只读取并保存 `data.access_token``token``accessToken``tokenValue` 均视为非法旧响应,不做兼容读取
短信类动作:
@@ -284,6 +328,7 @@ Apifox 是 method、path、参数、DTO、枚举、权限和错误码的唯一
现有页面整改点:
- 当前 `avatarOssId` 字段名与请求契约 `avatar` 不一致;
- 补齐 YAML 中 `avatar` 仍是 `integer<int64>`,但示例值已超过 JavaScript 安全整数范围;浏览器边界必须按十进制字符串保留精度,且只能由上传响应自动回填,不能转 `Number` 或让用户手填;
- 缺少 `realName``email` 和性别“未知”;
- 页面现居地区、父亲、微信/QQ、学历/职业不在 `ProfileUpdateBody`,不得混入保存请求;
- 在后端增加地区字段前,“保存地区”按钮必须关闭或改成纯查询演示;
@@ -312,7 +357,8 @@ Apifox 是 method、path、参数、DTO、枚举、权限和错误码的唯一
- `FileUploadVo.ossId`I,隐藏写入业务表单;
- `url``thumbnailUrl`R,用于预览;
- `fileName``originalName`R,用于文件列表;
- 初始化 `instant`、已上传分片和秒传 OSS 信息尚未定义,C09 完成前不得猜测
- 初始化 `instant=true` 时直接读取 `ossId/url/fileName` 完成秒传;`instant=false` 时使用服务端 `uploadId``uploadedChunks` 跳过已上传分片
- 初始化 Long `ossId` 和完成响应 string `ossId` 均在浏览器边界转为十进制字符串;
- 上传成功但业务保存失败时,当前契约没有释放引用接口,必须让后端补充生命周期规则。
统一由 `public/js/upload-pages.js` 管理分片、进度、重试、取消、MD5 和隐藏 ID。各业务页面不得复制上传算法,也不得出现“请输入 OSS ID”的可见输入框。
@@ -339,7 +385,7 @@ Apifox 是 method、path、参数、DTO、枚举、权限和错误码的唯一
### 7.5 行政区划
先完成 C01,只实现选中的唯一一套路径
本 PC 前端只实现 `/genealogy/pc/region/*`,不调用重复的 `/genealogy/region/*`,也不保留 fallback
| 字段 | 必填性 | 类型 | 页面处理 |
| --- | --- | --- | --- |
@@ -350,7 +396,7 @@ Apifox 是 method、path、参数、DTO、枚举、权限和错误码的唯一
| `limit` | 可选 query | A | 搜索组件固定合理上限,不让用户自由输入 |
| `clientid` | 可选 header | A | 统一请求层注入 |
`RegionView` 补齐前不能假设响应一定含 `regionCode``regionName``regionLevel`。个人资料当前没有可保存的地区字段,因此区划组件只能在有真实消费字段的页面启用提交
真实 Java `RegionSelectVo` 已明确 `regionCode``regionName``regionLevel` 等字段。个人资料当前没有可保存的地区字段,因此区划组件只提供级联、搜索和路径回显,不提交到资料更新接口
### 7.6 家族圈