API_REFERENCE.md 139 KB

浠艾福(XAF)后端接口参考文档

维护规范:

  1. 新增接口前必须先查阅本文档,确认是否已有可复用或可修改的接口
  2. 有相似功能但需调整 → 评估修改成本,必要时新增(标注依赖)
  3. 实在没有 → 才新增接口,并在此文档同步记录
  4. 废弃接口保留注释,不直接删除,待确认无调用后清理

一、接口规范

1.1 统一约定

项目 规范
请求方法 统一 @PostMapping,禁止 @GetMapping/@PutMapping/@DeleteMapping(仅支付回调等第三方 webhook 例外)
响应格式 Result<T> — { code, message, data }
认证 JWT Bearer Token,Header: Authorization: Bearer {token}
角色校验 Controller 内手动检查 @RequestAttribute("role")
DI @Resource,字段名与 Bean Name 一致
公开路径(免鉴权) /api/auth/*、/api/config/public/*、/api/media/upload、/api/articles/*(部分)

1.2 新增接口检查清单

# 1. 搜索现有相似接口
grep -rn "功能关键词" cfc-backend/src/main/java/com/etotem/cfc/controller/ --include="*.java"

# 2. 检查路由冲突
grep -rn '@PostMapping("' cfc-backend/src/main/java/com/etotem/cfc/controller/ | grep -oP '@\w+Mapping\("\K[^"]*' | sort -u

# 3. 检查 Bean 命名冲突(新增 Service/Controller 时)
find cfc-backend/src/main/java -name "*XxxService.java" -o -name "*XxxController.java" | xargs grep -l "class Xxx"

二、Controller 总览

Controller 路由前缀 说明 废弃状态
AuthController /api/auth 登录/注册/角色切换 —
UserController /api/user 用户信息/头像/吉祥物 —
FamilyController /api/family 家庭基础操作 部分废弃见下
FamilyMembersController /api/family/member 家庭成员 CRUD/切换/可见性 —
FamilyInviteController /api/family/invite 邀请码/二维码/申请加入 —
FamilyUserController /api/family/user 家长端家庭成员管理 部分废弃见下
PointsController /api/points 积分余额/流水 —
TaskController /api/tasks 任务 CRUD/完成/审核 —
WishController /api/wishes 心愿 CRUD/审批/兑换 —
RewardController /api/rewards 奖励模板/兑换 —
AssessmentAppointmentController /api/assessment/appointment 测评预约 —
DanAssessmentController /api/dan-assessment DAN 测评全链路 —
EnergyController /api/energy 五维能量概览/流水/配置 —
GrowthController /api/growth 成长记录 —
GrowthPlanController /api/growth/plan 成长计划 —
HealthCheckinController /api/health/checkin 健康打卡(行为记录) —
DailyCheckinController /api/daily/checkin 每日健康打卡(饮食/运动/心情) —
EmotionCheckinController /api/mind/checkin 情绪日记(心情打卡同步目标) —
HealthStatusController /api/health-status 健康现状档案 —
ProductController /api/product 商品 —
ProductOrderController /api/product/order 商品订单 —
CartController /api/cart 购物车 —
MembershipController /api/membership 会员 —
SubscriptionController /api/subscription 订阅 —
AIChatController /api/ai AI 对话 —
InnatePortraitController /api/mind/innate 先天画像(画像/AI解读/数字能量/成长轨迹) —
ArticleController /api/articles 文章 —
NotificationController /api/notification 通知 —
StatsController /api/stats 统计 —
CfCommissionController /api/commission/cf CF 分佣(团队规模/比例/钱包/流水) —
CfTransferController /api/cf/transfer CF 成员间转让 —
CfBalanceController /api/cf C 端 CF 查询(余额快照/流水/家庭券,只读) F-7a
AdminCfRateTierController /api/admin/cf-rate-tier CF 返佣阶梯配置(admin) —
ContactController /api/contact 联系人 CRUD/互动/邀请入家庭 —
ContactMatchController /api/contact/match 联系人对接(send/accept/reject/列表) —
OctopusController /api/octopus 章鱼图(帮助记录/触手聚合) —
PearlController /api/pearl 珍珠图(25 类社会连接聚合 + 互动/提醒/优先级) —
AbilityController /api/ability 能力图(SKILL 帮助记录聚合为能力节点) —
ServiceRoleApplicationController /api/service-role 统一服务角色申请(多角色合一 + 管理端审批) —
GuideTeamController /api/guide/team 规划师团队/邀请码/上下级 —
GuideFamilyTaskController /api/guide/families 规划师侧家庭任务管理 + 家庭解绑 —
PlannerCertificationController /api/planner 规划师培训认证中心(我的认证/课程/线下课打卡/考核) —
XiaoeWebhookController /api/xiaoe 小鹅通 webhook 回调(线上课时事件) —
AdminPlannerCertCategoryController /api/admin/planner-cert-categories 管理端-学习种类 CRUD —
AdminPlannerCourseController /api/admin/planner-courses 管理端-线上课程 CRUD —
AdminPlannerOfflineCourseController /api/admin/planner-offline-course-map 管理端-线下课↔类别映射 CRUD —
AdminActivityCheckinController /api/admin/activity-checkins 管理端-签到记录/手动补录 —
AdminPlannerExamController /api/admin/planner-exam 管理端-试卷/题库 CRUD —
AdminPlannerCertificationController /api/admin/planner-certifications 管理端-认证看板/同步课时/存量补登 —

三、已废弃接口清单

标记 410 Gone 响应,前端已迁移至新接口。可考虑在确认无调用后清理。

3.1 FamilyController — 邀请码系统(已废弃)

路径 说明 替代接口
POST /api/family/invite-code 获取邀请码(已废弃) POST /api/family/invite/generate
POST /api/family/invite-code/generate 生成邀请码(已废弃) POST /api/family/invite/generate

3.2 FamilyUserController — 角色切换(已废弃)

路径 说明 替代接口
POST /api/family/user/switch-mode 切换家长/孩子模式(已废弃) POST /api/family/member/switch
POST /api/family/user/switch-to-child 切换到孩子身份(已废弃) POST /api/family/member/switch
POST /api/family/user/switch-back-to-parent 切回家长身份(已废弃) POST /api/family/member/switch
POST /api/family/user/switch-back-verify 切换验证(已废弃) —

3.3 ButlerController — 服务记录/佣金(已废弃)

路径 说明 替代接口
POST /api/butler/service-records 服务记录(已废弃) —
POST /api/butler/commissions 佣金记录(已废弃) —

3.4 TeacherController — 教学任务(已废弃)

路径 说明 替代接口
POST /api/teacher/tasks 创建教学任务(已废弃) POST /api/guide/families/{familyId}/tasks/{taskId}
其余 /api/teacher/* 多个接口均标注 @Deprecated — —

3.5 DanAssessmentController — 当前测评(已废弃)

路径 说明 替代接口
POST /api/dan-assessment/current 获取当前测评(已废弃) —

3.6 NoticeController — 公告列表(已废弃)

路径 说明 替代接口
GET /api/notices/list 使用 GET 方法,违反统一 POST 规范 —

四、接口详细清单

4.1 认证与用户(/api/auth, /api/user)

路径 说明 参数 废弃
POST /api/auth/send-code 发送验证码 phone —
POST /api/auth/phone-login 手机号登录 phone, code —
POST /api/auth/wechat-phone-login 微信一键绑定手机号 code —
POST /api/auth/silent-login 静默登录(仅获取 token) — —
POST /api/auth/auto-login 自动登录(refresh token) — —
POST /api/auth/register-with-idcard 身份证注册 — —
POST /api/auth/wechat-login 微信授权登录 code —
POST /api/auth/info 获取当前用户信息 — —
POST /api/auth/set-password 设置密码 password —
POST /api/auth/verify 验证密码 password —
POST /api/auth/check-phone 检查手机号是否存在 phone —
POST /api/auth/direct-register 直接注册(无邀请码) — —
POST /api/auth/register-with-invite 邀请码注册 inviteCode —
POST /api/auth/switch-role 切换角色 role —
POST /api/user/address/list 收货地址列表 — —
POST /api/user/address/get 获取地址详情 id —
POST /api/user/address/create 创建地址 — —
POST /api/user/address/update 更新地址 — —
POST /api/user/address/delete 删除地址 id —
POST /api/user/address/setDefault 设为默认 id —
POST /api/user/mascot/set 设置吉祥物 mascotId —
POST /api/user/mascot/get 获取吉祥物 — —

4.2 家庭与成员(/api/family/*, /api/family/member/*)

路径 说明 废弃
POST /api/family/invite-code 获取邀请码 ✅ 废弃
POST /api/family/invite-code/generate 生成邀请码 ✅ 废弃
POST /api/family/guide-bind 绑定规划师 —
POST /api/family/member/add 添加成员 —
POST /api/family/member/list 成员列表(统一入口) —
POST /api/family/member/switch 切换成员视角 —
POST /api/family/member/kick 移除成员 —
POST /api/family/member/leave 主动退出家庭(微信用户;创建者需先转让管理员) —
POST /api/family/member/recycle 从回收箱回收成员(管理员操作) —
POST /api/family/member/update 更新成员信息 —
POST /api/family/member/editable 检查是否可编辑 —
POST /api/family/member/logs 成员变更日志 —
POST /api/family/invite/qrcode 生成邀请二维码 —
POST /api/family/invite/request-join-by-code 申请加入(token 路径绑定邀请人,等待邀请人确认;旧码路径管理员兜底) inviteCode 或 token + familyRole
POST /api/family/invite/approve-request 同意加入申请(审批人=邀请人且仍为目标家庭成员;旧数据无邀请人时家庭管理员兜底) —
POST /api/family/invite/reject-request 拒绝加入申请(权限规则同上) —
POST /api/family/invite/pending-requests 待我处理的申请列表(按邀请人查询;旧数据由目标家庭管理员兜底可见) —
POST /api/family/invite/my-request 我的申请 —
POST /api/family/invite/cancel-request 取消申请 —
POST /api/family/invite/generate 生成邀请令牌(复用同家庭未过期未用尽的有效令牌;仅未过期记录计入 10 条额度) —
POST /api/family/invite/validate 验证邀请令牌 —
POST /api/family/invite/accept 接受邀请 —
POST /api/family/invite/check-family 检查家庭状态 —
POST /api/family/invite/revoke 撤销邀请 —
POST /api/family/invite/transfer-admin 转让管理员 —
POST /api/family/invite/validate-family-code 验证家庭短邀请码(落地页展示用,不创建请求) inviteCode
POST /api/family/invite/bind-inviter 绑定家庭邀请人(仅首次注册调用) familyInviteCode

4.2 Family Member 接口详细(切换/回收箱)

POST /api/family/member/leave — 主动退出家庭

说明:微信登录用户主动退出当前家庭,回到自己的初始家庭(自己创建的家庭 families.creator_id = userId);若无初始家庭则自动创建新家庭。退出时成员资产(测评/报告/能量值/档案属性)随成员迁移到目标家庭,CF 值(system_points)清零丢弃留在原家庭。

约束:

  • 仅微信登录用户可退出(openid 非 phone: 前缀);非微信用户调用返回错误
  • 家庭创建者禁止退出,需先通过 POST /api/family/invite/transfer-admin 转让管理员
  • 退出后该用户自动归属初始家庭(或新建家庭),不会处于"无家庭"状态

请求体:无(空 body 或 {})

响应:

{
  "code": 200,
  "message": "退出成功",
  "data": null
}

错误码: | code | message | 处理建议 | |------|---------|----------| | 500 | 您是家庭创建者,请先转让管理员权限后再退出 | 先转让管理员 | | 500 | 非微信登录用户不能自主退出家庭 | 非微信用户不支持主动退出 | | 500 | 用户未加入家庭 / 家庭不存在 / 未找到该用户的家庭成员记录 | 提示用户状态异常 |


POST /api/family/member/kick — 移除成员(含回收箱分流)

说明:家庭管理员将成员移出家庭。行为按成员类型分流:

  • 微信登录用户:资产迁移回其初始家庭(无则自动创建),CF 值(system_points)随成员带走,同时收回该家庭发放给该成员的人口券(POPULATION,来源 member:{id},仅作废 AVAILABLE 状态的券)
  • 非微信登录用户:进入回收箱(family_members.status = recycled),users.family_id 置空,资产保留在原家庭记录上,后续可通过 POST /api/family/member/recycle 回收
  • 无关联用户的手动成员:直接删除记录

约束:仅家庭创建者可踢出;不能踢出家庭创建者本人。

请求体:

{
  "memberId": 12345
}

响应:

{
  "code": 200,
  "message": "踢出成功",
  "data": null
}

POST /api/family/member/recycle — 从回收箱回收成员

说明:目标家庭管理员将回收箱中的成员(非微信用户,status=recycled)重新加入指定家庭,资产(测评/报告/能量值/档案属性)迁移到目标家庭,关联用户 family_id 归位到目标家庭。

约束:仅目标家庭创建者可回收;成员必须在回收箱中。

请求体:

{
  "memberId": 12345,
  "targetFamilyId": 67890
}

响应:

{
  "code": 200,
  "message": "回收成功",
  "data": null
}

错误码: | code | message | 处理建议 | |------|---------|----------| | 500 | 该成员不在回收箱中 | 仅回收箱成员可回收 | | 500 | 只有目标家庭管理员才能回收成员 | 权限不足 |


4.2 Family Invite 接口详细

POST /api/family/invite/request-join-by-code — 申请加入家庭

说明:用户通过邀请码/令牌提交加入家庭的申请,等待邀请人审批。

请求体:

{
  "inviteCode": "fam_abc123",      // 必填,邀请码或令牌
  "familyRole": "爸爸"              // 可选,用户在目标家庭中的身份
}

响应:

{
  "code": 200,
  "message": "申请已提交,等待邀请人确认",
  "data": {
    "requestId": 12345,
    "familyName": "张三的家庭"
  }
}

POST /api/family/invite/bind-inviter — 绑定家庭邀请人

说明:新用户首次注册时调用,建立「被邀请人 → 邀请人」关系,用于追踪邀请来源。仅首次注册调用,已有家庭邀请人的用户调用会返回失败。

请求体:

{
  "familyInviteCode": "fam_abc123"
}

响应:

{
  "code": 200,
  "message": "绑定成功",
  "data": null
}

错误码: | code | message | 处理建议 | |------|---------|----------| | 400 | 用户已有家庭邀请人 | 跳过,已在目标家庭中 | | 404 | 邀请码无效 | 提示用户链接无效 |


POST /api/family/invite/validate — 验证邀请令牌

说明:邀请落地页使用,验证 token 有效性并返回家庭信息(仅供展示)。

请求体:

{
  "token": "abc123def456"
}

响应:

{
  "code": 200,
  "data": {
    "familyId": 100,
    "familyName": "张三的家庭",
    "inviterName": "张三",
    "inviterAvatar": "/static/avatar.jpg",
    "memberCount": 3
  }
}

POST /api/family/invite/check-family — 检查用户家庭状态

请求体:无额外参数(从 JWT 取 userId)

响应:

{
  "code": 200,
  "data": {
    "inFamily": true,
    "familyId": 100,
    "familyName": "张三的家庭",
    "isAdmin": true
  }
}

POST /api/family/invite/pending-requests — 查询待我处理的申请

说明:邀请人视角,查询他人提交给自己的加入申请。

请求体:无额外参数

响应:

{
  "code": 200,
  "data": [
    {
      "id": 1001,
      "requesterUserId": 200,
      "requesterNickname": "李四",
      "requesterAvatar": "/static/avatar.jpg",
      "familyRole": "妈妈",
      "status": "pending",
      "createdAt": "2026-08-31T10:00:00"
    }
  ]
}

POST /api/family/invite/approve-request — 批准加入申请

请求体:

{
  "requestId": 1001,
  "comment": ""
}

响应:

{
  "code": 200,
  "message": "已同意"
}

POST /api/family/invite/reject-request — 拒绝加入申请

请求体:

{
  "requestId": 1001,
  "comment": "不符合条件"
}

响应:

{
  "code": 200,
  "message": "已拒绝"
}

POST /api/family/invite/my-request — 查询我的申请

请求体:无额外参数

响应:

{
  "code": 200,
  "data": {
    "id": 1001,
    "targetFamilyId": 100,
    "targetFamilyName": "张三的家庭",
    "familyRole": "爸爸",
    "status": "pending",
    "createdAt": "2026-08-31T10:00:00"
  }
}

status 枚举:pending | approved | rejected

4.3 任务(/api/tasks)

路径 说明
POST /api/tasks/minigame-options 小游戏选项
POST /api/tasks/create 创建任务
POST /api/tasks/today 今日任务(memberId 查单成员;familyWide=true 查全家庭今日任务)
POST /api/tasks/{id}/start 开始任务(两阶段入口,含购物任务自动加购/下单)
POST /api/tasks/{id}/complete 完成任务
POST /api/tasks/{id}/review 审核任务
POST /api/tasks/history 历史任务
POST /api/tasks/pending-review 待审核
POST /api/tasks/today-parent 家长今日任务
POST /api/tasks/{id} 任务详情
POST /api/tasks/{id}/complete-minigame 小游戏完成
POST /api/tasks/batch-complete 批量完成
POST /api/tasks/batch-delete 批量删除
POST /api/tasks/my-pending 我的待办
POST /api/tasks/accept 接受任务
POST /api/tasks/reject/{id} 拒绝任务

4.3.1 购物任务联动(actionType = cart/order)

任务创建时通过 actionType + actionConfig 声明购物联动;调用 POST /api/tasks/{id}/start 时,后端自动执行加购/下单。

actionConfig JSON 格式:

字段 必填 说明
productId ✅ 商品ID
quantity ❌ 数量,默认 1
skuId ❌ SKU ID(可选)
consigneeId ❌ 收货地址ID(order 模式下可选;未提供时取用户默认地址)
deliveryMethod ❌ 配送方式:1=快递/2=自提/4=线上可选人/5=线上单人

actionType 行为:

actionType 行为 返回字段
minigame 跳转小游戏页 —
focus 跳转专注计时器页 —
survey 跳转问卷填写页 —
article 跳转文章中心页 —
activity 跳转活动列表页 —
cart 自动加购,返回加购结果 execution.extra 含 cartAdded=true、productId、quantity
order 先加购,再创建 pending 订单 execution.extra 含 orderId、orderNo(成功时)或 orderFailed=true、orderError(失败时)
diet 跳转饮食打卡页(/pages/growth/diet-checkin?taskId={id}) —
sleep 跳转睡眠打卡页(/pages/growth/sleep-checkin?taskId={id}) —
exercise 跳转运动打卡页(/pages/growth/exercise-checkin?taskId={id}) —

下单失败常见原因: 缺默认收货地址、商品已下架、库存不足、配送方式校验失败。失败时加购结果保留,任务状态正常置 in_progress,前端可引导用户去购物车/结算页手动完成。

4.4 心愿(/api/wishes)

路径 说明
POST /api/wishes/create 创建心愿
POST /api/wishes/{id}/set-price 设置价格
POST /api/wishes/{id}/reject 拒绝心愿
POST /api/wishes/{id}/exchange 兑换心愿
POST /api/wishes/{id}/approve-exchange 审批兑换
POST /api/wishes/{id}/fulfill 完成心愿
POST /api/wishes/{id}/confirm 确认心愿
POST /api/wishes/{id}/cancel 取消心愿
POST /api/wishes/list 心愿列表
POST /api/wishes/pending 待审批心愿
POST /api/wishes/{id} 心愿详情

4.5 能量与积分(/api/energy, /api/points)

路径 说明
POST /api/energy/overview 能量概览
POST /api/energy/logs 能量流水
POST /api/energy/config 能量配置
POST /api/energy/dimension 五维详情
POST /api/points/balance 积分余额
POST /api/points/logs 积分流水
POST /api/points/adjust 手动调整
POST /api/points/system-balance 系统余额
POST /api/points/logs-by-category 分类流水

4.6 成长档案(/api/growth/*)

路径 说明
POST /api/growth/record/create 创建记录
POST /api/growth/record/create-with-order 下单关联创建
POST /api/growth/record/list 记录列表
POST /api/growth/record/child/{memberId} 指定成员记录
POST /api/growth/record/{id} 记录详情
POST /api/growth/record/{id}/delete 删除记录
POST /api/growth/record/external/sync 外部同步
POST /api/growth/record/upload-and-parse 上传解析
POST /api/growth/record/create-from-upload 从上传创建
POST /api/growth/record/supplement 补充记录
POST /api/growth/plan/create 创建计划
POST /api/growth/plan/child/{memberId} 成员计划
POST /api/growth/plan/{id} 计划详情
POST /api/growth/plan/{id}/review 审核计划

4.7 健康打卡(/api/health/*, /api/daily/checkin, /api/mind/checkin)

路径 说明
POST /api/health/checkin/list 行为打卡列表
POST /api/health/checkin/create 创建行为打卡
POST /api/daily/checkin/list 每日打卡列表(饮食/运动/睡眠/心情)
POST /api/daily/checkin/create 创建每日打卡
POST /api/daily/checkin/update 更新打卡
POST /api/daily/checkin/delete 删除打卡
POST /api/mind/checkin/create 情绪日记创建
POST /api/mind/checkin/list 情绪日记列表
POST /api/mind/checkin/latest 最新情绪日记
POST /api/mind/checkin/trend 情绪趋势
POST /api/mind/checkin/stats 情绪统计
POST /api/mind/checkin/weekly-report 周报
POST /api/mind/checkin/emotion/recognize 情绪识别(URL方式,走Dify) — 已废弃
POST /api/mind/emotion/analyze 照片情绪识别(文件上传,走 LangGraph DeepFace)
POST /api/mind/emotion/analyze-url 照片情绪识别(URL方式,走 LangGraph DeepFace)
POST /api/health-status/get 健康现状档案获取
POST /api/health-status/save 健康现状档案保存
POST /api/health-status/signature 提交手签名(仅更新 signature + signed_at 列,不影响其他字段;body: {memberId, signature},signature 为 base64 PNG data URL)
POST /api/health/exercise/sync-wechat-steps 同步微信运动步数(传 encryptedData+iv,返回当日步数与近30天数据)
POST /api/health/meal/list 饮食打卡列表
POST /api/health/meal/create 创建饮食打卡(支持 taskId 任务联动 + isBackfill 补打)
POST /api/health/meal/daily 获取某天的饮食记录
POST /api/health/meal/weekly 获取某周食材频次与营养汇总
POST /api/health/meal/alerts 获取食材摄入预警
POST /api/health/sleep/list 睡眠打卡列表
POST /api/health/sleep/create 创建睡眠打卡(支持 taskId 任务联动)
POST /api/health/exercise/list 运动打卡列表
POST /api/health/exercise/create 创建运动打卡(支持 taskId 任务联动 + stepCount 微信步数)

健康打卡任务联动(taskId 参数)

饮食/睡眠/运动打卡接口均支持可选 taskId 参数(Long),用于将打卡记录与任务系统联动。

请求体新增参数:

参数 类型 必填 说明
taskId Long ❌ 关联任务ID;为 null 时仅存打卡记录,不触发任务逻辑

联动逻辑:

场景 行为
taskId 指向 tasks.is_daily_progress=1 的任务 调用 TaskService.updateProgress(userId, taskKey, 1) 累加进度,达标后自动 completed + 发放积分/能量
taskId 指向普通任务(is_daily_progress=0) 调用 TaskService.completeTask(taskId, memberId, ...) 直接完成
taskId 为 null 仅存打卡记录 + 发放 5CF 打卡积分,不触发任务逻辑
补打(isBackfill=1) 忽略 taskId,不触发任何任务逻辑

taskKey 约定(每日进度型任务):

actionType taskKey 匹配方式
diet "DIET" title 精确匹配 OR title 以 "[DIET]" 前缀匹配
sleep "SLEEP" 同上
exercise "EXERCISE" 同上

前端跳转路径:/pages/growth/{type}-checkin?taskId={id}(由 tasks.vue 的 navigateByAction() 自动构造)

4.8 商品与订单(/api/product/*)

路径 说明
POST /api/product/list 商品列表
POST /api/product/detail 商品详情
POST /api/product/create 创建商品
POST /api/product/update 更新商品
POST /api/product/my 我的商品
POST /api/product/shelve 上下架
POST /api/product/order/create 创建订单
POST /api/product/order/pay 支付
POST /api/product/order/cancel 取消订单
POST /api/product/order/my 我的订单
POST /api/product/order/detail 订单详情
POST /api/product/order/confirm 确认收货
POST /api/product/order/refund/apply 申请退款
POST /api/product/order/vendor 服务商查询收到的订单
POST /api/product/order/vendor-confirm 服务商确认发出/服务完成
POST /api/product/order/ship 服务商/管理端发货(填物流单号+快递公司)。发货成功后自动调用微信「小程序交易管理服务」upload_shipping_info 同步物流到微信订单管理(用户在微信侧收发货通知/查物流/确认收货);自提订单或无单号跳过;失败只记日志不阻塞(fail-open);wechat.test-mode=true 或 wechat.fulfillment-enabled=false(环境变量 WECHAT_FULFILLMENT_ENABLED)时跳过
POST /api/product/order/review/update 供应商审核修改待支付订单(修改价格/配送方式/添加优惠券/赠品)
POST /api/cart/add 加入购物车
POST /api/cart/list 购物车列表
POST /api/cart/update 更新数量
POST /api/cart/remove 移除商品
POST /api/cart/count 购物车数量
POST /api/consignee/list 收货地址列表
POST /api/consignee/save 保存地址
POST /api/consignee/delete 删除地址

4.9 AI 对话(/api/ai/*)

路径 说明
POST /api/ai/chat/send 发送消息
POST /api/ai/chat/conversations 对话列表
POST /api/ai/chat/messages 消息列表
POST /api/ai/chat/conversations/{id}/delete 删除对话
POST /api/ai/nutrition/send 营养对话
POST /api/ai/health-coach/send 健康教练(请求体可选字段 coach_id 由服务端自动注入,客户端无需传;LangGraph 按 xibao/fubao 三级回退路由话术)
POST /api/ai/butler/send 管家对话
POST /api/ai/context 上下文管理
POST /api/butler/sessions/create 创建会话
POST /api/butler/sessions/update-conversation 更新会话
POST /api/butler/sessions/archive 归档会话
POST /api/butler/sessions/list 会话列表
POST /api/butler/sessions/detail 会话详情
POST /api/butler/sessions/delete 删除会话

4.10 测评(/api/assessment/*, /api/dan-assessment/*)

路径 说明
POST /api/assessment/appointment/create 预约测评
POST /api/assessment/appointment/confirm/{id} 确认预约
POST /api/assessment/appointment/cancel/{id} 取消预约
POST /api/assessment/appointment/my-list 我的预约
POST /api/assessment/latest-result 最新测评结果
POST /api/assessment/history 测评历史
POST /api/dan-assessment/result/upload 上传报告
POST /api/dan-assessment/result/{resultId}/guidance/save 保存指导建议
POST /api/dan-execution/complete 完成测评执行
POST /api/dan-execution/confirm 确认执行
POST /api/dan-execution/rate 评分
POST /api/dan-execution/my-list 我的执行记录

4.11 饮食推荐(/api/diet/*)

路径 说明
POST /api/diet/preferences/current-member 当前成员饮食偏好
POST /api/diet/preferences/save 保存饮食偏好
POST /api/diet/recommendation/today 今日推荐(返回 data.id / data.menu / data.nutritionSummary / data.status)
POST /api/diet/recommendation/generate 生成推荐(body: date, meal_type, selected_foods JSON string;返回 data.id / data.menu / data.nutritionSummary)
POST /api/diet/recommendation/complete 完成推荐
POST /api/diet/record/save 保存饮食记录
POST /api/diet/record/daily 每日记录
POST /api/diet/ingredients/suggest 食材推荐(返回 data.ingredients 列表)
POST /api/diet/ingredients/recommend 换一批(返回 data.ingredients,每次不同)
POST /api/diet/ingredients/search 搜索食材(body {keyword},返回 data.foods:[{id, name, category}])
POST /api/diet/meals/config 餐食配置(body: date_type + meal_type,返回 data.participantMemberIds 等)
POST /api/diet/meals/config/save 保存餐食配置,批量格式(推荐,单次调用):body {date_type:"weekday", configs:{breakfast:"[1,2]", lunch:"[]", dinner:"[3]"}}(各餐次值为成员ID数组的 JSON 字符串);亦兼容单条格式:body {date_type, meal_type, participant_member_ids, notes?}。前端 saveMealConfig 位于 cfc-frontend/utils/api.js(2772行)

4.12 内容(/api/articles, /api/content/*)

路径 说明
POST /api/articles/list 文章列表
POST /api/articles/detail 文章详情
POST /api/articles/featured 精选文章
POST /api/articles/record-read 记录阅读
POST /api/articles/report-reading-time 上报阅读时长(按 articleId+childId+日期累加,首次上报递增 view_count)
POST /api/articles/reading-stats 阅读统计
POST /api/articles/daily-tip 每日提示
POST /api/articles/ai-questions AI 生成问题
POST /api/articles/submit-answers 提交答案
POST /api/articles/my-posts 我的文章
POST /api/articles/comments/list 评论列表
POST /api/articles/comments/create 创建评论
POST /api/articles/comments/audit 审核评论
POST /api/articles/quiz/generate 生成测验
POST /api/articles/quiz/submit 提交测验
POST /api/content-sections/visible 可见区块
POST /api/content-sections/list 区块列表
POST /api/content/related-items 内容关联推荐:以活动/文章/商品任一为源(sourceType+sourceId),按共享标签一次返回 data.articles / data.activities / data.products 三组(支持 size/page 分页,游客可访问)

4.13 管理员接口(/api/admin/*)

管理员接口需 role=admin,详见 AdminInterceptor。

路径前缀 说明
/api/admin/articles/* 文章管理
POST /api/admin/articles/move 调整精选文章的推荐顺序(`{ id, direction: 'up'
/api/admin/articles/reading-records 按文章查询阅读记录明细(分页,含孩子昵称/时长)
/api/admin/assessment/* 测评材料管理
/api/admin/bazi-config/* 八字配置
/api/admin/blood-type-config/* 血型配置
/api/admin/butler/* 管家分配管理(分配列表/强制解绑/停接开关)
/api/admin/commission/* 佣金管理
/api/admin/dimension/* 维度配置
/api/admin/dimension-config/* 维度权重
/api/admin/energy/* 能量配置
/api/admin/energy-config/* 五行能量来源/每日限制配置
/api/admin/ecom-supplier/* 电商供应商管理
/api/admin/file-record/* 后台素材库(上传入库/检索/标签字典/统计,见 §4.56)
/api/admin/guide/* 成长规划师管理(申请/套餐)
/api/admin/growth-archive-product/* 成长档案关联商品
/api/admin/health-plan/* 健康方案管理(跨家庭列表/详情)
/api/admin/knowledge-base/* 知识库管理
/api/admin/notices/* 公告管理
/api/admin/innate-portrait-config/* 先天画像来源权重配置(list/update/invalidate)
/api/admin/numsoul-detail-config/* 数字能量详细配置(list/create/update/delete)
/api/admin/package-templates/* 套餐模板
/api/admin/ppoint-config/* P点配置(品类级比例+商品级固定值)
/api/admin/product/* 商品管理
/api/admin/report-parser/* 报告解析配置
/api/admin/report-template/* 报告展示模板管理
/api/admin/supply-* 供应链相关
/api/admin/system/* 系统配置
/api/admin/unlock-gates/* 通关配置
/api/migration/run 数据迁移

4.14 先天画像(/api/mind/innate/*)

五维能量体系"心维度"先天画像聚合接口,基于星座/八字/血型/数字能量生成,AI 解读失败时自动降级模板文案。

路径 说明
POST /api/mind/innate/portrait 先天画像(聚合 mind_base_score + 数字能量详情 + 来源贡献明细)
POST /api/mind/innate/reading AI 解读(缓存到 innate_portrait_report,失败降级模板)
POST /api/mind/innate/numsoul 数字能量计算(生命灵数/天赋数/生日数/命运数)
POST /api/mind/innate/trajectory 先天+后天成长轨迹(EnergyBalance 后天能量对比)

请求参数(portrait/reading/trajectory):

{ "memberId": 123, "memberType": "child", "familyId": 1 }

numsoul 请求参数:

{ "year": 1990, "month": 5, "day": 15 }

4.15 统计与通知(/api/stats, /api/notification)

路径 说明
POST /api/stats/dashboard 统计仪表盘
POST /api/stats/overview 总览
POST /api/stats/revenue 收入统计
POST /api/stats/membership 会员统计
POST /api/stats/trend 趋势
POST /api/notification/list 通知列表
POST /api/notification/read 标记已读

4.16 报告模板管理(/api/admin/report-template)

路径 说明
POST /api/admin/report-template/list 模板列表,支持 reportType/isActive 过滤
POST /api/admin/report-template/get 按 reportType 获取模板,参数 reportType
POST /api/admin/report-template/save 保存模板(创建或更新),body 含 id/name/reportType/config
POST /api/admin/report-template/delete 删除模板,参数 id
POST /api/admin/report-template/toggle 启停模板,body { id, isActive }
POST /api/admin/report-template/indicators 获取可选指标列表,支持 domain 过滤

config JSON 结构:

{
  "fixedBlocks": [
    { "type": "score", "title": "健康评分", "items": ["overallScore","gutHealthScore"] },
    { "type": "indicator", "title": "血脂指标", "groupLabel": "血脂", "indicatorNames": ["总胆固醇","甘油三酯"] },
    { "type": "list", "title": "菌种详情", "listKey": "flora" },
    { "type": "text", "title": "评语", "content": "..." }
  ],
  "freeDisplay": { "enabled": true, "groupName": "其他指标" }
}

4.17 其他接口

路径 说明
POST /api/config/public/value 公开配置值
POST /api/media/upload 媒体上传(免鉴权)
POST /api/recommend/search 推荐搜索
POST /api/recommend/repurchase-reminders 复购提醒
POST /api/task-reminders/upcoming/{memberId} 即将到期提醒
POST /api/tianpan/dashboard 天盘概览
POST /api/tianpan/member/{memberId} 成员详情
POST /api/tianpan/compatibility 兼容性分析
POST /api/tianpan/annual-energy 年度能量
POST /api/tianpan/daily-fortune 每日运势
POST /api/tianpan/related-items 相关事项
POST /api/tianpan/recalibrate 重算五维基础分(管理员)
POST /api/wisdom/gut-cognition 肠道认知
POST /api/wealth/checkin/* 财富打卡
POST /api/insurance/* 保险规划

4.18 日常任务聚合(/api/daily-task/*)

路径 说明
POST /api/daily-task/overview 今日任务总览(打卡/任务/阅读活动/测评报告四类聚合)

4.19 健康维度评分(/api/dimension/*)

路径 说明
POST /api/dimension/overview 获取健康维度概览(七维评分+百分位)
POST /api/dimension/upload 手动录入维度评分
POST /api/dimension/questionnaire 问卷提交维度评分
POST /api/dimension/history 获取维度历史记录

4.20 家庭成员关系质量(/api/family/relationship/*)

路径 说明
POST /api/family/relationship/scores 获取家庭成员关系质量评分
POST /api/family/relationship/calculate 计算并保存关系质量评分
POST /api/family/relationship/health-alerts 获取健康预警列表
POST /api/family/relationship/milestones 获取即将到来的里程碑
POST /api/family/relationship/pairwise 获取以指定成员为中心的所有成员关系

4.21 佣金管理(/api/commission/*)

路径 说明
POST /api/commission/summary 获取佣金汇总
POST /api/commission/list 佣金流水列表
POST /api/commission/team 团队统计(L1/L2)
POST /api/commission/stats 佣金统计面板
POST /api/commission/balance 可提现余额详情
POST /api/commission/team/list 团队成员列表
POST /api/commission/funnel 佣金转化漏斗
POST /api/commission/team/list 扩展:返回中每个成员新增 memberConsumption(该成员已完成履约订单总额,分)、myCfEarnedFromMember(我从该成员消费获得的 CF 总额,分)
POST /api/commission/team/consumption 团队总消费额分级汇总,请求 {maxLevel}(默认 3),返回 {totalConsumption: 分, levelBreakdown[{level, memberCount, consumption}], totalMembers, maxLevel}
POST /api/commission/my-referrer 获取我的直推人信息,返回 {hasReferrer, referrerId, nickname, avatar, referralCode, bindTime},无推荐人时 hasReferrer=false
POST /api/commission/team/tree 团队树形扁平数据(不含根节点),请求 {maxLevel}(默认 3),返回 {nodes[{userId, nickname, avatar, level, parentId, referrerId, memberConsumption, myCfEarnedFromMember}], totalMembers, maxLevel}

4.22 管理端-能量配置(/api/admin/energy-config/*)

路径 说明
POST /api/admin/energy-config/source-list 能量来源配置列表
POST /api/admin/energy-config/source-save 保存能量来源配置(新增/更新)
POST /api/admin/energy-config/source-delete 删除能量来源配置
POST /api/admin/energy-config/daily-limits 获取每日能量限制
POST /api/admin/energy-config/daily-limit-save 保存每日能量限制
POST /api/admin/energy-config/overview 能量配置总览(来源+限制)

4.23 管理端-公告(/api/admin/notices/*)

路径 说明
POST /api/admin/notices/list 公告列表(分页)
POST /api/admin/notices/all 全量公告列表
POST /api/admin/notices/create 创建公告
POST /api/admin/notices/update 更新公告
POST /api/admin/notices/delete 删除公告(软删)
POST /api/admin/notices/pin 置顶公告

4.24 管理端-成长规划师(/api/admin/guide/*)

路径 说明
POST /api/admin/guide/applications/pending 待审批规划师申请
POST /api/admin/guide/applications/{id}/approve 审批通过
POST /api/admin/guide/applications/{id}/reject 驳回申请
POST /api/admin/guide/guides 获取所有成长规划师列表
POST /api/admin/guide/guides/level/{level} 按级别获取规划师
POST /api/admin/guide/guides/approved 获取已入驻(approved)的服务商列表
POST /api/admin/guide/packages 获取所有套餐模板
POST /api/admin/guide/packages/create 创建套餐
POST /api/admin/guide/packages/{id}/update 更新套餐
POST /api/admin/guide/packages/{id}/status 更新套餐状态

4.25 管理端-商品(/api/admin/product/*)

路径 说明
POST /api/admin/product/list 商品列表(分页/筛选/搜索)
POST /api/admin/product/review 审核商品(approve/reject)
POST /api/admin/product/shelve 商品上下架
POST /api/admin/product/detail 商品详情
POST /api/admin/product/create 创建商品
POST /api/admin/product/update 更新商品
POST /api/admin/product/copy 复制商品
POST /api/admin/product/delete 删除商品
POST /api/admin/product/batch-shelve 批量上下架(body: {productIds, shelve})

4.26 管理端-成长档案关联商品(/api/admin/growth-archive-product/*)

路径 说明
POST /api/admin/growth-archive-product/save 保存关联商品规则
POST /api/admin/growth-archive-product/detail 关联商品规则详情
POST /api/admin/growth-archive-product/delete 删除关联商品规则

4.27 管理端-电商供应商(/api/admin/ecom-supplier/*)

路径 说明
POST /api/admin/ecom-supplier/list 供应商列表(分页/搜索)
POST /api/admin/ecom-supplier/all 所有供应商(下拉选择)
POST /api/admin/ecom-supplier/save 创建供应商
POST /api/admin/ecom-supplier/update 更新供应商
POST /api/admin/ecom-supplier/delete 删除供应商

4.28 管理端-测评材料(/api/admin/assessment/*)

路径 说明
POST /api/admin/assessment/materials 测评资料列表
POST /api/admin/assessment/materials/{id} 测评资料详情
POST /api/admin/assessment/materials/create 创建测评资料
POST /api/admin/assessment/materials/{id}/update 更新测评资料
POST /api/admin/assessment/materials/{id}/delete 删除测评资料(软删)
POST /api/admin/assessment/config 获取积分配置
POST /api/admin/assessment/config/update 更新积分配置

4.29 管理端-P点配置(/api/admin/ppoint-config/*)

路径 说明
POST /api/admin/ppoint-config/category/list 品类级P点比例列表
POST /api/admin/ppoint-config/category/save 保存品类级P点比例
POST /api/admin/ppoint-config/category/delete 删除品类级P点比例
POST /api/admin/ppoint-config/category/by-category 按品类ID获取P点比例
POST /api/admin/ppoint-config/product/list 商品级P点列表
POST /api/admin/ppoint-config/product/save 保存商品级P点
POST /api/admin/ppoint-config/product/delete 删除商品级P点
POST /api/admin/ppoint-config/product/by-product 按商品ID获取P点
POST /api/admin/ppoint-config/effective 获取商品综合有效P点值

4.30 管理端-报告解析(/api/admin/report-parser/*)

路径 说明
POST /api/admin/report-parser/types 报告类型列表
POST /api/admin/report-parser/types/save 保存/更新报告类型
POST /api/admin/report-parser/types/toggle 启用/停用报告类型
POST /api/admin/report-parser/types/delete 删除报告类型
POST /api/admin/report-parser/fingerprints/list 指纹规则列表
POST /api/admin/report-parser/fingerprints/save 保存指纹规则
POST /api/admin/report-parser/fingerprints/delete 删除指纹规则
POST /api/admin/report-parser/imports 导入记录列表
POST /api/admin/report-parser/imports/import 上传导入包
POST /api/admin/report-parser/imports/approve 审批导入
POST /api/admin/report-parser/imports/reject 驳回导入
POST /api/admin/report-parser/unknown-clusters 未知报告聚类列表
POST /api/admin/report-parser/unknown-uploads 聚类上传记录
POST /api/admin/report-parser/generate-type 自学习生成报告类型

五、新增接口流程

1. 搜索现有接口:grep -rn "关键词" cfc-backend/src/main/java/com/etotem/cfc/controller/
2. 检查路由冲突:grep -rn '@PostMapping("' cfc-backend/src/main/java/com/etotem/cfc/controller/ | grep -oP '@\w+Mapping\("\K[^"]*' | sort -u
3. 检查 Bean 冲突:find ... -name "*XxxService.java" | xargs grep "class Xxx"
4. 如有相似接口:评估修改成本,必要时扩展
5. 如确需新增:
   a. 创建 Entity(如需要新表)
   b. 创建 Mapper
   c. 创建 Service
   d. 创建 Controller(放在合适子目录)
   e. 数据库迁移(DatabaseInitializer + schema.sql)
   f. 更新本文档
6. mvn clean compile 验证

4.31 家庭管家选择(/api/butler/*)

路径 说明
POST /api/butler/available-list 可选管家列表(浏览开放,脱敏;仅 L2 有效订阅家庭可绑定)
POST /api/butler/my-butler 我家当前管家绑定信息(含管家昵称/等级/分配时间)
POST /api/butler/select 绑定/更换管家(校验 L2 订阅、管家容量与接单状态;换绑自动解绑旧关系)

4.32 优惠券(家庭维度,/api/coupon/* + /api/admin/coupon/*)

2026-08-31 起,优惠券由「用户维度」全链路改为「家庭维度」。user_coupon 保留历史数据,新发放与消费统一走 family_coupon。

路径 说明
POST /api/admin/coupon/list 优惠券模板列表(admin)
POST /api/admin/coupon/create 新建优惠券模板(admin)
POST /api/admin/coupon/update 更新优惠券模板(admin)
POST /api/admin/coupon/issue 批量发放到家庭,{ couponId, familyIds: [Long] }(admin)
POST /api/admin/coupon/issue-family 单家庭发放,{ familyId, couponId, quantity }(admin,家庭管理页使用)
POST /api/admin/coupon/grant-log 家庭发券流水查询,{ familyId?, couponId?, grantType?, source? }(admin,返回 family_coupon_grant_log)
POST /api/admin/coupon/grant-user 管理员定向发放「会员升级券」给指定用户,{ userId, amountYuan \| amount, validUntil?, remark? }(admin,自动创建 applicableTo=MEMBERSHIP 无门槛券模板并发放到该用户家庭,落 grantType=MANUAL 流水)
POST /api/admin/coupon/toggle-status 启用/停用优惠券模板(admin)
POST /api/coupon/list 当前家庭可用优惠券(小程序)
POST /api/coupon/my 我的(家庭)优惠券(小程序)
POST /api/coupon/apply 下单抵扣(家庭券)
POST /api/coupon/claim 领取优惠券(发到家庭)
POST /api/coupon/checkout-list 结算页可兑换未拥有券

4.33 CF 值分佣(/api/commission/cf/*)

CF 值(平台积分)统一分佣体系(F-4 分佣收口,2026-10-25):普通订单双返(当前消费人 F02 + 推荐人两级销售奖),会员/订阅只返推荐人,同家庭互推跳过本人上溯。 推荐人返佣收口为 F03a 直接销售奖 + F03b 间接销售奖,共同基数 = 本单消费产生的 P 点;旧「团队规模阶梯 cf_rate_tier」已废弃(表保留只读,仅等级展示/历史查询使用)。

路径 说明
POST /api/commission/cf/rate 我的团队规模 + 两级销售奖档位。返回 { totalTeamSize, ratePercent, tierName, teamDepth, teamAnnualPpoints, selfAnnualPpoints, directRatePercent, directTierName, indirectRatePercent, indirectTierName };legacy 字段 ratePercent/tierName 取 F03a 值供旧端兼容(未入档时 ratePercent=0、tierName="未入档")
POST /api/commission/cf/summary 我的 CF 钱包汇总,返回 PlatformBalanceService.getBalance(userId) 结果
POST /api/commission/cf/list 我的 CF 流水(分页),请求 { page, size },返回 Page<PlatformBalanceLog>

两级销售奖档位(迁移418 种子,管理端可配置):

共同基数 = 本单消费产生的 P 点(商品:实付元 × 有效 P 点 / 100;非商品:实付元 × cf.commission.service_rate(bps) / 10000)。第 1 个非同家庭引荐人拿 F03a,第 2 个拿 F03b,最多两级。

F03a 直接销售奖(cf_direct_sales_tier,按团队 8 层内滚动一年累计 P 点):

团队年度 P 点下限 档位 比例
100 青铜 10%
500 白银 25%
2000 黄金 40%
5000 铂金 55%
10000 钻石 70%

F03b 间接销售奖(cf_indirect_sales_tier,按自身滚动一年累计消费 P 点):

自身年度 P 点下限 档位 比例
100 青铜 2%
500 白银 5%
2000 黄金 10%
5000 铂金 15%
10000 钻石 20%

匹配语义:enabled=1 AND min_xxx <= 值 ORDER BY min_xxx DESC LIMIT 1,无匹配档位不发放;比例按 cf_earn_rule.params_json.max_rate_percent(F03a=70、F03b=20)封顶。 金额由 cf_earn_rule.formula = floor(base_ppoints * rate_percent / 100) 计算,发放统一走 CfBalanceService.earnByRule(幂等键复用 F-2 uk_ref_type),只写 cf_balance + cf_balance_log。 滚动一年口径:消费支付成功时落 ppoint_consumption_log 一行(唯一键 order_type + order_id 幂等),按 created_at >= now() - 365d 聚合(迁移420)。

4.34 CF 成员间转让(/api/cf/transfer/*)

路径 说明
POST /api/cf/transfer/send 成员间转让 CF,请求 { toUserId, amount }。仅限同一家庭(校验 familyId 一致);amount 必须为正数。转出扣减 + 转入增加在同一事务
POST /api/cf/transfer/list 转让记录(分页,按当前用户家庭过滤),请求 { page, size },返回 Page<CfTransferRecord>

4.35 CF 返佣阶梯配置(admin,/api/admin/cf-rate-tier/*)

路径 说明
POST /api/admin/cf-rate-tier/list 阶梯列表(按 sort_order 升序),返回 List<CfRateTier>
POST /api/admin/cf-rate-tier/save 新增/更新阶梯,请求体为 CfRateTier(含 id 则更新,否则新增,默认 enabled=1),返回 "已保存"
POST /api/admin/cf-rate-tier/delete 删除阶梯,请求 { id },返回 "已删除"

CfRateTier 字段: id / tierName(档位名)/ minTeamSize(团队规模下限含)/ ratePercent(返佣比例%)/ sortOrder(排序,越大越高)/ enabled(1启用/0停用)/ createdAt / updatedAt。

注意:家庭券接口为 POST /api/coupon/my 与 POST /api/coupon/list(见 4.32),不存在 /api/coupon/family/list 路由。

4.36 健康报告异步采集(/api/health/report/*, /api/report-parser/*)

健康报告上传后进入异步采集流程:后端解析 PDF(先 pdftotext 提取文本内联,避免依赖代理工具执行),指纹判定报告类型 → 已知类型走专用采集脚本,未知类型交本地 opencode 服务(模型 agnes-ai/agnes-2.5-flash,在 session body 中显式指定)。前端提示「数据采集中」,完成后自动入库,列表页轮询刷新,无需用户等待。

路径 说明
POST /api/health/report/upload-only 生产小程序上传入口:上传 PDF → 落草稿 health_report_drafts(parse_status=collecting)→ 异步触发采集 → 返回草稿 ID(前端留意 data.draftId 后轮询)
POST /api/report-parser/upload 专用采集接口:同 async 流程,统一进异步采集
POST /api/health/report/collect/status 查询单草稿采集状态,请求 { draftId },返回 { status, parseError }(collecting/completed/failed)
POST /api/health/report/collecting-list 当前用户「采集中」草稿列表,返回 List<Draft>(前端轮询用)

采集流程状态机:

  • collecting:指纹判定 + 异步解析中
  • completed:解析成功 + 已自动入库(指标/菌群/疾病风险/食材)
  • failed:解析失败,parse_error 记录原因

专属采集脚本路径(在 HealthReportDraftService): getDraftById / markCollecting / updateParseMethod / markCollectCompleted / markCollectFailed / listCollectingByUser。

4.36.1 报告归属管理(/api/health/report/*)

报告归属由 health_reports.subject_id 字段表示(关联家庭成员 ID,可为 null)。无归属的报告不参与方案生成,但可在管理端或小程序手动绑定/重新分配。

路径 说明
POST /api/health/report/reassign 重新分配报告归属(含维度重算),请求 { reportId, subjectId? },subjectId 为 null 表示解绑
POST /api/health/report/unlinked 获取家庭内所有未绑定归属的报告,请求 { familyId },返回 List<HealthReport>
POST /api/health/report/bind 绑定报告到成员(仅绑定,不可解绑),请求 { reportId, subjectId }

/api/health/report/reassign 请求体:

{
  "reportId": 123,
  "subjectId": 456       // 可为 null 表示解除绑定
}

响应: Result<String>,"归属已更新"

归属变更触发联动:

  • 旧归属成员(若有):五维能量重算 + 食材推荐指数刷新
  • 新归属成员(若有):五维能量重算 + 食材推荐指数刷新
  • 方案生成:subject_id IS NULL 的报告自动跳过(triggerAutoPlanAfterConfirm 已有此逻辑)

权限检查: 通过 familyId(JWT 注入)验证报告属于当前家庭,跨家庭操作抛出 RuntimeException("报告不属于该家庭")。


4.36.2 舌诊 AI 集成(/api/health/report/*)

舌诊功能已集成 aikanshe.com(愛看舌)开放 API,作为首选方案;当 aikanshe.com 不可用时回退至 LangGraph Python 服务。调用流程如下:

请求路径:POST /api/health/report/parse-preview(type=tongue)

请求体示例:

{
  "type": "tongue",       // 必填:指定舌诊流程
  "memberId": 12345,      // 可选:家庭成员 ID
  "filePath": "/data/...",// 可选:图片路径(auto模式会先检测}
}

响应结构:

{
  "code": 200,
  "message": "success",
  "data": {
    "recordId": 67890,               // 舌诊记录 ID
    "imageUrl": "http://...",        // 图片访问 URL
    "overallAssessment": "舌象基本正常...", // 整体评估
    "indicators": [                  // 7类舌诊指标
      {"code": "tongue_color", "value": "淡红"},
      {"code": "coating_color", "value": "薄白"},
      {"code": "coating_texture", "value": "润"},
      {"code": "fissure", "value": "无"},
      {"code": "teeth_mark", "value": "无齿痕"},
      {"code": "sublingual_vein", "value": "无点刺"},
      {"code": "constitution", "value": "平和质"}
    ],
    "createTime": "2026-10-08T..."
  }
}

优先级方案(aikanshe.com 优先,LangGraph 兜底):

  1. 首选:调用 aikanshe.com API(POST /agency/quanxi,基于 AI 视觉模型)
  2. 兜底:若 aikanshe.com 超时/失败,自动回退至 LangGraph Python 服务(/api/v1/tongue/diagnose)
  3. 最终兜底:两者均失败时返回默认 mock 数据,确保业务不中断

置信度阈值:默认 0.2,可通过 application.yml 的 aikanshe.confidence 配置。

相关配置:

aikanshe:
  appkey: ${AIKANSHE_APPKEY:}
  base-url: ${AIKANSHE_BASE_URL:https://api.aikanshe.com}
  token: ${AIKANSHE_TOKEN:}
  confidence: ${AIKANSHE_CONFIDENCE:0.2}
  lang: ${AIKANSHE_LANG:zh-CN}

已废弃接口(保留,待清理):

  • POST /api/health/report/upload-only(PDF流程入口,已被 /api/health/report/parse-preview?type=tongue 部分取代)

4.37 报告反馈与 AI 解答(/api/health/feedback/*)

用户对健康报告提交疑问/建议,后端持久化到 report_feedback 表并调用 AI 解答(经 AiGateway,免费版每日 1 次,付费版不限)。反馈记录含 aiAnswer/aiStatus,前端可据此展示 AI 解答结果。

路径 说明
POST /api/health/feedback/submit 提交报告反馈(持久化 + AI 解答),请求 { reportId?, draftId?, memberId?, type, content },返回 Result<ReportFeedback>
POST /api/health/feedback/list 我的报告反馈列表(含 AI 解答),请求 { reportId? },返回 Result<List<ReportFeedback>>(按创建时间倒序,最多 50 条)

/api/health/feedback/submit 请求体:

{
  "reportId": 123,              // 可选,关联健康报告ID
  "draftId": null,              // 可选,关联解析草稿ID(reportId 与 draftId 二选一,均可为空)
  "memberId": 456,              // 可选,关联家庭成员ID(默认当前成员)
  "type": "question",           // question=疑问 / suggestion=建议,其他值默认 question
  "content": "这份报告里菌群多样性偏低是什么意思?"
}

响应示例(Result<ReportFeedback>,data 字段):

{
  "code": 200,
  "message": "ok",
  "data": {
    "id": 1,
    "userId": 1001,
    "memberId": 456,
    "reportId": 123,
    "draftId": null,
    "feedbackType": "question",
    "content": "这份报告里菌群多样性偏低是什么意思?",
    "aiAnswer": "菌群多样性反映肠道微生物的丰富程度……",
    "aiStatus": "answered",
    "conversationId": "conv_abc123",
    "createdAt": "2026-09-22 14:30:00"
  }
}
  • aiStatus 取值:pending(待解答)/ answered(AI 已解答)/ failed(AI 调用失败,仍会落库,aiAnswer 为空)。
  • 免费版每日仅限 1 次反馈解答(Redis 计数 report:feedback:free:{userId}:{date},memberLevel=FREE 或为空时生效),超限返回 Result.error("免费版每日仅限 1 次反馈解答,升级会员解锁更多");Redis 异常时 fail-open 放行。
  • content 必填且不超过 500 字。

4.38 认知维度(/api/cognitive/*)

六维认知体系:感知(perception) / 专注(focus) / 记忆(memory) / 逻辑(logic) / 空间(spatial) / 加工速度(processingSpeed)。

路径 说明
POST /api/cognitive/child 获取孩子最新六维认知得分
POST /api/cognitive/family 获取家庭所有孩子最新六维认知得分
POST /api/cognitive/update 更新认知维度得分(由规划师录入,需已有 completed 行)
POST /api/cognitive/self-test 提交认知自测结果(自动创建档案,写入六维认知档案,综合分自动计算)
POST /api/cognitive/norms 获取认知维度百分位常模
POST /api/cognitive/trend 获取认知维度历史趋势
POST /api/cognitive/recommendations 获取认知训练建议(按薄弱维度生成)
POST /api/cognitive/recommendations/create-task 从建议创建每日任务

/api/cognitive/self-test 请求体:

{
  "memberId": 12345,
  "dimension": "memoryScore",
  "score": 85
}

dimension 取值:memoryScore / logicScore / perceptionScore / spatialScore / processingSpeedScore score 范围:0-100(整数)

响应: Result<String>,成功返回 "提交成功",失败返回错误原因。

行为: 若该孩子尚无任何 status=completed 的 DanAssessmentResult 行,自动创建(source='self_test'),写入对应维度分,重新计算综合分(7 维度非空均值)。

已记录认知自测 API 端点 — 禁止重复注册。

4.39 珍珠图/能力图(/api/pearl/*, /api/ability/*)

关系三图体系:章鱼图(谁帮过我)→ 珍珠图(我有什么)→ 能力图(谁会什么)。珍珠图聚合 25 类社会连接(12 必备内圈 + 13 理想外圈),附带互动日志、价值分级、定期提醒。

路径 说明
POST /api/pearl/resources 珍珠图聚合:25 组(ESSENTIAL 内圈 + IDEAL 外圈)+ legacyGroups(历史资源)
POST /api/pearl/connection-types 获取 25 类连接类型列表(code/label/category/suggestIntervalMonth)
POST /api/pearl/item/add 登记珍珠图资源(connectionType 必填,type 可选,name 必填,contactId 可选)
POST /api/pearl/item/delete 删除登记的珍珠图资源(itemId)
POST /api/pearl/item/update-priority 手动覆盖优先级(itemId/priority 1-3),同步 valueScore
POST /api/pearl/interaction/add 记录互动(itemId/interactionType/content),更新价值分并关闭 PENDING 提醒
POST /api/pearl/interaction/list 互动历史分页(itemId/page/size)
POST /api/pearl/reminder/list 待办提醒列表(PENDING)
POST /api/ability/map 能力图:SKILL 帮助记录按联系人聚合为能力节点

/api/pearl/resources 响应结构:

{
  "code": 200,
  "data": {
    "groups": [
      {
        "type": "MEDICAL", "typeName": "医疗", "category": "ESSENTIAL", "ring": "inner",
        "items": [
          {
            "id": 1, "name": "社区王医生", "description": "儿科主治", "avatar": null,
            "valueScore": 72, "priority": 1, "contactId": 5,
            "lastInteractionAt": "2026-08-15T10:30:00",
            "interactionCount": 8, "daysSinceLast": 26
          }
        ]
      }
      // ... 共 25 组,为空时 items=[]
    ],
    "legacyGroups": [
      { "type": "PERSON", "typeName": "人脉", "items": [...] },
      { "type": "SKILL", "typeName": "技能", "items": [...] },
      { "type": "INFO", "typeName": "信息", "items": [...] },
      { "type": "PLACE", "typeName": "场所", "items": [...] }
    ]
  }
}

价值分算法(/api/pearl/interaction/add 后自动重算):

  • 类型基础权重:ESSENTIAL=30,IDEAL=20
  • 近 90 天互动次数 × 5,上限 30
  • 最近互动时效性:≤30天=+20,≤90天=+10,≤180天=+5
  • 互动总量 × 2,上限 20
  • 总分 0-100,priority=1(高/大珍珠)→ valueScore≥70,priority=2(中)→ 40-69,priority=3(低/小珍珠)→ <40

/api/ability/map 响应结构: data 为数组,元素结构同 SKILL 组 items(contactId/name/avatar/relationshipType/skillCount/skills/lastHelpedAt)。

珍珠图前端组件: PearlDiagram.vue(Canvas 2D,两层同心圆,内圈 radiusPct=0.28 / 外圈 0.55,珍珠半径按 priority/valueScore 映射 8-26px)。

珍珠图定时提醒: PearlReminderScheduledTask 每日 08:00 执行,遍历 connection_type 非空资源,daysSinceLast ≥ suggestIntervalMonth×30 时生成 PENDING 提醒。

珍珠图交互流程: 打开页 → 加载 resources → 渲染两层同心圆 → 点击珍珠弹窗(联系/优先级/删除)→ 记录互动 → 重算价值分 → 逾期角标红点。

/api/pearl/interaction/add 请求体: { "itemId": 1, "interactionType": "WECHAT", "content": "咨询过敏问题" } interactionType 取值:PHONE / WECHAT / MEETING / OTHER。

/api/pearl/item/update-priority 请求体: { "itemId": 1, "priority": 1 }(1=高/大珍珠,2=中,3=低/小珍珠)。

珍珠图前端页面:

  • 珍珠图:pages/action-detail/index.vue(内嵌 PearlDiagram.vue 组件)
  • 登记资源:pages/action-detail/pearl-add-resource.vue(25 类类型分组选择器)
  • 互动提醒:pages/pearl-reminders/index.vue(PENDING 提醒列表)

前端 API(utils/api.js):

  • getPearlResources()
  • getConnectionTypes()
  • addPearlResource(data) (data.connectionType 必填)
  • deletePearlResource(data)
  • addPearlInteraction(data)
  • getPearlInteractionList(data)
  • getPearlReminders()
  • updatePearlPriority(data)

已记录珍珠图/能力图 API 端点 — 禁止重复注册。

4.40 关键人拓展章鱼图(/api/octopus/*)

替代旧章鱼图(help_logs)。核心:成效记录 → 关键人画像 → 高频词分析 → 拓展方向。

路径 说明
POST /api/octopus/tentacles ⚠️ 已废弃(410) 旧章鱼图:触手榜
POST /api/octopus/add ⚠️ 已废弃(410) 旧章鱼图:新增帮助记录
POST /api/octopus/delete ⚠️ 已废弃(410) 旧章鱼图:删除帮助记录
POST /api/octopus/records ⚠️ 已废弃(410) 旧章鱼图:帮助记录明细
POST /api/octopus/effect/list 成效记录分页列表(支持 effect_type 筛选)
POST /api/octopus/effect/add 新增成效(member_order_id + effect_type bitmask + amount + desc)
POST /api/octopus/effect/delete 删除成效(级联关系)
POST /api/octopus/key-person/add 新增关键人(姓名/单位/部门/职务/初识场合/如何认识)
POST /api/octopus/key-person/update 修改关键人画像
POST /api/octopus/key-person/delete 删除关键人(级联关系)
POST /api/octopus/effect/key-persons 某成效的关键人列表
POST /api/octopus/analysis/keywords 高频词统计(单位/部门/职务/场合/路径)
POST /api/octopus/analysis/summary 高频词提炼 ≤8 个拓展方向
POST /api/octopus/expansion/suggest 基于分析推荐关键人画像模板(预填)

已记录关键人拓展 API 端点 — 禁止重复注册。

4.41 DOA 个人目标(家庭打卡个人目标模块)

路径 说明
POST /api/doa/stage/create 创建阶段(memberId?+title+durationWeeks+goals[1-3])
POST /api/doa/overview 家庭总览:各成员当前 active 阶段
POST /api/doa/stage/detail 阶段详情:stage + goals + weeks
POST /api/doa/stage/cancel 取消阶段(仅 active 可取消)
POST /api/doa/week/plan 提交周计划(A表周行动宣告)
POST /api/doa/week/review 提交周复盘(B表五问)
POST /api/doa/week/list 周记录列表(按阶段查周记录)

已记录 DOA 个人目标 API 端点 — 禁止重复注册。

4.42 引导弹窗配置化管理

路径 说明
POST /api/guide/popup/list 查询当前用户应展示的激活弹窗列表
POST /api/guide/popup/trigger 上报触发行为,返回匹配弹窗
POST /api/guide/popup/consume 消费弹窗(点击/关闭上报,防止重复弹出)
POST /api/admin/guide/popup/list 管理端:列表(分页筛选 status/slug)
POST /api/admin/guide/popup/create 管理端:创建弹窗(含触发条件+步骤)
POST /api/admin/guide/popup/update 管理端:更新弹窗(全量覆盖步骤和条件)
POST /api/admin/guide/popup/status 管理端:启用/禁用(toggle)
POST /api/admin/guide/popup/delete 管理端:软删除
POST /api/admin/guide/popup/stats 管理端:数据看板(曝光/点击/完成率/分时段趋势)

设计文档:docs/superpowers/specs/2026-09-22-guide-popup-config-design.md

实施计划:docs/superpowers/plans/2026-09-22-guide-popup-config.md

说明:本功能将小程序弹窗引导页从硬编码改为配置化管理,支持管理员在后台配置弹出条件与内容。旧方案(sys_config onboarding_guide_config)保留,新方案通过 4 张新表 + 9 接口实现。


六、待清理的废弃接口

Controller 废弃接口 替代方案 当前状态 清理条件
------------ ---------- ---------- ---------- ----------
FamilyController /invite-code, /invite-code/generate /api/family/invite/generate @Deprecated + 410 ✓ 确认前端无调用
FamilyUserController /switch-mode, /switch-to-child /api/family/member/switch @Deprecated + 410 ✓ 确认前端无调用
FamilyUserController /switch-back-to-parent, /switch-back-verify /api/family/member/switch 已修复:@Deprecated + 410 确认前端无调用
ButlerController /service-records, /commissions — @Deprecated + 410 ✓ 可删除
TeacherController 全部 /api/teacher/* 方法 /api/guide/families/* @Deprecated + UnsupportedOperationException 确认规划师端无调用
DanAssessmentController /current — 需验证 无前端调用方
NoticeController GET /list(违反 POST 规范) /api/admin/notices/list 已修复:@Deprecated + 410 可删除
OctopusController /tentacles, /add, /delete, /records /api/octopus/effect/*, /api/octopus/key-person/* @Deprecated + 410 ✓(2026-09-10 替换为关键人拓展) 确认前端无调用(旧页面已删除)

4.37 情绪识别(/api/mind/emotion/*)

基于 DeepFace 的人脸情绪识别,通过 LangGraph /api/v1/emotion/recognize 调用。

路径 说明
POST /api/mind/emotion/analyze 上传照片进行情绪识别(multipart 文件)
POST /api/mind/emotion/analyze-url 通过 URL 进行情绪识别(兼容旧调用方)

POST /api/mind/emotion/analyze

请求:multipart/form-data,字段 file(JPEG/PNG,最大 10MB)

返回:

{
  "code": 200,
  "data": {
    "dominant_emotion": "happy",
    "dominant_label_zh": "开心",
    "emotions": [
      { "emotion": "happy", "confidence": 0.85 },
      { "emotion": "neutral", "confidence": 0.10 },
      { "emotion": "sad", "confidence": 0.03 },
      { "emotion": "surprise", "confidence": 0.01 },
      { "emotion": "angry", "confidence": 0.005 },
      { "emotion": "fear", "confidence": 0.003 },
      { "emotion": "disgust", "confidence": 0.002 }
    ],
    "all_emotions": {
      "happy": 0.85,
      "neutral": 0.10,
      "sad": 0.03,
      "surprise": 0.01,
      "angry": 0.005,
      "fear": 0.003,
      "disgust": 0.002
    }
  }
}

POST /api/mind/emotion/analyze-url

请求体:

{ "image_url": "https://cdn.example.com/photo.jpg" }

返回:同上。


4.43 商品赠送会员(/api/membership/gift-membership-progress)

家庭维度累计「赠会员商品」原价实付金额,达到阈值后自动赠送会员。

路径 说明
POST /api/membership/gift-membership-progress 获取当前家庭的赠会员累计进度

POST /api/membership/gift-membership-progress

请求:无(familyId 由 JWT userId 反查)

返回:

{
  "code": 200,
  "data": {
    "familyId": 12,
    "accumulatedAmount": 158000,
    "granted": 0,
    "grantedLevel": null,
    "grantedOrderNo": null,
    "grantedAt": null,
    "threshold": 198000,
    "remaining": 40000
  }
}
字段 类型 说明
accumulatedAmount Integer 累计赠会员商品原价金额(分),仅统计无积分/无券/无折扣的实付订单
granted Integer 1=已赠送 0=未赠送
grantedLevel String 已赠送的会员等级(当前全局配置默认 FAMILY)
threshold Integer 阈值(分),由 sys_config.gift_membership_threshold 动态填入
remaining Integer 还差多少达标(分)= max(0, threshold - accumulatedAmount),已达标为 0

注意:threshold、remaining 为 @TableField(exist = false) 非数据库列,仅接口返回用。 无家庭时:接口返回空对象,threshold/remaining/accumulatedAmount 均为 null(此时不存在赠会员累计口径),前端据此隐藏进度条。 阈值单位为分(1980 元 = 198000 分),实际生效值以 sys_config 表中 gift_membership_threshold 为准(insertSysConfigSeed 仅在缺失时插入,不覆盖已有配置)。


4.44 统一服务角色申请(/api/service-role/*)

多角色(规划师/营养师/管家/供应商/内容管理员/活动策划)统一申请入口,一次提交可含多个角色,管理端审批通过后回写 users.roles 并按角色初始化附属记录。

路径 说明
POST /api/service-role/apply 提交服务角色申请(roles 必填)
POST /api/service-role/my-apply 查询我的最新申请记录
POST /api/service-role/upload-image 上传身份证/资质证书图片(multipart,字段名 file)
POST /api/service-role/admin/list 管理端:申请列表(status 查询参数,默认 0)
POST /api/service-role/admin/approve 管理端:批准({ id })
POST /api/service-role/admin/reject 管理端:驳回({ id, reason })

权限:admin/list、admin/approve、admin/reject 三个端点校验 @RequestAttribute("role"),仅 role=admin 或 role=operator 可访问(与 AdminHealthPlanController 审核类端点口径一致),其他角色返回「无权限」。前端菜单由 perm: 'audit:service-role' 控制。

状态语义(service_role_applications.status)

值 含义
0 待审核(同一 userId 仅允许一条待审,重复提交返回「您已提交过申请,请等待审核」)
1 已通过
2 已驳回(原因存 reject_reason)

POST /api/service-role/apply 请求体(ServiceRoleApplyDTO)

字段 类型 说明
roles List<String> 申请角色,@NotEmpty 至少一个
idCard String 身份证号
idCardImages List<String> 身份证图片 URL 数组(落库转 JSON 字符串)
certificateImages List<String> 资质证书图片 URL 数组
province / city / district / street String 四级地址
addressDetail String 详细地址

审批通过后的角色落地规则(ServiceRoleApplicationServiceImpl.approve)

申请角色 副作用
planner guides 新增一行(status=active)+ users.roles 追加 teacher
nutritionist users.nutritionist_status=approved + roles 追加 nutritionist
butler users.butler_status=approved + butler_profiles 新增一行 + roles 追加 butler
vendor users.vendor_status=approved + roles 追加 supplier
article_admin users.article_admin_status=approved + roles 追加 knowledge_admin
activity_provider users.activity_provider_status=approved + roles 追加 activity_manager

注意:approve/reject 仅对 status=0 的记录生效,已处理返回「该申请已处理」。 upload-image 对图片类型文件先走 wechatService.checkImage() 内容安全检测,未通过直接拒绝。


4.45 规划师解除家庭绑定(POST /api/guide/families/unbind)

路径 说明
POST /api/guide/families/unbind 规划师解除自己名下的家庭绑定(请求体 { id },即 guide_families.id)
  • 角色校验:仅 role=teacher 可调用,否则返回 Access denied。
  • 归属校验:GuideFamilyService.unbindByGuide() 按 id + guide_id + status='binding' 定位,只能解除属于自己的绑定。
  • 副作用:将 guide_families.status 置为 cancelled。
  • 家长侧解绑为独立接口 POST /api/bind/unbind(按 familyId 定位,并通知规划师)。

注意:前端 unbindFamily(id) 需传 guide_families.id(绑定记录 ID),不是 familyId。


4.46 规划师方案审核(/api/health/plan/pending-review/*)

路径 说明
POST /api/health/plan/pending-review/list 待审核方案列表(teacher 取当前登录人;admin 可传 teacherId 过滤,不传则返回该家庭全部)
POST /api/health/plan/pending-review/update 编辑方案内容(仅 status 为 draft/pending_review 允许)
POST /api/health/plan/pending-review/approve 审核通过并发布
POST /api/health/plan/pending-review/reject 驳回
  • 角色校验:仅 role=teacher 或 role=admin,且必须携带 familyId,否则返回 familyId不能为空。
  • 未分配池规则:listPendingReviewPlans() 在 teacherId 非空时按 (teacher_id = ? OR teacher_id IS NULL) 过滤 —— 规划师既能看到分配给自己的方案,也能看到本家庭内尚未指定规划师的方案(health_plans.teacher_id 为 NULL),避免用户未选规划师时保存的 pending_review 方案成为无人可见的孤儿记录。
  • 入选范围限定 status IN ('draft','pending_review'),按 created_at 倒序。

注意:health_plans.teacher_id 列由迁移 251 建立(DatabaseInitializer),schema.sql 已同步。 前端 getPendingReviewPlans()(utils/api.js)目前尚无页面消费,规划师审核页未接通;新审核工作台改用 4.47 的 plans/pending 端点,本节 4 个端点保留但不再被前端调用。

⚠️ 2026-10-04:/pending-review/approve 响应由 Result<HealthPlan> 改为 Result<PlanApproveResultDTO>(新增 taskGenerated / taskCount / message 字段)。该端点无前端调用点(health-plan-summary.vue 仅有未调用的死导入),变更安全。

✅ 2026-10-04:/{familyId}/overview、/{familyId}/children/{memberId}/tasks、/{familyId}/children/{memberId}/pending-review、/{familyId}/tasks/{taskId}/review、/{familyId}/tasks/batch-review、/{familyId}/tasks/{taskId}、/{familyId}/tasks/{taskId}/delete 共 7 个端点已接入 guide_families 绑定校验,修复跨家庭越权。


4.47 规划师审核工作台(/api/guide/families/*)

规划师侧审核工作台的统一入口,授权源为 guide_families.status='binding'(与 GuideFamilyService.isBound(guideId, familyId) 同源),不使用 users.teacher_family_ids。

端点 权限
POST /api/guide/families/my-families teacher / admin
POST /api/guide/families/{familyId}/members teacher 需 isBound;admin 放行
POST /api/guide/families/{familyId}/plans/pending teacher 需 isBound;admin 可传 teacherId 过滤
POST /api/guide/families/{familyId}/plans/{planId}/update 同上 + planId IDOR 反查
POST /api/guide/families/{familyId}/plans/{planId}/approve 同上 + planId IDOR 反查;返回 PlanApproveResultDTO
POST /api/guide/families/{familyId}/plans/{planId}/reject 同上 + planId IDOR 反查
  • my-families 不走 checkFamilyAccess(role, userId, null) —— 该路径下 familyId == null 会把 teacher 直接拒掉,故改为显式角色判断 + 按 guide_id 查本人绑定家庭,返回体含 familyName(取自 Family.name,注意字段名不是 familyName)。
  • members 返回该家庭可审核成员,供工作台「成员」选择器使用。
  • 未分配池规则:plans/pending 复用 listPendingReviewPlans(),teacherId 非空时按 (teacher_id = ? OR teacher_id IS NULL) 过滤;teacher 无需传该参数,admin 可显式传以过滤。
  • IDOR 防护:{planId} 类端点先 checkFamilyAccess(role, userId, familyId),再用 getPlanForFamily(planId, familyId) 按 familyId 反查,返回 null 即 403。控制器内 resolvePlan 的第二次 recheck 仅为纵深防御,getPlanForFamily 已按 familyId 过滤,该 recheck 永不单独拦截请求,不可依赖它替代首道校验。
  • approve 返回 PlanApproveResultDTO:planId / status / taskGenerated / taskCount / message。任务生成器 generateDailyTasksFromPlan 返回 void,故实现改为生成后按 source_type='health_plan' AND source_id=planId 统计实际条数;生成异常或计数为 0 时方案仍发布并返回 taskGenerated=false,属部分成功,前端须与失败区分提示。

注意:配套前端为 pages/teacher/review-workbench.vue、review-family.vue、plan-detail.vue,入口在 pages/teacher/families.vue。


4.48 指标统一层(/api/indicator/* + /api/admin/indicator/*)

指标变化曲线 / 指标速查 / 指标关联的统一读接口与管理端接口。读接口 subjectId 必填且做家庭归属校验(family_members.id = subjectId AND family_id = 当前用户家庭,由 JwtInterceptor 注入 @RequestAttribute("familyId"));管理端接口校验 @RequestAttribute("role"),仅 role=admin 可访问,否则「无权操作」。

视图接口(IndicatorController,/api/indicator)

端点 请求要点 用途
POST /api/indicator/trend {subjectId, definitionIds:[...]} 指标曲线(按 definitionId 分组、report_date 升序点序列)
POST /api/indicator/change-ranking {subjectId, reportType?, category?, scope:adjacent\|first-vs-latest, orderBy:up\|down\|magnitude, limit} 变化幅度排名(含 overall.improvedCount/worsenedCount/flatCount 汇总)
POST /api/indicator/quick-lookup {subjectId, category?, page, pageSize} 指标速查(分类分页 + 类别汇总 + dimensionScores 五/七维评分小节)
POST /api/indicator/correlation/list {subjectId, definitionId} 指标关联查询(含 subjectEvidence 成员级配对证据)

管理端接口(/api/admin/indicator/correlation/*、/api/admin/indicator/mapping/*)

端点 请求要点 用途
POST /api/admin/indicator/correlation/save {definitionIdA, definitionIdB, direction, manualStrength, description, manualLocked, sourceNote} 关联对定义/编辑(写入前按 indicator_definitions.code 字典序强制对序,保证唯一键对称)
POST /api/admin/indicator/correlation/list {page, size} 关联对分页(按 updated_at 倒序,含校准状态)
POST /api/admin/indicator/correlation/calibrate {pairId?} 手动触发校准(返回「校准完成,共更新 N 对」)
POST /api/admin/indicator/mapping/import {sourceType, seeds:[{rawName, definitionId?}]} 映射种子批量导入(返回「导入完成,共 N 条」)
POST /api/admin/indicator/mapping/list {page, size, status?, sourceType?} 映射规则分页/review(status=0 为 ai_fallback 待确认)

关联校准:save 时 effective_strength = manual_strength;每日 03:00 IndicatorCalibrationJob(@Scheduled(cron = "0 0 3 * * ?"))对 status=active 且 manual_locked=0 的关联对按 subject 分组做 Spearman + Fisher z 聚合,有效样本 >=30 才用 computed_strength 覆盖 manual_strength。correlation/calibrate 手动触发同一逻辑(pairId 传入时仍走全量逐对幂等)。 统一指标层写入(单一写者):报告入库 / 报告编辑 / 食材推荐刷新三处流程由 NormalizeIndicatorPipeline 幂等写入 indicator_values(唯一键 source_type + source_id + definition_id,upsertMapping ON DUPLICATE KEY)。本层读接口只读 indicator_values,不写时序;五维/七维评分在速查接口按原表 join,不进时序。 关联表:indicator_correlations(迁移 360)、indicator_mapping_rules(迁移 359)。

文档更新:2026-10-09(指标统一层新增,见 specs/2026-10-09-indicator-change-curve-design.md)

⚠️ /api/health/indicator/list 已被取代:老接口返回裸 List<HealthIndicator>(无上一期对照、无 summary)。新接口 /api/health/report/indicators 返回同一批指标 + previous / change / summary 五档形态数据。/api/health/indicator/list 保留不动(cfc-web views/nutritionist/HealthIndicators.vue 仍在调),新接入一律走 /api/health/report/indicators。


4.48.1 指标多期展示 · 后端接口(/api/health/report/indicators、/api/indicator/periods、/api/admin/indicator/backfill)

本节为 §4.48 指标统一层的多期展示增量。所有 change 计算统一由 IndicatorChangeService.computeChange 单点产出(trendCode 五档:improved / worsened / flat / first_record / pending_backfill),读路径一律过滤 indicator_definitions.status=1,拿不到 active definition 的观测直接剔除,不降级为「指标」+id 假名称(QP17)。

① POST /api/health/report/indicators — 报告指标明细(含上一期对照,D12 报告详情页接入点)

端点 权限 请求 返回
POST /api/health/report/indicators 登录(JWT;管理员/本人/被授权成员,校验逻辑同 /api/health/report/detail) {reportId, withPrevious?} {reportId, reportType, subjectId, reportDate, dateSource, olderReportCount, summary, items}
  • 入参:reportId(必填);withPrevious(选填,默认 true,false 时跳过 previous/change 计算,供编辑模式快速返回单期)。
  • 权限:无 subjectId 的报告(历史未绑定成员)仅本人上传者或家庭管理员可见;有 subjectId 时走 ReportMemberPermissionService.canViewMemberReports。
  • items[] 每项含:指标原字段(indicatorId/definitionId/category/indicatorName/indicatorValue/numericValue/unit/refRange/status)+ 字典字段(goodDirection/valueType)+ previous(上一期观测,无则 null)+ change({delta, deltaPct, movement, trendLabel, trendCode, skipGaps, unitMismatch, comparable},首期时为 first_record,报告日期未知时为 pending_backfill)。
  • summary:totalCount / abnormalCount(status 非「正常」)/ abnormalDelta(预留字段,当前固定 0,单报告视角无法直接算)/ changedCount(trendCode 为 improved/worsened 的条数)/ comparableCount / firstRecordCount / pendingCount / dataIncomplete(存在 pending_backfill 时为 true,驱动残缺横幅组件)。
  • 与 withPrevious=false:返回单期 items(每项含 indicatorId/category/indicatorName/indicatorValue/unit/refRange/status,不含 definitionId/previous/change/goodDirection/valueType)。
  • olderReportCount:该成员在本报告之前(同 sourceType)的历史报告数,用于 first_record 档区分「真的首期」与「更早报告未回填」。
  • N+1 约束:42 项指标一次请求的 SQL ≤ 5 次(指标行 1 + 上期批量解析 1 + 字典/定义 1 + 报告 1);IndicatorMappingService.resolveBatch 用 indicator_mapping_rules JOIN indicator_definitions 单查询批量解析,严禁逐指标查库。

② POST /api/indicator/periods — 期次列表(双期对比页 picker 数据源)

端点 权限 请求 返回
POST /api/indicator/periods 登录(JWT;subjectId 须属于当前家庭) {subjectId, sourceType?} {subjectId, sourceType, items}
  • items[]:{reportDate, reportId, dateSource, indicatorCount},按 reportDate 倒序;reportDate=null(日期未知期)恒定排最后,picker 显示「日期未知」。
  • dateSource:该期所有观测中最差的一个(unknown < confirm < upload < real),诚实口径——只要有一项来源是上传推断,整期就标 upload。
  • indicatorCount:该期有有效值(value 非空)的指标数,picker 显示「2026-10-08(42 项)」。
  • 不分页(单人单类型期次数实测 < 30);只读幂等。

③ POST /api/admin/indicator/backfill — 存量时序回填(admin)

端点 权限 请求 返回
POST /api/admin/indicator/backfill admin(@RequestAttribute("role") 校验,非 admin 返回「权限不足」) {subjectId?, reportId?, limit?, dryRun?, fixReportDates?} {scanned, eligible, written, skippedNoSubject, skippedNoPayload, failed, dryRun, fixReportDates, dateFixable, dateFixed, details[]}
  • 用途:把 confirm 链路补写之前的历史报告补进 indicator_values(P0-3 数据面补全),并可顺带用 ReportDateExtractor 修复被 new Date() 污染的历史报告日期。
  • 入参:subjectId(选填,指定成员;不传扫全部 status=active 报告);reportId(选填,只回填指定报告,灰度验证用);limit(选填,默认 200,上限 500);dryRun(默认 true);fixReportDates(默认 false)。
  • dryRun=true:预演只统计不写入,返回 eligible/dateFixable 计数,且不触发 mappingService.resolve(避免惰性建定义这类副作用);首次执行必须 dryRun,核对无误后传 false。
  • 顺序红线:先修日期、再补时序(污染日期若固化进 indicator_values 再修就晚了)。日期修复判定条件:能提取到真实日期 且 report_date != extracted 且 report_date >= created_at 当天(new Date() 污染特征签名);修后需连带 refreshMemberIndicatorCurrent。
  • 幂等:NormalizeIndicatorPipeline 按唯一键 source_type + source_id + definition_id upsert,已覆盖报告返回 already_covered,重复执行不产生重复时序。

④ 升级改造的既有端点(IndicatorController)

端点 变更
POST /api/indicator/trend 新增可选入参 {sourceType, fromDate, toDate, granularity: raw\|month, sourceKind: all\|report\|device};出参新增 refLow/refHigh/goodDirection/valueType/pointsCount/totalReportCount/olderReportCount/chartMode/unitMismatch/latest/change/points/missingPeriods。破坏性:无
POST /api/indicator/change-ranking 新增可选入参 {scope: pair, fromReportDate, toReportDate, filter: improved\|worsened\|flat\|incomparable\|all, page, pageSize};scope=pair 缺 fromReportDate/toReportDate 返回明确错误;magnitude 排序口径从 \|Δ\| 改为 \|Δ%\| 降序(视觉有变化,属预期修正,见 §4.48 变更汇总);deltaPct=null 的项恒定排最后且不参与 improved/worsened 筛选(Q14)。破坏性:无
POST /api/indicator/quick-lookup 新增可选入参 {withSparkline, sparkLimit};出参每项新增 previous/change/latestDateSource/latestReportId/goodDirection/valueType/sparkline;修复 reportDate=null 观测被当作最新值的 bug。破坏性:无
POST /api/indicator/source-types 出参新增 periodCount / latestReportDate(曲线页类型筛选用,原只返回类型名)。破坏性:无

chartMode 判定表(后端单点定义,IndicatorChangeService.chartModeOf):pointsCount=0 → empty;=1 → single;=2 → pair;<20 → line;≥20 → line_aggregated(granularity=month 时强制 line_aggregated)。 SQL 预算(严禁 N+1,均有单测锁死):/report/indicators 42 项指标 → 服务层恒 3 次协作调用(控制器另加 2 次,合计 ≤ 5);/quick-lookup 与 /source-types 均恒 1 次 indicator_values 查询(上一期与 periodCount 全部内存计算)。 IndicatorService.listDefinitions:status 传 null 时默认按 status=1 过滤(防止 P1-6 自动创建的 status=0 definition 冒进管理端字典列表,QP17)。 missingPeriods:该成员有报告、但本指标无有效值的期次,IndicatorTimelineService 固定 2 次查询算完(原 1+缺失期数,会 N+1)。 老接口兼容矩阵见 specs/2026-10-25-indicator-timeline-display-design.md §4.7。

文档更新:2026-10-27(指标多期展示 T02 后端接口,见 specs/2026-10-25-indicator-timeline-display-design.md)


4.48.2 指标收藏 · 后端接口(/api/indicator/favorite/*)

本节为 T04「关注指标收藏」后端化(方案A)增量。收藏从 localStorage(方案B)升级为后端持久化,可跨设备同步、跨端一致。全部 @PostMapping;JWT Bearer 鉴权;@Resource 注入;userId/familyId 由 JwtInterceptor 注入 @RequestAttribute,服务端不信任前端传值。

① POST /api/indicator/favorite/toggle — 收藏/取消(存在则删、不存在则插,幂等于单次调用)

端点 权限 请求 返回
POST /api/indicator/favorite/toggle 登录(JWT;已加入 LOGIN_REQUIRED_PATHS,无 token 直接 401;memberId 须属于当前家庭) {memberId, sourceType, definitionId} {definitionId, added}
  • 入参:memberId/definitionId(必填 Long)、sourceType(必填 String,非空)。
  • 返回:added=true 本次加入收藏(新插入);added=false 本次取消收藏(已删除)。
  • 错误码:400(缺参/成员不属家庭/definitionId 非法)、401(未登录)。

② POST /api/indicator/favorite/list — 查已收藏集合

端点 权限 请求 返回
POST /api/indicator/favorite/list 登录(JWT;memberId 须属于当前家庭) {memberId, sourceType} {memberId, sourceType, definitionIds}
  • definitionIds:该成员×该报告类型下已收藏的指标定义 ID 列表(升序,按 id);空集合返回 []。
  • 查询范围限定 user_id = userId AND family_id = familyId AND member_id AND source_type(家庭/用户隔离)。

③ POST /api/indicator/favorite/remove — 移除收藏(显式删除)

端点 权限 请求 返回
POST /api/indicator/favorite/remove 登录(JWT;memberId 须属于当前家庭) {memberId, sourceType, definitionId} {definitionId, removed}
  • removed=true:该条收藏已删除(不存在则视作已删除,幂等)。供前端「清空对比/切换成员」等需显式删除而非 toggle 语义的场景使用。

文档更新:2026-10-30(T04 指标收藏后端化,见 specs/2026-10-30-indicator-favorite-backend-design.md)


4.49 健康方案删除(/api/health/plan/delete、/api/admin/health-plan/delete)

已生成的健康方案可删除,级联删除其产生的全部任务(含每日实例)。

端点 权限 请求 返回
POST /api/health/plan/delete 登录用户(JWT) {planId} {planId, taskCount}
POST /api/admin/health-plan/delete admin/teacher/butler/nutritionist/operator {planId} {planId, taskCount}
  • 级联范围:health_plans 方案行 + tasks 中 source_type='health_plan' AND source_id=planId 的直接任务(周期模板/一次性任务/购买锚点)+ tasks 中 template_id IN 直接任务ID 的每日实例(RepeatTaskGenerator 生成,只透传 template_id 不带 source_id,必须二次删除,否则任务删后次日仍被再生产)。
  • 保留不删:points_log(积分流水,已完成任务的积分保留不撤回)、task_executions / growth_task_log(执行历史)。
  • 事务:HealthPlanServiceImpl.deletePlanCascade 标注 @Transactional(rollbackFor = Exception.class),任一步失败整体回滚,不留无方案的孤儿任务。
  • IDOR:用户端接口从 @RequestAttribute("familyId") 取家庭做归属校验,方案不属于该家庭返回「无权删除该方案」;管理端传 familyId=null 跳过归属校验。
  • 状态:任何状态(draft/pending_review/published/rejected)均可删除;前端以确认弹窗兜底提醒。

文档更新:2026-10-17(健康方案级联删除,见 specs/2026-10-17-health-plan-deletion-design.md)

4.50 活动海报模板(/api/admin/poster-template/* + /api/poster-template/*)

Web 管理端定义活动海报模板(迁移381 activity_poster_templates 表),小程序端活动详情页「生成海报」拉取可用模板渲染画布。管理端接口校验 @RequestAttribute("role"),仅 admin/operator 可访问;templateKey 限定 gradient(渐变)/minimal(深色)/card(白底卡片),name 全局唯一。

端点 权限 用途
POST /api/admin/poster-template/list admin/operator 模板列表(含停用,按 sort_order + id 升序)
POST /api/admin/poster-template/save admin/operator 新增/更新(body 为实体字段:id/name/templateKey/mainColor/darkColor/lightColor/bgColors/qrSize/sortOrder/status;id 为空为新增;色板须为合法 JSON 数组,空则按主色生成,qrSize 默认 100)
POST /api/admin/poster-template/delete admin/operator 删除(body: {id})
POST /api/poster-template/list 登录 小程序端可用模板(status=1;生成海报场景本身要求登录)

文档更新:2026-10-17(活动海报模板管理,见 specs/2026-10-17-activity-poster-template-design.md)


4.50 会员权益对比表(/api/membership/compare)

购买页(pages/membership/upgrade.vue)与会员中心(pages/membership/index.vue)的权益对比表数据源。全部权益值由后端聚合实际逻辑后返回展示文本,前端不再硬编码权益文案,避免出现「文案说不限量 / 实际 20 个」这类偏差。

路径 说明
POST /api/membership/compare 返回 {columns, rows},无需请求参数

返回值结构

{
  "code": 200,
  "data": {
    "columns": ["FREE", "BASIC", "FAMILY", "PREMIUM"],
    "rows": [
      { "name": "商品折扣", "free": "普通价格", "basic": "—", "family": "9折", "premium": "8折" },
      { "name": "家庭成员上限", "free": "1人", "basic": "3人", "family": "6人", "premium": "10人" },
      { "name": "每日任务上限", "free": "5个/日", "basic": "3个/日", "family": "20个/日", "premium": "50个/日" }
    ]
  }
}

行值口径(事实源)

权益行 数据来源
商品折扣 sys_config.member_discount_family / member_discount_premium(bps:9000→9折、8000→8折),BASIC 无折扣配置显示 —
家庭成员上限 membership_levels.max_children(0/空视为无该权益 → —)
每日任务上限 membership_levels.max_tasks_per_day
AI健康顾问 / 报告解读 / 测评预约 / 食材图片解析 BasicQuotaService.QUOTA_LIMITS 月度配额常量(BASIC 限次)+ canUseFeature 判定(FAMILY/PREMIUM 不限)
优惠券权益 普通券面向所有登录用户(discount_purchase feature,BASIC 起可用);会员专享券仅 FAMILY/PREMIUM(CouponService.canUseMemberCoupon)
会员专属活动 member_activities feature,BASIC 及以下为部分活动
邀请佣金 / 消费返佣 referral_commission / purchase_commission feature
专属管家、规划师咨询 membership_levels.priority_support / teacher_consultation 对应的产品权益设定

列口径:仅 FREE/BASIC/FAMILY/PREMIUM 四列。LIFETIME 为赠送/特殊发放、不可购买,不作为列展示;PROVIDER 是服务商角色,不属于会员权益体系(level_order=1 与 FREE 同级,features 为 NULL),不参与本表。 /api/membership/plans 同步变更:除 LIFETIME 外再过滤 PROVIDER,并附加 maxChildren / maxTasksPerDay 两个字段,前端档位卡片可直接引用。

文档更新:2026-10-18(会员权益对比表动态化 + PROVIDER 退出会员权益体系)


文档最后更新:2026-10-04


5.0 减脂专题(/api/fatloss/*)

减脂专题(xiaofat-miniprogram)新增接口,与主系统用户体系共享(JWT 认证,需登录)。 所有接口统一 @PostMapping,响应格式 Result<T>。

端点 权限 说明
POST /api/fatloss/weight/list 登录 体重记录列表(params: memberId/startDate/endDate,memberId 优先取 params,fallback currentMemberId)
POST /api/fatloss/weight/create 登录 创建体重记录(body: memberId/weight/bodyFatPercent/waistCircumference/measureDate/remark)
POST /api/fatloss/weight/update 登录 更新体重记录(body: id/weight/bodyFatPercent/waistCircumference)
POST /api/fatloss/weight/delete 登录 删除体重记录(body: id)
POST /api/fatloss/diet/list 登录 饮食记录列表(params: memberId/startDate/endDate)
POST /api/fatloss/diet/create 登录 创建饮食记录(body: memberId/mealType/foodName/foodWeight/calories/protein/fat/carbs/eatDate/remark)
POST /api/fatloss/diet/delete 登录 删除饮食记录(body: id)
POST /api/fatloss/diet/calories-summary 登录 当日总热量(params: memberId/date,date 默认今日)
POST /api/fatloss/exercise/list 登录 运动记录列表(params: memberId/startDate/endDate)
POST /api/fatloss/exercise/create 登录 创建运动记录(body: memberId/exerciseType/durationMin/distanceKm/caloriesBurned/exerciseDate/remark)
POST /api/fatloss/exercise/delete 登录 删除运动记录(body: id)
POST /api/fatloss/goal/active 登录 获取当前活跃目标(params: memberId,返回最新 status=active 的目标)
POST /api/fatloss/goal/create 登录 创建目标(body: memberId/startWeight/targetWeight/targetBodyFat/targetDate/startDate,targetWeight/startWeight/startDate 必填)
POST /api/fatloss/goal/update 登录 更新目标(body: id/targetWeight/targetBodyFat/targetDate)
POST /api/fatloss/goal/complete 登录 完成目标(body: id,status → completed)
POST /api/fatloss/goal/abandon 登录 放弃目标(body: id,status → abandoned)

新增表: fat_weight_record、fat_diet_record、fat_exercise_record、fat_goal(迁移 355–358,DatabaseInitializer)

文档更新:2026-10-09(减脂专题新增)


4.53 限时特价(扫码闪购)

设计规格:specs/2026-10-20-limited-time-special-price-design.md; 新建 special_price_deals 表(迁移 389)+ product_orders.special_deal_id 列(迁移 390)。

用户端(公开接口,无需登录)

路径 说明
POST /api/special-price/info 查询活动详情(白名单,JwtInterceptor 公开路径;userPurchased/userRemaining 恒 0,每人限购由下单接口兜底)

请求体:{ "dealId": 1 } 响应 data 字段:

{
  "id": 1, "productId": 10, "productName": "示例商品",
  "name": "开售闪购", "specialPrice": 500, "productPrice": 990,
  "startTime": "2026-10-20 12:00:00", "endTime": "2026-10-21 12:00:00",
  "totalQuantity": 100, "soldQuantity": 23, "remainingQuantity": 77,
  "perUserLimit": 2, "allowCoupon": 0, "runStatus": "ACTIVE",
  "userPurchased": 0, "userRemaining": 0
}

runStatus 枚举:ACTIVE(进行中)/NOT_STARTED(未开始)/SOLD_OUT(已售罄)/ENDED(已结束)/DISABLED(已停用)/DRAFT(草稿)/INVALID(活动不存在)。白名单路径不写 request attribute,每人限购由下单接口最终校验。

下单(特价路径)

POST /api/product/order/create 请求体新增 specialDealId(Long,可选)。若 specialDealId != null 走特价下单分支:

  1. 校验活动存在、status=active、NOW() ∈ [start_time, end_time]、商品一致
  2. 每人限购校验(countByDeal 累计 < perUserLimit)
  3. allowCoupon=0 且 couponId 非空 → 拒绝
  4. 原子扣量 consumeQuota(id, qty)(失败按 runStatus 返回明确原因)
  5. insert 订单行 special_deal_id = dealId,unit_price = specialPrice
  6. 回滚挂载点:cancel(用户取消)、approveRefund(退款完成)、OrderTimeoutCancelTask(超时取消),三处调用 releaseQuota(GREATEST(sold_quantity - qty, 0) 防负)

供应商改价拒绝:reviewUpdate 开头若 order.specialDealId != null 直接 Result.error("特价订单不允许修改价格")。

管理端(admin 角色)

路径 权限 说明
POST /api/admin/special-price/list admin 分页列表(body: {page,size,keyword,runStatus};runStatus 可传 ACTIVE/NOT_STARTED/SOLD_OUT/ENDED 或 draft/disabled,空=全部;响应 data.records[] + data.total)
POST /api/admin/special-price/create admin 新建(body: {productId,name,specialPrice,startTime,endTime,totalQuantity,perUserLimit,allowCoupon};specialPrice/productPrice/totalQuantity 单位均为分;同商品互斥 active)
POST /api/admin/special-price/update admin 修改(body 同 create + id;仅 draft/disabled 可修改)
POST /api/admin/special-price/status admin 启停(body: {id, action};action ∈ {enable, disable};启用时再次校验互斥)
POST /api/admin/special-price/delete admin 删除(body: {id};已有特价订单时拒绝)
POST /api/admin/special-price/qrcode admin 生成小程序码(body: {id};scene=id={productId}&sp={dealId},落地页 product-detail;返回 data:{qrCodeBase64, scene, note?};测试模式 note 提示无法生成真实码)

文档更新:2026-10-20(限时特价/扫码闪购新增)

4.54 活动报名情况(POST /api/activity/registration-roster)

活动详情页「报名情况」区块数据源。面向所有访客(含游客,/api/** 下无需登录),返回脱敏的报名统计与最近已通过报名人,用于社交证明与名额紧迫感展示。姓名经 DataMaskUtil.maskName 脱敏(如"张小明"→"张某"),不返回手机号。

请求体: { "activityId": 1 }(兼容 id)

响应 data 字段:

{
  "activityId": 1,
  "maxParticipants": 50,
  "approvedCount": 12,
  "pendingCount": 3,
  "remaining": 38,
  "registrants": [
    { "name": "张某", "registeredAt": "2026-10-22T10:00:00" }
  ]
}
字段 说明
maxParticipants 人数上限(0 = 不限制)
approvedCount 已通过报名人数
pendingCount 待审核报名人数
remaining 剩余名额 = max - approved(不限制时为 null,下限 0)
registrants 最多 20 条已通过报名人(按报名时间倒序,姓名脱敏)

前端使用:activity-detail.vue 加载详情后并行拉取;报名成功/取消报名后重新拉取。区块仅当 activity.requireRegistration === 1 时展示,含统计列、进度条(限人数时)与最近报名人列表。

文档更新:2026-10-22(活动详情页新增报名情况)

4.55 活动报名/签到/问卷(本次回归补登记)

以下接口在 2026-10-23 的 T15/T16/T17 任务链路中新增或变更,此前未在本文档登记,此处统一补录。

4.55.1 活动报名(ActivityController,前缀 /api/activity)

路径 说明
POST /api/activity/register 活动报名(body: activityId;批量报名历史字段 registrants)。活动 requireReview=1(默认免审)→ 报名记录为 pending 不占名额;免审即 approved 并原子占用名额

4.55.2 活动签到与签到审核(ActivityController)

路径 说明
POST /api/activity/checkin 活动签到(body: activityId)。活动级 requireCheckinReview=1 时签到进入 pending_review,审核通过才发奖励;免审直接发放
POST /api/activity/checkin-review 签到审核(仅活动管理员/平台管理员)。通过发放积分/能量/CF,驳回不发放

4.55.3 管理端签到(AdminActivityCheckinController,前缀 /api/admin/activity-checkins)

路径 说明
POST /api/admin/activity-checkins/list 按活动分页查询签到记录
POST /api/admin/activity-checkins/add 手动补录签到(幂等,桥接触发课时入账)
POST /api/admin/activity-checkins/review 修改签到审核状态(通过发放课时/奖励)

与规划师课时桥接:签到审核通过会触发课时发放,与 AdminPlannerOfflineCourseController 的活动↔类别映射联动(见第五章)。

4.55.4 家庭关系问卷(RelationshipQuestionnaireController,前缀 /api/family/questionnaire)

路径 说明
POST /api/family/questionnaire/generate AI 生成关系问卷快照(body: memberId;respondentId 由后端按登录用户覆盖,校验调用人与目标成员同家庭),返回题目集与 snapshotId
POST /api/family/questionnaire/submit 提交答卷(body: snapshotId + 答案),写入响应记录
POST /api/family/questionnaire/snapshot/{memberId} 查询某成员当前快照
POST /api/family/questionnaire/history/{memberId} 某成员问卷历史提交记录

4.55.5 报名名册数据口径(2026-10-23 本次回归涉及)

POST /api/activity/registration-roster 的 approvedCount 现直接读 activities.approved_count(迁移回填),不再实时统计;剩余名额 = max - approved,下单/退款链路(register/cancel/OrderTimeoutCancelTask)通过原子 SQL 维护该计数,防超卖。

4.55.6 审核中心统计口径变更(2026-10-23)

ReviewCenterController 的 guidePending / nutritionistPending 统计新增 real_name IS NOT NULL 过滤,与列表接口口径一致(commit f61547a21);前端 ArticleAudit.vue 驳回原因字段由 row.reason 修正为 row.rejectReason。

文档更新:2026-10-23(T15/T16/T17 回归补登记:活动报名、签到与签到审核、管理端签到、家庭关系问卷、名册口径、审核中心统计口径)


4.48 组织管理(机构/企业组织)

平台角色(admin/operator/finance)可管理所有组织并查看全量统计;组织管理员(users.roles 含 org_admin)登录管理端后默认跳转自身组织统计大屏,仅能访问本组织数据。实现方案见规格 docs/superpowers/specs/2026-10-22-org-admin-management-design.md。

数据模型:

  • organizations:组织主表(name/type/code/admin_userid/contact*/description/status)
  • org_members:组织成员关联表(org_id/user_id/member_type/role_in_org/status),唯一键 (org_id, user_id)

