# 浠艾福小程序改版:需求驱动 · 逐步解锁 > 阶段:实施计划 v1.0 | 分支:cfclub | 产品决策已确认(2026-08-13) ## 一、背景与目标 现状:小程序首页对所有用户一视同仁地堆内容(商品/活动/文章/任务),未区分用户需求深度,转化链路不清晰。 改版核心:**从用户需求出发,先识别用户类型,按需求深度逐步解锁内容与功能,无关内容不展示。** 三类用户: - **A类 目标明确型**:已接受平台理念,直接买 DAN测评 / 菌群检测 → 上传报告 → 出方案 → 生成任务 → 执行(方案任务需会员) - **B类 观望型**:登录看看 → 轻问卷 → 按答案开放相关科普内容 - **C类 问题导向型**:带具体问题来(减肥/睡眠/便秘)→ 服务流程介绍 → 专项调研 → 匹配推荐套餐 → 购买 → 试剂盒寄送/样本寄回 → 报告完成系统通知 → 方案确认 → 任务分解执行 → 全部完成奖励 CF 值 已确认决策: 1. 入口呈现:**首次登录强制选择**;已登录但从未选过的用户,下次进入也要弹出选择 2. 问题域首版:**减肥 / 睡眠 / 便秘** 三个 3. 会员任务边界:**仅"方案生成"的任务需会员**;未缴费用户可以自己创建任务自己完成(免费) 4. 完成回馈奖励:**主要奖励 CF 值**(复用 PlatformPointsService) 5. 实施优先级:**C类优先 → A类会员任务解锁 → B类问卷引流** ## 二、现状摸底结论(已核实) | 模块 | 现状 | 结论 | |------|------|------| | 首页分流 | `pages/index-home/index.vue` 内嵌登录/游客两态,游客看商品+活动+文章,登录看沙盘+动态+会员入口+快捷功能+任务+挑战+推荐 | 需重构为"旅程状态驱动" | | 测评链路 | `DanAssessmentController`: order/create→pay→appointment→record→result→report 全链路已有 | ★★★ 直接复用 | | 报告解析 | `DanReportController`: upload→edit→confirm→complete-analysis | ★★★ 直接复用 | | 菌群检测 | `BeijingNutritionController`: bacteria/save + analysis + recommend;送会员走 `TrialMembership` | ★★★ 直接复用 | | 会员 | `FamilyMembership`(FREE/BASIC/PROFESSIONAL/ENTERPRISE) + `MembershipController`(upgrade/trial/my/can-use/benefits) | ★★★ 直接复用 | | 问卷 | `SurveyTemplate`(questionsJson 题目JSON) + `SurveyRecord`(answersJson) + `ReportSurveyController`(create/submit/status);前端 `pages/health/survey-questionnaire.vue` 通用渲染页已有 | ★★ 扩展(题目JSON 加 resultMapping) | | 套餐 | `GuidePackage`(price/validityDays) + `TaskTemplatePackage`(cycleDays/category/price) + `AssessmentProduct`(single/bundle) | ★★ 需补"套餐→检测→任务模板"关联 | | 任务 | `Task` 有 sourceType/sourceId/dimensionCode,**无会员字段** | ★ 需加 `member_only` | | CF值 | `PlatformPointsService.earn/spend/freeze/unfreeze` + 家庭池 `FamilyPlatformPointsService`;`UnlockGateService` 已实现关卡奖励发 CF 值(幂等) | ★★★ 复用 earn() 发奖励 | | 优惠券 | `Coupon`/`UserCoupon`/`CouponController`(exchange/claim) | ★★★ 备用 | | 通知 | `NoticeController` 仅 `/list`(GET,且不合规),无主动通知 | ★ 需新建通知表+写入+列表接口 | ## 三、数据模型设计 ### 3.1 新增 `problem_domains`(问题域表) ```sql CREATE TABLE IF NOT EXISTS problem_domains ( id BIGINT AUTO_INCREMENT PRIMARY KEY, code VARCHAR(50) NOT NULL COMMENT '唯一编码: weight_loss/sleep/constipation', name VARCHAR(50) NOT NULL COMMENT '名称: 减肥/睡眠/便秘', icon VARCHAR(255) DEFAULT '' COMMENT '图标', description VARCHAR(500) DEFAULT '' COMMENT '一句话描述', flow_intro_json TEXT COMMENT '服务流程介绍(7步) JSON', survey_template_id BIGINT DEFAULT NULL COMMENT '专项调研问卷模板ID(SurveyTemplate.id)', content_tags VARCHAR(500) DEFAULT '' COMMENT '内容标签,逗号分隔(过滤文章/知识库)', recommended_product_ids VARCHAR(500) DEFAULT '' COMMENT '推荐产品ID,逗号分隔(Product.id)', task_template_package_ids VARCHAR(500) DEFAULT '' COMMENT '套餐绑定的任务模板包ID(TaskTemplatePackage.id)', reward_cf_value INT DEFAULT 0 COMMENT '全部完成奖励CF值', status TINYINT DEFAULT 1 COMMENT '1启用 0停用', sort_order INT DEFAULT 0, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, UNIQUE KEY uk_code (code) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='问题域定义(改版v1)'; ``` ### 3.2 新增 `user_intents`(用户意图/旅程表) ```sql CREATE TABLE IF NOT EXISTS user_intents ( id BIGINT AUTO_INCREMENT PRIMARY KEY, user_id BIGINT NOT NULL COMMENT '用户ID', intent_type VARCHAR(20) DEFAULT '' COMMENT 'A/B/C 用户类型', problem_domain_code VARCHAR(50) DEFAULT '' COMMENT '问题域编码(仅C类)', journey_stage INT DEFAULT 0 COMMENT '旅程阶段 0-7,语义见下方状态机', stage_updated_at DATETIME DEFAULT NULL COMMENT '最近阶段变化时间', survey_template_id BIGINT DEFAULT NULL COMMENT '最近作答问卷模板ID', survey_submitted_at DATETIME DEFAULT NULL COMMENT '最近问卷提交时间', survey_result_json TEXT COMMENT '问卷答案→推荐结果快照', created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, UNIQUE KEY uk_user (user_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户意图与服务旅程(改版v1)'; ``` **journey_stage 状态机(C类,0-7)**: | stage | 语义 | 进入条件 | 推进动作 | |-------|------|----------|----------| | 0 | 已选择问题域,未看流程 | 用户选择 C 类+问题域 | 打开流程介绍页 | | 1 | 已看流程介绍 | 流程介绍页曝光完成 | 提交调研 | | 2 | 调研已提交 | 调研提交成功 | 购买套餐 | | 3 | 已购买 | 支付回调成功 | 管理员发货 | | 4 | 试剂盒已发/样本已收 | 物流状态更新 | 报告生成 | | 5 | 报告已出 | completeAnalysis 完成 | 用户确认方案 | | 6 | 方案已确认,任务已生成 | 方案确认接口 | 任务全部完成 | | 7 | 任务完成,CF奖励已发 | 奖励发放成功 | —(终态,展示回馈) | A类简化:0=已选A类,1=已购测评/检测,2=报告已出,3=方案确认,4=任务完成。B类简化:0=已选B类,1=问卷已答(此后首页按结果定向展示内容)。 ### 3.2b 通知表与既有 `notices` 的边界 - `notices`(`Notice.java`, @TableName("notices")):**平台级公告**,管理员发布(platform/activity/promotion),全员可见,`NoticeController` 仅 GET /list(遗留不合规,不动)。 - `user_notifications`(新增):**用户级主动通知**,按 user_id 定向(报告完成/奖励到账/物流变化),带 ref_type/ref_id 可跳转。二者并存不冲突。 ### 3.3 Task 表加会员字段 ```sql ALTER TABLE task ADD COLUMN member_only TINYINT DEFAULT 0 COMMENT '1=会员任务(方案生成),执行需会员'; ``` ### 3.4 新增 `user_notifications`(站内通知表) ```sql CREATE TABLE IF NOT EXISTS user_notifications ( id BIGINT AUTO_INCREMENT PRIMARY KEY, user_id BIGINT NOT NULL COMMENT '接收用户ID', type VARCHAR(30) DEFAULT 'report_ready' COMMENT 'report_ready/reward_granted/system', title VARCHAR(200) NOT NULL, content VARCHAR(1000) DEFAULT '', ref_type VARCHAR(30) DEFAULT '' COMMENT '关联对象类型: report/package/task', ref_id BIGINT DEFAULT NULL COMMENT '关联对象ID', is_read TINYINT DEFAULT 0, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, INDEX idx_user_read (user_id, is_read) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='站内通知(改版v1)'; ``` ### 3.5 套餐/物流状态扩展(复用 PackageOrder / ProductOrder) - `package_orders` 表(`entity/PackageOrder.java` 已存在,含 userId/familyId/packageId/contactName/contactPhone/contactAddress)加: - `logistics_status VARCHAR(20) DEFAULT 'none'`(none/kit_shipped/kit_received/sample_shipped/sample_received) - `tracking_no VARCHAR(100) DEFAULT ''` ### 3.6 调研问卷 → 推荐结果映射 `SurveyTemplate.questionsJson` 题目结构扩展:每题的 option 支持 `resultTags`: ```json [ {"text": "您的睡眠问题持续多久了?", "options": [ {"text": "1-3个月", "resultTags": "短期,轻中度"}, {"text": "半年以上", "resultTags": "长期,重度"} ]} ] ``` 后端提交问卷时汇总所有选中 option 的 resultTags + 问题域 code,返回推荐产品列表快照,存入 `user_intents.survey_result_json`。 ## 四、后端改动清单(cfc-backend) ### 阶段1:C类问题导向型闭环(优先交付) | # | 文件 | 改动 | 验证 | |---|------|------|------| | B1 | `entity/ProblemDomain.java` | 新实体(§3.1) | compile | | B2 | `mapper/ProblemDomainMapper.java` | 新 Mapper | compile | | B3 | `entity/UserIntent.java` | 新实体(§3.2) | compile | | B4 | `mapper/UserIntentMapper.java` | 新 Mapper | compile | | B5 | `entity/UserNotification.java` | 新实体(§3.4) | compile | | B6 | `mapper/UserNotificationMapper.java` | 新 Mapper | compile | | B7 | `entity/Task.java` | 加 `memberOnly` 字段 | compile | | B8 | `config/DatabaseInitializer.java` | 迁移:3 张新表 + task.member_only + package_order 物流字段 | compile | | B9 | `resources/schema.sql` | 同步建表语句 | — | | B10 | `controller/ProblemDomainController.java` | 接口:`POST /api/problem-domain/list`(启用中,含问卷模板+推荐产品+任务模板) | compile | | B11 | `controller/UserIntentController.java` | 接口:`POST /api/user-intent/get`(当前意图) / `POST /api/user-intent/choose`(首次选择A/B/C) / `POST /api/user-intent/update-stage`(旅程推进) | compile | | B12 | `controller/UserNotificationController.java` | 接口:`POST /api/notification/list` / `POST /api/notification/read` | compile | | B13 | `controller/ProblemSurveyController.java` | 接口:`POST /api/problem-survey/submit`(提交调研→汇总resultTags→查推荐产品→存快照→返回推荐列表) | compile | | B14 | `controller/ProblemPackageController.java` | 接口:`POST /api/problem-package/detail`(套餐详情:介绍/使用方式/包含检测/任务模板/奖励说明) | compile | | B15 | `controller/TaskController.java` | 补会员校验:`/{id}/complete`、`/accept` 时若 `task.memberOnly==1` 且非会员 → 拒绝(提示开通会员) | compile | | B16 | `service/DanReportService.completeAnalysis`(报告确认处) | 报告完成解析后:写 `user_notifications`(report_ready) + 更新 `user_intents.journey_stage`=5 | compile | | B17 | `service/ProblemCompletionService.java` | 新 Service:任务全部完成后发放 CF 值。**奖励对象:家庭池(FamilyPlatformPointsService.earn,familyId 维度)**,金额=问题域配置 reward_cf_value;幂等:按 (familyId, problemDomainCode, 'completion') 查唯一发放记录;写通知(reward_granted) + 更新旅程 stage=7 | compile | | B18 | `entity/PackageOrder.java` | 加 `logisticsStatus` / `trackingNo`(表 package_orders) | compile | | B19 | `controller/LogisticsController.java` | 接口:`POST /api/logistics/update`(管理端发货/收样) / `POST /api/logistics/my`(用户查状态) | compile | ### 阶段2:A类会员任务解锁 | # | 文件 | 改动 | |---|------|------| | B20 | `service/TaskPlanService`(任务实例生成处)+ `TaskService.createSingleTask` | 方案/套餐确认生成任务实例时标记 `memberOnly=1`;`createSingleTask` 从 DTO 透传 memberOnly | | B21 | `service/RepeatTaskGenerator` | 重复任务复制模板时**透传 memberOnly 字段**(否则方案任务实例的会员标记丢失) | | B22 | `TaskController.create` | 未缴费用户自建任务:`memberOnly=0`,不校验会员(确认现有 create 已放行) | ### 阶段3:B类问卷引流 | # | 文件 | 改动 | |---|------|------| | B23 | `SurveyTemplate` 扩展 | questionsJson 支持 resultTags;`getActiveTemplates` 支持按问题域过滤 | | B24 | `controller/ContentFilterController.java` | 接口:`POST /api/content/by-tags`(按 resultTags + 问题域 code 过滤文章/知识库/饮食推荐) | ## 五、前端改动清单(cfc-frontend) ### 阶段1:C类闭环 | # | 文件 | 改动 | |---|------|------| | F1 | `pages/index-home/index.vue` | **首页重构**:登录后顶部"旅程状态卡"(进度+下一步);未选择过意图的用户弹"首次选择"层(A直达/B问卷/C问题域) | | F2 | `components/intent-picker.vue`(新) | 首次选择弹层:三个入口卡片 | | F3 | `components/journey-card.vue`(新) | 旅程进度条 + 下一步动作按钮(按 user_intents 渲染) | | F4 | `pages/problem/domain-list.vue`(新) | 问题域列表页(3个卡片) | | F5 | `pages/problem/flow-intro.vue`(新) | 服务流程介绍页(7步,来自 flow_intro_json) | | F6 | `pages/problem/survey.vue`(新) | 专项调研页(复用 survey-questionnaire 模式,提交走 problem-survey/submit) | | F7 | `pages/problem/package-match.vue`(新) | 调研结果→推荐套餐列表(只显示相关) | | F8 | `pages/problem/package-detail.vue`(新) | 套餐详情(介绍/使用方式/包含检测/任务模板/奖励)→ 购买按钮 | | F9 | `pages/problem/logistics.vue`(新) | 试剂盒寄送/样本寄回状态 | | F10 | `pages/problem/plan-confirm.vue`(新) | 报告出来后查看方案 → 确认 → 生成任务 | | F11 | `pages/notification/index.vue`(新) | 站内通知列表(报告完成/奖励到账) | | F12 | `pages/tasks/tasks.vue` | 会员任务角标(memberOnly 显示🔒,点击提示开通会员) | | F13 | `utils/api.js` | 新接口封装(problem-domain/user-intent/notification/problem-survey/problem-package/logistics) | ### 阶段2:A类 | # | 文件 | 改动 | |---|------|------| | F14 | `pages/index-home/index.vue` | 入口A直达"测评/检测选购页" | | F15 | 方案确认页复用 F10 | A类报告出方案→确认→生成任务(带 memberOnly) | ### 阶段3:B类 | # | 文件 | 改动 | |---|------|------| | F16 | `pages/problem/quick-survey.vue`(新) | 5-8题轻问卷 | | F17 | `pages/index-home/index.vue` | 按调研结果定向展示科普内容模块 | ## 六、管理端改动清单(cfc-web) | # | 文件 | 改动 | |---|------|------| | W1 | `views/admin/ProblemDomainManage.vue`(新) | 问题域 CRUD:编码/名称/图标/描述/流程介绍(7步编辑)/绑定问卷模板/内容标签/推荐产品/任务模板包/奖励CF值 | | W2 | 套餐管理增强 | 绑定检测项目、任务模板包、完成奖励CF值 | | W3 | 通知模板管理 | report_ready / reward_granted 文案配置(可选) | | W4 | 物流管理 | 试剂盒发货/样本签收状态更新(可选,后端接口已备) | ## 七、实施顺序(里程碑) | 里程碑 | 内容 | 验收标准 | |--------|------|----------| | M1 数据层 | B1-B9 | mvn clean compile 通过;3 张新表 + task.member_only 迁移幂等 | | M2 C类后端接口 | B10-B19 | compile 通过;关键接口(survey submit→推荐、报告完成→通知+旅程推进、任务完成→CF奖励)逻辑可测 | | M3 C类前端闭环 | F1-F13 + W1 | 用户在开发者工具可走通:选减肥→流程介绍→调研→套餐→购买→物流→通知→方案确认→任务→完成得CF值 | | M4 A类会员任务 | B20-B21 + F14-F15 | 方案任务带锁,非会员执行被拦截;自建任务免费可用 | | M5 B类问卷引流 | B22-B23 + F16-F17 | 观望用户填问卷后首页只显示相关内容 | ## 八、风险与注意事项 1. **首次选择弹层**:必须在登录后数据加载前弹出一次,且"跳过"不得导致下次不再弹出(storage 标记 `intent_skipped`,弹层关闭时写标记但 user_intents 未创建 → 下次仍弹)。决策1要求"未选过就要弹"。**teacher(规划师)角色不弹**(服务商不是 C 类客户,仅 parent/child 视角弹)。 2. **memberOnly 校验**:校验点在 TaskController complete/accept,需同时覆盖规划师批量审核路径(GuideFamilyTaskController)与家长代完成路径(complete-parent)。 3. **CF 奖励幂等 + 归属**:按 (familyId, problemDomainCode, 'completion') 唯一记录防重复发放(参照 UnlockGateService 已实现模式);**奖励进家庭池**(FamilyPlatformPointsService),不落个人池,避免"执行者是孩子、购买者是家长"的归属争议。 4. **问卷 resultTags**:老模板无 resultTags 时兼容(option 是纯字符串),解析器需双态处理。 5. **小程序规范**:新页面全部 Options API、禁止可选链、禁止 :key 表达式、日期用 parseDate、路由用 POST。 6. **通知合规**:`NoticeController` 现有 `/list` 是 GET(不合规遗留),新建的 `UserNotificationController` 一律 POST;不动旧接口。 7. **问卷模板 JSON 迁移**:现有调研模板数据结构不含 resultTags,提交接口需对"无 resultTags"模板返回空推荐(不报错)。 8. **物流状态**:已确认 `package_orders` 表存在(`PackageOrder.java`),物流字段加其上;kit_shipped 即"试剂盒已寄出"。 9. **会员判断复用**:调 `MembershipController.can-use` 或直接查 `FamilyMembership` levelCode != FREE 且未过期。 10. **C类流程承载物**:流程描述页/套餐详情页写死"菌群检测试剂盒"是错误的——**套餐(TaskTemplatePackage/GuidePackage)是承载物**,flow_intro_json 每步文案可配置,检测项目通过套餐绑定的 assessmentProduct 决定。减肥/睡眠/便秘各自的套餐与检测项在管理端配置,代码不写死。 11. **新增 Controller 前置检查**:新增 ProblemDomainController/UserIntentController 等前,先跑路由重复检查(AGENTS.md 工作流)与 Bean 名冲突检查。