阶段:实施计划 v1.0 | 分支:cfclub | 产品决策已确认(2026-08-13)
现状:小程序首页对所有用户一视同仁地堆内容(商品/活动/文章/任务),未区分用户需求深度,转化链路不清晰。
改版核心:从用户需求出发,先识别用户类型,按需求深度逐步解锁内容与功能,无关内容不展示。
三类用户:
已确认决策:
| 模块 | 现状 | 结论 |
|---|---|---|
| 首页分流 | 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,且不合规),无主动通知 |
★ 需新建通知表+写入+列表接口 |
problem_domains(问题域表)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)';
user_intents(用户意图/旅程表)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=问卷已答(此后首页按结果定向展示内容)。
notices 的边界notices(Notice.java, @TableName("notices")):平台级公告,管理员发布(platform/activity/promotion),全员可见,NoticeController 仅 GET /list(遗留不合规,不动)。user_notifications(新增):用户级主动通知,按 user_id 定向(报告完成/奖励到账/物流变化),带 ref_type/ref_id 可跳转。二者并存不冲突。ALTER TABLE task ADD COLUMN member_only TINYINT DEFAULT 0 COMMENT '1=会员任务(方案生成),执行需会员';
user_notifications(站内通知表)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)';
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 ''SurveyTemplate.questionsJson 题目结构扩展:每题的 option 支持 resultTags:
[
{"text": "您的睡眠问题持续多久了?", "options": [
{"text": "1-3个月", "resultTags": "短期,轻中度"},
{"text": "半年以上", "resultTags": "长期,重度"}
]}
]
后端提交问卷时汇总所有选中 option 的 resultTags + 问题域 code,返回推荐产品列表快照,存入 user_intents.survey_result_json。
| # | 文件 | 改动 | 验证 |
|---|---|---|---|
| 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 |
| # | 文件 | 改动 |
|---|---|---|
| B20 | service/TaskPlanService(任务实例生成处)+ TaskService.createSingleTask |
方案/套餐确认生成任务实例时标记 memberOnly=1;createSingleTask 从 DTO 透传 memberOnly |
| B21 | service/RepeatTaskGenerator |
重复任务复制模板时透传 memberOnly 字段(否则方案任务实例的会员标记丢失) |
| B22 | TaskController.create |
未缴费用户自建任务:memberOnly=0,不校验会员(确认现有 create 已放行) |
| # | 文件 | 改动 |
|---|---|---|
| B23 | SurveyTemplate 扩展 |
questionsJson 支持 resultTags;getActiveTemplates 支持按问题域过滤 |
| B24 | controller/ContentFilterController.java |
接口:POST /api/content/by-tags(按 resultTags + 问题域 code 过滤文章/知识库/饮食推荐) |
| # | 文件 | 改动 |
|---|---|---|
| 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) |
| # | 文件 | 改动 |
|---|---|---|
| F14 | pages/index-home/index.vue |
入口A直达"测评/检测选购页" |
| F15 | 方案确认页复用 F10 | A类报告出方案→确认→生成任务(带 memberOnly) |
| # | 文件 | 改动 |
|---|---|---|
| F16 | pages/problem/quick-survey.vue(新) |
5-8题轻问卷 |
| F17 | pages/index-home/index.vue |
按调研结果定向展示科普内容模块 |
| # | 文件 | 改动 |
|---|---|---|
| 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 | 观望用户填问卷后首页只显示相关内容 |
intent_skipped,弹层关闭时写标记但 user_intents 未创建 → 下次仍弹)。决策1要求"未选过就要弹"。teacher(规划师)角色不弹(服务商不是 C 类客户,仅 parent/child 视角弹)。NoticeController 现有 /list 是 GET(不合规遗留),新建的 UserNotificationController 一律 POST;不动旧接口。package_orders 表存在(PackageOrder.java),物流字段加其上;kit_shipped 即"试剂盒已寄出"。MembershipController.can-use 或直接查 FamilyMembership levelCode != FREE 且未过期。