优先级: P0
预计工时: 后端 3d + 迁移 1d
状态: 设计待确认
日期: 2026-09-04
关联文档: 2026-09-04-task-system-unification-design.md(统一任务系统总设计,本设计为其"方案转任务"子模块深化)
系统存在 4 套并行的"方案转任务"体系,各自独立演进,source_type 语义混乱:
| # | 方案体系 | 方案表 | 任务来源 | source_type | source_id 指向 | 状态机 | 生成方法 |
|---|---|---|---|---|---|---|---|
| 1 | 套餐方案 | task_plan_instances |
task_plan_items(镜像) |
plan |
task_plan_instances.id |
active(无审核) | TaskPlanService.generatePlanTasks |
| 2 | 测评方案 | task_plan_instances |
task_template_items(直读) |
plan |
task_plan_instances.id |
generated→reviewed→active | PlanActivationService.activate |
| 3 | 健康方案 | health_plans |
方案文本正则解析 / plan_json | plan |
health_plans.id |
draft→pending_review→published | HealthPlanServiceImpl.generateDailyTasksFromPlan |
| 4 | 认知训练方案 | training_plans |
training_plan_items |
未设 | — | draft→published | TrainingPlanService.deployPlan |
source_type='plan' 被 3 套体系共用,但 source_id 指向 3 张不同的表(task_plan_instances / health_plans / 无)。导致:
ProblemCompletionService(第 106-110 行)按 source_type='plan' + source_id IN (planIds) 统计完成度时,planIds 来自 task_plan_instances,但健康方案任务也标 source_type='plan',若 source_id 撞上 task_plan_instances.id 会被误统计。HealthPlanServiceImpl.getPlanTasks(第 196 行)按 source_type='plan' + source_id=healthPlanId 查任务,可能误捞套餐方案任务。deployPlan 走 taskService.createTask 后任务无法溯源。task_plan_items vs task_template_items)、deadline 语义不同(方案结束日 vs 当天 23:59:59)、familyMemberId 一个设一个不设。| 决策项 | 结论 |
|---|---|
| 覆盖范围 | 全部 4 套方案体系 |
| source_type 策略 | 拆分枚举:新增 health_plan / training_plan,source_type 与 source_id 一一对应 |
| 套餐/测评方案 | 保留 plan 枚举(同表 task_plan_instances),收敛为单一任务生成器 |
| 任务来源 | 套餐/测评统一从 task_template_items 读取(task_plan_items 降级为审计快照) |
| deadline 语义 | 统一为当天 23:59:59(对齐 activate 现有语义) |
familyMemberId |
统一设置 |
| 状态机 | 套餐/测评统一 generated → reviewed → active |
| 前端家长端 | 本次不做(由其他进程负责) |
tasks.source_type 最终枚举(在总设计文档第 3 节基础上扩展):
| source_type | 含义 | source_id 指向 |
|---|---|---|
self |
用户创建给自己 | — |
assigned |
他人分配(家庭/规划师) | — |
plan |
套餐/测评方案实例化 | task_plan_instances.id |
health_plan |
健康方案实例化(新增) | health_plans.id |
training_plan |
认知训练方案实例化(新增) | training_plans.id |
onboarding |
新人引导 | — |
ai |
AI 对话生成 | conversation_id |
template |
模板快速创建 | template_id |
article |
文章阅读联动 | article_id |
activity |
活动签到联动 | activity_id |
purchase |
购买/消费联动 | — |
关键收益:拆分后
source_type与source_id一一对应,ProblemCompletionService只查source_type='plan'天然隔离健康方案任务,无需额外过滤。
tasks 表source_type 列当前为 VARCHAR(20),需扩展注释说明新增枚举(无需改列类型,20 足够容纳 training_plan)。无 DDL 变更,仅语义扩展。
task_plan_instances 表(补齐缺失列)TaskPlanInstance 实体已声明以下字段,但 schema.sql 建表语句缺失,需补齐(否则 review/activate 写这些字段会 Unknown column 报错):
| 字段 | 类型 | 说明 |
|---|---|---|
source |
VARCHAR(20) | manual/assessment/template |
source_result_id |
BIGINT | 关联测评结果 |
remark |
TEXT | 方案备注 |
reviewed_by |
BIGINT | 审核人 |
reviewed_at |
DATETIME | 审核时间 |
review_comment |
TEXT | 审核意见 |
confirmed_by |
BIGINT | 确认人 |
confirmed_at |
DATETIME | 确认时间 |
activated_at |
DATETIME | 激活时间 |
task_plan_items 表降级为审计快照:保留 applyPackage 时的写入,不再作为任务生成来源。不物理删除(保留只读备份,符合总设计第 4.4 节)。
在 TaskPlanService 新增统一方法,作为套餐/测评方案"方案→任务"的唯一入口:
/**
* 统一方案任务生成器:套餐/测评方案激活时调用。
* 幂等:sourceType=plan & sourceId=planId 已存在任务则跳过。
* 任务来源:task_template_items(按 sort_order)。
* deadline:当天 23:59:59;familyMemberId:统一设置。
*/
@Transactional
public int generateTasksFromTemplate(TaskPlanInstance plan, Long operatorId)
PlanActivationService.activate 和 ProblemPackageController.confirm 都改为调用它,消除 generatePlanTasks 与 activate 的分裂。
| 入口 | 改造前 | 改造后 |
|---|---|---|
applyPackage |
直接建 active |
建 generated |
review |
要求 generated |
不变(generated → reviewed/rejected) |
activate |
要求 reviewed |
不变(reviewed → active),内部改用统一生成器 |
confirm(家长自助) |
建 active + generatePlanTasks | 建 generated → 直接置 active(自助跳过审核)+ 统一生成器 |
HealthPlanServiceImpl.generateDailyTasksFromPlan 中 task.setSourceType("plan") → task.setSourceType("health_plan")getPlanTasks 查询条件 source_type='plan' → source_type='health_plan'health_planTrainingPlanService.deployPlan 中 taskService.createTask 后,补设 sourceType="training_plan" + sourceId=planIdCreateTaskDTO 增加 sourceType/sourceId 字段,TaskService.createSingleTask 透传MarketController.purchasePackage(入口3):补幂等(同家庭同套餐已有实例则复用)+ 补调任务生成,消除"active 但零任务"空壳TaskPlanService.cancelPlan:取消时级联清理 sourceType='plan' & sourceId=planId 的未完成任务(pending 状态)在 DatabaseInitializer.runMigrations() 新增迁移:
task_plan_instances 缺失列(ensureColumn 逐个添加,见 4.2)存量健康方案任务改枚举:
UPDATE tasks SET source_type = 'health_plan'
WHERE source_type = 'plan'
AND source_id IN (SELECT id FROM health_plans);
存量认知训练方案任务补枚举:
UPDATE tasks SET source_type = 'training_plan'
WHERE source_id IN (SELECT task_id FROM training_plan_tasks);
同步 schema.sql:task_plan_instances 建表语句补齐缺失列
注意:迁移 2/3 依赖
health_plans/training_plan_tasks表存在,需先确认表存在再执行(幂等 try-catch)。
新增 TaskPlanServiceTest(或集成测试)覆盖:
generated 不能直接 activate、reviewed 才能 activatesource_type='health_plan',ProblemCompletionService 不误统计source_type='training_plan' 可溯源| 不做 | 原因 |
|---|---|
| 前端家长端 plans 页面 | 其他进程负责 |
| 健康方案/认知训练方案状态机统一 | 各自状态机已独立成熟,本次只统一 source_type 溯源 |
task_plan_items 物理删除 |
保留只读备份 |
| 家庭挑战/五维打卡合并 | 总设计文档已明确本次不合并 |
tasks.source_type 支持 health_plan / training_plan 新枚举generateTasksFromTemplate,deadline=当天 23:59:59,familyMemberId 统一设置generated → reviewed → activesource_type='health_plan',ProblemCompletionService 不再误统计source_type='training_plan' 可溯源task_plan_instances 缺失列补齐,review/activate 不再 Unknown columnmvn clean compile 编译验证