From fb1743aa2a6e76b3c0356e633054b5c8fe5b4cca Mon Sep 17 00:00:00 2001
From: fizzleaf
Date: Wed, 29 Jul 2026 16:57:27 +0800
Subject: [PATCH] =?UTF-8?q?feat(api):=20=E5=AE=8C=E5=96=84=E5=AE=B6?=
=?UTF-8?q?=E8=B0=B1=E7=B3=BB=E7=BB=9FAPI=E5=AE=A2=E6=88=B7=E7=AB=AF?=
=?UTF-8?q?=E5=A5=91=E7=BA=A6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 实现家谱管理相关方法,包括创建、详情、概览、我的家谱和选项查询
- 添加家谱加入申请功能,支持申请、审核、取消和待审核列表操作
- 集成通知详情获取方法和通知ID安全验证机制
- 完善功德记录、谱文、相册、视频、祭祀活动的完整CRUD操作契约
- 实现家谱成员管理功能,包含成员列表、更新、移除和转让所有者操作
- 优化路径ID验证逻辑,拒绝不安全的数值ID并提供明确错误提示
- 更新测试用例以验证所有新增API方法的路径和请求体白名单机制
---
docs/PC接口对接规划.md | 549 ++++++++++-
...2026-07-29-genealogy-create-first-batch.md | 30 +-
.../plans/2026-07-29-stage6-pc-pages.md | 509 ++++++++++
.../2026-07-29-stage6-pc-pages-design.md | 119 +++
join-genealogy.html | 16 +-
profile-album-detail.html | 120 +++
profile-album-edit.html | 100 ++
profile-album.html | 101 +-
profile-article-edit.html | 29 +-
profile-article.html | 30 +-
profile-ceremony-detail.html | 67 ++
profile-ceremony.html | 50 +
profile-content.html | 22 +-
profile-create-family.html | 28 +-
profile-families.html | 8 +-
profile-family-admin.html | 124 +--
profile-family-home.html | 16 +-
profile-feed-detail.html | 72 ++
profile-feed-edit.html | 23 +-
profile-feed.html | 29 +-
profile-generation.html | 5 +-
profile-gift-edit.html | 48 +-
profile-gift.html | 50 +-
profile-growth-edit.html | 32 +-
profile-growth.html | 13 +-
profile-memo-edit.html | 15 +-
profile-memo.html | 11 +-
profile-merit-edit.html | 85 +-
profile-merit.html | 64 +-
profile-messages.html | 76 +-
profile-relative-edit.html | 137 ++-
profile-relative.html | 76 +-
profile-tree.html | 144 ++-
profile-video-edit.html | 128 +++
profile-video.html | 73 +-
profile.html | 10 +-
public/css/profile-module.css | 80 ++
public/js/album-pages.js | 736 ++++++++++++++
public/js/article-pages.js | 567 +++++++++++
public/js/ceremony-admin-pages.js | 920 ++++++++++++++++++
public/js/ceremony-pages.js | 316 ++++++
public/js/feed-pages.js | 559 +++++++++--
public/js/genealogy-entry-pages.js | 287 +++++-
public/js/generation-pages.js | 130 ++-
public/js/growth-pages.js | 577 ++++++++---
public/js/lineage-pages.js | 343 ++++++-
public/js/member-admin-pages.js | 581 +++++++++++
public/js/memo-pages.js | 565 ++++++++---
public/js/merit-pages.js | 644 ++++++++++++
public/js/notification-pages.js | 332 ++++++-
public/js/profile-common.js | 10 +-
public/js/relative-pages.js | 654 +++++++++++--
public/js/video-pages.js | 616 ++++++++++++
tests/album-pages.test.js | 195 ++++
tests/api-client-contract.test.js | 446 ++++++++-
tests/article-pages.test.js | 188 ++++
tests/ceremony-admin-pages.test.js | 251 +++++
tests/ceremony-pages.test.js | 138 +++
tests/feed-pages.test.js | 196 ++++
tests/genealogy-entry-pages.test.js | 202 +++-
tests/generation-pages.test.js | 115 ++-
tests/growth-pages.test.js | 203 +++-
tests/lineage-pages.test.js | 249 ++++-
tests/member-admin-pages.test.js | 176 ++++
tests/memo-pages.test.js | 207 +++-
tests/merit-pages.test.js | 216 ++++
tests/notification-pages.test.js | 109 ++-
tests/pc-scope.test.js | 7 +-
tests/pending-pages.test.js | 33 +-
tests/relative-pages.test.js | 198 +++-
tests/security-upload-scope.test.js | 5 +-
tests/stage6-navigation.test.js | 35 +
tests/video-pages.test.js | 154 +++
utils/ApiClient.js | 237 ++++-
74 files changed, 13166 insertions(+), 1320 deletions(-)
create mode 100644 docs/superpowers/plans/2026-07-29-stage6-pc-pages.md
create mode 100644 docs/superpowers/specs/2026-07-29-stage6-pc-pages-design.md
create mode 100644 profile-album-detail.html
create mode 100644 profile-album-edit.html
create mode 100644 profile-ceremony-detail.html
create mode 100644 profile-ceremony.html
create mode 100644 profile-feed-detail.html
create mode 100644 profile-video-edit.html
create mode 100644 public/js/album-pages.js
create mode 100644 public/js/article-pages.js
create mode 100644 public/js/ceremony-admin-pages.js
create mode 100644 public/js/ceremony-pages.js
create mode 100644 public/js/member-admin-pages.js
create mode 100644 public/js/merit-pages.js
create mode 100644 public/js/video-pages.js
create mode 100644 tests/album-pages.test.js
create mode 100644 tests/article-pages.test.js
create mode 100644 tests/ceremony-admin-pages.test.js
create mode 100644 tests/ceremony-pages.test.js
create mode 100644 tests/member-admin-pages.test.js
create mode 100644 tests/merit-pages.test.js
create mode 100644 tests/stage6-navigation.test.js
create mode 100644 tests/video-pages.test.js
diff --git a/docs/PC接口对接规划.md b/docs/PC接口对接规划.md
index ec25e2d..089713f 100644
--- a/docs/PC接口对接规划.md
+++ b/docs/PC接口对接规划.md
@@ -156,13 +156,39 @@
| C11 | `completed` 只有 string 类型,无枚举 | 不能决定复选框提交 `0/1`、true/false 或其他值 | Apifox 增加枚举和中文含义 |
| C12 | `feedType`、`recordType`、`registerSource` 等无枚举 | 无法判断文本输入还是选择项 | 明确为自由文本,或补全枚举 |
| C13 | 多个日期字段没有 format/时区规则 | 页面值和后端解析可能不一致 | 明确 date 或 date-time,并统一时区 |
-| C14 | 只有配额,没有我的家谱/成员入口 | 无法取得 `genealogyId`、成员或受邀用户选项 | 增加 PC 家谱列表/选项和成员选项接口,或明确外部上下文契约 |
+| 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/空值语义 |
当前复核状态:
@@ -175,8 +201,28 @@
| 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 验收标准:
@@ -376,12 +422,13 @@
`-1` 显示为“不限”,不能参与普通减法或显示负数。
-配额响应不包含 `genealogyId`,不能替代“我的家谱”。在 C14 完成前:
+配额响应不包含 `genealogyId`,不能替代“我的家谱”。当前由 `GET /genealogy/pc/genealogies/mine` 返回完整 `AppGenealogyVo`:
-- 所有家谱内页面缺少真实 `genealogyId` 时必须阻止请求;
-- 不显示静态家谱卡片作为真实数据;
-- 不从 APP 接口获取家谱;
-- 不允许用户手工输入家谱 ID。
+- `profile-families.html` 从真实列表生成家谱入口;
+- `genealogyId` 在浏览器边界保持字符串,并由 `profile-common.js` 统一读取和传播;
+- 所有家谱内页面缺少真实 `genealogyId` 时必须阻止请求并回到家谱选择入口;
+- 不显示静态家谱卡片,不从 APP 接口获取家谱,不允许用户手工输入家谱 ID;
+- 切换家谱通过进入新的带 `genealogyId` URL 完成整页导航,旧页面模块状态不会复用。
### 7.5 行政区划
@@ -455,6 +502,17 @@
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` 同时提供“单条维护”和“批量维护”。
@@ -486,6 +544,14 @@
普通展示列表使用正常字辈接口;管理页面使用 management 接口以包含停用项。
+当前实现状态:
+
+- 页面先读取家谱详情,以 `canEditContent` 决定调用正常列表还是 management 列表;无维护权限时不渲染新增、编辑、停用和批量维护控件,后端继续执行最终权限校验。
+- `genealogyId` 只来自家谱上下文,`poemId` 只来自列表响应;所有业务 ID 在浏览器边界保持字符串,不提供手工 ID 输入。
+- 单条新增、修改和状态切换成功后重新读取列表;批量维护严格执行 preview → 当前请求体签名确认 → save → 重新读取列表。
+- 批量预览逐项校验 `action`、状态、必需的新旧文本和内部 ID,并核对四类汇总计数;勾选 `disableMissing` 时保存确认明确说明只停用后续世代、不删除历史。
+- 已在真实 Chrome 登录态验证无家谱上下文分支:不发送字辈业务请求,新增按钮和批量面板隐藏,家谱上下文入口统一返回家谱选择页。当前账号家谱列表为空,因此正常/management 列表、单条写入和批量写入仍缺少真实家谱数据联调证据。
+
### 7.8 世系人物
全部操作集中在 `profile-tree.html`,详情和编辑可使用抽屉/弹窗,但所有字段都要有明确控件。
@@ -493,7 +559,7 @@
| 字段 | 必填性 | 类型 | 页面处理 |
| --- | --- | --- | --- |
| `bindingMode` | 必填 | S | NONE 不绑定、SELF 当前账号、SPECIFIED 指定账号 |
-| `appUserId` | SPECIFIED 时必填 | S/I | 从真实业务用户选项选择;没有接口时禁用 SPECIFIED,禁止文本 ID |
+| `appUserId` | SPECIFIED 时必填 | S/I | 从当前家谱 `members/options` 的正常且已绑定账号成员中选择;禁止文本 ID |
| `personNo` | 可选 | U/A | 高级设置可填;留空由服务端生成 |
| `name` | 必填 | U | 姓名 |
| `aliasName` | 可选 | U | 别名/曾用名 |
@@ -543,6 +609,19 @@
`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` 负责列表。
@@ -560,7 +639,25 @@
流程:选视频 → 分片上传 → 得到 `videoOssId` → 可选封面上传 → 填标题说明 → 保存 → 重新读取详情。
-当前视频列表、详情、新增和修改均返回泛型对象/列表。C17 完成前可以完成静态表单布局和 `ApiClient` 契约测试,但不得把真实 CRUD 页面标记为已完成。
+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 贺礼邀约与祭祀
@@ -583,6 +680,8 @@
“我的邀请”接口有完整响应,可独立实现接受/拒绝流程。管理端替换受邀人依赖 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 后开放:
@@ -605,9 +704,27 @@
| `remindTime` | 可选 | S | 日期时间控件 |
| `mediaOssIds` | 可选 | F/I | 多附件上传 |
| `sortOrder` | 可选 | U/S | 管理高级设置 |
-| `status` | 可选 | S | 0 正常、1 停用 |
+| `status` | 可选 | A | 当前固定提交 0 正常;C26 解决前不开放 1 停用 |
-列表、详情、新增和修改响应仍是泛型对象。补齐 `GrowthRecordView` 前不得展示原始 JSON,也不得猜 `recordId` 开启编辑和删除。
+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 亲友记录
@@ -619,13 +736,33 @@
| `relationName` | 可选 | U | 关系名称 |
| `eventName` | 可选 | U | 事件名称 |
| `eventTime` | 可选 | S | 日期时间选择器 |
-| `giftAmount` | 可选 | U | 金额输入,明确精度和非负规则后校验 |
+| `giftAmount` | 可选 | U | 金额输入;只提交 JSON 序列化后数值不变的有限数字,C27 解决前不猜精度、范围或非负规则 |
| `recordContent` | 可选 | U | 内容 |
| `mediaOssIds` | 可选 | F/I | 多附件上传 |
| `sortOrder` | 可选 | U/S | 管理高级设置 |
-| `status` | 可选 | S | 0 正常、1 停用 |
+| `status` | 可选 | A | 当前固定提交 0 正常;C29 解决前不开放 1 停用 |
-补齐 `RelativeRecordView` 前只完成页面字段布局和请求契约,不开放真实列表、编辑和删除。
+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 备忘录
@@ -635,13 +772,31 @@
| --- | --- | --- | --- |
| `memoTitle` | 必填 | U | 标题 |
| `memoContent` | 可选 | U | 内容 |
-| `remindTime` | 可选 | S | 日期时间 |
-| `completed` | 可选 | S | 应为开关;C11 明确提交值前保持禁用 |
-| `mediaOssIds` | 可选 | F/I | 多附件上传 |
-| `sortOrder` | 可选 | U/S | 管理高级设置 |
-| `status` | 可选 | S | 0 正常、1 停用 |
+| `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`;不开放不可重读的停用状态 |
-`completed` 表示业务完成状态,`status` 表示记录正常/停用,两者不能合并。补齐 `MemoView` 前不得猜 `memoId` 或响应字段。
+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 功德记录
@@ -653,12 +808,33 @@
| `meritType` | 可选 | S | donation 捐赠、repair 修祠、public 公益、other 其他 |
| `meritTitle` | 必填 | U | 标题 |
| `meritContent` | 可选 | U | 内容 |
-| `amount` | 可选 | U | 金额 |
-| `meritTime` | 可选 | S | date-time |
-| `sortOrder` | 可选 | U/S | 管理高级设置 |
-| `status` | 可选 | S | 0 正常、1 停用 |
+| `amount` | 可选 | U | YAML `number`;提交前拒绝 JSON 序列化会改变精确数值的输入,不自行限制小数位、范围或正负 |
+| `meritTime` | 可选 | S | `datetime-local` 选择,提交为后端示例和 `Date` 接受的 `yyyy-MM-dd HH:mm:ss` |
+| `sortOrder` | 可选 | U/S | 安全整数;创建默认 `0` |
+| `status` | 可选 | I/A | 页面固定隐藏提交 `0`;不开放不可重读的停用状态 |
-现有页面错误地使用了 `service`,但契约枚举中不存在该值;必须删除 `service`,增加 `repair` 和 `public`。现有页面还缺少 `sortOrder`、`status`。
+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。
@@ -666,28 +842,276 @@
页面:`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、业务失败和网络失败。
+
+| 字段 | 必填性 / 类型 | 标记 | 页面用途、来源与提交时机 |
| --- | --- | --- | --- |
-| `readStatus` | 可选 query | S | 全部=省略、未读=0、已读=1 |
-| `notificationId` | 单条已读必填 path | I/A | 从被点击通知记录带入 |
-| 未读数量 `data` | 响应 | R | 顶部徽标,int64 按安全数值/字符串处理 |
+| 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 | 顶部计数;只接受非负安全整数 |
-通知列表当前是 `ListResult
+
+
+
+
+
Video Editor
+
+
+
发布视频
+
文件通过统一分片上传取得内部 OSS ID,页面不允许手工填写文件编号。
+
+
+
+
+
+
+
+
+
+ 视频内容
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
请选择视频文件
+
+
+
+
+
+
+
未选择封面
+
+
+
+
+
+
+
选择视频后自动读取,不会要求手工填写。
+
+
+
+
+
+
+
+
+
+ 正在核对视频维护权限…
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/profile-video-edit.html b/profile-video-edit.html
new file mode 100644
index 0000000..d6ac5bd
--- /dev/null
+++ b/profile-video-edit.html
@@ -0,0 +1,128 @@
+
+
+