权限规则:

  • 平台角色(admin/operator/finance)→ 全量访问
  • org_admin → 仅能访问自身组织(organizations.admin_user_id = userId 且 status='active'),返回 403「无权访问该组织」/「组织已停用」
  • 组织管理员身份登录复用现有 /api/admin/auth/login 流(AdminRoles.RESIDENT_ROLES 新增 org_admin)

接口列表(13 个,全部 @PostMapping)

路径 说明
/api/admin/org/list 组织列表(分页/筛选;org_admin 只返回自己组织)
/api/admin/org/create 创建组织(同步创建管理员账号;仅平台角色)
/api/admin/org/update 更新组织信息
/api/admin/org/disable 停用/启用组织(仅平台角色)
/api/admin/org/detail 组织详情
/api/admin/org/my-org 组织管理员获取自身组织(登录跳转目标)
/api/admin/org/user/search 按手机号/昵称搜索平台用户(添加成员下拉选人)
/api/admin/org/member/list 成员列表(含家庭数/订单数/消费额摘要)
/api/admin/org/member/add 添加成员(软删成员复活为 active 并更新类型)
/api/admin/org/member/remove 移除成员(软删 status=inactive)
/api/admin/org/member/change-type 变更成员类型(planner ↔ user,复活 inactive)
/api/admin/org/stats/overview 总览卡片(成员/规划师/家庭/订单/消费)
/api/admin/org/stats/families 家庭维度(活跃家庭/任务完成率/打卡率)
/api/admin/org/stats/active 活跃度趋势(任务完成/打卡/报告上传,按天)
/api/admin/org/stats/revenue 营收(订单金额/会员订阅/佣金,按天)
/api/admin/org/stats/trend 趋势图(活跃成员数/订单数/收入,按天)

