309598bfa6
- 在ApiClient中新增submitFeedback、myFeedback、helpArticles、helpArticleDetail、 siteArticles、promotions、vipPackages、createVipOrder、vipOrders等方法 - 添加帮助文章和站点资讯的参数验证逻辑 - 更新测试文件添加新的API方法测试用例 - 在HTML页面中添加反馈、帮助和VIP服务相关页面的脚本引用 - 更新加入家谱页面为完整的申请流程界面 - 修改资讯详情页面为站点资讯展示页面 - 更新AxiosRequestUtil中认证处理逻辑 - 添加世系树渲染的HTML生成函数用于页面复用 - 更新文档中的API契约说明和页面规划
1667 lines
122 KiB
Markdown
1667 lines
122 KiB
Markdown
# 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 | 已由后端 PC 实链接决 | `GET /genealogy/pc/genealogies/mine` 和 `/options` 返回完整 `AppGenealogyVo`,`genealogyId` 从响应取得 | 前端只从真实列表选择,不允许手填 ID |
|
||
| C15 | `bindingMode=SPECIFIED` 需要 `appUserId`,但无业务用户选项接口 | 不能提供合法选择器 | 增加家谱成员/业务用户选项接口 |
|
||
| C16 | 邀约的 `inviteeUserIds` 没有选项接口 | 不能让管理员选择受邀人 | 增加同一家谱成员选项接口 |
|
||
| C17 | 视频、成长、亲友、备忘、功德、通知响应未展开 | 无法安全展示、编辑或单条操作 | 分别增加资源 View 和列表/详情响应 |
|
||
| C18 | 更新接口未说明缺省、null、空串语义 | 可选字段可能无法清空 | Apifox 对每个可清空字段写明更新规则 |
|
||
| C19 | 多数 View 没有 `canEdit` / `canDelete` 等权限字段 | 页面无法可靠决定按钮可见性 | 增加能力字段,或提供明确且可实现的角色规则 |
|
||
| C20 | 文章、相册、祭祀只有删除操作 | 没有真实 ID 来源和完整资源流程 | 补全 PC 列表/详情/新增/修改后才开放页面 |
|
||
| C21 | 家族圈动态只返回 `mediaOssIds`,PC 没有 OSS ID 批量解析/访问 URL 接口 | 已上传图片只能统计数量,不能在列表和详情安全回显缩略图 | PC 增加按 OSS ID 返回授权 URL、文件名和媒体类型的接口,或让动态 View 直接返回媒体对象数组 |
|
||
| C22 | 停用动态不会出现在普通列表,普通详情接口也拒绝读取 | 管理员可以停用,但停用后无法从 PC 页面重新读取、恢复或验证最终状态 | 增加包含停用记录的管理列表/详情,或增加独立的状态恢复接口 |
|
||
| C23 | `VideoVo` 只返回 `coverOssId` / `videoOssId`,没有 PC 文件访问 URL 或解析接口 | 可以维护视频记录,但不能安全播放视频或回显封面 | 视频 View 直接返回授权 URL,或增加按 OSS ID 获取文件访问地址的 PC 接口 |
|
||
| C24 | 视频列表只返回正常记录,详情拒绝读取停用记录 | `status=1` 后无法从页面重新读取和恢复 | 增加视频 management 列表/详情,或增加独立状态恢复接口 |
|
||
| C25 | `GrowthRecordVo` 只返回附件 `mediaOssIds`,没有 PC 文件访问 URL 或解析接口 | 可以维护附件引用,但不能安全预览、下载或回显文件名 | 成长记录 View 返回附件对象,或增加按 OSS ID 获取授权地址、文件名和类型的 PC 接口 |
|
||
| C26 | 成长记录列表只返回正常记录,详情拒绝读取停用记录 | `status=1` 后无法写后重读、恢复或再次编辑 | 增加成长记录 management 列表/详情,或增加独立状态恢复接口 |
|
||
| C27 | `giftAmount` 只有 `number` / `BigDecimal` 类型,没有精度、范围和正负规则 | 前端不能自行限定两位小数、最大金额或禁止负数 | Apifox 明确 scale、precision、minimum/maximum 和负数业务含义 |
|
||
| C28 | `RelativeRecordVo` 只返回附件 `mediaOssIds`,没有 PC 文件访问 URL 或解析接口 | 可以维护附件引用,但不能安全预览、下载或回显文件名 | 亲友记录 View 返回附件对象,或增加按 OSS ID 获取授权地址、文件名和类型的 PC 接口 |
|
||
| C29 | 亲友记录列表只返回正常记录,详情拒绝读取停用记录 | `status=1` 后无法写后重读、恢复或再次编辑 | 增加亲友记录 management 列表/详情,或增加独立状态恢复接口 |
|
||
| C30 | `MemoVo` 只返回附件 `mediaOssIds`,没有 PC 文件访问 URL 或解析接口 | 可以维护附件引用,但不能安全预览、下载或回显文件名 | 备忘录 View 返回附件对象,或增加按 OSS ID 获取授权地址、文件名和类型的 PC 接口 |
|
||
| C31 | 备忘录列表只返回正常记录,详情拒绝读取停用记录 | `status=1` 后无法写后重读、恢复或再次编辑 | 增加备忘录 management 列表/详情,或增加独立状态恢复接口 |
|
||
| C32 | 功德金额只有 `number` / `BigDecimal` 类型,没有精度、范围和正负规则 | 前端不能自行限定两位小数、最大金额或禁止负数 | Apifox 明确 scale、precision、minimum/maximum 和负数业务含义 |
|
||
| C33 | 功德记录列表只返回正常记录,详情拒绝读取停用记录 | `status=1` 后无法写后重读、恢复或再次编辑 | 增加功德记录 management 列表/详情,或增加独立状态恢复接口 |
|
||
| C34 | YAML `NotificationView` 声明了家谱编号/名称、发送人昵称/手机号和业务摘要,但 PC `toVo` 未填充这些字段 | 页面可能长期显示空白,导出契约与真实 PC 响应不一致 | 后端补齐字段,或从 PC Schema 删除不会返回的字段并明确隐私策略 |
|
||
| C35 | PC 谱文后端列表支持可选 `categoryId`,YAML 未声明该 query,且没有文章分类选项接口 | 前端无法可靠提供分类筛选或编辑分类 | YAML 补齐 query,并提供当前家谱文章分类选项接口 |
|
||
| C36 | `ArticleVo` 只返回 `coverOssId`,没有 PC 文件访问 URL | 谱文可维护封面引用,但不能安全回显封面图片 | Article View 返回封面 URL,或增加 OSS ID 授权解析接口 |
|
||
| C37 | 谱文列表只返回正常记录,详情拒绝读取停用记录 | `status=1` 后无法写后重读或恢复 | 增加谱文 management 列表/详情,或独立状态恢复接口 |
|
||
| C38 | `AlbumVo` / `AlbumPhotoVo` 只返回 `coverOssId` / `ossId`,没有 PC 文件访问 URL | 相册和照片记录可维护,但不能安全回显封面或照片内容 | View 返回授权 URL,或增加 OSS ID 授权解析接口 |
|
||
| C39 | 相册和照片列表只返回正常记录,且没有停用记录的 management 入口 | `status=1` 后无法从页面重读、恢复或再次编辑 | 增加相册/照片 management 列表,或独立状态恢复接口 |
|
||
| C40 | `CeremonyVo` 只返回 `coverOssId`,没有 PC 文件访问 URL | 活动记录可维护,但不能安全回显封面 | View 返回封面授权 URL,或增加 OSS ID 授权解析接口 |
|
||
| C41 | 活动列表和详情只允许读取正常记录 | `status=1` 后无法从页面重读、恢复或再次编辑 | 增加活动 management 列表/详情,或独立状态恢复接口 |
|
||
| C42 | `CeremonyGiftBody.giftAmount` 的 YAML 没有精度和最大值,后端实际拒绝负数 | 页面可按后端约束拒绝负数,但不能自行限定小数位或最大金额 | YAML 补充 minimum、scale、precision 和 maximum |
|
||
| C43 | YAML 成员更新角色枚举含 `owner/visitor`,PC 后端 DTO 只接受 `admin/editor/member` | 按 YAML 展示会产生必然失败的写入 | YAML 收紧枚举;本轮前端按 PC 后端校验冻结为三种可分配角色 |
|
||
| C44 | `GenealogyMemberVo` 声明昵称、手机号、家谱和世系人物名称等字段,PC `toVo` 实际只填充 ID、成员名、角色、关系、来源和时间 | 列表部分说明可能长期为空,手机号还有隐私风险 | 后端补齐非敏感展示字段并删除手机号,或从 PC Schema 删除不会返回的字段 |
|
||
| C45 | PC 没有世系关系解除接口 | 页面无法合法解除父母、配偶、子女或兄弟姐妹关系 | 后端增加带权限和关系完整性校验的解除接口 |
|
||
| C46 | 成员更新只在 `lineagePersonId != null` 时写入,没有解除成员与世系人物绑定的语义 | 下拉留空只能表示“不修改”,不能完成解绑 | 增加明确解绑接口或约定可验证的 null/空值语义 |
|
||
|
||
当前复核状态:
|
||
|
||
| 阻断项 | 状态 | 在线/补齐文件证据 |
|
||
| --- | --- | --- |
|
||
| 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` |
|
||
| C11(备忘录) | 本轮按后端 PC 实链解决 | YAML 仍只有 string;PC `AppMemoServiceImpl` 明确校验 `completed` 只能为 `0/1`,含义为否/是,前端冻结为未完成/已完成 |
|
||
| C13 | 后续日期模块仍阻断 | 本阶段上传与区划响应不消费日期;其他模块仍需逐字段核验 Java 日期类型 |
|
||
| C17(成长记录) | 本轮按后端 PC 实链解决 | YAML 响应仍为泛型;PC `PcGrowthRecordController` 明确返回 `GrowthRecordVo`,前端只冻结该 PC 响应,不读取 APP 路径 |
|
||
| C17(亲友记录) | 本轮按后端 PC 实链解决 | YAML 响应仍为泛型;PC `PcRelativeRecordController` 明确返回 `RelativeRecordVo`,前端只冻结该 PC 响应,不读取 APP 路径 |
|
||
| C17(备忘录) | 本轮按后端 PC 实链解决 | YAML 响应仍为泛型;PC `PcMemoController` 复用的 PC 支持层明确返回 `MemoVo`,前端只冻结该 PC 响应,不读取 APP 路径 |
|
||
| C17(功德记录) | 本轮按后端 PC 实链解决 | YAML 响应仍为泛型;PC `PcMeritRecordController` 复用的 PC 支持层明确返回 `MeritRecordVo`,前端只冻结该 PC 响应,不读取 APP 路径 |
|
||
| C17(消息通知) | 本轮按 YAML 详情 DTO 和后端 PC 实链解决 | 详情为完整 `NotificationView`;列表导出仍是泛型数组,但 PC 控制器实际返回同一 `NotificationVo`。前端只接受直接数组,不读取 APP 路径 |
|
||
| C20(谱文) | 本轮按后端 PC 实链解决 | PC 控制器实际具备列表、详情、新增、修改、删除并返回 `ArticleVo`;页面不再只开放删除 |
|
||
| C18 | 阻断 | 未说明可选更新字段的省略、`null`、空串语义 |
|
||
| C34 | 阻断非核心展示 | PC 实际未填充 `genealogyNo/genealogyName/senderNickName/senderPhone/bizSummary`;页面兼容空值并始终隐藏手机号,核心通知读取和已读闭环不依赖这些字段 |
|
||
| C35 | 阻断分类能力 | 本轮不发送 YAML 未声明的 `categoryId` query,也不提供手填分类 ID |
|
||
| C36/C37 | 阻断非核心展示/停用管理 | 本轮不猜封面 URL,并固定提交 `status=0`,避免产生不可重读谱文 |
|
||
| C20(相册/照片) | 本轮按后端 PC 实链接决 | PC 控制器具备相册列表、新增、修改、删除和照片列表、新增、删除;页面只从响应取得稳定 ID |
|
||
| C38/C39 | 阻断非核心展示/停用管理 | 本轮不猜文件 URL,并固定提交 `status=0`,避免产生不可重读的相册或照片 |
|
||
| C20(祭祀活动/祭品) | 本轮按后端 PC 实链接决 | PC 控制器具备活动完整 CRUD 和祭品列表、新增、删除;页面只使用响应中的稳定 ID |
|
||
| C16 | 本轮按后端 PC 实链接决 | `members/options` 返回同一家谱成员及真实 `appUserId`;管理员邀约名单只允许选择正常且已绑定账号的成员 |
|
||
| C15 | 本轮按后端 PC 实链接决 | `members/options` 是当前家谱真实业务账号的唯一选择源;`SPECIFIED` 只提交正常且已绑定账号成员的 `appUserId` |
|
||
| C40/C41 | 阻断非核心展示/停用管理 | 本轮不猜封面 URL,并固定提交 `status=0`,避免产生不可重读活动 |
|
||
| C42 | 阻断金额精度/上限 | 前端只执行后端已确认的非负校验,不自行限制小数位和最大金额 |
|
||
| C43 | 前端按后端 PC 实链收紧 | 成员角色选择器只允许 `admin/editor/member`;不发送 YAML 中后端拒绝的 `owner/visitor` |
|
||
| C44 | 阻断非核心 enrichment | 页面兼容未填充名称,始终隐藏成员、邀请人手机号和内部用户 ID;核心成员管理不依赖这些字段 |
|
||
| C45/C46 | 阻断 | 页面不提供世系关系解除,也不把空 `lineagePersonId` 解释为解绑 |
|
||
|
||
阶段 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`,不能替代“我的家谱”。当前由 `GET /genealogy/pc/genealogies/mine` 返回完整 `AppGenealogyVo`:
|
||
|
||
- `profile-families.html` 从真实列表生成家谱入口;
|
||
- `genealogyId` 在浏览器边界保持字符串,并由 `profile-common.js` 统一读取和传播;
|
||
- 所有家谱内页面缺少真实 `genealogyId` 时必须阻止请求并回到家谱选择入口;
|
||
- 不显示静态家谱卡片,不从 APP 接口获取家谱,不允许用户手工输入家谱 ID;
|
||
- 切换家谱通过进入新的带 `genealogyId` URL 完成整页导航,旧页面模块状态不会复用。
|
||
|
||
### 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 直接移除整棵回复。
|
||
|
||
2026-07-28 家族圈实施状态:
|
||
|
||
- `ApiClient` 的 14 个家族圈 PC 操作已由契约测试锁定;页面首屏只调用 `/feeds/page`,评论和回复分别调用各自的 `/page`。
|
||
- 已新增 `profile-feed-detail.html`,以 `genealogyId + feedId` 形成稳定详情深链;列表、详情和编辑链接都保留字符串 ID。
|
||
- 列表和详情消费 `AppFamilyFeedVo` 的发布人、点赞状态与计数、评论计数、置顶、状态和时间字段;评论消费 `FamilyFeedCommentVo` 的归属、父评论、层级、删除占位、回复计数和时间字段。
|
||
- `GET /genealogy/pc/genealogies/{genealogyId}` 的 `canEditContent/canManage` 控制编辑和高级设置,`GET /genealogy/pc/auth/profile` 的 `userId` 结合响应中的发布人/评论人 ID 控制本人删除按钮;后端仍执行最终权限校验。
|
||
- 发布图片只允许文件选择;`mediaOssIds` 为隐藏的上传派生字段,多文件结果使用英文逗号连接,不允许手填 OSS ID。
|
||
- 新增、修改、点赞、取消点赞、评论和删除均有同资源动作锁;成功后重新读取详情、分页列表或评论分页以校正页面状态。
|
||
- `status=1` 使用后端定义的“停用”语义,不再显示为“草稿”。C21、C22 未解决前,图片缩略图回显和停用记录恢复仍属于后端阻断,不宣称这两项闭环完成。
|
||
- 已在真实 Chrome 登录态验证:当前账号的 `/genealogies/mine` 返回空列表;无家谱上下文时家族圈不发业务请求,所有发布入口统一改写到 `profile-families.html?next=profile-feed-edit.html`。发布表单实测为多文件选择、隐藏 OSS ID、普通用户隐藏且禁用管理字段。由于账号没有家谱,本轮不能进行真实动态列表/详情读取或写操作联调。
|
||
|
||
### 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 接口以包含停用项。
|
||
|
||
当前实现状态:
|
||
|
||
- 页面先读取家谱详情,以 `canEditContent` 决定调用正常列表还是 management 列表;无维护权限时不渲染新增、编辑、停用和批量维护控件,后端继续执行最终权限校验。
|
||
- `genealogyId` 只来自家谱上下文,`poemId` 只来自列表响应;所有业务 ID 在浏览器边界保持字符串,不提供手工 ID 输入。
|
||
- 单条新增、修改和状态切换成功后重新读取列表;批量维护严格执行 preview → 当前请求体签名确认 → save → 重新读取列表。
|
||
- 批量预览逐项校验 `action`、状态、必需的新旧文本和内部 ID,并核对四类汇总计数;勾选 `disableMissing` 时保存确认明确说明只停用后续世代、不删除历史。
|
||
- 已在真实 Chrome 登录态验证无家谱上下文分支:不发送字辈业务请求,新增按钮和批量面板隐藏,家谱上下文入口统一返回家谱选择页。当前账号家谱列表为空,因此正常/management 列表、单条写入和批量写入仍缺少真实家谱数据联调证据。
|
||
|
||
### 7.8 世系人物
|
||
|
||
全部操作集中在 `profile-tree.html`,详情和编辑可使用抽屉/弹窗,但所有字段都要有明确控件。
|
||
|
||
| 字段 | 必填性 | 类型 | 页面处理 |
|
||
| --- | --- | --- | --- |
|
||
| `bindingMode` | 必填 | S | NONE 不绑定、SELF 当前账号、SPECIFIED 指定账号 |
|
||
| `appUserId` | SPECIFIED 时必填 | S/I | 从当前家谱 `members/options` 的正常且已绑定账号成员中选择;禁止文本 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 猜树结构。
|
||
|
||
当前实现状态:
|
||
|
||
- 已接入 PC 世系树、普通列表、分页列表、人物选项、详情、新增、修改、逻辑停用,以及父母、子女、兄弟姐妹、配偶四类关系新增;成功写入后统一重新读取树、列表、分页和选项,返回稳定 `personId` 时再读取详情。
|
||
- 页面先读取家谱详情,`canEditContent` 只控制新增、编辑、停用和关系维护;树、列表、详情、筛选和分页保持只读可用,后端继续执行最终查看和编辑权限校验。
|
||
- `LineagePersonBody` 的全部字段均有明确来源:世代从正常字辈列表选择并自动回填字辈,父母从世系人物选项选择,头像通过统一上传组件产生隐藏 `avatarOssId`,所有业务 ID 在浏览器边界保持字符串且不可手填。
|
||
- 新增和编辑人物开放 `NONE`、`SELF`、`SPECIFIED`;`SPECIFIED` 选择器只消费当前家谱 `members/options`,过滤未绑定账号、停用成员和当前账号,不显示手机号,不允许手填 `appUserId`。
|
||
- 编辑已绑定其他账号的人物时,用详情响应的 `appUserId` 精确匹配同一成员选项;真实选项不存在时不伪造回填,保存会被前端校验阻止。
|
||
- 分页查询已接入 `keyword`、`generation`、`personStatus`、`pageNum/pageSize`;详情展示家谱、绑定账号、父母、配偶、出生、逝世、安葬、人物状态、简介和备注等响应字段。
|
||
- DELETE 确认明确使用“停用”语义,并提示存在正常子女时后端会拒绝;页面没有伪造解除关系或物理删除。
|
||
- 已在真实 Chrome 登录态验证无家谱上下文分支:不发送世系业务请求,读区域显示选择家谱提示,新增、关系维护和完整表单隐藏,分页与配偶专用字段不误显示,所有家谱链接返回家谱选择页。当前账号家谱列表为空,因此真实树、列表、详情和写操作仍缺少有数据账号联调证据。
|
||
- C18 仍适用于本模块:可选字段清空语义未明确,本轮仅提交非空值,不宣称可选字段清空闭环。
|
||
- `SPECIFIED` 账号绑定相关聚焦测试 42/42 通过;真实账号页面验证统一留到阶段 6 收尾执行。
|
||
|
||
### 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` → 可选封面上传 → 填标题说明 → 保存 → 重新读取详情。
|
||
|
||
YAML 的视频响应仍使用泛型 `ObjectResult` / `ListResult`,但后端已存在独立 `PcVideoController`,其 PC method/path 与 YAML 一致,并明确返回 `VideoVo`。根据本轮“后端源码可作为可靠补充契约”的约定,页面响应字段由该 PC 控制器及 `VideoVo` 冻结:
|
||
|
||
- I:`videoId`、`genealogyId`、`coverOssId`、`videoOssId`、`publisherUserId`;
|
||
- R:`genealogyNo`、`genealogyName`、`surname`、`publisherNickName`、`publisherPhone`、`publishTime`、`viewCount`、`remark`;
|
||
- U/R:`videoTitle`、`videoDesc`;
|
||
- F/A/R:`durationSeconds`;
|
||
- U/S/R:`sortOrder`;
|
||
- A/R:`status`,当前固定提交 `0`。
|
||
|
||
当前接入状态:
|
||
|
||
- `profile-video.html` 已接入正常视频列表、详情读取、权限化编辑/删除入口、空错状态和无家谱上下文分支;
|
||
- 新增 `profile-video-edit.html`,新增和修改只提交 `VideoBody` 七个字段;视频与封面都通过统一分片上传产生隐藏 OSS ID,不允许手填;
|
||
- 选择视频文件后由浏览器媒体元数据自动读取时长,`durationSeconds` 只读;
|
||
- 保存成功后使用稳定 `videoId` 重新读取详情,再返回列表;删除确认明确会释放视频和封面文件引用,删除后重读列表;
|
||
- 后端 `BigNumberSerializer` 对超出 JavaScript 安全整数范围的 `Long` 输出字符串,对安全整数输出 number;前端接受两种输入并统一保留为字符串;
|
||
- C23 未解决前只显示文件“已上传”,不猜测 OSS URL,不宣称播放或封面预览完成;
|
||
- C24 未解决前不开放 `status=1`,避免产生无法重新读取和恢复的停用视频;
|
||
- 2026-07-29 已在真实登录 Chrome 验证无家谱上下文:视频列表不发业务请求,发布入口及编辑表单保持隐藏,所有上下文链接返回家谱选择页,控制台无错误。当前账号没有家谱,真实列表、详情、上传和 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.html` 已使用 `GET /genealogy/pc/genealogies/ceremony-invitations/mine` 展示当前账号的邀请列表和响应内详情;仅 `PENDING` 邀请显示接受/拒绝,并向 `PUT /genealogy/pc/genealogies/{genealogyId}/ceremonies/{ceremonyId}/invitations/me` 提交唯一字段 `inviteStatus`,成功后重读列表。内部 ID 和坐标不直接展示,坐标仅用于生成地图链接。2026-07-29 使用真实账号联调,PC “我的邀请”接口成功返回空数组,页面空状态和鉴权正常;由于当前账号没有待响应邀请,真实接受/拒绝写入仍待有邀请数据时复核。后端仓库中的同组 `AppCeremonyController` 仍以 `/genealogy/app/genealogies` 为基础路径,与冻结 YAML 的 `/genealogy/pc` 不一致,但线上 PC mine 路径已实际可用,前端继续以 YAML 为唯一契约,不回退 APP 路径。
|
||
|
||
当前没有祭祀活动列表、详情、新增、修改和献礼列表/新增接口。现有 `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` | 可选 | A | 当前固定提交 0 正常;C26 解决前不开放 1 停用 |
|
||
|
||
YAML 的列表、详情、新增和修改响应仍是泛型对象,但后端已存在独立 `PcGrowthRecordController`,其 PC method/path 与 YAML 一致,并明确返回 `GrowthRecordVo`。根据本轮“后端源码可作为可靠补充契约”的约定,页面响应字段由该 PC 控制器及 `GrowthRecordVo` 冻结:
|
||
|
||
- I:`recordId`、`genealogyId`、`appUserId`、`lineagePersonId`、`mediaOssIds`;
|
||
- R:`genealogyNo`、`genealogyName`、`surname`、`appUserNickName`、`appUserPhone`、`lineagePersonNo`、`lineagePersonName`、`remark`;
|
||
- U/R:`recordType`、`recordTitle`、`recordContent`;
|
||
- S/R:`recordDate`、`remindTime`;
|
||
- U/S/R:`sortOrder`;
|
||
- A/R:`status`,当前固定提交 `0`。
|
||
|
||
当前接入状态:
|
||
|
||
- `profile-growth.html` 已接入当前账号成长记录列表、详情、编辑和删除入口;列表接口不传后端额外的 `all` 参数,只消费当前 YAML 声明的请求;
|
||
- `profile-growth-edit.html` 已接入新增和修改;`lineagePersonId` 只从真实世系人物选项接口选择,`recordId` 只来自列表响应或 URL,均按字符串处理且不能手填;
|
||
- `recordType` 后端 DTO 和服务均为不带枚举的自由字符串,因此保留可选文本输入;`recordDate` 提交 `yyyy-MM-dd`,`remindTime` 由 `datetime-local` 转为后端 `Date` 接受的 `yyyy-MM-dd HH:mm:ss`;
|
||
- 多附件通过统一分片上传产生隐藏 `mediaOssIds`,支持保留、追加和清除附件选择,不显示 OSS ID;
|
||
- 新增和修改成功后必须使用稳定 `recordId` 重读同一条详情并校验身份,再返回列表;删除成功后重读列表,确认文案明确逻辑删除且会释放附件引用;
|
||
- C18 未解决前,标题以外可选文本、人物和日期字段清空不宣称闭环;前端对空可选字段保持省略,附件清除使用后端已明确的空引用处理;
|
||
- C25 未解决前只显示附件数量,不猜测 OSS URL、文件名或下载地址;C26 未解决前固定 `status=0`,不产生无法重新读取和恢复的停用记录;
|
||
- 2026-07-29 已在真实登录 Chrome 验证无家谱上下文:列表和详情不发成长记录业务请求,编辑表单及页头保存按钮隐藏,入口统一返回家谱选择页。当前账号没有家谱,真实列表、详情、世系选项、上传和 CRUD 写入仍待有数据账号验证。
|
||
|
||
### 7.12 亲友记录
|
||
|
||
页面:`profile-relative.html`、`profile-relative-edit.html`。
|
||
|
||
| 字段 | 必填性 | 类型 | 页面处理 |
|
||
| --- | --- | --- | --- |
|
||
| `relativeName` | 必填 | U | 亲友姓名 |
|
||
| `relationName` | 可选 | U | 关系名称 |
|
||
| `eventName` | 可选 | U | 事件名称 |
|
||
| `eventTime` | 可选 | S | 日期时间选择器 |
|
||
| `giftAmount` | 可选 | U | 金额输入;只提交 JSON 序列化后数值不变的有限数字,C27 解决前不猜精度、范围或非负规则 |
|
||
| `recordContent` | 可选 | U | 内容 |
|
||
| `mediaOssIds` | 可选 | F/I | 多附件上传 |
|
||
| `sortOrder` | 可选 | U/S | 管理高级设置 |
|
||
| `status` | 可选 | A | 当前固定提交 0 正常;C29 解决前不开放 1 停用 |
|
||
|
||
YAML 的列表、详情、新增和修改响应仍是泛型对象,但后端已存在独立 `PcRelativeRecordController`,其 PC method/path 与 YAML 一致,并明确返回 `RelativeRecordVo`。根据本轮“后端源码可作为可靠补充契约”的约定,页面响应字段由该 PC 控制器及 `RelativeRecordVo` 冻结:
|
||
|
||
- I:`relativeId`、`genealogyId`、`appUserId`、`mediaOssIds`;
|
||
- R:`genealogyNo`、`genealogyName`、`surname`、`appUserNickName`、`appUserPhone`、`remark`;
|
||
- U/R:`relativeName`、`relationName`、`eventName`、`recordContent`;
|
||
- S/R:`eventTime`;
|
||
- U/R:`giftAmount`,后端 `BigDecimal` 响应按字符串保留;
|
||
- U/S/R:`sortOrder`;
|
||
- A/R:`status`,当前固定提交 `0`。
|
||
|
||
当前接入状态:
|
||
|
||
- `profile-relative.html` 已接入当前账号亲友记录列表、详情、编辑和删除入口;列表接口不传后端额外的 `all` 参数,只消费当前 YAML 声明的请求;
|
||
- `profile-relative-edit.html` 已接入新增和修改;`relativeId` 只来自列表响应或 URL,按字符串处理且不能手填;
|
||
- `eventTime` 使用 `datetime-local`,提交前转为后端 `Date` 接受的 `yyyy-MM-dd HH:mm:ss`,并校验真实月日和时分秒;
|
||
- `giftAmount` 请求按 YAML 的 `number` 提交;提交前比较用户十进制输入与 `JSON.stringify(Number(value))` 的精确数值,序列化会改值的超大或高精度金额直接拒绝。后端 `BigDecimal` 响应按原字符串展示,不转回 `Number`;
|
||
- 多附件通过统一分片上传产生隐藏 `mediaOssIds`,支持保留、追加和清除附件选择,不显示 OSS ID;
|
||
- 新增和修改成功后必须使用稳定 `relativeId` 重读同一条详情并校验身份,再返回列表;删除成功后重读列表,确认文案明确逻辑删除且会释放附件引用;
|
||
- C18 未解决前,可选文本、时间和金额字段的清空不宣称闭环;附件清除使用后端已明确的空引用处理;
|
||
- C27 未解决前不增加两位小数、最大金额或非负限制;C28 未解决前只显示附件数量;C29 未解决前固定 `status=0`,并拒绝编辑停用响应,避免意外恢复;
|
||
- 2026-07-29 已在真实登录 Chrome 验证无家谱上下文:列表和详情不发亲友记录业务请求,编辑表单及页头保存按钮隐藏,入口统一返回家谱选择页。当前账号没有家谱,真实列表、详情、上传和 CRUD 写入仍待有数据账号验证。
|
||
|
||
### 7.13 备忘录
|
||
|
||
页面:`profile-memo.html`、`profile-memo-edit.html`。
|
||
|
||
| 字段 | 必填性 | 类型 | 页面处理 |
|
||
| --- | --- | --- | --- |
|
||
| `memoTitle` | 必填 | U | 标题 |
|
||
| `memoContent` | 可选 | U | 内容 |
|
||
| `remindTime` | 可选 | S | `datetime-local` 选择,提交为 `yyyy-MM-dd HH:mm:ss` 并校验真实日期 |
|
||
| `completed` | 可选 | S | PC 后端已核验:`0` 未完成、`1` 已完成;创建默认 `0` |
|
||
| `mediaOssIds` | 可选 | F/I | 多附件上传自动产生;隐藏保存,允许追加和清除,不允许手填 |
|
||
| `sortOrder` | 可选 | U/S | 安全整数;创建默认 `0` |
|
||
| `status` | 可选 | I/A | 页面固定隐藏提交 `0`;不开放不可重读的停用状态 |
|
||
|
||
PC `MemoVo` 响应字段及页面用途:
|
||
|
||
| 字段 | 类型 | 标记 | 页面处理 |
|
||
| --- | --- | --- | --- |
|
||
| `memoId`、`genealogyId`、`appUserId` | Long | I | 仅从 PC 响应取得并按十进制字符串保存;用于详情、编辑、删除和写后重读,不显示、不手填 |
|
||
| `genealogyNo`、`genealogyName`、`surname` | string | R | 家谱上下文只读信息;当前备忘录页不重复展示 |
|
||
| `appUserNickName` | string | R | 详情显示记录人 |
|
||
| `appUserPhone` | string | I | 隐私字段,不渲染 |
|
||
| `memoTitle`、`memoContent`、`remindTime`、`completed` | string | R | 列表摘要、详情展示和编辑回填 |
|
||
| `mediaOssIds` | string | I | 只统计附件数量并回填隐藏上传字段,不暴露原始 OSS ID |
|
||
| `sortOrder` | Long | I | 编辑回填;列表顺序由后端负责 |
|
||
| `status` | string | I | 仅接受正常记录 `0`;停用响应拒绝进入编辑器 |
|
||
| `remark` | string | R | 详情只读展示,MemoBody 不含此字段,因此不提交 |
|
||
|
||
`completed` 表示业务完成状态,`status` 表示记录正常/停用,两者不能合并。列表、详情、新增、修改和删除只调用 `/genealogy/pc/genealogies/{genealogyId}/memos` 及其 `/{memoId}` 子路径;列表不发送后端管理专用的 `all` 查询。新增/修改成功后使用稳定 `memoId` 重读同一详情,删除后重读列表。
|
||
|
||
- C18 未解决前,可选内容和提醒时间的清空不宣称闭环;附件清除使用后端已明确的空引用处理;
|
||
- C30 未解决前只显示附件数量;C31 未解决前固定 `status=0`,拒绝编辑停用响应,避免意外恢复;
|
||
- 2026-07-29 已在真实登录 Chrome 验证无家谱上下文:列表和详情显示明确提示,编辑表单及页头保存按钮隐藏,控制台无错误。当前账号没有可用家谱,真实列表、详情、上传和 CRUD 写入仍待有数据账号验证。
|
||
|
||
### 7.14 功德记录
|
||
|
||
页面:`profile-merit.html`、`profile-merit-edit.html`。
|
||
|
||
| 字段 | 必填性 | 类型 | 页面处理 |
|
||
| --- | --- | --- | --- |
|
||
| `donorName` | 必填 | U | 功德人姓名 |
|
||
| `meritType` | 可选 | S | donation 捐赠、repair 修祠、public 公益、other 其他 |
|
||
| `meritTitle` | 必填 | U | 标题 |
|
||
| `meritContent` | 可选 | U | 内容 |
|
||
| `amount` | 可选 | U | YAML `number`;提交前拒绝 JSON 序列化会改变精确数值的输入,不自行限制小数位、范围或正负 |
|
||
| `meritTime` | 可选 | S | `datetime-local` 选择,提交为后端示例和 `Date` 接受的 `yyyy-MM-dd HH:mm:ss` |
|
||
| `sortOrder` | 可选 | U/S | 安全整数;创建默认 `0` |
|
||
| `status` | 可选 | I/A | 页面固定隐藏提交 `0`;不开放不可重读的停用状态 |
|
||
|
||
PC `MeritRecordVo` 响应字段及页面用途:
|
||
|
||
| 字段 | 类型 | 标记 | 页面处理 |
|
||
| --- | --- | --- | --- |
|
||
| `meritId`、`genealogyId`、`appUserId` | Long | I | 仅从 PC 响应取得并按十进制字符串保存;用于详情、编辑、删除和写后重读,不显示、不手填 |
|
||
| `genealogyNo`、`genealogyName`、`surname` | string | R | 家谱上下文只读信息;当前功德页不重复展示 |
|
||
| `appUserNickName` | string | R | 详情显示记录人 |
|
||
| `appUserPhone` | string | I | 隐私字段,不渲染 |
|
||
| `donorName`、`meritType`、`meritTitle`、`meritContent` | string | R | 列表摘要、详情展示和编辑回填;HTML 内容转义后展示 |
|
||
| `amount` | BigDecimal | R | 按响应原始字符串展示,不转回 `Number` |
|
||
| `meritTime` | Date | R | 列表、详情展示和 `datetime-local` 编辑回填 |
|
||
| `sortOrder` | Long | I | 编辑回填;列表顺序由后端负责 |
|
||
| `status` | string | I | 仅接受正常记录 `0`;停用响应拒绝进入编辑器 |
|
||
| `remark` | string | R | 详情只读展示,`MeritRecordBody` 不含此字段,因此不提交 |
|
||
|
||
现有页面中的契约外 `service` 已删除,补齐 `repair` 和 `public`;由于 `MeritRecordBody` 没有附件字段,功德页不借用其他模块的 `mediaOssIds` 或上传控件。ApiClient 的新增和修改方法再次按 8 个 YAML 字段白名单过滤,调用者额外传入 `appUserId`、`mediaOssIds` 等字段也不会发送。
|
||
|
||
- 列表、详情、新增、修改和删除只调用 `/genealogy/pc/genealogies/{genealogyId}/merit-records` 及其 `/{meritId}` 子路径;
|
||
- 新增/修改成功后使用稳定 `meritId` 重读同一详情,删除成功后重读列表;
|
||
- C18 未解决前,可选内容、金额和时间的清空不宣称闭环;C32 未解决前不增加两位小数、最大金额或非负限制;C33 未解决前固定 `status=0` 并拒绝编辑停用响应;
|
||
- PC 写操作最终由 `assertCanEditContent` 鉴权;当前 View 没有 `canEdit/canDelete`,页面保留操作入口并明确处理 403,不猜角色字段;
|
||
- 2026-07-29 已在真实登录 Chrome 验证无家谱上下文:列表和详情显示明确提示,编辑表单及页头保存按钮隐藏,契约外类型和附件控件不存在,控制台无错误。当前账号没有可用家谱,真实列表、详情和 CRUD 写入仍待有数据账号验证。
|
||
|
||
列表、详情、新增和修改仍是泛型响应。补齐 `MeritRecordView` 后再开放完整 CRUD。
|
||
|
||
### 7.15 消息通知
|
||
|
||
页面:`profile-messages.html`。
|
||
|
||
接口冻结:
|
||
|
||
- `GET /genealogy/pc/notifications`:可选 query `readStatus=0|1`,返回非分页直接数组;全部通知时省略 query。
|
||
- `GET /genealogy/pc/notifications/unread-count`:返回非负 int64 未读数量。
|
||
- `GET /genealogy/pc/notifications/{notificationId}`:读取当前账号可见的正常通知详情。
|
||
- `POST /genealogy/pc/notifications/{notificationId}/read`:将当前账号的一条正常未读通知标记已读。
|
||
- `POST /genealogy/pc/notifications/read-all`:将当前账号全部未读通知标记已读。
|
||
- 五个接口均由 `ApiClient` 自动携带 Bearer 和 `clientid`;页面不采集 Header。YAML 未声明业务错误码;前端统一处理未登录/401、403、404、业务失败和网络失败。
|
||
|
||
| 字段 | 必填性 / 类型 | 标记 | 页面用途、来源与提交时机 |
|
||
| --- | --- | --- | --- |
|
||
| query `readStatus` | 可选 string;枚举 `0/1` | S | 消息页筛选选择;全部=省略、未读=0、已读=1;切换筛选时提交 |
|
||
| path `notificationId` | 详情/单条已读必填 int64 | I/A | 从列表响应的稳定十进制字符串取得;点击详情或“标记已读”时自动进入 path,不允许手填或转 `Number` |
|
||
| `notificationId` | 响应 int64 | I | 列表行内部关联详情和已读动作;不在可见页面展示 |
|
||
| `genealogyId` | 响应 int64,可空 | I | 仅保留为响应内部上下文;不展示、不提交、不允许手填 |
|
||
| `genealogyNo` | 响应 string | R | 详情只读候选字段;当前 PC 未填充,不作为功能依赖 |
|
||
| `genealogyName` | 响应 string | R | 详情只读展示;当前 PC 可能为空 |
|
||
| `senderUserId` | 响应 int64,可空 | I | 内部关联字段;不展示、不提交 |
|
||
| `senderNickName` | 响应 string | R | 详情只读展示;当前 PC 可能为空 |
|
||
| `senderPhone` | 响应 string | I | 隐私字段,页面始终隐藏 |
|
||
| `noticeType` | 响应 string,无枚举/默认值 | R | 列表和详情只读展示;不据此猜测跳转 |
|
||
| `noticeTitle` | 响应 string | R | 列表和详情标题,转义后展示 |
|
||
| `noticeContent` | 响应 string | R | 列表摘要和详情正文,转义后展示 |
|
||
| `bizType` | 响应 string,无枚举/默认值 | R | 详情只读展示;不据此拼业务 URL |
|
||
| `bizId` | 响应 int64,可空 | I | 内部业务关联字段;PC 未提供目标路由契约前不展示、不跳转 |
|
||
| `bizSummary` | 响应 string | R | 详情只读展示;当前 PC 可能为空 |
|
||
| `publishTime` | 响应 string `date-time` | R | 列表和详情只读展示,不由页面提交 |
|
||
| `readStatus` | 响应 string;枚举 `0/1` | R | 0=未读、1=已读;仅正常未读记录显示单条已读按钮 |
|
||
| `readTime` | 响应 string `date-time`,可空 | R | 详情只读展示,未读时为空 |
|
||
| `status` | 响应 string;枚举 `0/1` | I | 仅用于确认正常状态 `0` 才能执行单条已读,不提供页面编辑 |
|
||
| `remark` | 响应 string | R | 详情只读展示 |
|
||
| 未读数量 `data` | 响应 int64 | R | 顶部计数;只接受非负安全整数 |
|
||
|
||
响应和权限边界:
|
||
|
||
- YAML 的详情对象没有声明字段级 `required`、长度、范围或默认值;页面不补造限制,并兼容可选展示字段为空。
|
||
- PC 后端按当前 `APP_USER` 登录账号隔离通知,只返回 `status=0` 的正常通知;列表按接收记录倒序,非分页。
|
||
- 详情和单条已读必须命中当前账号的接收记录;重复单条已读保持已读状态,页面仍做写操作防重复。
|
||
- C34 未解决前,`genealogyNo/genealogyName/senderNickName/senderPhone/bizSummary` 不能被视为稳定可用;手机号即使后端补齐也不展示。
|
||
- 页面不展示原始 JSON,不使用 APP 接口,不开放删除,不根据 `bizType/bizId` 猜业务深链。
|
||
- 2026-07-29 已在真实登录 Chrome 验证当前账号:未读数为 0,全部和仅未读筛选均成功同步,空列表/空详情状态正确。账号暂无通知,因此有数据详情和单条/全部已读真实写入仍待有数据时复核。
|
||
|
||
### 7.16 谱文
|
||
|
||
页面:`profile-article.html`、`profile-article-edit.html`。
|
||
|
||
| 请求字段 | 必填性 / 类型 | 标记 | 页面来源与提交时机 |
|
||
| --- | --- | --- | --- |
|
||
| `categoryId` | 可选 int64 | I/S | C35 未解决前省略;没有真实分类选项时不提供输入框 |
|
||
| `articleTitle` | 必填 string | U | 编辑页标题;保存时提交 |
|
||
| `articleSummary` | 可选 string | U | 编辑页摘要;非空时提交 |
|
||
| `coverOssId` | 可选 string/int64 | F/I | 选择封面并完成统一上传后自动产生;隐藏保存,禁止手填 |
|
||
| `articleContent` | 必填 string | U | wangEditor 正文;同步到 textarea 后提交 |
|
||
| `authorName` | 可选 string | U | 编辑页落款;非空时提交 |
|
||
| `sortOrder` | 可选 int64 | U/S | 编辑页安全整数;非空时提交 |
|
||
| `status` | 可选 string `0/1` | A/I | C37 未解决前固定隐藏提交 `0` |
|
||
| `genealogyId`、`articleId` | path int64 | I/A | 家谱上下文和列表/详情响应;按十进制字符串处理,不显示、不手填 |
|
||
|
||
PC `ArticleVo` 响应字段及页面用途:
|
||
|
||
| 字段 | 类型 | 标记 | 页面处理 |
|
||
| --- | --- | --- | --- |
|
||
| `articleId`、`genealogyId` | Long | I | 列表、详情、编辑、删除和写后重读的稳定 ID |
|
||
| `genealogyNo`、`genealogyName`、`surname` | string | R | 家谱只读上下文 |
|
||
| `categoryId` | Long,可空 | I | 仅内部保留;无分类选项源时不回填为可编辑 ID |
|
||
| `categoryName`、`categoryCode` | string | R | 详情分类只读展示 |
|
||
| `articleTitle`、`articleSummary`、`articleContent`、`authorName` | string | R/U | 列表、详情展示和编辑回填;可见内容均转义 |
|
||
| `coverOssId` | Long,可空 | I | 编辑隐藏回填;C36 未解决前不拼封面 URL |
|
||
| `publishTime`、`viewCount` | Date/Long | R | 详情发布时间和浏览量 |
|
||
| `sortOrder` | Long | I/U | 编辑回填;列表顺序由后端负责 |
|
||
| `status` | string `0/1` | I | 只允许正常记录进入编辑器 |
|
||
| `remark` | string | R | 详情只读展示,不进入 ArticleBody |
|
||
|
||
接入边界:
|
||
|
||
- 列表、详情、新增、修改和删除只调用 `/genealogy/pc/genealogies/{genealogyId}/articles` 及其 `/{articleId}` 子路径;
|
||
- YAML 响应仍为泛型包装,但 PC 控制器明确返回 `ArticleVo`,前端严格校验该 VO,不读取 APP 路径;
|
||
- 新增/修改成功后使用稳定 `articleId` 重读同一详情;删除后重读列表;所有写操作防重复;
|
||
- 页面先读取家谱详情,只有 `canEditContent/canManage` 显示新增、编辑和删除;后端继续执行最终权限校验;
|
||
- C35 未解决前不开放分类筛选/编辑;C36 未解决前不猜封面地址;C37 未解决前不开放停用;
|
||
- 相关聚焦测试 49/49 通过;真实账号页面验证统一留到阶段 6 收尾执行。
|
||
|
||
### 7.17 相册与照片
|
||
|
||
页面:`profile-album.html`、`profile-album-edit.html`、`profile-album-detail.html`。
|
||
|
||
相册请求字段:
|
||
|
||
| 请求字段 | 必填性 / 类型 | 标记 | 页面来源与提交时机 |
|
||
| --- | --- | --- | --- |
|
||
| `albumName` | 必填 string | U | 编辑页相册名称;保存时提交 |
|
||
| `albumDesc` | 可选 string | U | 编辑页描述;非空时提交 |
|
||
| `coverOssId` | 可选 string/int64 | F/I | 选择封面并完成统一上传后自动产生;隐藏保存,禁止手填 |
|
||
| `sortOrder` | 可选 int64 | U/S | 编辑页安全整数;非空时提交 |
|
||
| `status` | 可选 string `0/1` | A/I | C39 未解决前固定隐藏提交 `0` |
|
||
| `genealogyId`、`albumId` | path int64 | I/A | 家谱上下文及相册响应;按十进制字符串处理,不显示、不手填 |
|
||
|
||
照片请求字段:
|
||
|
||
| 请求字段 | 必填性 / 类型 | 标记 | 页面来源与提交时机 |
|
||
| --- | --- | --- | --- |
|
||
| `ossId` | 必填 string/int64 | F/I | 选择照片并完成统一上传后自动产生;隐藏保存,禁止手填 |
|
||
| `photoTitle`、`photoDesc`、`photographer` | 可选 string | U | 照片表单;非空时提交 |
|
||
| `shootTime` | 可选 date | S | 日期选择器;非空时提交 `YYYY-MM-DD` |
|
||
| `sortOrder` | 可选 int64 | U/S | 照片表单安全整数;非空时提交 |
|
||
| `status` | 可选 string `0/1` | A/I | C39 未解决前固定隐藏提交 `0` |
|
||
| `albumId`、`photoId` | path int64 | I/A | 相册和照片响应;按十进制字符串处理,不显示、不手填 |
|
||
|
||
PC 响应字段及页面用途:
|
||
|
||
| 对象 | 字段 | 标记 | 页面处理 |
|
||
| --- | --- | --- | --- |
|
||
| `AlbumVo` | `albumId`、`genealogyId` | I | 列表、编辑、详情、删除和写后重读的稳定 ID |
|
||
| `AlbumVo` | `genealogyNo`、`genealogyName`、`surname` | R | 家谱只读上下文 |
|
||
| `AlbumVo` | `albumName`、`albumDesc` | R/U | 列表/详情展示和编辑回填;可见内容均转义 |
|
||
| `AlbumVo` | `coverOssId` | F/I | 编辑隐藏回填;C38 未解决前不拼封面 URL |
|
||
| `AlbumVo` | `photoCount` | R | 列表和详情照片数量 |
|
||
| `AlbumVo` | `sortOrder`、`status` | I/U | 编辑回填;只允许正常记录进入编辑器 |
|
||
| `AlbumVo` | `remark` | R | 详情只读展示,不进入请求 Body |
|
||
| `AlbumPhotoVo` | `photoId`、`genealogyId`、`albumId` | I | 照片删除和写后重读的稳定 ID |
|
||
| `AlbumPhotoVo` | `genealogyNo`、`genealogyName`、`surname`、`albumName` | R | 家谱与相册只读上下文 |
|
||
| `AlbumPhotoVo` | `ossId` | F/I | 文件引用;C38 未解决前不拼照片 URL |
|
||
| `AlbumPhotoVo` | `photoTitle`、`photoDesc`、`photographer`、`shootTime` | R/U | 照片列表展示;可见内容均转义 |
|
||
| `AlbumPhotoVo` | `sortOrder`、`status` | I | 列表顺序和正常状态校验 |
|
||
| `AlbumPhotoVo` | `remark` | R | 只读展示,不进入请求 Body |
|
||
|
||
接入边界:
|
||
|
||
- 相册只调用 `/genealogy/pc/genealogies/{genealogyId}/albums` 及其 `/{albumId}` 子路径;照片只调用该相册下的 `/photos` 及 `/{photoId}`;
|
||
- 后端没有单独的相册详情接口,详情和编辑页必须重读相册列表并用响应中的稳定 `albumId` 精确匹配;
|
||
- YAML 响应仍为泛型包装,前端只接受后端 PC 控制器实际返回的 `AlbumVo` / `AlbumPhotoVo` 直接数组,不读取 APP 路径;
|
||
- 新增/修改相册后重读相册列表;新增/删除照片后重读照片列表;所有写操作防重复;
|
||
- 页面先读取家谱详情,只有 `canEditContent/canManage` 显示新增、编辑、删除和照片维护;
|
||
- C38 未解决前不猜文件地址;C39 未解决前不开放停用;
|
||
- 相关聚焦测试 49/49 通过;真实账号页面验证统一留到阶段 6 收尾执行。
|
||
|
||
### 7.18 祭祀活动、祭品与管理员受邀名单
|
||
|
||
页面:`profile-ceremony.html`、`profile-gift-edit.html`、`profile-ceremony-detail.html`;当前账号收到的邀请继续由 `profile-gift.html` 负责。
|
||
|
||
活动请求字段:
|
||
|
||
| 请求字段 | 必填性 / 类型 | 标记 | 页面来源与提交时机 |
|
||
| --- | --- | --- | --- |
|
||
| `ceremonyType` | 必填 string,无枚举 | U | 编辑页活动类型;保存时提交,不借用其他端枚举 |
|
||
| `ceremonyTitle` | 必填 string | U | 编辑页标题;保存时提交 |
|
||
| `ceremonyDesc` | 可选 string | U | 编辑页说明;非空时提交 |
|
||
| `ceremonyTime` | 可选 date-time | S | 日期时间选择器;转换为后端 Date 可解析格式后提交 |
|
||
| `location` | 可选 string | U | 编辑页地点名称;非空时提交 |
|
||
| `locationAddress` | 可选 string,最长 300 | U | 编辑页详细地址;非空时提交 |
|
||
| `longitude` | 可选 number,`[-180, 180]` | U/S | 与纬度同时填写并保存 |
|
||
| `latitude` | 可选 number,`[-90, 90]` | U/S | 与经度同时填写并保存 |
|
||
| `coverOssId` | 可选 string/int64 | F/I | 选择封面并完成统一上传后自动产生;隐藏保存,禁止手填 |
|
||
| `sortOrder` | 可选 int64 | U/S | 编辑页安全整数;非空时提交 |
|
||
| `status` | 可选 string `0/1` | A/I | C41 未解决前固定隐藏提交 `0` |
|
||
| `genealogyId`、`ceremonyId` | path int64 | I/A | 家谱上下文和活动响应;按十进制字符串处理,不显示、不手填 |
|
||
|
||
祭品与受邀名单请求字段:
|
||
|
||
| 请求字段 | 必填性 / 类型 | 标记 | 页面来源与提交时机 |
|
||
| --- | --- | --- | --- |
|
||
| `giverName` | 可选 string | U | 祭品表单赠送人姓名;非空时提交 |
|
||
| `giftAmount` | 必填 number,后端要求非负 | U | 祭品表单金额;添加祭品时提交;C42 未解决前不限制精度和最大值 |
|
||
| `giftMessage` | 可选 string | U | 祭品留言;非空时提交 |
|
||
| `inviteeUserIds` | 必填、唯一 int64 数组,可为空 | S/I | 从 `members/options` 的正常且已绑定账号成员多选产生;更新名单时提交完整数组,禁止手填 |
|
||
| `giftId`、`invitationId`、`inviteeUserId` | path/response int64 | I/A | 只从 PC 响应取得;用于删除、名单匹配和写后重读,不显示原值 |
|
||
|
||
PC 响应字段及页面用途:
|
||
|
||
| 对象 | 字段 | 标记 | 页面处理 |
|
||
| --- | --- | --- | --- |
|
||
| `CeremonyVo` | `ceremonyId`、`genealogyId`、`sponsorUserId` | I | 活动 CRUD、详情和写后重读的稳定 ID |
|
||
| `CeremonyVo` | `genealogyNo`、`genealogyName`、`surname` | R | 家谱只读上下文 |
|
||
| `CeremonyVo` | `sponsorNickName` | R | 发起人只读展示 |
|
||
| `CeremonyVo` | `sponsorPhone` | I | 隐私字段,始终不展示 |
|
||
| `CeremonyVo` | `ceremonyType`、`ceremonyTitle`、`ceremonyDesc`、`ceremonyTime`、`location`、`locationAddress` | R/U | 列表/详情展示和编辑回填;可见内容均转义 |
|
||
| `CeremonyVo` | `longitude`、`latitude` | I/S | 仅用于生成安全地图链接,不直接展示数值 |
|
||
| `CeremonyVo` | `coverOssId` | F/I | 编辑隐藏回填;C40 未解决前不拼封面 URL |
|
||
| `CeremonyVo` | `giftCount`、`giftAmount` | R | 详情祭品数量与礼金合计 |
|
||
| `CeremonyVo` | `sortOrder`、`status` | I/U | 编辑回填;只允许正常记录进入编辑器 |
|
||
| `CeremonyVo` | `remark` | R | 详情只读展示,不进入请求 Body |
|
||
| `CeremonyGiftVo` | `giftId`、`genealogyId`、`ceremonyId`、`giverUserId` | I | 祭品删除、关联和写后重读的稳定 ID |
|
||
| `CeremonyGiftVo` | `genealogyNo`、`genealogyName`、`surname`、`ceremonyTitle` | R | 家谱与活动只读上下文 |
|
||
| `CeremonyGiftVo` | `giverNickName`、`giverName`、`giftAmount`、`giftMessage`、`giftTime` | R | 祭品列表展示;可见内容均转义 |
|
||
| `CeremonyGiftVo` | `giverPhone` | I | 隐私字段,始终不展示 |
|
||
| `CeremonyGiftVo` | `status`、`remark` | R/I | 正常状态校验和只读备注 |
|
||
| `CeremonyInvitationVo` | 全部 ID、版本 | I | 邀请状态匹配和更新后的重读校验,不显示原值 |
|
||
| `CeremonyInvitationVo` | `inviteStatus`、投递/阅读/响应时间 | R | 管理员邀请列表只读展示 |
|
||
| `GenealogyMemberVo` 选项 | `appUserId` | I/S | 受邀人的唯一真实业务用户 ID 来源 |
|
||
| `GenealogyMemberVo` 选项 | `memberName`、`appUserNickName` | R/S | 受邀人选择器标签;手机号不展示 |
|
||
|
||
接入边界:
|
||
|
||
- 活动只调用 `/genealogy/pc/genealogies/{genealogyId}/ceremonies` 及 `/{ceremonyId}`;祭品只调用其 `/gifts` 子路径;
|
||
- 管理员邀请列表和替换只调用同一活动下的 `/invitations` 与 `/invitees`,受邀人来源只调用当前家谱 `/members/options`;
|
||
- 新增/修改活动后重读同一详情,新增/删除祭品后重读祭品列表,更新受邀人后重读邀请列表;所有写操作防重复;
|
||
- 页面先读取家谱详情,只有 `canEditContent/canManage` 显示活动、祭品和受邀名单维护;
|
||
- 空数组允许取消全部尚未响应邀请;响应过的历史邀请由后端保留状态,前端不伪造删除;
|
||
- C40 未解决前不猜封面地址;C41 未解决前不开放停用;C42 未解决前不猜金额精度和上限;
|
||
- 相关聚焦测试 56/56 通过;真实账号页面验证统一留到阶段 6 收尾执行。
|
||
|
||
### 7.19 家谱成员管理、退出与谱主转移
|
||
|
||
页面:`profile-family-admin.html`。
|
||
|
||
成员修改请求字段:
|
||
|
||
| 请求字段 | 必填性 / 类型 | 标记 | 页面来源与提交时机 |
|
||
| --- | --- | --- | --- |
|
||
| `memberName` | 可选 string,最长 50 | U | 管理员编辑表单;非空时提交 |
|
||
| `relationName` | 可选 string,最长 100 | U | 管理员编辑表单;后端明确接收空串时可清空 |
|
||
| `roleType` | 可选 string,`admin/editor/member` | S | 按当前管理者和目标角色过滤;保存时提交,不发送 `owner/visitor` |
|
||
| `lineagePersonId` | 可选 int64 | S/I | 从当前家谱世系人物选项选择;非空时提交,留空表示不修改而不是解绑 |
|
||
| `genealogyId`、`memberId` | path int64 | I/A | 家谱上下文和成员列表响应;按字符串处理,不显示、不手填 |
|
||
|
||
退出与谱主转移:
|
||
|
||
| 字段/操作 | 必填性 / 类型 | 标记 | 页面来源与提交时机 |
|
||
| --- | --- | --- | --- |
|
||
| `DELETE /members/me` | 无 Body | S/A | 当前正常成员二次确认后提交;谱主不显示退出按钮 |
|
||
| `targetMemberId` | 必填 int64 | S/I | 谱主从当前正常成员列表选择新谱主;禁止选择自己和手填 ID |
|
||
| `DELETE /members/{memberId}` | path int64 | S/I | 管理员从真实成员行执行“移出家谱”;谱主不可被移出 |
|
||
|
||
PC `GenealogyMemberVo` 响应字段及页面用途:
|
||
|
||
| 字段 | 标记 | 页面处理 |
|
||
| --- | --- | --- |
|
||
| `memberId`、`genealogyId`、`appUserId`、`lineagePersonId`、`inviterUserId` | I | 当前成员匹配、修改、移出、转让和世系绑定的稳定 ID;不显示原值 |
|
||
| `genealogyNo`、`genealogyName`、`surname` | R | C44 未解决前允许为空的家谱只读上下文 |
|
||
| `appUserNickName`、`lineagePersonNo`、`lineagePersonName`、`memberName` | R/U | 成员列表标签和编辑回填;可见内容均转义 |
|
||
| `appUserPhone`、`inviterPhone` | I | 隐私字段,始终不展示 |
|
||
| `roleType` | R/S | 响应可含 `owner/admin/editor/member/visitor`;修改只提交三种后端可分配角色 |
|
||
| `relationName` | R/U | 列表展示和编辑回填 |
|
||
| `joinSource`、`inviterNickName`、`joinTime` | R | 加入来源只读说明;C44 未填充时允许为空 |
|
||
| `status` | I | 列表只接受后端返回的正常状态 `0` |
|
||
|
||
权限与状态边界:
|
||
|
||
- 所有账号可按家谱查看权限读取正常成员;只有家谱详情 `canManage=true` 时显示修改和移出;
|
||
- 谱主不能直接修改或移出;只有谱主可管理管理员、分配 `admin` 或转让谱主;管理员只能管理非管理员成员并分配 `editor/member`;
|
||
- 普通成员、编辑和管理员可退出家谱;谱主必须先转让谱主。退出和移出只停用成员关系,不删除世系人物;
|
||
- 更新后重读成员列表并核对同一 `memberId`;移出后核对该成员不再出现在正常列表;谱主转移后重读家谱详情和成员列表;
|
||
- 页面没有直接新增成员接口;新增成员必须通过后端已有的加入/邀请业务闭环;
|
||
- C44 未解决前不依赖 enrichment 字段并隐藏手机号;C45/C46 未解决前不伪造关系解除或成员-世系人物解绑;
|
||
- 相关聚焦测试 49/49 通过;真实账号页面验证统一留到阶段 6 收尾执行。
|
||
|
||
### 7.20 家谱创建与加入申请契约
|
||
|
||
页面:`profile-create-family.html`、`join-genealogy.html`、`profile-join-family.html`、`profile-join-review.html`。
|
||
|
||
`AppGenealogyCreateBody`:
|
||
|
||
| 字段 | 类型 | 必填 | 来源 | 页面与提交时机 |
|
||
| --- | --- | --- | --- | --- |
|
||
| `genealogyName` | string | 是 | U | 创建页谱名;提交时发送 |
|
||
| `surname` | string | 是 | U | 创建页姓氏;提交时发送 |
|
||
| `regionCode` | string | 是 | S | 省市区选择器自动取最后一级;提交时发送 |
|
||
| `ancestralHall`、`originPlace`、`addressDetail`、`intro` | string | 否 | U | 创建页可选输入;非空时发送 |
|
||
| `coverOssId` | int64/string | 否 | F | 封面上传成功后自动产生;不允许手填 |
|
||
| `visibility` | string enum `0/1/2` | 否 | S | 私密/公开/成员可见 |
|
||
| `joinMode` | string enum `0/1/2` | 否 | S | 关闭/审核/邀请模式 |
|
||
|
||
实现边界:
|
||
|
||
- 创建只调用 `POST /genealogy/pc/genealogies`,提交前读取 `GET /genealogy/pc/genealogies/quota`;
|
||
- 地区选项复用 `/genealogy/pc/region/children?parentCode=...`,不手写地区编码;
|
||
- 创建成功后使用响应中的稳定 `genealogyId` 重读同一家谱,匹配后进入家谱主页;
|
||
- 申请页先从 `GET /genealogy/pc/genealogies/options` 选择响应中的家谱,再调用 `POST /genealogy/pc/genealogies/{genealogyId}/join-applies`;
|
||
- 我的申请页调用 `GET /genealogy/pc/genealogies/join-applies/mine`;只有 `status=0` 的响应项可以调用 `DELETE /genealogy/pc/genealogies/join-applies/{applyId}`;
|
||
- 审核页只从当前家谱上下文取得 `genealogyId`,先读取家谱详情并要求 `canManage=true`,再读取 `GET /genealogy/pc/genealogies/{genealogyId}/join-applies/pending`;
|
||
- 审核只调用 `PUT /genealogy/pc/genealogies/{genealogyId}/join-applies/{applyId}/audit`,`status=1` 通过、`status=2` 拒绝;
|
||
- `inviterUserId` 没有安全 PC 邀请来源,本轮加入申请契约不发送该字段;
|
||
- 创建/申请/审核页面均无家谱 ID、申请 ID、用户 ID 或 OSS ID 文本输入,所有写操作防重复并在成功后重读对应资源。
|
||
|
||
`AppGenealogyJoinApplyBody`:
|
||
|
||
| 字段 | 类型/约束 | 必填 | 来源 | 页面与提交时机 |
|
||
| --- | --- | --- | --- | --- |
|
||
| `applicantName` | string,最长 50 | 否 | U | 申请页姓名;非空时提交 |
|
||
| `phone` | string,最长 30 | 否 | U | 申请页联系电话;非空时提交 |
|
||
| `relationDesc` | string,最长 100 | 否 | U | 申请页关系说明;非空时提交 |
|
||
| `applyReason` | string,最长 500 | 否 | U | 申请页申请理由;非空时提交 |
|
||
| `inviterUserId` | int64/string | 邀请模式条件必填 | I | PC 无安全来源,不展示、不发送;邀请模式继续阻断 |
|
||
|
||
`GenealogyJoinApplyVo` 与审核:
|
||
|
||
| 字段 | 类型/枚举 | 来源 | 页面用途 |
|
||
| --- | --- | --- | --- |
|
||
| `applyId`、`genealogyId` | int64/string | R/I | 响应按钮属性和写入 path;不显示、不手填 |
|
||
| `genealogyName`、`surname` | string | R | 我的申请列表只读展示 |
|
||
| `applicantName`、`phone`、`relationDesc`、`applyReason` | string | R | 管理员待审核列表;只展示申请人主动提交的 `phone` |
|
||
| `auditTime`、`auditRemark` | datetime/string | R | 我的申请审核结果展示 |
|
||
| `status` | string `0/1/2/3` | R | 待审核/通过/拒绝/撤销;仅 `0` 可撤销 |
|
||
| `appUserId`、`inviterUserId`、`auditUserId` | int64/string | I | 普通列表和审核列表均不展示 |
|
||
| `appUserPhone`、`inviterPhone`、`auditPhone` | string | I | 账号/邀请/审核人员隐私字段均不展示 |
|
||
| 审核 `status` | string `1/2` | S | 管理员点击通过或拒绝时提交 |
|
||
| 审核 `auditRemark` | string,最长 500 | U | 拒绝时可选填写,非空时提交 |
|
||
|
||
### 7.21 意见反馈与工单契约
|
||
|
||
页面:`profile-feedback.html`、`submit-ticket.html`、`my-tickets.html`、`ticket-detail.html`。
|
||
|
||
后端只提供统一反馈集合:
|
||
|
||
- `POST /genealogy/pc/feedback`:当前业务用户提交反馈;
|
||
- `GET /genealogy/pc/feedback`:读取当前业务用户自己的反馈列表;
|
||
- 没有独立 ticket path;“工单”只是帮助中心对同一反馈记录的页面名称;
|
||
- 没有用户侧回复、追问、关闭或删除接口,页面不制造这些操作。
|
||
|
||
`AppFeedbackBody`:
|
||
|
||
| 字段 | 类型/约束 | 必填 | 来源 | 页面与提交时机 |
|
||
| --- | --- | --- | --- | --- |
|
||
| `feedbackType` | string enum `advice/bug/complaint/other` | 否 | S | 两个提交页选择;空值省略并由后端默认 `advice` |
|
||
| `feedbackContent` | string,非空 | 是 | U | 问题或建议正文;提交时发送 |
|
||
| `contactInfo` | string | 否 | U | 用户主动提供的联系方式;非空时发送 |
|
||
| `feedbackTitle` | — | — | V | 旧页面字段不属于 DTO,已从表单移除且不发送 |
|
||
|
||
`FeedbackVo`:
|
||
|
||
| 字段 | 类型/枚举 | 来源 | 页面用途 |
|
||
| --- | --- | --- | --- |
|
||
| `feedbackId` | int64/string | R/I | 提交后重读匹配、列表详情链接和 URL;不展示、不手填 |
|
||
| `feedbackType`、`feedbackContent`、`contactInfo` | string | R | 列表或详情只读展示 |
|
||
| `handleStatus` | string `0/1/2/3` | R | 待处理/处理中/已处理/已关闭 |
|
||
| `handleResult`、`handleTime`、`remark` | string/datetime | R | 后端存在时在详情展示 |
|
||
| `status` | string `0/1` | I | 响应有效性校验,不提供用户修改入口 |
|
||
| `appUserId`、`handlerId` | int64/string | I | 内部用户/处理人编号,不展示 |
|
||
| `appUserNickName`、`appUserPhone` | string | I | 后台 enrichment,不在用户页面展示 |
|
||
|
||
实现边界:
|
||
|
||
- ApiClient 是 GET/POST path 和三字段 body 白名单唯一 owner;
|
||
- 提交使用防重复锁;成功响应必须包含稳定字符串 `feedbackId`;
|
||
- 提交后重读我的反馈列表并精确找到同一 `feedbackId`,否则不宣称成功;
|
||
- 工单详情从 URL 读取列表响应产生的 `feedbackId`,只在我的列表中精确匹配,不回退第一条;
|
||
- 401 清理登录态;403 保留登录态并显示后端权限错误;页面不展示原始 JSON。
|
||
|
||
### 7.22 VIP 套餐与会员订单契约
|
||
|
||
页面:`profile-services.html`。
|
||
|
||
PC 端只开放三条业务用户接口:
|
||
|
||
- `GET /genealogy/pc/vip/packages`:读取可购买套餐,成功响应 `List<VipPackageVo>`,无分页结构;
|
||
- `POST /genealogy/pc/vip/orders`:创建当前业务用户的会员订单,body 为 `AppVipOrderBody`,成功响应 `VipOrderVo`;
|
||
- `GET /genealogy/pc/vip/orders`:读取当前业务用户的订单,成功响应 `List<VipOrderVo>`,无分页结构;
|
||
- 三条接口均要求 APP_USER 登录态;创建接口有后端防重复提交;
|
||
- PC Controller 没有支付发起、支付回调、取消、关闭或退款接口,页面不得制造这些动作。
|
||
|
||
`AppVipOrderBody`:
|
||
|
||
| 字段 | 类型/约束 | 必填 | 来源 | 页面与提交时机 |
|
||
| --- | --- | --- | --- | --- |
|
||
| `packageId` | int64,稳定字符串 ID | 是 | S/I | 用户点击套餐响应生成的卡片时选择;创建订单时发送,禁止手填 |
|
||
| `genealogyId` | int64,稳定字符串 ID | 否 | S/I | 用户从“我的家谱”响应生成的下拉项中选择;非空时创建订单发送,禁止手填 |
|
||
| `payType` | string;后端空值默认 `wechat` | 否 | A | PC 页面不提供支付方式选择且默认省略;等待后端开放真实支付能力后再确认枚举 |
|
||
|
||
`VipPackageVo`:
|
||
|
||
| 字段 | 类型/枚举 | 来源 | 页面用途 |
|
||
| --- | --- | --- | --- |
|
||
| `packageId` | int64/string | R/I | 套餐卡片选择和订单 body;不展示、不手填 |
|
||
| `packageName`、`packageDesc` | string | R | 套餐名称和说明 |
|
||
| `packageType` | string `vip/storage` | R | 显示为会员套餐/存储扩容;未知值整条过滤 |
|
||
| `price`、`originalPrice` | decimal,非负 | R | 价格展示;不参与前端金额计算 |
|
||
| `durationValue` | integer,非负,可空 | R | 与期限单位组合展示 |
|
||
| `durationUnit` | string `permanent/day/month/year` | R | 永久/天/月/年 |
|
||
| `genealogyLimit`、`memberLimit`、`storageLimitMb` | integer,非负,可空 | R | 套餐额度只读展示 |
|
||
| `featureJson` | string/JSON | I | 契约未说明用户侧展示结构,当前不解析、不展示 |
|
||
| `sortOrder` | integer | I | 后端列表顺序 owner,前端不重新排序 |
|
||
| `status` | string `0/1` | I | 只接受正常 `0` 套餐;不提供修改入口 |
|
||
| `remark` | string | R | 非空时作为套餐补充说明展示 |
|
||
|
||
`VipOrderVo`:
|
||
|
||
| 字段 | 类型/枚举 | 来源 | 页面用途 |
|
||
| --- | --- | --- | --- |
|
||
| `orderId` | int64/string | R/I | 创建后重读精确匹配;不展示、不手填 |
|
||
| `orderNo` | string | R | 订单列表展示 |
|
||
| `packageId` | int64/string | R/I | 响应有效性校验,不展示 |
|
||
| `packageName` | string | R | 订单套餐名称 |
|
||
| `genealogyId` | int64/string,可空 | R/I | 响应有效性校验,不展示 |
|
||
| `genealogyNo`、`genealogyName` | string,可空 | R | 关联家谱信息展示 |
|
||
| `orderAmount`、`payAmount` | decimal,非负 | R | 订单金额和应付金额展示;以后端值为准 |
|
||
| `payType` | string,可空 | R | 后端返回时只读展示,不作为支付入口 |
|
||
| `payStatus` | string `0/1/2/3` | R | 待支付/已支付/已关闭/已退款 |
|
||
| `payTime`、`expireTime` | datetime,可空 | R | 支付和有效期信息展示 |
|
||
| `status` | string `0/1` | I | 响应有效性校验,不提供修改入口 |
|
||
| `remark` | string | R | 非空时展示 |
|
||
| `appUserId`、`appUserNickName`、`appUserPhone` | int64/string | I | 当前账号及 enrichment 字段,不在页面展示 |
|
||
|
||
实现边界:
|
||
|
||
- `ApiClient` 是三条 path 与三字段请求白名单唯一 owner;
|
||
- 页面启动时并行读取套餐、我的家谱和订单;所有业务 ID 仅来自响应;
|
||
- 创建使用前端防重复锁;创建响应必须是完整有效 `VipOrderVo`,随后重读订单列表并精确找到同一 `orderId` 才宣称成功;
|
||
- 页面省略 `payType`,由后端使用已确认的默认值;不展示后端尚未提供的支付、取消或退款按钮;
|
||
- 401 清理登录态;403 保留登录态并展示后端错误;非法套餐、订单、金额、枚举或不安全数字 ID 整条过滤。
|
||
|
||
### 7.23 家谱主页只读概览契约
|
||
|
||
页面:`profile-family-home.html`。
|
||
|
||
只使用两条现有 PC 读取接口:
|
||
|
||
- `GET /genealogy/pc/genealogies/{genealogyId}/overview`:返回当前家谱 `AppGenealogyVo`;
|
||
- `GET /genealogy/pc/genealogies/{genealogyId}/lineage/tree`:返回 `List<LineagePersonTreeView>`;
|
||
- `genealogyId` 只从 `profile-common.js` 的当前家谱上下文取得,两条请求使用同一个稳定字符串 ID;
|
||
- 后端 `overview` 当前实际复用家谱详情服务,不包含文章、相册、视频、祭祀或动态聚合统计。
|
||
|
||
`AppGenealogyVo` 主页字段:
|
||
|
||
| 字段 | 类型/约束 | 来源 | 页面用途 |
|
||
| --- | --- | --- | --- |
|
||
| `genealogyId` | int64/string | I/A/R | 当前上下文、两条请求 path、响应一致性校验;不展示、不手填 |
|
||
| `genealogyNo` | string | R | 家谱编号只读展示 |
|
||
| `genealogyName` | string,非空 | R | 页面标题和概览名称 |
|
||
| `surname` | string | R | 姓氏只读展示 |
|
||
| `ancestralHall` | string,可空 | R | 堂号非空时展示 |
|
||
| `originPlace` | string,可空 | R | 祖籍非空时展示 |
|
||
| `regionFullName` | string,可空 | R | 完整地区非空时展示 |
|
||
| `memberCount`、`personCount` | integer,非负 | R | 家谱成员数和世系人物数;不在前端计算 |
|
||
| `status` | string `0/1` | I | 只接受正常 `0` 响应 |
|
||
| `canManage` | boolean | I | 严格为 `true` 时显示家谱管理入口 |
|
||
| `canEditContent` | boolean | I | 保留为内容权限上下文,主页不据此制造写操作 |
|
||
| `ownerUserId`、`coverOssId` | int64/string | I | 当前主页不展示、不手填 |
|
||
| 其余地址、角色、成员状态字段 | 对应 DTO 类型 | I | 当前主页不消费,不输出原始 JSON |
|
||
|
||
`LineagePersonTreeView`:
|
||
|
||
| 字段 | 类型/结构 | 来源 | 页面用途 |
|
||
| --- | --- | --- | --- |
|
||
| `personId`、`genealogyId` | int64/string | R/I | 树节点稳定标识和响应校验;不直接展示 |
|
||
| `name`、`generationName`、人物摘要字段 | string | R | 复用世系页的安全节点渲染 |
|
||
| `relationType` | string `father/mother/spouse/child/adoptive` | R | 关系数据;主页不提供关系写操作 |
|
||
| `relationName` | string | R | 非空时作为关系说明 |
|
||
| `spouses`、`children` | `LineagePersonTreeView[]` | R | 递归世系预览 |
|
||
|
||
实现边界:
|
||
|
||
- `lineage-pages.js` 是世系节点规范化和树 HTML 的唯一 owner;主页不得复制一套树字段解释;
|
||
- 页面并行读取概览和世系树,只展示基础信息、后端已有计数和真实树;
|
||
- `/genealogy/dashboard/overview` 是后台权限接口,不属于 PC 家谱主页契约,前端不调用;
|
||
- PC 没有成员邀请创建或分享接口,“邀请家人”只显示阻断说明,不提供可点击操作;
|
||
- 主页没有写请求;401 清理登录态,403 保留登录态并显示读取错误。
|
||
|
||
### 7.24 帮助中心文章契约
|
||
|
||
页面:`help.html`。契约 owner:`utils/ApiClient.js` 的 `helpArticles` / `helpArticleDetail` 和 `public/js/help-pages.js`。
|
||
|
||
接口:
|
||
|
||
| method | 完整 path | 目录 | 鉴权 | 页面时机 |
|
||
| --- | --- | --- | --- | --- |
|
||
| GET | `/genealogy/pc/help-articles` | 内容文章 / PC 帮助文章列表 | APP_USER 登录态 | 帮助中心初始化或用户点击刷新 |
|
||
| GET | `/genealogy/pc/help-articles/{helpId}` | 内容文章 / PC 帮助文章详情 | APP_USER 登录态 | 用户从列表点击“查看完整解答” |
|
||
|
||
请求字段:
|
||
|
||
| 位置 | 字段 | 必填 | 类型/约束 | 分类 | 页面来源与提交时机 |
|
||
| --- | --- | --- | --- | --- | --- |
|
||
| Query | `helpCategory` | 否 | string;后端按完全相等过滤 | S | 当前页面不提供猜测分类选项,因此初始化时省略;后端提供正式分类字典后才能开放选择 |
|
||
| Path | `helpId` | 是 | int64;前端始终按非零十进制字符串处理 | I | 只能来自列表响应;用户点击该文章详情时进入 path |
|
||
| Header | `clientid` | 基础请求自动 | string | A | `AxiosRequestUtil` 统一填写;页面不输入 |
|
||
| Header | `Authorization` | 是 | `Bearer <access_token>` | A | `AxiosRequestUtil` 从登录态自动填写;页面不读取、不展示 token |
|
||
| Body | — | — | 两个接口均无 Body | — | — |
|
||
|
||
`HelpArticleVo` 响应字段:
|
||
|
||
| 字段 | 类型 | 分类 | 页面使用 |
|
||
| --- | --- | --- | --- |
|
||
| `helpId` | int64/string | I | 校验稳定 ID、绑定列表项并精确重读详情;不向用户显示 |
|
||
| `helpCategory` | string | R | 列表和详情分类文字,可空 |
|
||
| `helpTitle` | string | R | 列表标题,空值使整条响应失败 |
|
||
| `helpContent` | string | R | 详情正文;转义并保留换行,不执行响应 HTML |
|
||
| `coverOssId` | int64/string | I | 当前响应没有文件 URL,页面不显示、不拼接、不允许手填 |
|
||
| `sortOrder` | int64 | I | 仅后端排序,不展示 |
|
||
| `viewCount` | int64/string | R | 非负十进制计数;详情 GET 会由后端累计浏览量 |
|
||
| `status` | string | I | 只接受正常值 `0`;停用文章整条拒绝 |
|
||
| `remark` | string | I | 后台备注,不展示 |
|
||
|
||
响应与错误边界:
|
||
|
||
- 列表响应必须是直接数组,不接受分页 `rows` 猜测;任一元素缺少稳定 ID、标题、正文或正常状态时整批失败;
|
||
- 详情必须返回与 path 中相同的 `helpId`,不回退到列表第一条;
|
||
- YAML 把两条接口标为 `security: []`,但 `PcHelpArticleController` 没有 `@SaIgnore`,部署环境无 token 实测返回“认证失败”;按用户指定的后端项目为准,当前客户端必须携带登录 token,此项作为 Apifox/后端冲突保留;
|
||
- 后端只声明统一成功包装,未提供帮助文章专属失败码;详情不存在或停用时按业务错误展示,不制造 404 枚举;
|
||
- 无登录态或 401 清理登录状态并进入登录页;403 保留登录态并展示读取错误;
|
||
- 页面只有读取动作,不提供编辑、发布、分类管理、封面 OSS ID 或成员邀请操作。
|
||
|
||
### 7.25 应用推广契约
|
||
|
||
页面:`app.html` 的“应用推广”区域。契约 owner:`utils/ApiClient.js` 的 `promotions` 和 `public/js/app-promotion-pages.js`。
|
||
|
||
接口:
|
||
|
||
| method | 完整 path | 目录 | 鉴权 | 页面时机 |
|
||
| --- | --- | --- | --- | --- |
|
||
| GET | `/genealogy/pc/promotions` | 应用推广 / PC 应用推广列表 | APP_USER 登录态 | 应用下载页初始化;仅在本地已有登录 token 时请求一次 |
|
||
|
||
请求字段:
|
||
|
||
| 位置 | 字段 | 必填 | 类型/约束 | 分类 | 页面来源与提交时机 |
|
||
| --- | --- | --- | --- | --- | --- |
|
||
| Query | `platform` | 否 | string;SQL 字典 `gen_promotion_platform`:`all` 全部(默认)、`app` APP、`pc` PC、`wechat` 小程序 | A | 应用下载页初始化时固定发送 `pc`;服务端返回 `platform=pc` 或 `platform=all` 的正常记录,不让用户选择或手填 |
|
||
| Header | `clientid` | 基础请求自动 | string | A | `AxiosRequestUtil` 统一填写;页面不输入 |
|
||
| Header | `Authorization` | 是 | `Bearer <access_token>` | A | `AxiosRequestUtil` 从登录态自动填写;页面不读取、不展示 token |
|
||
| Path | — | — | 无 Path 参数 | — | — |
|
||
| Body | — | — | 无 Body | — | — |
|
||
|
||
`AppPromotionVo` 列表元素字段:
|
||
|
||
| 字段 | 类型 | 必填/约束 | 分类 | 页面使用 |
|
||
| --- | --- | --- | --- | --- |
|
||
| `promotionId` | int64/string | SQL `BIGINT NOT NULL` 主键;前端按非零十进制字符串处理 | I | 稳定绑定卡片,不展示、不允许手填 |
|
||
| `promotionKey` | string | SQL `varchar(80) NOT NULL DEFAULT 'banner'` | I | 后台识别字段,页面不展示、不提交 |
|
||
| `promotionTitle` | string | SQL `varchar(200) NOT NULL`;页面要求非空 | R | 推广卡片标题,HTML 转义后展示 |
|
||
| `promotionDesc` | string | SQL `varchar(500) DEFAULT ''`,可空 | R | 推广卡片说明,HTML 转义后展示 |
|
||
| `coverOssId` | int64/string | 可空;响应没有可访问文件 URL | I | 不显示、不拼接 URL、不允许用户手填 OSS ID |
|
||
| `targetUrl` | string | SQL `varchar(500) DEFAULT ''`,可空;页面只接受绝对 `http`/`https` URL | R | 合法时作为新窗口外链;危险、相对或无效地址降级为不可点击卡片 |
|
||
| `platform` | string | SQL `varchar(30) NOT NULL DEFAULT 'all'`;字典枚举 `all/app/pc/wechat` | I | 仅后端筛选,当前页面不展示 |
|
||
| `sortOrder` | int64 | SQL `BIGINT NOT NULL DEFAULT 0`;后端按升序排序,同序按 `promotionId` 降序 | I | 仅后端排序,页面不二次解释或展示 |
|
||
| `status` | string | SQL `char(1) NOT NULL DEFAULT '0'`;`0` 正常、`1` 停用,页面只接受 `0` | I | 停用或缺失状态的记录使整批响应失败 |
|
||
| `remark` | string | SQL `varchar(500) DEFAULT NULL`,可空 | I | 后台备注,不展示 |
|
||
|
||
响应、权限与错误边界:
|
||
|
||
- 成功响应经统一请求层解包后必须是直接 `AppPromotionVo[]`,不是分页结构;任一元素缺少稳定 ID、标题或正常状态时整批失败;
|
||
- 空数组显示“当前暂无应用推广”;未登录时页面本身仍可浏览,但推广区域只显示登录入口且不发请求;
|
||
- YAML 把该接口标为 `security: []`,并且未导出真实 Query `platform`;后端 `PcPromotionApiController` 没有 `@SaIgnore`,全局拦截器要求 APP_USER 登录态。SQL 字典已确认 `all/app/pc/wechat`,服务层按“请求平台或 `all`”过滤,因此当前实现携带登录 token 并固定发送 `platform=pc`;
|
||
- SQL `gen_app_promotion` 另有 `(tenant_id, platform, status, del_flag)` 和 `(tenant_id, sort_order)` 索引;`del_flag`、租户及审计字段不属于 `AppPromotionVo`,页面不接收、不展示;
|
||
- 401 清理失效 token 并把推广区域切回登录提示;403、网络失败或畸形响应只在推广区域显示读取失败,不跳转、不清理有效登录态;
|
||
- 后端只声明统一成功包装,未提供推广专属失败响应和错误码;字段长度、默认值及平台枚举已由后端 SQL 冻结,不再作为阻断项;
|
||
- 页面没有推广新增、编辑、上下架、排序、封面上传能力,不调用 APP 或后台管理接口,也不向用户暴露推广 ID、推广键或 OSS ID。
|
||
|
||
### 7.26 官网资讯契约
|
||
|
||
页面:`news.html`、`article-detail.html`。契约 owner:`utils/ApiClient.js` 的 `siteArticles`、`utils/AxiosRequestUtil.js` 的公开请求鉴权语义和 `public/js/site-news-pages.js`。
|
||
|
||
接口:
|
||
|
||
| method | 完整 path | 目录 | 鉴权 | 页面时机 |
|
||
| --- | --- | --- | --- | --- |
|
||
| GET | `/genealogy/pc/site/articles` | 站点内容 / PC 站点文章列表 | 公开,`auth: false` | 资讯列表初始化、分类切换后的页面初始化,以及详情页按列表响应 ID 精确重读 |
|
||
|
||
请求字段:
|
||
|
||
| 位置 | 字段 | 必填 | 类型/约束 | 分类 | 页面来源与提交时机 |
|
||
| --- | --- | --- | --- | --- | --- |
|
||
| Query | `articleType` | 否 | string;SQL 字典 `gen_site_article_type`:`news` 新闻(默认)、`notice` 公告、`download` 下载 | S | 用户点击固定分类链接后从 URL Query 取得;“全部”省略该字段,非法值不发请求 |
|
||
| Query | `limit` | 否 | integer,客户端只允许 1–100;服务端正数最大取 100 | A | 列表和详情重读均由页面固定提交 `100` |
|
||
| Header | `clientid` | 基础请求自动 | string | A | `AxiosRequestUtil` 统一填写;页面不输入 |
|
||
| Header | `Authorization` | 不发送 | — | — | 方法设置 `auth: false`;即使本地已有 token 也不发送,公开请求 401/403 不清理既有登录态 |
|
||
| Path | — | — | 无 Path 参数 | — | — |
|
||
| Body | — | — | 无 Body | — | — |
|
||
|
||
`SiteArticleVo` 列表元素字段:
|
||
|
||
| 字段 | 类型 | 必填/约束 | 分类 | 页面使用 |
|
||
| --- | --- | --- | --- | --- |
|
||
| `articleId` | int64/string | SQL `BIGINT NOT NULL` 主键;前端按非零十进制字符串处理 | I | 只用于生成详情链接和精确匹配,不展示、不允许手填 |
|
||
| `articleType` | string | SQL `varchar(50) NOT NULL DEFAULT 'news'`;枚举 `news/notice/download` | R | 转换为新闻、公告、下载标签;枚举外记录使整批失败 |
|
||
| `articleTitle` | string | SQL `varchar(200) NOT NULL`;页面要求非空 | R | 列表和详情标题,HTML 转义 |
|
||
| `articleSummary` | string | SQL `varchar(500) DEFAULT ''`,可空 | R | 列表摘要和详情导语,HTML 转义 |
|
||
| `articleContent` | string | SQL `text`,可空 | R | 详情正文;HTML 转义并只保留换行,不执行响应 HTML |
|
||
| `coverOssId` | int64/string | SQL `BIGINT`,可空;没有文件 URL 契约 | I | 不显示、不拼接 URL、不允许手填 |
|
||
| `externalUrl` | string | SQL `varchar(500) DEFAULT ''`,可空 | R | 只接受绝对 HTTP/HTTPS;合法时显示安全新窗口外链 |
|
||
| `publishTime` | string/date | SQL `datetime`,可空 | R | 列表和详情发布时间文本,HTML 转义 |
|
||
| `sortOrder` | int64 | SQL `BIGINT NOT NULL DEFAULT 0` | I | 仅后端排序,不展示 |
|
||
| `status` | string | SQL `char(1) NOT NULL DEFAULT '0'`;`0` 正常、`1` 停用 | I | 页面只接受 `0`,其他值使整批失败 |
|
||
| `remark` | string | SQL `varchar(500) DEFAULT NULL`,可空 | I | 后台备注,不展示 |
|
||
|
||
响应、详情与错误边界:
|
||
|
||
- 成功响应经统一请求层解包后必须是直接 `SiteArticleVo[]`;不接受分页 `rows`、旧字段别名或任一非法元素;
|
||
- 服务端只查正常状态,按 `sortOrder ASC`、`publishTime DESC`、`articleId DESC` 排序;页面保持服务端顺序;
|
||
- 后端没有站点文章单条详情接口;详情 ID 只能来自列表链接,详情页重读 `{ limit: 100 }` 后精确匹配同一字符串 ID,不存在时不得回退第一条;
|
||
- 标题、摘要、正文、类型和时间全部转义;正文只保留换行,危险或相对外链不渲染;
|
||
- 空数组显示“当前暂无资讯”;非法分类/详情 ID 不发请求;网络、业务或畸形响应只更新内容区域,不跳转登录;
|
||
- YAML 已导出 method/path、`articleType`、`limit` 和 `security: []`,但响应只引用通用列表结果,未导出 `SiteArticleVo` 11 个字段;完整字段、长度、默认值和枚举由后端 VO、SQL 与字典补齐;
|
||
- 2026-07-30 使用本地页面对当前部署环境做匿名实测时,接口返回“认证失败,无法访问系统资源”;页面保持在资讯页且不清理已有 token。该行为与 YAML 的 `security: []` 冲突,后端需确认部署环境是否遗漏公开放行;前端不通过附带登录 token 绕过公开契约;
|
||
- `coverOssId` 的文件 URL 和站点文章单条详情接口继续作为后端契约阻断;页面不猜 URL、不制造详情路径;
|
||
- 本批不修改 `about/culture/privacy/terms/surname`,也不复用登录后的家谱谱文 CRUD 脚本。
|
||
|
||
## 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. 我的贺礼邀请。
|
||
|
||
当前进度:阶段 4 已按顺序完成。家族圈的列表、正常状态详情、新增、修改、删除、点赞、评论、回复、权限显隐、空/错状态、防重复和写后重读已接入,C21 图片 URL 回显和 C22 停用记录管理继续阻断;字辈谱的正常/management 权限分流、单条新增修改和状态切换、批量预览保存、响应校验、防重复、写后重读及无家谱上下文分支已接入;世系人物的树、列表、分页、详情、完整字段表单、权限显隐、四类关系新增、逻辑停用、防重复和写后重读已接入,C15 继续阻断新增 `SPECIFIED` 账号绑定,C18 继续阻断可选字段清空闭环;我的贺礼邀请已接入当前账号列表、响应内详情、PENDING 接受/拒绝、长 ID 校验、权限/空错状态、防重复和写后重读,C16 继续阻断管理员替换受邀人。真实账号已验证邀请读取和空状态;该账号没有待响应邀请,接受/拒绝真实写入仍待有数据时复核。下一阶段为阶段 5,按顺序先核对视频 DTO 是否已完整。
|
||
|
||
每个模块采用同一闭环:
|
||
|
||
1. `ApiClient` 方法和契约测试;
|
||
2. 列表/详情读取;
|
||
3. 新增;
|
||
4. 修改;
|
||
5. 删除/停用;
|
||
6. 权限、空状态、错误状态、重复提交;
|
||
7. 写入后重新读取验证。
|
||
|
||
### 阶段 5:补齐 DTO 后的资源模块
|
||
|
||
顺序:
|
||
|
||
1. 视频;
|
||
2. 成长记录;
|
||
3. 亲友记录;
|
||
4. 备忘录;
|
||
5. 功德记录;
|
||
6. 消息通知。
|
||
|
||
任何模块的 View/List DTO 未补齐时,只完成表单布局和契约测试,不宣称真实功能完成。
|
||
|
||
当前进度:阶段 5 已按顺序完成。视频、成长记录、亲友记录、备忘录、功德记录和消息通知均已按对应 PC 契约开放;各模块的文件 URL、停用记录、可选字段清空和金额业务边界仍按 C18、C23–C34 保持阻断,不通过 APP 接口或猜测字段补齐。
|
||
|
||
### 阶段 6:当前 PC 契约可闭环模块
|
||
|
||
已完成:
|
||
|
||
- 谱文列表、详情、新增、修改和删除;
|
||
- 相册列表、新增、修改、删除,以及照片列表、新增和删除;
|
||
- 祭祀活动列表、详情、新增、修改和删除,祭品列表、新增和删除;
|
||
- 管理员受邀名单读取和完整替换,当前账号邀请读取与响应;
|
||
- 从同家谱正常成员选项中选择账号完成 `SPECIFIED` 世系人物绑定;
|
||
- 家谱成员列表、修改、移出、当前成员退出和谱主转移;
|
||
- 个人中心、家谱首页和家谱内容页的稳定入口。
|
||
|
||
契约收口:
|
||
|
||
- `replaceCeremonyInvitees(genealogyId, ceremonyId, inviteeUserIds)` 只接收真实成员选项产生的 ID 数组,`utils/ApiClient.js` 唯一封装 `{ inviteeUserIds }`;
|
||
- `/members/options` 严格按 YAML 不发送 Query;后端存在但 YAML 未定义的 `keyword` 不进入前端契约;
|
||
- 成员角色构造边界只接受 `admin/editor/member`,`owner/visitor` 在请求构造前失败;
|
||
- 所有业务 ID 来自 URL、上下文或响应选项,页面不提供手填 ID/OSS ID。
|
||
|
||
仍阻断:
|
||
|
||
- C35–C46 中记录的分类选项、文件 URL、停用记录、金额业务精度/上限、响应 enrichment 与解绑契约;
|
||
- 世系关系解除没有 PC 接口;成员移出/退出不会伪造成世系关系解除或成员与世系人物解绑;
|
||
- 真实账号 `19181970173` 已验证登录和无家谱上下文分支:阶段 6 页面均阻止业务请求、隐藏管理操作并返回家谱选择页,浏览器控制台无错误。该账号当前无家谱数据,因此列表有数据态、详情以及真实写操作仍待有数据账号复核,未制造家谱或业务记录。
|
||
|
||
### 阶段 7:剩余 PC 页面分批开放
|
||
|
||
首批已完成家谱生命周期 ApiClient 契约和创建家谱页面:额度、三级地区、封面上传派生、严格 DTO 校验、防重复与创建后重读均已接入。第二批已完成申请加入、我的申请、撤销和管理员审核页面;家谱/申请 ID 均来自响应或当前上下文,写后重读确认。第三批已完成意见反馈和工单展示:四页共用 PC 反馈集合、提交后三字段白名单重读、详情精确匹配和隐私过滤。第四批已完成 VIP 套餐、我的家谱选项和会员订单:页面不手填业务 ID,不伪造支付能力,创建后重读同一订单确认。第五批已完成家谱主页只读概览:复用 PC overview 与世系树,权限控制管理入口,不制造聚合统计或邀请能力。第六批已完成帮助中心:登录后读取 PC 帮助文章列表,列表响应产生详情 ID,详情精确重读并安全展示正文;Apifox 的匿名标记与后端实际鉴权冲突已记录。第七批已完成应用下载页的 PC 推广列表:未登录不发请求,登录后固定发送 SQL 字典确认的 `platform=pc`,只读取服务端返回的 `pc + all` 正常记录,外链仅允许绝对 HTTP/HTTPS;推广 ID、后台键和 OSS ID 均不向用户开放。第八批已完成官网资讯列表与详情:公开请求不发送或清理 token,分类使用 SQL 字典 `news/notice/download`,详情 ID 只来自列表响应并通过重读列表精确匹配;YAML 通用响应缺失完整 `SiteArticleVo`,且当前部署环境匿名访问仍返回认证失败,两项差异均已记录。成员邀请、分享和资料完善提醒没有 PC Controller,继续阻断。
|
||
|
||
## 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/video-pages.js` | 视频列表、详情、编辑、上传元数据和 CRUD |
|
||
| `public/js/growth-pages.js`、`relative-pages.js`、`memo-pages.js` | 对应族务记录 |
|
||
| `public/js/ceremony-pages.js` | 当前用户贺礼邀请列表、响应内详情和接受/拒绝 |
|
||
| `public/js/article-pages.js`、`album-pages.js` | 谱文、相册和照片 |
|
||
| `public/js/ceremony-admin-pages.js` | 祭祀活动、祭品与管理员邀约 |
|
||
| `public/js/member-admin-pages.js` | 成员修改、移出、退出和谱主转移 |
|
||
|
||
不得创建一个包揽所有业务的巨型页面脚本,也不得为了单一页面引入通用框架。
|
||
|
||
## 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: 下一阶段可以开始的最小范围。
|
||
```
|
||
|
||
不得用“应该可以”“大概完成”代替测试证据。
|