Files
jiapu/docs/PC接口对接规划.md
T
fizzleaf ce4f05b60f 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的选项保持界面简洁
2026-07-28 15:06:34 +08:00

906 lines
48 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# PC 接口字段与页面落地规划(供 AI 执行)
> 文档状态:规划,不代表当前代码已经完成
> 基线日期:2026-07-27
> 当前本地快照:根目录 `PC.openapi.json`OpenAPI 3.1.0
> 使用对象:另一台电脑上的执行 AI
> 本轮边界:只写规划;执行 AI 才能修改页面、脚本和测试
## 0. 强制要求:必须打开 Apifox 查看
执行 AI 在修改任何代码前,必须实际登录并打开 Apifox 的“家谱”项目,进入每一个本轮接口的详情页逐项查看。不得只读取 `PC.openapi.json`、Apifox 本地缓存、旧截图或历史文档。
每个接口都必须在 Apifox 详情页记录:
1. method、完整 path、接口状态和所属 PC 目录;
2. Path、Query、Header、Cookie 和 Body 的全部字段;
3. 每个字段的类型、必填/可选/条件必填、默认值、枚举、格式、长度和取值范围;
4. 字段说明、示例值、关联字典和条件显示规则;
5. 请求体中折叠对象、数组元素和嵌套字段的完整结构;
6. 成功响应、失败响应、列表元素、详情对象和分页结构的完整字段;
7. 登录要求、角色权限、业务前置条件和错误码;
8. Apifox 页面有但 OpenAPI 导出遗漏的字段或说明。
核对结果必须写入本规划对应模块的字段表,并为每个字段标明 U/S/F/A/R/I/V 分类、使用页面、数据来源和提交时机。Apifox 详情没有确认的字段不得进入代码;Apifox 与导出文件不一致时,以现场核对结果形成问题清单,先让接口 owner 修正并重新导出,再实施。
## 1. 最终目标
执行 AI 要把 Apifox 中的 PC 接口准确落到现有 PC 页面,最终同时满足:
1. 请求体中的必填字段、可选字段全部有明确页面归属。
2. 字段被明确分成:
- 用户输入;
- 用户选择;
- 文件选择后自动生成;
- 页面上下文自动带入;
- 接口响应后只读展示;
- 仅内部保存、不得展示或手工填写;
- 纯前端校验字段、不得发给后端。
3. ID、Token、`clientid``tenantId`、OSS ID、分页参数等系统字段不得让用户手工输入。
4. 下拉框和选择器必须有真实数据源;没有选项接口时不得改成“请输入 ID”。
5. Apifox 未展开的响应 DTO、未声明的枚举和互相冲突的路径不得靠前端猜测。
6. APP 接口不得用于填补 PC 接口缺口。
7. 所有家谱内业务必须使用真实 `genealogyId`,不得写死示例值。
8. 每一阶段必须有契约测试、页面行为测试和真实联调结果。
## 2. 执行 AI 的工作协议
执行 AI 开始前必须按顺序完成:
1. 阅读项目根目录 `AGENTS.md`
2. 检查工作树,只修改本计划点名的文件;保留用户已有改动。
3. 登录 Apifox,打开“家谱”项目,逐条核对实时 PC 接口详情。
4. 从 Apifox 重新导出最新 OpenAPI,和仓库 `PC.openapi.json` 做结构化差异比较。
5. 完成第 5 节“契约阻断项”;阻断项未解决的模块只保留页面设计,不接真实写操作。
6. 按第 8 节阶段顺序施工,每完成一阶段立即验证,不能把所有模块一次性混改。
遇到以下情况时,停止当前模块并整理成一份待后端确认清单,同时继续其他不受影响的模块:
- Apifox 页面和导出文件的 method、path、必填性、枚举或类型不一致;
- 响应仍是无属性的 `ObjectResult` / `ListResult`
- 选择字段没有合法选项来源;
- 更新接口没有说明“字段不传”和“传 null/空串”的区别;
- 页面需要的业务能力在 PC 目录中不存在。
不得通过兼容多个旧字段、读取 APP DTO、保留旧路径 fallback 或展示原始 JSON 绕过阻断。
## 3. 契约依据与优先级
发生冲突时按以下顺序处理:
1. Apifox “家谱”项目中当前 PC 接口详情;
2. 从该详情当场重新导出的 OpenAPI 文件;
3. 本规划中的字段和流程分类;
4. 当前仓库代码;
5. 旧规划和历史交接记录。
通常以 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、本规划的受影响章节和契约测试,再修改运行时代码。不得让文档、测试和运行时同时保留两套契约。
## 4. 当前基线与复核结论
### 4.1 当前导出范围
当前 `PC.openapi.json` 共 96 个操作、15 个标签、68 个 Schema
| 模块 | 操作数 | 当前主要页面 |
| --- | ---: | --- |
| 验证中心 | 3 | 登录、注册、找回密码、安全设置 |
| 认证登录 | 11 | `login.html``register.html``forgot-password.html`、个人资料和安全页 |
| 文件上传 | 3 | 所有头像、图片、附件和视频选择控件 |
| 家谱 | 1 | `profile-families.html` |
| 家族圈 | 14 | `profile-feed.html``profile-feed-edit.html`、待新增动态详情页 |
| 行政区划 | 8 | 个人资料及以后需要地区的表单 |
| 字辈谱 | 6 | `profile-generation.html` |
| 世系人物 | 12 | `profile-tree.html` |
| 内容文章 | 1 | `profile-article.html``profile-article-edit.html` |
| 相册 | 2 | `profile-album.html` |
| 视频 | 5 | `profile-video.html`、待新增视频编辑页 |
| 贺礼邀约 | 4 | `profile-gift.html`、邀约管理面板 |
| 祭祀 | 2 | `profile-gift.html` |
| 族务记录 | 20 | 成长、亲友、备忘录、功德录页面 |
| 消息通知 | 4 | `profile-messages.html` |
| **合计** | **96** | |
### 4.2 已对照到的 Apifox 现状
本机 Apifox 缓存中的“家谱”项目包含 APP、PC、共享区划等 246 条接口记录。当前导出的 96 条路径均能在该项目缓存的接口树中找到,但存在以下差异:
1. Apifox 缓存同时保留了两条逻辑相同的短信接口:
- 错误旧路径:`genealogy/pc/auth/sms/{operationCode}/code`
- 正确路径:`/genealogy/pc/auth/sms/{operationCode}/code`
当前导出只保留正确路径。执行前必须在 Apifox 删除或正式废弃缺少 `/` 的旧定义,前端只实现正确路径。
2. 导出文件同时含 `/genealogy/region/*``/genealogy/pc/region/*` 两套共 8 个区划操作;两套的参数、响应和描述完全相同。执行前必须由后端选定一套唯一正式路径并删除另一套。选定后实际唯一操作数应从 96 收口为 92。
3. 旧版“85 接口规划”已经失效。新增范围主要包括 PC 区划 4 条、视频列表/新增/详情/修改 4 条、功德列表/新增/详情/修改 4 条。
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 明确:
| 编号 | 问题 | 影响 | 完成条件 |
| --- | --- | --- | --- |
| C01 | 两套区划路径完全重复 | 页面和客户端会形成双路径 | Apifox 只保留一套;导出和客户端只出现一次 |
| C02 | 短信接口有缺少开头 `/` 的旧记录 | 可能生成错误 URL | 删除/废弃旧记录,只保留正确路径 |
| C03 | 所有操作均要求 Authorization | 未登录流程无法成立 | 注册、登录、找回、验证、短信等逐项标明公开;登录后接口明确鉴权 |
| C04 | 33 个操作使用泛型对象/列表响应 | 列表、详情、编辑回填和 ID 来源不确定 | 为每个业务资源增加明确 View/DTO Schema |
| C05 | `LineagePersonTreeView` 没有属性 | 世系树只能猜字段 | 补齐节点 ID、人物资料、配偶、子女和递归结构 |
| C06 | 用户资料响应未展开 | 个人资料无法可靠回填 | 增加 `ProfileView`,明确所有可读字段 |
| C07 | `ProfileUpdateBody` 没有地区字段 | 现居地区无法保存 | 明确增加地区编码字段或删除“保存地区”功能 |
| C08 | 区划响应没有元素 DTO | 下拉选项的 code/name/level 不受契约约束 | 增加 `RegionView` 及列表/路径响应 |
| C09 | 上传初始化响应未展开,却描述了 `instant=true` | 秒传、续传和 `uploadId` 状态不明确 | 增加初始化响应 DTO,明确 `instant`、已传分片和 OSS 信息 |
| C10 | OSS ID 类型冲突 | 可能发生 JS 精度丢失或校验失败 | 所有 `ossId``avatar``avatarOssId`、视频和附件 ID 统一为 string |
| C11 | `completed` 只有 string 类型,无枚举 | 不能决定复选框提交 `0/1`、true/false 或其他值 | Apifox 增加枚举和中文含义 |
| C12 | `feedType``recordType``registerSource` 等无枚举 | 无法判断文本输入还是选择项 | 明确为自由文本,或补全枚举 |
| C13 | 多个日期字段没有 format/时区规则 | 页面值和后端解析可能不一致 | 明确 date 或 date-time,并统一时区 |
| C14 | 只有配额,没有我的家谱/成员入口 | 无法取得 `genealogyId`、成员或受邀用户选项 | 增加 PC 家谱列表/选项和成员选项接口,或明确外部上下文契约 |
| C15 | `bindingMode=SPECIFIED` 需要 `appUserId`,但无业务用户选项接口 | 不能提供合法选择器 | 增加家谱成员/业务用户选项接口 |
| C16 | 邀约的 `inviteeUserIds` 没有选项接口 | 不能让管理员选择受邀人 | 增加同一家谱成员选项接口 |
| C17 | 视频、成长、亲友、备忘、功德、通知响应未展开 | 无法安全展示、编辑或单条操作 | 分别增加资源 View 和列表/详情响应 |
| C18 | 更新接口未说明缺省、null、空串语义 | 可选字段可能无法清空 | Apifox 对每个可清空字段写明更新规则 |
| 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 中不存在旧短信路径和双区划路径;
- 重新导出的 OpenAPI 只包含一套正式契约;
- 公开与鉴权接口标记正确;
- 本阶段要实现的每个列表/详情都有明确响应 DTO;
- 所有枚举、日期和 ID 类型已确定;
- 将旧输入发送给后端时会明确失败,前端不保留兼容读取。
## 6. 页面字段分类标准
执行 AI 对每个请求字段都要采用下面一种处理类型:
| 类型 | 含义 | 页面处理 |
| --- | --- | --- |
| U:用户输入 | 姓名、标题、正文、手机号等 | 可见输入框/文本域,展示必填或选填 |
| S:用户选择 | 枚举、人员、字辈、地区、状态等 | 单选、下拉、多选、日期或开关;选项必须有真实来源 |
| F:文件派生 | OSS ID、文件名、MD5、大小等 | 用户只选文件;值由上传组件生成并隐藏 |
| A:自动填写 | header、租户、上下文 ID、分页、默认值等 | 页面不可编辑,由统一 owner 注入 |
| R:响应只读 | 创建时间、计数、发布人、状态文本等 | 列表、详情、徽标或只读信息 |
| I:内部状态 | token、challengeId、validToken、资源 ID 等 | 仅内存/安全存储/URL 中保存,不显示原值 |
| V:前端校验 | 确认密码、注销确认文字等 | 可见但不得发给后端 |
通用规则:
1. 必填字段使用明确的必填标识,并在提交前校验。
2. 可选字段也必须有页面归属;不填写时直接省略,除非 Apifox 明确要求传 null。
3. 枚举必须使用选择控件,禁止自由文本。
4. 外键 ID 必须使用搜索/选择控件,禁止“请输入人物 ID”“请输入 OSS ID”。
5. `sortOrder``status` 这类管理字段:
- 有管理权限时放在“高级设置”;
- 普通用户使用隐藏默认值;
- 后端未返回权限时不得自行开放高级设置。
6. 所有 int64 ID 在浏览器中按字符串保存和比较。
7. 响应中的 `code``msg` 由请求层统一处理;业务页只消费 `data``rows/total`
## 7. 字段、页面和流程规划
### 7.1 全局自动字段
| 字段 | 类型 | 唯一来源 | 规则 |
| --- | --- | --- | --- |
| `clientid` | A | `ApiClient` 配置 | 每个需要它的请求自动加 Header,不进入表单或 body |
| `Authorization` | I/A | 登录响应 token | 仅鉴权接口携带;注册登录等公开接口不携带 |
| `tenantId` | A | 环境配置 | 登录、注册、验证等自动带入,不让用户输入 |
| `genealogyId` | I/A | PC 家谱上下文 | `profile-common.js` 读取和传播;缺失时阻止家谱内请求 |
| `feedId``commentId``personId``poemId``articleId``albumId``photoId``videoId``ceremonyId``giftId``recordId``relativeId``memoId``meritId``notificationId` | I/A | 列表/详情响应或 URL | 由被点击记录带入,禁止文本框输入 |
| `pageNum``pageSize` | A/S | 分页组件 | 页码由组件维护;用户只操作翻页/每页条数 |
| `ossId` / `mediaOssIds` | F/I | 文件上传响应 | 页面展示预览和文件名,隐藏保存 ID |
| `sortOrder` | S/A | 高级设置或默认值 | 不得把空字符串转成 0;未填写时省略 |
| `status` | S/A | 权限化状态选择或默认值 | 枚举 0=正常、1=停用;不得把 1 标成“草稿” |
### 7.2 验证中心与认证登录
#### 页面字段矩阵
| 字段 | 必填性 | 类型 | 页面/流程 | 处理 |
| --- | --- | --- | --- | --- |
| `operationCode` | 必填 path | A | 所有认证动作 | 页面动作固定为 `password-login``sms-login``register``forgot-password``phone-change``account-deactivate` |
| `clientid` | 必填 header | A | 所有认证请求 | `ApiClient` 自动注入 |
| `tenantId` | 必填 | A | 所有登录/验证表单 | 环境配置自动注入 |
| `subject` | require 可选,challenge/verify 必填 | A | 验证流程 | 从当前手机号/账号派生,用户不重复填写 |
| `grantType` | 必填 | A | 注册、登录、短信、找回 | 密码动作固定 `password`,短信动作固定 `sms` |
| `phone` | 必填 | U | 登录、注册、找回、换绑 | 手机号输入和格式校验 |
| `password` | 必填 | U/A | 密码登录、注册 | 用户输入明文,提交前生成 32 位 MD5;日志不得记录 |
| `oldPassword` | 必填 | U/A | 修改密码 | 同上 |
| `newPassword` | 必填 | U/A | 修改/重置密码 | 同上 |
| `confirmPassword` | 前端字段 | V | 注册、修改、找回 | 只比较一致性,不发送 |
| `smsCode` | 必填 | U | 短信登录、注册、找回、换绑、注销 | 4 位验证码输入 |
| `nickName` | 可选 | U | 注册 | 昵称输入 |
| `registerSource` | 可选 | A | 注册 | 当前端固定 `PC`Apifox 需确认枚举 |
| `validToken` | 条件必填 | I/A | 密码登录、发送短信 | 验证成功后仅存内存,使用一次即清除 |
| `challengeId` | 必填 | I/A | 验证校验 | 挑战响应自动回填 |
| `providerCode``captchaType` | 可选 | A | 验证校验 | 挑战响应决定,用户不可修改 |
| `payload.track` | 条件必填 | A | 天爱验证码 | 控件原样生成轨迹、尺寸和时间 |
| `payload.uuid` | 条件必填 | I/A | 系统图形验证码 | 挑战响应回填 |
| `payload.code` | 条件必填 | U | 系统图形验证码 | 用户输入图片答案 |
天爱控件产生的嵌套字段全部属于 A,不得另做表单让用户填写:
- `bgImageWidth``bgImageHeight`:控件实际显示尺寸,必填;
- `templateImageWidth``templateImageHeight`:模板实际显示尺寸,可选;
- `startTime``stopTime`:操作开始和结束毫秒时间戳,必填;
- `left``top`:控件最终偏移,可选;
- `trackList`:必填轨迹数组;
- 每个轨迹点的 `x``y``t``type` 均由控件生成;
- `data`:不同验证码类型的扩展数据,原样提交。
验证和登录响应字段:
| 响应字段 | 类型 | 页面处理 |
| --- | --- | --- |
| `required` | R/A | 决定是否进入挑战流程 |
| `providerCode``captchaType` | I/A | 选择正确验证码控件 |
| `sceneCode` | I/R | 服务端解析结果,可用于只读诊断;不得回传 |
| `ttlSeconds``expireSeconds` | R/A | 倒计时和过期重试 |
| `challengeId``uuid` | I | 只在当前挑战内保存 |
| `img` | R | 系统图形验证码图片 |
| `payload` | I/A | 天爱控件初始化数据 |
| `passed` | R/A | 决定校验成功或失败 |
| `validToken` | I | 一次性票据,不显示、不落长期存储 |
| `message` | 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 | 后端登录上下文;只读或内部诊断 |
#### 认证业务流程
密码登录:
1. 用户输入手机号和密码。
2.`password-login + tenantId + phone` 调用 `require`
3.`required=false`,直接提交密码登录。
4. 若需要验证,调用 challenge,展示服务端指定控件,再调用 verify。
5. 得到 `validToken` 后与 MD5 密码一起登录。
6. 成功后只读取并保存 `data.access_token``token``accessToken``tokenValue` 均视为非法旧响应,不做兼容读取。
短信类动作:
1. 用户输入手机号。
2. 按当前动作完成 require → challenge → verify。
3. 把一次性 `validToken` 提交给发送短信接口。
4. 用户输入短信码后执行短信登录、注册、找回、换绑或注销。
5. `validToken` 不进入最终注册、短信登录、换绑或注销 body,除非 Apifox 明确修改契约。
#### 个人资料字段
`ProfileUpdateBody` 的所有字段必须进入 `profile-data.html`
| 字段 | 必填性 | 类型 | 控件 |
| --- | --- | --- | --- |
| `nickName` | 可选 | U | 文本,最长 30 |
| `realName` | 可选 | U | 文本,最长 30 |
| `avatar` | 可选 | F/I | 图片上传、预览、删除;隐藏保存 OSS ID |
| `sex` | 可选 | S | 男 0、女 1、未知 2,三项都要有 |
| `birthday` | 可选 | S | 日期选择器,`yyyy-MM-dd` |
| `email` | 可选 | U | email 输入,最长 100 |
现有页面整改点:
- 当前 `avatarOssId` 字段名与请求契约 `avatar` 不一致;
- 补齐 YAML 中 `avatar` 仍是 `integer<int64>`,但示例值已超过 JavaScript 安全整数范围;浏览器边界必须按十进制字符串保留精度,且只能由上传响应自动回填,不能转 `Number` 或让用户手填;
- 缺少 `realName``email` 和性别“未知”;
- 页面现居地区、父亲、微信/QQ、学历/职业不在 `ProfileUpdateBody`,不得混入保存请求;
- 在后端增加地区字段前,“保存地区”按钮必须关闭或改成纯查询演示;
- `GET /auth/profile` 必须补齐 `ProfileView` 后才能严格回填。
### 7.3 文件上传
用户在任何业务页只操作“选择文件、取消、重试”;下面字段全部自动产生:
| 阶段 | 字段 | 必填性 | 类型 | 来源 |
| --- | --- | --- | --- | --- |
| 初始化 | `uploadId` | 必填 | I/A | 客户端生成一次并贯穿全过程 |
| 初始化 | `fileName` | 必填 | F | `File.name` |
| 初始化 | `fileMd5` | 必填 | F | 文件内容计算 |
| 初始化 | `totalSize` | 必填 | F | `File.size` |
| 初始化 | `totalChunks` | 必填 | F | 根据大小和分片大小计算 |
| 初始化 | `chunkSize` | 必填 | A | 上传组件统一配置,默认示例 4 MiB,最后一片除外 |
| 初始化 | `contentType` | 可选 | F | `File.type` |
| 分片 | `chunkIndex` | 必填 | A | 上传循环生成 |
| 分片 | `chunkMd5` | 必填 | F | 当前分片计算 |
| 分片 | `file` | 必填 | F | 当前 Blob |
| 完成 | `uploadId/fileName/fileMd5/totalSize/totalChunks` | 必填 | I/A/F | 必须与初始化一致 |
响应处理:
- `FileUploadVo.ossId`I,隐藏写入业务表单;
- `url``thumbnailUrl`R,用于预览;
- `fileName``originalName`R,用于文件列表;
- 初始化 `instant=true` 时直接读取 `ossId/url/fileName` 完成秒传;`instant=false` 时使用服务端 `uploadId``uploadedChunks` 跳过已上传分片;
- 初始化 Long `ossId` 和完成响应 string `ossId` 均在浏览器边界转为十进制字符串;
- 上传成功但业务保存失败时,当前契约没有释放引用接口,必须让后端补充生命周期规则。
统一由 `public/js/upload-pages.js` 管理分片、进度、重试、取消、MD5 和隐藏 ID。各业务页面不得复制上传算法,也不得出现“请输入 OSS ID”的可见输入框。
### 7.4 家谱上下文与配额
`GET /genealogy/pc/genealogies/quota` 只负责在 `profile-families.html` 展示:
| 响应字段 | 类型 | 页面呈现 |
| --- | --- | --- |
| `createUsed``createLimit``createRemaining` | R | 创建额度已用/上限/剩余 |
| `canCreate` | R | 控制“创建家谱”是否可用 |
| `joinUsed``joinLimit``joinRemaining` | R | 加入额度已用/上限/剩余 |
| `canJoin` | R | 控制“加入家谱”是否可用 |
`-1` 显示为“不限”,不能参与普通减法或显示负数。
配额响应不包含 `genealogyId`,不能替代“我的家谱”。在 C14 完成前:
- 所有家谱内页面缺少真实 `genealogyId` 时必须阻止请求;
- 不显示静态家谱卡片作为真实数据;
- 不从 APP 接口获取家谱;
- 不允许用户手工输入家谱 ID。
### 7.5 行政区划
本 PC 前端只实现 `/genealogy/pc/region/*`,不调用重复的 `/genealogy/region/*`,也不保留 fallback。
| 字段 | 必填性 | 类型 | 页面处理 |
| --- | --- | --- | --- |
| `parentCode` | 可选 query | A/S | 省级不传;选择上一级后自动查询下级 |
| `regionCode` | 必填 path | I/A | 从被选择的区划记录带入 |
| `keyword` | 必填 query | U | 搜索框 |
| `level` | 可选 query | S | 1 省、2 市、3 区县、4 乡镇街道、5 村社区 |
| `limit` | 可选 query | A | 搜索组件固定合理上限,不让用户自由输入 |
| `clientid` | 可选 header | A | 统一请求层注入 |
真实 Java `RegionSelectVo` 已明确 `regionCode``regionName``regionLevel` 等字段。个人资料当前仍没有可保存的地区字段,因此区划组件只提供级联、搜索和路径回显,不提交到资料更新接口。
### 7.6 家族圈
页面归属:
- `profile-feed.html`:分页列表、点赞、轻量评论;
- `profile-feed-edit.html`:新增和编辑;
- 新增 `profile-feed-detail.html`:详情、完整评论树、回复、通知跳转和分享深链。
#### 写入字段
| 字段 | 必填性 | 类型 | 页面处理 |
| --- | --- | --- | --- |
| `genealogyId` | 必填 path | I/A | 家谱上下文 |
| `feedId` | 详情/修改/删除必填 | I/A | 列表记录或 URL |
| `feedType` | 可选 | A 或 S | 当前默认隐藏 `text`;Apifox 补枚举后才能改成选择 |
| `feedContent` | 必填 | U | 正文编辑器 |
| `mediaOssIds` | 可选 | F/I | 多文件上传结果拼成英文逗号串,用户只看缩略图 |
| `sortOrder` | 可选 | S/A | 管理员高级设置;普通发布默认省略/0 |
| `status` | 可选 | S/A | 0 正常、1 停用;不得显示为“发布/草稿” |
| `parentCommentId` | 可选 | I/A | 点击“回复”后自动带入;一级评论省略或 null |
| `commentContent` | 必填 | U | 评论输入,最多 1000 字 |
| `pageNum/pageSize` | 可选 | A/S | 分页组件 |
#### 动态响应字段
| 字段 | 页面处理 |
| --- | --- |
| `feedId``genealogyId` | I,用于路由和后续操作 |
| `genealogyNo``genealogyName` | R,详情来源信息 |
| `publisherUserId` | I,用于权限判断,但不能单独代替后端鉴权 |
| `publisherNickName``publisherStatus` | R,发布人和状态 |
| `feedType``feedContent` | R,类型和正文 |
| `mediaOssIds` | I/F,解析后通过文件 URL 规则展示,不直接显示 ID |
| `likedByMe` | R,决定点赞按钮状态 |
| `likeCount``commentCount` | R,计数 |
| `pinned``pinnedTime` | R,置顶徽标和时间 |
| `sortOrder``status` | R/管理信息 |
| `remark` | R,仅在产品确认需要时展示,不能当正文 |
| `createTime``updateTime` | R,发布时间和编辑时间 |
评论响应字段:
- `commentId``genealogyId``feedId``parentCommentId``appUserId``parentAppUserId`I
- `appUserNickName``appUserAvatar``parentAppUserNickName`R
- `commentContent`R;为 null 且 `userDeleted=1` 时显示“该评论已删除”占位;
- `replyCount`R,控制“展开回复”;
- `commentLevel`R`root``reply`
- `status``createTime`R。
流程:
1. 列表首屏调用分页接口,不同时调用非分页接口重复取数。
2. 点击记录进入详情,以 `genealogyId + feedId` 取详情。
3. 一级评论调用 comments 分页;回复只调用对应 comment 的 replies 分页。
4. 点赞、取消、评论、删除成功后以接口返回和重新读取结果校正计数。
5. 删除有回复的评论后保留占位,不从 DOM 直接移除整棵回复。
### 7.7 字辈谱
`profile-generation.html` 同时提供“单条维护”和“批量维护”。
单条字段:
| 字段 | 必填性 | 类型 | 控件 |
| --- | --- | --- | --- |
| `generationNo` | 必填 | U/S | 正整数世代序号 |
| `generationText` | 必填 | U | 最长 50 |
| `description` | 可选 | U | 文本域,最长 500 |
| `sortOrder` | 可选 | U/S | 管理员高级数字字段 |
| `status` | 可选 | S | 0 正常、1 停用 |
| `poemId` | 修改必填 path | I/A | 列表记录 |
批量字段:
| 字段 | 必填性 | 类型 | 控件 |
| --- | --- | --- | --- |
| `poemText` | 必填 | U | 文本域,最长 26000;支持合同中列出的分隔符 |
| `disableMissing` | 可选 | S | 复选框,必须有“将停用后续世代、不删除历史”的确认说明 |
批量流程必须是 preview → 用户检查 → save
- 预览展示 `createCount``updateCount``keepCount``disableCount`
- 逐项结果来自 `items`;每项展示 `generationNo``oldGenerationText``newGenerationText``oldStatus``newStatus``action``warning`
- `poemId``genealogyId` 是内部字段;
- 保存前再次确认,因为服务端会基于最新数据重新计算差异。
普通展示列表使用正常字辈接口;管理页面使用 management 接口以包含停用项。
### 7.8 世系人物
全部操作集中在 `profile-tree.html`,详情和编辑可使用抽屉/弹窗,但所有字段都要有明确控件。
| 字段 | 必填性 | 类型 | 页面处理 |
| --- | --- | --- | --- |
| `bindingMode` | 必填 | S | NONE 不绑定、SELF 当前账号、SPECIFIED 指定账号 |
| `appUserId` | SPECIFIED 时必填 | S/I | 从真实业务用户选项选择;没有接口时禁用 SPECIFIED,禁止文本 ID |
| `personNo` | 可选 | U/A | 高级设置可填;留空由服务端生成 |
| `name` | 必填 | U | 姓名 |
| `aliasName` | 可选 | U | 别名/曾用名 |
| `sex` | 可选 | S | 0 男、1 女、2 未知 |
| `generation` | 可选 | S/I | 从正常字辈列表选择世代 |
| `generationName` | 可选 | A/R | 随字辈选项自动回填并只读显示 |
| `fatherId` | 可选 | S/I | 世系人物搜索选择器 |
| `motherId` | 可选 | S/I | 世系人物搜索选择器 |
| `avatarOssId` | 可选 | F/I | 上传头像自动回填 |
| `birthDate` | 可选 | S | date-time 选择器 |
| `birthLunar` | 可选 | S | 0 公历、1 农历开关 |
| `birthPlace` | 可选 | U | 出生地文本 |
| `deathDate` | 可选 | S | date-time 选择器 |
| `deathLunar` | 可选 | S | 0 公历、1 农历开关 |
| `deathPlace` | 可选 | U | 逝世地 |
| `burialPlace` | 可选 | U | 安葬地 |
| `personStatus` | 可选 | S | 0 健在、1 已故、2 未知 |
| `biography` | 可选 | U | 人物简介 |
| `sortOrder` | 可选 | U/S | 管理高级设置 |
| `remark` | 可选 | U | 备注 |
| `relationName` | 可选 | U | 仅“添加配偶”快捷流程显示 |
人物响应字段按以下方式使用:
- `personId``genealogyId``appUserId``fatherId``motherId``avatarOssId`I
- `genealogyName``genealogyNo`R
- `appUserNickName`R,显示绑定账号;
- `personNo``name``aliasName``sex``generation``generationName`R/编辑回填;
- `fatherName``motherName``spouseNames`R
- 出生、逝世、安葬、状态、简介、备注、排序字段:R/编辑回填。
关系流程:
1. 先选中一个现有 `personId` 作为关系锚点。
2. 点击父母、子女、兄弟姐妹或配偶。
3. 打开完整 `LineagePersonBody` 表单,创建的是一个新人物并建立关系,不是绑定两个现有人物 ID。
4. 配偶流程才显示 `relationName`
5. 当前没有解除关系接口,页面不得伪造“解除关系”。
6. DELETE 是逻辑停用;存在正常子女时可能失败,确认文案不能写成物理删除。
列表筛选:
- `keyword`U,搜索姓名、别名或人物编号;
- `generation`S,从字辈接口选择;
- `personStatus`S0/1/2
- `pageNum/pageSize`:分页组件自动维护。
`LineagePersonTreeView` 补全前,不得继续依靠多个字段 fallback 猜树结构。
### 7.9 视频
计划新增 `profile-video-edit.html``profile-video.html` 负责列表。
| 字段 | 必填性 | 类型 | 页面处理 |
| --- | --- | --- | --- |
| `videoTitle` | 必填 | U | 标题 |
| `videoDesc` | 可选 | U | 说明文本域 |
| `coverOssId` | 可选 | F/I | 封面上传、预览、隐藏 ID |
| `videoOssId` | 必填 | F/I | 视频文件上传;不得输入 ID |
| `durationSeconds` | 可选 | F/A/R | 从视频元数据读取,只读显示 |
| `sortOrder` | 可选 | U/S | 管理高级设置 |
| `status` | 可选 | S | 0 正常、1 停用 |
| `genealogyId``videoId` | path | I/A | 上下文和记录 |
流程:选视频 → 分片上传 → 得到 `videoOssId` → 可选封面上传 → 填标题说明 → 保存 → 重新读取详情。
当前视频列表、详情、新增和修改均返回泛型对象/列表。C17 完成前可以完成静态表单布局和 `ApiClient` 契约测试,但不得把真实 CRUD 页面标记为已完成。
### 7.10 贺礼邀约与祭祀
邀约字段:
| 字段 | 必填性 | 类型 | 页面处理 |
| --- | --- | --- | --- |
| `inviteeUserIds` | 必填 | S/I | 家谱成员多选;提交完整名单,空数组表示取消全部未响应邀请 |
| `inviteStatus` | 必填 | S | 当前用户只能选择 ACCEPTED 接受或 DECLINED 拒绝 |
| `genealogyId``ceremonyId` | path | I/A | 活动上下文 |
邀约响应在 `profile-gift.html` 展示:
- `invitationId``genealogyId``ceremonyId``inviteeUserId`I
- `inviteStatus`RPENDING/ACCEPTED/DECLINED/CANCELED 徽标;
- `inviteVersion`I/R,只在管理审计需要时显示;
- `deliveredTime``readTime``responseTime`R
- `ceremonyTitle``ceremonyTime``location``locationAddress`R
- `longitude``latitude`:地图定位内部值,页面显示地图/地址而非原始数字。
“我的邀请”接口有完整响应,可独立实现接受/拒绝流程。管理端替换受邀人依赖 C16,且必须先有真实活动 ID。
当前没有祭祀活动列表、详情、新增、修改和献礼列表/新增接口。现有 `profile-gift-edit.html` 中的 `ceremonyType``ceremonyTitle``ceremonyTime``location``ceremonyDesc``coverOssId` 不属于任何现有 PC 写入 DTO,必须继续保持禁用,不得向猜测路径提交。
两条删除接口只能在后端补齐列表和详情、产生稳定 ID 后开放:
- 删除活动是逻辑删除活动及祭品并释放封面引用;
- 删除祭品只操作被选中的真实 `giftId`
- 删除确认必须说明影响范围。
### 7.11 成长记录
页面:`profile-growth.html``profile-growth-edit.html`
| 字段 | 必填性 | 类型 | 页面处理 |
| --- | --- | --- | --- |
| `lineagePersonId` | 可选 | S/I | 世系人物搜索选择器,禁止 ID 输入框 |
| `recordType` | 可选 | U 或 S | C12 未解决前按 Apifox 明确结果决定,不能猜枚举 |
| `recordTitle` | 必填 | U | 标题 |
| `recordContent` | 可选 | U | 正文编辑器 |
| `recordDate` | 可选 | S | 日期控件,等待 C13 明确格式 |
| `remindTime` | 可选 | S | 日期时间控件 |
| `mediaOssIds` | 可选 | F/I | 多附件上传 |
| `sortOrder` | 可选 | U/S | 管理高级设置 |
| `status` | 可选 | S | 0 正常、1 停用 |
列表、详情、新增和修改响应仍是泛型对象。补齐 `GrowthRecordView` 前不得展示原始 JSON,也不得猜 `recordId` 开启编辑和删除。
### 7.12 亲友记录
页面:`profile-relative.html``profile-relative-edit.html`
| 字段 | 必填性 | 类型 | 页面处理 |
| --- | --- | --- | --- |
| `relativeName` | 必填 | U | 亲友姓名 |
| `relationName` | 可选 | U | 关系名称 |
| `eventName` | 可选 | U | 事件名称 |
| `eventTime` | 可选 | S | 日期时间选择器 |
| `giftAmount` | 可选 | U | 金额输入,明确精度和非负规则后校验 |
| `recordContent` | 可选 | U | 内容 |
| `mediaOssIds` | 可选 | F/I | 多附件上传 |
| `sortOrder` | 可选 | U/S | 管理高级设置 |
| `status` | 可选 | S | 0 正常、1 停用 |
补齐 `RelativeRecordView` 前只完成页面字段布局和请求契约,不开放真实列表、编辑和删除。
### 7.13 备忘录
页面:`profile-memo.html``profile-memo-edit.html`
| 字段 | 必填性 | 类型 | 页面处理 |
| --- | --- | --- | --- |
| `memoTitle` | 必填 | U | 标题 |
| `memoContent` | 可选 | U | 内容 |
| `remindTime` | 可选 | S | 日期时间 |
| `completed` | 可选 | S | 应为开关;C11 明确提交值前保持禁用 |
| `mediaOssIds` | 可选 | F/I | 多附件上传 |
| `sortOrder` | 可选 | U/S | 管理高级设置 |
| `status` | 可选 | S | 0 正常、1 停用 |
`completed` 表示业务完成状态,`status` 表示记录正常/停用,两者不能合并。补齐 `MemoView` 前不得猜 `memoId` 或响应字段。
### 7.14 功德记录
页面:`profile-merit.html``profile-merit-edit.html`
| 字段 | 必填性 | 类型 | 页面处理 |
| --- | --- | --- | --- |
| `donorName` | 必填 | U | 功德人姓名 |
| `meritType` | 可选 | S | donation 捐赠、repair 修祠、public 公益、other 其他 |
| `meritTitle` | 必填 | U | 标题 |
| `meritContent` | 可选 | U | 内容 |
| `amount` | 可选 | U | 金额 |
| `meritTime` | 可选 | S | date-time |
| `sortOrder` | 可选 | U/S | 管理高级设置 |
| `status` | 可选 | S | 0 正常、1 停用 |
现有页面错误地使用了 `service`,但契约枚举中不存在该值;必须删除 `service`,增加 `repair``public`。现有页面还缺少 `sortOrder``status`
列表、详情、新增和修改仍是泛型响应。补齐 `MeritRecordView` 后再开放完整 CRUD。
### 7.15 消息通知
页面:`profile-messages.html`
| 字段 | 必填性 | 类型 | 页面处理 |
| --- | --- | --- | --- |
| `readStatus` | 可选 query | S | 全部=省略、未读=0、已读=1 |
| `notificationId` | 单条已读必填 path | I/A | 从被点击通知记录带入 |
| 未读数量 `data` | 响应 | R | 顶部徽标,int64 按安全数值/字符串处理 |
通知列表当前是 `ListResult<object>`,没有通知 ID、标题、正文、类型、时间、已读状态和目标深链。补齐 `NotificationView` 前:
- 可以调用未读数量和全部已读;
- 不得展示原始对象;
- 不得猜 `notificationId` 开放单条已读;
- 不得根据未声明字段拼详情跳转。
### 7.16 当前只有删除能力的模块
| 模块 | 当前操作 | 页面策略 |
| --- | --- | --- |
| 内容文章 | 删除文章 | `profile-article*` 保持设计;没有列表/详情时不开放删除 |
| 相册 | 删除相册、删除照片 | `profile-album.html` 保持设计;不使用静态 ID 调删除 |
| 祭祀 | 删除活动、删除祭品 | 活动 CRUD 和礼物列表补齐前保持禁用 |
删除按钮必须由真实响应中的 ID 和权限字段产生。禁止用 DOM 序号、示例 ID 或 URL 猜测资源 ID。
## 8. 分阶段执行顺序
### 阶段 0:冻结契约
工作:
1. 完成第 5 节 C01-C20 的本阶段相关项。
2. 从 Apifox 重导 OpenAPI。
3. 写契约快照测试,统计操作、请求字段、required、枚举、response `$ref`
4. 确认旧路径和旧字段会失败,不保留兼容代码。
验证:
- JSON 可被解析;
- 实际接口数与收口后的 Apifox 一致;
- 0 个重复逻辑路径;
- 本轮实现模块不存在泛型业务响应;
- 登录注册等公开接口不带 Authorization。
### 阶段 1:请求基础设施、验证和认证
工作:
1. 收口 `config.js``AxiosRequestUtil.js``ApiClient.js` 的 header、token、tenant 和错误处理。
2. 完成验证中心、登录、注册、短信、找回、换绑、注销、退出。
3. 完成个人资料全部 6 个写入字段。
4. 为每条认证流程测试 body 中不存在 `clientId``sceneCode` 和旧验证码字段。
验证:
- 密码、短信两种登录成功;
- 验证策略开/关两条路径都成功;
- 一次性 `validToken` 不能复用;
- 401 清除登录态,403 保留登录态;
- 确认密码等 V 类字段未进入请求。
### 阶段 2:文件上传和区划
前提:C01、C08、C09、C10、C13 完成。
工作:
1. 实现单分片小文件和多分片大文件同一流程。
2. 实现秒传、进度、重试、重复提交锁。
3. 只保留一套区划 API,并实现级联、搜索、路径回显。
4. 所有业务页移除可见 OSS ID 输入框。
验证:
- 普通图片、最后一片不足 chunkSize、大视频、秒传分别通过;
- MD5、大小、分片数量与初始化一致;
- 页面刷新后的业务对象能重新显示文件;
- 区划不同时请求两套路径。
### 阶段 3:家谱上下文
前提:C14 完成,或产品正式给出可验证的外部上下文契约。
工作:
1. `profile-common.js` 成为 `genealogyId` 的唯一 owner。
2. 我的家谱页提供真实选择入口。
3. 所有家谱内链接传播同一个 ID,切换家谱时清空旧页面状态。
验证:
- 无 ID 不发请求;
- 切换两个家谱不串数据;
- ID 始终按字符串处理;
- 不存在示例 ID 和 APP 请求。
### 阶段 4:已具备明确 DTO 的家谱模块
顺序:
1. 家族圈;
2. 字辈谱;
3. 世系人物;
4. 我的贺礼邀请。
每个模块采用同一闭环:
1. `ApiClient` 方法和契约测试;
2. 列表/详情读取;
3. 新增;
4. 修改;
5. 删除/停用;
6. 权限、空状态、错误状态、重复提交;
7. 写入后重新读取验证。
### 阶段 5:补齐 DTO 后的资源模块
顺序:
1. 视频;
2. 成长记录;
3. 亲友记录;
4. 备忘录;
5. 功德记录;
6. 消息通知。
任何模块的 View/List DTO 未补齐时,只完成表单布局和契约测试,不宣称真实功能完成。
### 阶段 6:后端补齐后再开放的模块
范围:
- 文章;
- 相册/照片;
- 祭祀活动/祭品;
- 管理员邀约名单;
- 指定账号绑定世系人物;
- 家谱和成员管理;
- 世系关系解除。
这些模块不允许通过 APP 接口或猜测路径提前实现。
## 9. 文件级施工建议
执行 AI 应优先修改现有 owner,避免页面各自复制逻辑:
| 文件 | 职责 |
| --- | --- |
| `PC.openapi.json` | 当次 Apifox 导出快照,不手工补字段 |
| `config.js` | 环境、API 基础地址、非敏感客户端配置 |
| `utils/ApiClient.js` | 所有正式 PC method/path/query/body |
| `utils/AxiosRequestUtil.js` | header、鉴权、响应解包、401/403 |
| `utils/FormUtil.js` | 表单取值、空可选字段省略、前端校验 |
| `public/js/profile-common.js` | 登录页外的家谱上下文 |
| `public/js/upload-pages.js` | 唯一上传流程 |
| `public/js/auth-pages.js` / `security-pages.js` | 认证业务流程 |
| `public/js/feed-pages.js` | 家族圈 |
| `public/js/generation-pages.js` | 字辈 |
| `public/js/lineage-pages.js` | 世系 |
| `public/js/growth-pages.js``relative-pages.js``memo-pages.js` | 对应族务记录 |
| 新增专用视频/功德/邀约脚本 | 仅在 DTO 完整后新增 |
不得创建一个包揽所有业务的巨型页面脚本,也不得为了单一页面引入通用框架。
## 10. 测试与验收
### 10.1 必须新增或更新的测试
1. OpenAPI 契约快照:
- operation 数;
- method/path
- body Schema
- required
- enum
- response `$ref`
- 公开/鉴权标记。
2. `ApiClient` 契约测试:
- URL、query、body、header
- int64 ID 不转 Number
- 可选空字段被省略;
- 旧路径/旧字段不存在。
3. 页面字段覆盖测试:
- 每个请求 Schema 字段都能在本规划的 U/S/F/A/I/V 分类中找到;
- 用户可编辑字段有对应 `name`
- 自动字段没有可见文本输入;
- 枚举选项和值与 Apifox 一致。
4. 流程测试:
- 验证与短信;
- 上传;
- 家谱上下文;
- 列表 → 详情 → 编辑 → 重读;
- 删除/停用;
- 401/403/404/409/422/429。
5. 安全测试:
- 富文本经过净化;
- 密码、token、validToken 不写日志;
- 外链和上传文件类型受限;
- 错误消息不直接插入 HTML。
### 10.2 建议验证命令
先跑最小相关测试,再跑全量:
```powershell
node --test tests/api-client-contract.test.js
node --test tests/auth-pages.test.js tests/captcha-pages-contract.test.js
node --test tests/feed-pages.test.js tests/generation-pages.test.js tests/lineage-pages.test.js
node --test tests/growth-pages.test.js tests/relative-pages.test.js tests/memo-pages.test.js tests/notification-pages.test.js
node --test tests/*.test.js
```
执行 AI 若新增测试文件,应在本节补上精确命令。
### 10.3 模块完成定义
一个模块只有同时满足以下条件才可标记完成:
1. Apifox 契约无未决冲突。
2. 所有请求字段已分类并落到页面。
3. 列表和详情响应有明确 DTO。
4. `ApiClient` 不存在旧路径或 fallback。
5. 页面有加载、空、成功、校验失败、无权限和网络失败状态。
6. 写操作防重复提交。
7. 成功写入后通过重新读取验证。
8. 相关测试和全量测试通过。
9. 没有原始 JSON、手填 ID、示例业务数据或 APP 接口冒充真实能力。
## 11. 执行完成后的报告格式
执行 AI 每个阶段只报告:
```text
Changed: 修改了哪些 owner、页面和契约。
Verified: 运行了哪些测试,真实联调覆盖了哪些流程。
Blocked: 哪些字段或流程仍缺 Apifox/后端契约,具体缺什么。
Next: 下一阶段可以开始的最小范围。
```
不得用“应该可以”“大概完成”代替测试证据。