请求参数: 成员/统计接口统一从 body 取 orgId;stats 可选 startDate/endDate(yyyy-MM-dd,默认近 30 天)。

统计口径:

  • 成员范围:org_members 中 status='active' 的 user_id 集合
  • 家庭数:families.creator_id IN (成员userId) 去重计数
  • 订单:product_orders.buyer_id IN (成员userId) AND status IN ('PAID','COMPLETED')
  • 消费:上述订单 total_amount 求和(单位分)
  • 打卡:health_checkins.user_id + daily_checkin(经 family_members.user_id 关联)+ emotion_checkin
  • 报告:dan_report_uploads.uploader_user_id
  • 佣金:commission_records.referrer_id(受益人)commission_amount 求和
  • 订阅:member_subscription_order.status='paid'

前端入口: cfc-web 新增 /org 路由四页面(List/Form/Detail/Dashboard);菜单「组织管理」挂在系统配置分组下。组织管理员登录后自动跳 /org/:id/dashboard,不展示组织列表页。

文档更新:2026-10-22(组织管理功能上线)

五、规划师培训认证(/api/planner/*, /api/admin/planner-*, /api/xiaoe/*)

设计文档:docs/superpowers/specs/2026-10-22-planner-learning-assessment-gate-design.md 核心链路:身份审核通过 → Guide.status=pending_cert + 按类别初始化 planner_certifications → 线上课时(小鹅通 webhook/手动同步)+ 线下课时(activities 打卡桥接)→ 考核通过 → 类别 certified(基础类别 planner 通过时同步翻 Guide.status=active)→ 接单闸门放行。

5.1 规划师端(/api/planner/*)

路径 说明
POST /api/planner/certification/my 我的全部类别认证状态(线上/线下课时拆分、考核分、证书号、是否可考)
POST /api/planner/courses 某类别线上课程列表(含小鹅通跳转/H5 链接;body: categoryCode)
POST /api/planner/training-activities 可报名/签到的培训活动列表(复用 activities,过滤映射表+规划师可见)
POST /api/planner/training-activities/check-in 扫码/手动签到(body: qr_token 或 activityId+admin)→ 桥接发放课时
POST /api/planner/exam/start 开始某类别考核(前置校验课时达标;body: categoryCode)
POST /api/planner/exam/submit 提交判分(body: attemptId+答案,写入 exam_score/exam_passed)
POST /api/planner/exam/result 考核结果

5.2 管理端(/api/admin/*)

路径 说明
POST /api/admin/planner-cert-categories/list 学习种类列表
POST /api/admin/planner-cert-categories/create 创建学习种类(含 required_hours、is_base,首批种子:planner/nutritionist/assessor)
POST /api/admin/planner-cert-categories/update 更新学习种类
POST /api/admin/planner-cert-categories/delete 删除学习种类
POST /api/admin/planner-courses/list 线上课程列表
POST /api/admin/planner-courses/create 创建线上课程(挂类别)
POST /api/admin/planner-courses/update 更新线上课程
POST /api/admin/planner-courses/delete 删除线上课程
POST /api/admin/planner-offline-course-map/list 培训活动↔类别映射列表
POST /api/admin/planner-offline-course-map/create 创建映射(activities 建课后关联类别与计课时)
POST /api/admin/planner-offline-course-map/update 更新映射
POST /api/admin/planner-offline-course-map/delete 删除映射
POST /api/admin/activity-checkins/list 签到记录查询
POST /api/admin/activity-checkins/add 手动补录签到(桥接触发课时入账)
POST /api/admin/activity-checkins/review 签到审核
POST /api/admin/planner-exam/papers 试卷列表(按类别)
POST /api/admin/planner-exam/paper/create 创建试卷
POST /api/admin/planner-exam/paper/update 更新试卷
POST /api/admin/planner-exam/paper/delete 删除试卷
POST /api/admin/planner-exam/questions 题库列表
POST /api/admin/planner-exam/questions/save 保存题目(新建/更新)
POST /api/admin/planner-certifications/list 认证看板(按类别:课时进度、考核分、证书号、有效期)
POST /api/admin/planner-certifications/sync-hours 手动同步线上课时(小鹅通 webhook 兜底,body: userId+categoryCode+课时)
POST /api/admin/planner-certifications/sync-hours/batch 批量同步线上课时
POST /api/admin/planner-certifications/init-by-user 按用户初始化各类别认证记录
POST /api/admin/planner-certifications/backfill 存量补登(迁移401 幂等重跑)

5.3 小鹅通回调(/api/xiaoe/*)

路径 说明
POST /api/xiaoe/webhook 线上学习进度/课程完成事件(签名校验、幂等;课时入账 + 认证记录更新)
POST /api/xiaoe/webhook/test webhook 联调用测试入口

5.4 接单闸门(PlannerCertificationGuard)

  • 中央守卫 assertCertified(userId, categoryCode[, baseRequired]):查询该类别 planner_certifications.status == certified(且 Guide.status == active)方可放行,否则返回 Result.error("规划师未完成【类别名】培训认证,暂不可提供该类服务")(null=放行,非 null=拒绝)。
  • 已注入闸门的服务入口(设计 §9 映射表):
服务动作 入口 所需类别
上架/修改服务套餐 GuideManagementController package/add、package/{packageId}/update planner
家庭绑定(开始服务) BindController.accept planner
激活成长方案(下发任务) PlanReviewController.activate planner
咨询响应/接单 TeacherMessageController.reply planner
订单中心(列表/统计/详情) GuideOrderController /list、/stats、/detail planner
测评录入/解读 GuideAssessmentController family/enable assessor
  • 待建设入口(当前代码不存在,预留):营养方案/饮食建议(nutritionist)。

六、CF 值体系统一 · 配置治理接口(F-1 / W0.1)

口径:docs/superpowers/plans/2026-10-24-cf-value-unification-plan.md §3.6.6 / §3.7 W0.1 本批只提供 数据层 + 配置层 接口,发放/扣减接口在 F-2/F-3 批新增。

6.1 服务配置中心(/api/admin/service-config)

唯一配置中心(service_config 表):CF 通用运营参数(key 前缀 cf.,product_key 为空)+ product 侧配置(product_key 非空,key 形如 product.{productKey}.{key},W0.2 由 product_config 并入)。保存后自动 CfConfigCache.invalidate()(本地缓存 TTL 60s)+ cf.version 自增。

路径 说明
POST /api/admin/service-config/list 配置列表,body 可选 {"groupKey":"cf.rate","productKey":"gut_health"},不传返回全部(productKey 为产品维度筛选,W0.2 新增)
POST /api/admin/service-config/save 保存配置(upsert),body {"configKey":"cf.rate.points_multiplier","configValue":"1.0","updatedBy":1};传 productKey 则写入 product 侧配置(自动加 product.{productKey}. 前缀并回填 product_key,W0.2 新增),可另传 description
POST /api/admin/service-config/invalidate 手动失效 CF 配置缓存(排障用)

已登记配置项:cf.rate.points_multiplier、cf.rate.repeat_rate_default、cf.commission.settle_days、cf.invite.valid_days、cf.price.default_factor、cf.stock.deduction_mode、cf.rate.share_read_reward_points、cf.commission.service_rate、cf.product.gut_health_price、cf.product.platform_points_share、cf.version。

6.2 CF 值获取规则(/api/admin/cf-earn-rule)

24 条规则(F02–F24,F03 拆 F03a/F03b)配置入口;每次保存/开关写 cf_earn_rule_history 并失效配置缓存。

路径 说明
POST /api/admin/cf-earn-rule/list 规则列表,body 可选 {"category":"behavior","enabled":1}
POST /api/admin/cf-earn-rule/save 新建/编辑(按 code 判重),body 含 code/name/category/ruleType/amount/formula/paramsJson/dailyLimitPerMember/totalLimitPerMember/cooldownSeconds/dedupRefType/remark/changedBy/changeReason
POST /api/admin/cf-earn-rule/toggle 启停,body {"code":"F07","enabled":0,"changedBy":1,"changeReason":"..."}
POST /api/admin/cf-earn-rule/history 变更历史,body 可选 {"code":"F07","limit":100}

读取封装:ConfigService.getConfig(key)(缓存 60s → DB → 兜底常量);product 侧配置读取:ConfigService.getProductConfig(productKey, key)(W0.2);规则读取:CfEarnRuleService.getByCode(code)。

6.3 产品配置中心(/api/admin/product-config,已废弃 410 Gone)

W0.2 双配置中心合并:product_config 已并入 service_config(唯一配置中心),product 侧配置通过 product_key 关联产品;本控制器写接口统一返回 410 Gone(HTTP 410 + body code=410),保留 30 天只读窗口后由运维删表。

路径 说明
POST /api/admin/product-config/list 【410 Gone】已废弃,改用 POST /api/admin/service-config/list(body 传 productKey 筛选)
POST /api/admin/product-config/save 【410 Gone】已废弃,改用 POST /api/admin/service-config/save(body 传 productKey)

时间线:2026-10-24 起写接口下线(product_config 只读保留 30 天回滚用);2026-11-23 起确认无回滚需求后删表并移除本控制器。

6.4 F-6 存量账本迁移(迁移417,无新增接口)

启动时由 DatabaseInitializer → CfLegacyLedgerMigrationService 一次性执行,无 REST API。迁移只读旧表、不回写旧表:

来源 目标成员 cf_balance_log.ref_type ref_id 口径
family_platform_balance 家庭 families.creator_id 对应的 family_members migration_family_pool 0 available + frozen 合入新 available,withdrawn/exchanged 原样带入
family_members.system_points > 0 当前成员 migration_system_points family_members.id system_points 合入新 available
user_platform_balance 该用户本人对应的 family_members migration_user_wallet user_platform_balance.id available + frozen 合入新 available,withdrawn/exchanged 原样带入

幂等键为 (member_id, type='adjust', ref_type, ref_id)(对齐 F-2 迁移416 升级后的唯一键 uk_ref_type);重复启动按三类 ref_type 逐笔跳过,余额与流水同事务提交。三套旧账本保留为只读历史,写接口 410 Gone 由 F-8 收口。

6.5 F-4 分佣收口 + F03a/F03b 发放接入(迁移418 / 迁移420,无新增接口)

口径:计划 §四 / §3.1 / §4.2 / §4.4。发放链路由 CfCommissionService 统一承载,无新增 REST 接口;/api/commission/cf/rate 返回值扩展两级档位字段(见 4.33)。

迁移内容:

迁移 内容 幂等键
418 cf_direct_sales_tier / cf_indirect_sales_tier 各补 5 档种子(青铜/白银/黄金/铂金/钻石,缺行才补、不覆盖)+ cf_earn_rule.dedup_ref_type 对齐为规则编码(F03a→'F03a'、F03b→'F03b') 按 min_annual_ppoints / min_self_ppoints 判重;UPDATE 带 WHERE dedup_ref_type <> code
420 新建 ppoint_consumption_log(滚动一年档位聚合数据源:消费支付成功落一行,created_at >= now()-365d 聚合)。注:迁移419 已被 membership_levels.max_daily_analyze 占用,本表顺延为 420 UNIQUE uk_order (order_type, order_id) 同一订单重复触发只记一行

发放链路(CfCommissionService.settle / settleReferrerOnly):

本单 P 点基数(商品: 元×有效P点/100;非商品: 元×service_rate bps/10000)
  → 落 ppoint_consumption_log(幂等)
  → referral_tree 按 level 升序上溯,跳过同家庭(D5)
  → 第1个非同家庭引荐人 → getTeamAnnualPpoints(referrerId, 8) → matchDirectSalesTier → F03a
  → 第2个非同家庭引荐人 → getSelfAnnualPpoints(referrerId)      → matchIndirectSalesTier → F03b
  → cfBalanceService.earnByRule(memberId, "F03a"/"F03b", orderId, {base_ppoints, rate_percent})
      (公式 floor(base_ppoints*rate_percent/100),幂等键复用 F-2 uk_ref_type,只写 cf_balance + cf_balance_log)
  → F03a 且非幂等命中时 autoCreateGratitudeEffect(感恩记录)
  • 数量与比例零硬编码:比例来自档位表,上限来自 cf_earn_rule.params_json.max_rate_percent,金额由公式计算。
  • 与 F-3a 共存:CfCommissionService 同时承载两条链路 —— 当前消费人 F02(CfEarnDispatchService.earnConsumeCf,按实付金额,商品订单实付与分润基数分离)与推荐人 F03a/F03b(本节);两条链路都只写 cf_balance + cf_balance_log,cf_transfer_record 不再由本服务写入。
  • 旧分佣写接口 CommissionDistService.distribute 已废弃:抛 IllegalStateException(消息含 "410 Gone",经 GlobalExceptionHandler 转 Result.error(400, ...)),无调用方;commission_dist_log 转只读历史表,管理端读取接口(/api/admin/commission-dist/*)保留不变。
  • cf_rate_tier 表保留只读,仅供等级展示(PromotionTierService / 管理端档位配置)使用。

文档更新:2026-10-24(CF 值体系统一 F-1 数据层 + W0.1 配置归口:8 张新表/迁移407-412 + service_config 与 cf_earn_rule 管理端接口);同日补登 W0.2 双配置中心合并(service_config 收编 product_config:迁移413 + product_key 维度 + product-config 接口 410 Gone + 配置中心统一入口);同日补登 F-6 存量迁移(迁移417 + 三套旧账本幂等迁入 cf_balance);2026-10-25 补登 F-4 分佣收口(迁移418/420 + 两级销售奖档位 + /rate 扩展字段 + CommissionDistService.distribute 410 Gone)

6.6 C 端 CF 查询接口(F-7a,只读)

口径:计划 §七 F-7a。个人 CF 值账本为成员维度(family_members.id),登录 userId → memberId 解析与 CfEarnDispatchService.resolveMemberId(F-3a)口径一致:user_id 匹配 + 按 id 升序 LIMIT 1;未找到对应家庭成员时返回 Result.error(404, "未找到当前用户对应的家庭成员,..."),不返回空数据。

控制器:CfBalanceController,前缀 /api/cf(GET,需登录;注:本项目接口惯例为 POST,本组 只读接口按 F-7a 任务要求采用 GET,若团队统一要求 POST 可一行改回)。

路径 说明
GET /api/cf/balance 我的 CF 值快照。按登录用户解析 memberId 后读 cf_balance,返回 CfBalanceView:memberId / available(可用) / frozen(冻结) / totalEarned(累计获得) / totalWithdrawn(已提现) / exchanged(已兑换消费)。无 cf_balance 记录时返回全 0
GET /api/cf/logs?page=1&size=20 我的 CF 流水分页(时间倒序),复用 CfBalanceService.getLogs(memberId, page, size),输出转 CfBalanceLogVO:id / type(earn/spend/freeze/unfreeze/withdraw/adjust/skip) / refType(规则编码或迁移标识) / amount(带符号变动) / balanceAfter(变动后可用余额) / remark / createdAt(ISO 8601)。返回 MyBatis-Plus Page 结构(current/size/total/pages/records)
GET /api/cf/family-coupons 家庭共享优惠券列表(N3 口径)。复用 CouponService.listMyCoupons(userId):按登录用户所属家庭查 family_coupon + coupon 联合数据(券家庭化全链路已切换至 family_coupon,user_coupon 为只读历史表),返回 userCouponId / couponId / name(券名) / type / value(面额,分) / discountRate / minSpend / applicableTo / status(AVAILABLE/USED/EXPIRED/DISABLED) / validFrom / validUntil(有效期) / receivedAt / usedAt / orderId / productId,家庭内成员共享可见
  • 实现走统一账本 CfBalanceService / CouponService,本控制器不直接写库、不提供任何写接口。
  • 流水/余额响应结构单测:cfc-backend/src/test/java/com/etotem/cfc/unit/CfBalanceControllerTest.java(memberId 解析命中/未命中 + balance/logs 字段映射)。

4.56 管理端-素材库(/api/admin/file-record/*)

控制器:FileRecordController(controller/admin/FileRecordController.java),前缀 /api/admin/file-record。 服务层:FileRecordService;文件存储复用 StorageService.storeFileRecord(MultipartFile, category) (JdCloudStorageService / LocalDiskStorageService 实现),统一写入 file_record 并推导 file_type。 权限:全部 @PostMapping,控制器内 @RequestAttribute("role") == "admin" 守卫(无 token 时为 anonymous,直接拒绝)。 数据表:file_record(唯一键 uk_hash 去重)、file_tag(uk_name)、file_tag_rel(uk_file_tag),均为既有表,无新增迁移。

file_type 口径(与 util/FileTypeResolver.java 一致):

file_type 判定
image content_type LIKE 'image/%'
video content_type LIKE 'video/%'
audio content_type LIKE 'audio/%'
document content_type LIKE 'text/%' 或 PDF/Office/RTF/ODF 白名单
other 其它(含 application/octet-stream、content_type 缺失)

写入侧(新数据):content_type 缺失或为 application/octet-stream 时按扩展名兜底;历史回填见 docs/migrations/20261025_asset_library_file_type_backfill.sql(严格按 content_type 分类,不用扩展名兜底)。

接口清单:

路径 说明
POST /api/admin/file-record/list 分页检索。Body:{ page, pageSize, category, fileType, search, dateFrom, dateTo, tagIds };tagIds 为数组或逗号分隔字符串,前置过滤(先按标签 JOIN 过滤再分页,保证 total 正确)。返回 { records, total, page, pageSize },records 元素含 id/hash/url/fileSize/contentType/originalFilename/category/fileType/description/createdAt/updatedAt/tags
POST /api/admin/file-record/upload 统一上传入库。multipart 字段:file(必填)、category(选填,默认 general)、tagIds(选填,数组或逗号分隔)。存储 → 写 file_record(SHA-256 去重,命中返回既有记录并补打本次标签)→ 关联标签。图片(contentType 以 image 开头)先过微信内容安全检测(WechatServiceInterface.checkImage,fail-open,与旧 AdminArticleController#uploadImage 保持一致)。返回素材记录 map
POST /api/admin/file-record/update 更新描述/标签。Body:{ id, description?, tagIds? };tagIds 传空数组表示清空标签,不传表示不改动
POST /api/admin/file-record/delete 删除素材。Body:{ id };先删 OSS 文件(失败仅告警)再删记录及其标签关联
POST /api/admin/file-record/tags 标签字典列表(按 sortOrder 排序)
POST /api/admin/file-record/tag/create 新建标签。Body:{ name, color?, sortOrder? },name 唯一
POST /api/admin/file-record/tag/update 更新标签。Body:{ id, name?, color?, sortOrder? }
POST /api/admin/file-record/tag/delete 删除标签。Body:{ id }(级联清理 file_tag_rel)
POST /api/admin/file-record/stats 统计。返回 { total, totalBytes, byFileType: [{file_type, cnt}], byCategory: [{category, cnt}] }

上传响应示例(data 为素材记录):

{
  "id": 1024,
  "hash": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08",
  "url": "https://bucket.endpoint/uploads/general/xxx.png",
  "fileSize": 102400,
  "contentType": "image/png",
  "originalFilename": "cover.png",
  "category": "articles",
  "fileType": "image",
  "description": null,
  "createdAt": "2026-10-25T12:00:00",
  "updatedAt": "2026-10-25T12:00:00",
  "tags": []
}

前端配套: cfc-web/src/utils/asset.js(API 封装 + resolveAssetUrl)、cfc-web/src/components/AssetPicker.vue(素材选择弹窗,image/video/document 三类)、cfc-web/src/views/admin/AssetLibrary.vue(素材库管理页,路由 /admin/asset-library)、cfc-web/src/utils/editorAssetUpload.js(wangEditor 上传配置公共封装,端点统一指向本组 upload)。

上传点接入范围与跳过说明(cfc-web/src 全量 el-upload 排查结果):

页面 处理
ArticleEdit / ActivityEdit / ProductEdit 接入:富文本 MENU_CONF.uploadImage/uploadVideo.server 改指本组 upload(fieldName=file + Bearer),customInsert 统一 resolveAssetUrl;新增「从素材库选择图片/视频」按钮
HomeBannerManage / ProductSkuEditor / GuidePackages 接入:封面上传改指本组 upload,并加「从素材库选择」
KnowledgeDialog 接入:文档可从素材库选取(assetType=document),原有的本地知识文件上传通道保留不变
Activities / ArticleManage / SupplierProductManage 跳过:仅列表展示页,无上传控件
RecommendationRules / IndicatorMappings 跳过:无文件上传控件(后者为文本批量导入)
ProxyReportUpload / teacher/ProxyReport / ReportParserImport / ReportCollectorTrainer / ReportUnknownCluster / teacher/GrowthRecords 跳过:业务报告/JSON 解析包上传,走报告解析专用端点(/api/admin/report-parser/* 等),非 jdcloud 媒体资产,纳入素材库会污染 file_record 分类语义
ReportTemplateManage 跳过:仅表单 tab,无图片字段

旧端点 POST /api/admin/articles/upload/image|video 保留可用(兼容既有调用方),但后台页面已统一改走素材库 upload,以便自动入库与打标签。

存量回填: docs/migrations/20261025_asset_library_file_type_backfill.sql(备份 → 按 content_type 回填 file_type → 修正列注释 → 校验),不占用 DatabaseInitializer 迁移编号(407-421 为 CF 体系保留)。

文档更新:2026-10-25(后台素材库:/api/admin/file-record/ 上传入库 + 标签字典 + 统计;file_type 口径统一为 image/video/audio/document/other)*


4.49 家庭归因核心闭环(/api/attribution/* + /api/survey/attribution/*)

阶段二(ATT-S2,B1–B4):「归因分析 → 条件问卷 → 自然语言调整 → 七章干预方案」。 E12 合规后置:全流程由 app.attribution.enabled(默认 false)开关控制,仅测试/mock 数据环境开启; 真实用户放行 = 阶段四 D1 完成日。未开启时返回 Result.error(4001, …)。 合规即服务:红线 RL01–RL10 由规则层硬注入,AI 只产叙述/调整,不负责合规判定(§1.3)。

POST /api/attribution/analyze — ③ 归因分析(十节结构报告)

  • Body:{ familyId?, memberIds[], gutReportIds[], danResultIds[], confirmSurveyRecordId?, planId?, mock?, mockFlags? } (mockFlags 仅 E12 测试环境,可显式注入中间态键)
  • Resp data:AttributionReportVO { id, familyId, status, reportJson, intermediateState, redlineHits, conclusionLocked, createdAt }
    • reportJson:十节结构(一结论先行/二四人数据速览/三逐人归因/四家庭系统归因/五应对方案/六12周可检验目标/七教练提问序列/八问诊清单/九红线与转介/十一句话收尾)
    • intermediateState:含 l.reuteriAbnormal/ironLow/hasDan/isFemaleTeen/hasDiabetes 等键(B1 中间态)
    • redlineHits:RL01–RL08(阶段③④注入);RL09/RL10 属方案阶段⑤
    • 状态流转:ANALYZING(插入)→ READY(回填报告后更新)
  • 前置:常模缺失指标 → 「待补」,不猜值(warnings 携带说明)

POST /api/survey/attribution/confirm-questions — ② 条件问卷路由

  • Body:{ familyId, memberId, attributionId, answeredSummary? }
  • Resp data:ConfirmQuestionVO { templateId, questions[], hasHighRisk, highRiskQuestionIds }
    • questions[]:按 对象×年龄×结论 条件下发 family_attribution 模板子集(16 条中)
    • 对象级题目只下发给该对象;家庭级(四人/全家)恒发
    • Q11–Q13 携带 riskLevel=high;命中 → hasHighRisk=true(E4 弱提示,不阻断)

POST /api/survey/submit — ② 提交(B2 扩展:riskHits)

  • Body:{ userId, memberId, templateId, answersJson, periodStart?, periodEnd?, riskHits? }
    • riskHits(Q11/Q12/Q13 命中标记)并入 answersJson._attributionRiskHits 落库,供 B1 红线检测
    • E4:高风险命中不阻断提交,仅标记「建议专业评估」

POST /api/attribution/adjust — ④ 自然语言调整

  • Body:{ attributionId, message, conversationId? }
  • Resp data:AdjustResult { attributionId, status, answer, fieldDeltas, intermediateState, redlineHits, redlineTerminate, blocking, referral, planInvalidated }
    • AI 回答可携带 [ATTR_DELTA]{"键":新值} 结构化增量 → 回填 intermediate_state(七层 Socratic,PRD §C ④)
    • RL02 命中 → redlineTerminate=true、blocking=false(E4 弱提示不阻断)、referral 露出转介信息 + 家长确认
    • 若已关联方案且 status=GENERATED → 作废为 INVALIDATED(⑤ 失效重生成)
    • AI 不可用 → 规则兜底话术,流程不阻断

POST /api/attribution/confirm-adjust — ④ 确认调整

  • Body:{ attributionId }
  • Resp data:AdjustResult { status=CONFIRMED, conclusionLocked=true }(结论锁定,B4 前置条件)

POST /api/attribution/plan — ⑤ 七章干预方案

  • Body:{ attributionId }
  • 前置:归因结论须 CONFIRMED(否则 Result.error(4000, …))
  • Resp data:FamilyPlanVO { planId, planJson, totalDays, status }
    • planJson:header + 7 章(数据速览/主线产品/分人方案/家庭共享/12周节奏/红线与转介/附录)
    • 人范围:仅 妈妈/女儿/儿子(E6,爸爸链外);每动作带 level(P0/P1/daily/P2) + reviewHook(复盘钩子)
    • 儿童补剂动作仅写「医生定」,无剂量数字(RL03);产品品牌级(Enagic 还原水/姜黄、PHGG、菌株名)且带 RL05 合规口径
    • 落库 health_plans,plan_type=family_attribution_plan,status=GENERATED(⑤)

文档更新:2026-10-28(家庭归因核心闭环 B1–B4:/api/attribution/analyze、/api/attribution/adjust、/api/attribution/confirm-adjust、/api/attribution/plan、/api/survey/attribution/confirm-questions;/api/survey/submit 扩展 riskHits)