# 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`,而 `FileUploadVo.ossId`、`LineagePersonView.avatarOssId` 等 OSS ID 为 `string`;部分头像字段也仍为 `integer`。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 / 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`,但示例值已超过 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`:S,0/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`:R,PENDING/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`,没有通知 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: 下一阶段可以开始的最小范围。 ``` 不得用“应该可以”“大概完成”代替测试证据。