|
|
@@ -0,0 +1,691 @@
|
|
|
+# DAN 测评商城化改造 — 实施计划
|
|
|
+
|
|
|
+> 版本: v1.0
|
|
|
+> 日期: 2026-07-10
|
|
|
+> 状态: 待实施
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 业务模型
|
|
|
+
|
|
|
+```
|
|
|
+供应商管理员 ──维护──> 商品(单包/套餐)
|
|
|
+ │
|
|
|
+ ▼
|
|
|
+商城体系 ──购买──> 家长
|
|
|
+ │
|
|
|
+ ▼
|
|
|
+发放测评额度(采购与测评执行解耦)
|
|
|
+ │
|
|
|
+ ▼
|
|
|
+预约 → 确定具体测评项目 → 执行测评
|
|
|
+ │
|
|
|
+ ▼
|
|
|
+报告(规划师录入 / 家长上传 / 后续API自动获取)
|
|
|
+ │
|
|
|
+ ▼
|
|
|
+规划师给出结构化指导意见
|
|
|
+ │
|
|
|
+ ▼
|
|
|
+系统自动生成个性化任务方案
|
|
|
+ │
|
|
|
+ ▼
|
|
|
+规划师审核方案 ──> 家长确认方案 ──> 执行跟踪
|
|
|
+ │ │
|
|
|
+ └── 驳回/修改 ←────────────────┘
|
|
|
+ │
|
|
|
+ ▼
|
|
|
+ 方案完成 → 复测提醒 → 再次购买/测评
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 全五阶段依赖关系
|
|
|
+
|
|
|
+```
|
|
|
+阶段一 (商品化)
|
|
|
+ ↓
|
|
|
+阶段二 (采购与执行解耦) ←─ 依赖阶段一的商品购买流程
|
|
|
+ ↓
|
|
|
+阶段三 (报告双通道) ←─ 独立,可与阶段二并行
|
|
|
+ ↓
|
|
|
+阶段四 (方案生成引擎) ←─ 依赖阶段三的完整结果数据
|
|
|
+ ↓
|
|
|
+阶段五 (审核→确认→执行) ←─ 依赖阶段四的方案生成
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 阶段一:测评商品化
|
|
|
+
|
|
|
+### 目标
|
|
|
+
|
|
|
+将 DAN 测评单包/套餐作为 `Product` 存在于商城体系中,由供应商管理员维护。
|
|
|
+
|
|
|
+### 实体扩展
|
|
|
+
|
|
|
+#### Product 类型扩展
|
|
|
+
|
|
|
+```java
|
|
|
+// entity/Product.java — 新增常量
|
|
|
+public static final String TYPE_ASSESSMENT = "assessment";
|
|
|
+```
|
|
|
+
|
|
|
+`productType` 字段已存在,无需改表。
|
|
|
+
|
|
|
+#### AssessmentProduct 扩展实体
|
|
|
+
|
|
|
+**DB 迁移(`schema.sql` + `DatabaseInitializer`)**:
|
|
|
+
|
|
|
+```sql
|
|
|
+CREATE TABLE IF NOT EXISTS assessment_products (
|
|
|
+ id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
|
|
+ product_id BIGINT NOT NULL COMMENT '关联products表',
|
|
|
+ assessment_type VARCHAR(20) NOT NULL COMMENT 'single=单包, bundle=套餐',
|
|
|
+ total_sessions INT NOT NULL DEFAULT 1 COMMENT '包含测评次数',
|
|
|
+ validity_days INT NOT NULL DEFAULT 365 COMMENT '有效期(天)',
|
|
|
+ guide_scope VARCHAR(50) DEFAULT 'all' COMMENT '规划师范围: all/assigned/auto',
|
|
|
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
|
+ updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
|
+ INDEX idx_product_id (product_id)
|
|
|
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='测评商品扩展信息';
|
|
|
+```
|
|
|
+
|
|
|
+**实体**:
|
|
|
+
|
|
|
+```java
|
|
|
+// entity/AssessmentProduct.java
|
|
|
+@Data
|
|
|
+@TableName("assessment_products")
|
|
|
+public class AssessmentProduct implements Serializable {
|
|
|
+ @TableId(type = IdType.AUTO)
|
|
|
+ private Long id;
|
|
|
+ private Long productId;
|
|
|
+ private String assessmentType; // single / bundle
|
|
|
+ private Integer totalSessions;
|
|
|
+ private Integer validityDays;
|
|
|
+ private String guideScope; // all / assigned / auto
|
|
|
+ private Date createdAt;
|
|
|
+ private Date updatedAt;
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+#### DTO
|
|
|
+
|
|
|
+```java
|
|
|
+// dto/ProductCreateRequest.java
|
|
|
+@Data
|
|
|
+public class ProductCreateRequest {
|
|
|
+ private Product product;
|
|
|
+ private AssessmentProduct assessmentExt; // productType=assessment 时必填
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### Service
|
|
|
+
|
|
|
+```java
|
|
|
+// service/AssessmentProductService.java
|
|
|
+@Service
|
|
|
+public class AssessmentProductService {
|
|
|
+ @Resource private AssessmentProductMapper mapper;
|
|
|
+
|
|
|
+ public AssessmentProduct getByProductId(Long productId) { ... }
|
|
|
+
|
|
|
+ @Transactional
|
|
|
+ public void saveOrUpdate(Long productId, AssessmentProduct ext) {
|
|
|
+ mapper.delete(new LambdaQueryWrapper<AssessmentProduct>()
|
|
|
+ .eq(AssessmentProduct::getProductId, productId));
|
|
|
+ ext.setId(null);
|
|
|
+ ext.setProductId(productId);
|
|
|
+ mapper.insert(ext);
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### Controller 改造
|
|
|
+
|
|
|
+`AdminProductController.create()` 改造:当 `productType=assessment` 时,同时保存 `AssessmentProduct` 扩展信息。
|
|
|
+
|
|
|
+### 管理端前端
|
|
|
+
|
|
|
+新建 `cfc-web/views/admin/assessment-products.vue`:
|
|
|
+
|
|
|
+- 测评商品专用管理页
|
|
|
+- 商品表单:类型选择"测评"时展开额外字段(测评类型、次数、有效期、规划师范围)
|
|
|
+- 商品列表:类型标识、次数、状态列
|
|
|
+
|
|
|
+### 购买流程
|
|
|
+
|
|
|
+测评商品作为普通商品在商城展示,走现有 `ProductOrder` 体系:
|
|
|
+
|
|
|
+```
|
|
|
+用户浏览商城 → 点击测评商品 → 商品详情页
|
|
|
+ ↓
|
|
|
+ 选择购买数量 → 加入购物车/立即购买
|
|
|
+ ↓
|
|
|
+ 填写购买信息
|
|
|
+ ↓
|
|
|
+ 提交 → ProductOrder.create() → payment → paySuccess()
|
|
|
+```
|
|
|
+
|
|
|
+`ProductOrderService.paySuccess()` 中判断 `productType=assessment` 时,调用 `AssessmentQuotaService.grantQuota()`(阶段二实现,先留桩)。测评商品为虚拟商品,支付成功自动确认收货。
|
|
|
+
|
|
|
+### 验证标准
|
|
|
+
|
|
|
+```
|
|
|
+□ 管理员可在管理端创建/编辑/上下架测评商品
|
|
|
+□ 测评商品在商城展示,用户可下单购买
|
|
|
+□ 购买后走 ProductOrder 流程,productType='assessment'
|
|
|
+□ 管理端订单列表可区分测评商品订单
|
|
|
+□ 供应商可管理自己的测评商品
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 阶段二:采购与测评执行解耦
|
|
|
+
|
|
|
+### 目标
|
|
|
+
|
|
|
+购买测评商品后获得"测评额度",具体测什么在测评时确定,而不是购买时绑定。
|
|
|
+
|
|
|
+### 测评额度表 assessment_quotas
|
|
|
+
|
|
|
+**DB 迁移**:
|
|
|
+
|
|
|
+```sql
|
|
|
+CREATE TABLE IF NOT EXISTS assessment_quotas (
|
|
|
+ id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
|
|
+ quota_no VARCHAR(32) NOT NULL COMMENT '额度编号',
|
|
|
+ family_id BIGINT NOT NULL COMMENT '家庭ID',
|
|
|
+ child_id BIGINT COMMENT '指定孩子ID(NULL=不限)',
|
|
|
+ product_order_id BIGINT NOT NULL COMMENT '来源订单ID',
|
|
|
+ product_id BIGINT NOT NULL COMMENT '商品ID',
|
|
|
+ product_name VARCHAR(100) NOT NULL COMMENT '商品名快照',
|
|
|
+ total_sessions INT NOT NULL DEFAULT 1 COMMENT '总次数',
|
|
|
+ remaining_sessions INT NOT NULL DEFAULT 1 COMMENT '剩余次数',
|
|
|
+ validity_start DATETIME NOT NULL COMMENT '有效期开始',
|
|
|
+ validity_end DATETIME NOT NULL COMMENT '有效期截止',
|
|
|
+ status VARCHAR(20) NOT NULL DEFAULT 'active' COMMENT 'active/expired/used_all/cancelled',
|
|
|
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
|
+ updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
|
+ INDEX idx_family (family_id),
|
|
|
+ INDEX idx_order (product_order_id),
|
|
|
+ UNIQUE KEY uk_quota_no (quota_no)
|
|
|
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='测评额度表';
|
|
|
+```
|
|
|
+
|
|
|
+**实体**:
|
|
|
+
|
|
|
+```java
|
|
|
+// entity/AssessmentQuota.java
|
|
|
+@Data
|
|
|
+@TableName("assessment_quotas")
|
|
|
+public class AssessmentQuota implements Serializable {
|
|
|
+ @TableId(type = IdType.AUTO)
|
|
|
+ private Long id;
|
|
|
+ private String quotaNo;
|
|
|
+ private Long familyId;
|
|
|
+ private Long childId;
|
|
|
+ private Long productOrderId;
|
|
|
+ private Long productId;
|
|
|
+ private String productName;
|
|
|
+ private Integer totalSessions;
|
|
|
+ private Integer remainingSessions;
|
|
|
+ private Date validityStart;
|
|
|
+ private Date validityEnd;
|
|
|
+ private String status; // active / expired / used_all / cancelled
|
|
|
+ private Date createdAt;
|
|
|
+ private Date updatedAt;
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### 测评执行记录表 assessment_executions
|
|
|
+
|
|
|
+**DB 迁移**:
|
|
|
+
|
|
|
+```sql
|
|
|
+CREATE TABLE IF NOT EXISTS assessment_executions (
|
|
|
+ id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
|
|
+ quota_id BIGINT NOT NULL COMMENT '关联额度ID',
|
|
|
+ child_id BIGINT NOT NULL COMMENT '被测评孩子',
|
|
|
+ guide_id BIGINT COMMENT '执行规划师ID',
|
|
|
+ assessment_type VARCHAR(30) COMMENT '本次具体测评类型(如attention/memory/full)',
|
|
|
+ appointment_id BIGINT COMMENT '关联预约ID',
|
|
|
+ result_id BIGINT COMMENT '关联测评结果ID',
|
|
|
+ status VARCHAR(20) NOT NULL DEFAULT 'pending' COMMENT 'pending/in_progress/completed/cancelled',
|
|
|
+ scheduled_date DATETIME COMMENT '预约执行时间',
|
|
|
+ completed_at DATETIME COMMENT '实际完成时间',
|
|
|
+ notes VARCHAR(500) COMMENT '备注',
|
|
|
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
|
+ updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
|
+ INDEX idx_quota (quota_id),
|
|
|
+ INDEX idx_child (child_id),
|
|
|
+ INDEX idx_appointment (appointment_id)
|
|
|
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='测评执行记录表';
|
|
|
+```
|
|
|
+
|
|
|
+### 额度服务 AssessmentQuotaService
|
|
|
+
|
|
|
+核心方法:
|
|
|
+
|
|
|
+| 方法 | 说明 | 调用方 |
|
|
|
+|------|------|--------|
|
|
|
+| `grantQuota(ProductOrder)` | 支付成功后发放额度 | `ProductOrderService.paySuccess()` |
|
|
|
+| `consumeQuota(quotaId, childId)` | 预约时消耗一次额度 | `AssessmentAppointmentService.createAppointment()` |
|
|
|
+| `getAvailableQuotas(familyId, childId)` | 查询家庭可用额度列表 | 前端展示 |
|
|
|
+| `getQuotaDetail(quotaId)` | 额度使用明细 | 前端展示 |
|
|
|
+
|
|
|
+### 支付回调集成
|
|
|
+
|
|
|
+```java
|
|
|
+// ProductOrderService.paySuccess() 中新增
|
|
|
+if ("assessment".equals(order.getProductType())) {
|
|
|
+ assessmentQuotaService.grantQuota(order);
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### 预约流程改造
|
|
|
+
|
|
|
+改造前:预约时创建订单 + 预约
|
|
|
+改造后:预约时消耗额度 → 创建预约 → 关联执行记录
|
|
|
+
|
|
|
+```java
|
|
|
+// AssessmentAppointmentController.createAppointment() 改造
|
|
|
+// 1. 消耗额度(内含校验)
|
|
|
+int remaining = quotaService.consumeQuota(quotaId, childId);
|
|
|
+// 2. 创建预约(只创建预约,不再创建订单)
|
|
|
+AssessmentAppointment appointment = appointmentService.createAppointment(...);
|
|
|
+// 3. 关联执行记录
|
|
|
+executionService.linkAppointment(quotaId, childId, appointment.getId());
|
|
|
+```
|
|
|
+
|
|
|
+### 旧 Controller 清理
|
|
|
+
|
|
|
+| 端点 | 处理 |
|
|
|
+|------|------|
|
|
|
+| `AssessmentOrderController.*` | 标记 `@Deprecated`,保留兼容 |
|
|
|
+| `DanAssessmentController` 中的订单方法 | 标记 `@Deprecated` |
|
|
|
+
|
|
|
+### 前端:我的额度页面
|
|
|
+
|
|
|
+新建 `pages/assessment/quota.vue`:展示家庭可用额度(剩余次数、有效期、进度条)
|
|
|
+
|
|
|
+**预约流程改造**:`apply.vue` 中先选择额度包 → 选择孩子 → 选择规划师+日期 → 提交
|
|
|
+
|
|
|
+### 验证标准
|
|
|
+
|
|
|
+```
|
|
|
+□ 购买测评商品后自动发放额度到家庭
|
|
|
+□ 家庭可用额度列表 API 返回正确
|
|
|
+□ 预约时消耗额度,剩余次数递减
|
|
|
+□ 额度过期自动标记 expired
|
|
|
+□ 执行记录完整追溯:订单→额度→预约→结果
|
|
|
+□ 前端"我的额度"页面展示所有可用额度
|
|
|
+□ 预约流程改为先选额度再预约
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 阶段三:报告双通道 + 规划师指导意见
|
|
|
+
|
|
|
+### 目标
|
|
|
+
|
|
|
+家长可上传报告,规划师录入结果时附带结构化指导意见,预留 API 自动获取扩展点。
|
|
|
+
|
|
|
+### DanAssessmentResult 增加来源字段
|
|
|
+
|
|
|
+**DB 迁移**:
|
|
|
+
|
|
|
+```sql
|
|
|
+ensureColumn("dan_assessment_results", "source",
|
|
|
+ "VARCHAR(20) DEFAULT 'planner_entry' COMMENT '报告来源: planner_entry/parent_upload/auto_fetch'");
|
|
|
+```
|
|
|
+
|
|
|
+**状态常量**:
|
|
|
+
|
|
|
+```java
|
|
|
+public static final String SOURCE_PLANNER_ENTRY = "planner_entry";
|
|
|
+public static final String SOURCE_PARENT_UPLOAD = "parent_upload";
|
|
|
+public static final String SOURCE_AUTO_FETCH = "auto_fetch";
|
|
|
+```
|
|
|
+
|
|
|
+历史数据回填 `source = 'planner_entry'`。
|
|
|
+
|
|
|
+### 家长端上传报告 API
|
|
|
+
|
|
|
+```java
|
|
|
+@PostMapping("/api/dan-assessment/result/upload")
|
|
|
+public Result<DanAssessmentResult> uploadReport(
|
|
|
+ @RequestParam("file") MultipartFile file,
|
|
|
+ @RequestParam("childId") Long childId,
|
|
|
+ @RequestParam(value = "notes", required = false) String notes) {
|
|
|
+ // 1. 权限校验
|
|
|
+ // 2. 保存文件(FileStorageService)
|
|
|
+ // 3. 基础解析元信息
|
|
|
+ // 4. 创建结果记录(source=parent_upload, status=parent_uploaded)
|
|
|
+ // 5. 异步触发深度解析(OCR)
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### 文件存储服务
|
|
|
+
|
|
|
+```java
|
|
|
+// service/FileStorageService.java
|
|
|
+public String upload(MultipartFile file, String subDir) {
|
|
|
+ // UUID文件名 + 保存到本地文件系统
|
|
|
+ // 返回相对URL
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### 报告解析服务
|
|
|
+
|
|
|
+```java
|
|
|
+// service/ReportParseService.java
|
|
|
+// extractMeta(): 提取文件名、日期等元信息(同步)
|
|
|
+// asyncDeepParse(): 异步OCR深度解析(当前为桩,后续扩展)
|
|
|
+
|
|
|
+// ★ SPI 扩展点:ReportFetchProvider
|
|
|
+public interface ReportFetchProvider {
|
|
|
+ boolean supports(String sourceType);
|
|
|
+ DanAssessmentResult fetch(Long childId, Map<String, Object> params);
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### 规划师指导意见结构化
|
|
|
+
|
|
|
+**DB 迁移**:
|
|
|
+
|
|
|
+```sql
|
|
|
+CREATE TABLE IF NOT EXISTS growth_guidances (
|
|
|
+ id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
|
|
+ result_id BIGINT NOT NULL COMMENT '关联测评结果ID',
|
|
|
+ dimension VARCHAR(30) NOT NULL COMMENT '维度: attention/focus/memory/logic/emotion/general',
|
|
|
+ score INT COMMENT '该维度得分(0-100)',
|
|
|
+ suggestion TEXT NOT NULL COMMENT '建议内容',
|
|
|
+ priority INT DEFAULT 0 COMMENT '优先级(0=普通, 1=重要, 2=紧急)',
|
|
|
+ sort_order INT DEFAULT 0 COMMENT '排序',
|
|
|
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
|
+ updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
|
+ INDEX idx_result (result_id)
|
|
|
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='测评指导意见(结构化)';
|
|
|
+```
|
|
|
+
|
|
|
+**API**:
|
|
|
+
|
|
|
+| 端点 | 方法 | 说明 |
|
|
|
+|------|------|------|
|
|
|
+| `/api/dan-assessment/result/{resultId}/guidance/save` | POST | 保存结构化指导意见 |
|
|
|
+| `/api/dan-assessment/result/{resultId}/guidance` | GET | 获取指导意见 |
|
|
|
+
|
|
|
+### 前端改造
|
|
|
+
|
|
|
+| 页面 | 改动 |
|
|
|
+|------|------|
|
|
|
+| `upload-report.vue`(新建) | 家长上传报告页面(选择孩子、文件、备注)|
|
|
|
+| `results.vue` | 展示报告来源标签(规划师录入/家长上传/系统获取)|
|
|
|
+| `record.vue` | 指导意见改为结构化录入(每个维度独立建议框 + 优先级选择)|
|
|
|
+
|
|
|
+### 规划师确认家长上传报告
|
|
|
+
|
|
|
+```java
|
|
|
+@PostMapping("/api/dan-assessment/result/{resultId}/confirm-upload")
|
|
|
+// 规划师补充结构化评分后确认,status→completed
|
|
|
+```
|
|
|
+
|
|
|
+### 验证标准
|
|
|
+
|
|
|
+```
|
|
|
+□ 测评结果来源字段正确记录
|
|
|
+□ 家长可上传 PDF/JPG 格式报告
|
|
|
+□ 上传后状态为 parent_uploaded,等待规划师确认
|
|
|
+□ 规划师可查看上传的报告文件并补充结构化评分
|
|
|
+□ 指导意见从大文本升级为结构化多维度存储
|
|
|
+□ record.vue 录入界面支持每个维度独立指导意见
|
|
|
+□ 报告列表展示来源标签和图标
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 阶段四:结果→任务方案自动生成引擎
|
|
|
+
|
|
|
+### 架构
|
|
|
+
|
|
|
+```
|
|
|
+DanAssessmentResult + GrowthGuidance[]
|
|
|
+ │
|
|
|
+ ▼
|
|
|
+AssessmentPlanGenerator
|
|
|
+ │
|
|
|
+ ┌───┴───┐
|
|
|
+ ▼ ▼
|
|
|
+ 规则引擎 AI增强(后续SPI)
|
|
|
+ │ │
|
|
|
+ └───┬───┘
|
|
|
+ ▼
|
|
|
+TaskPlanInstance + TaskPlanItem[]
|
|
|
+ │
|
|
|
+ ▼
|
|
|
+ 规划师审核 → 家长确认 → 执行跟踪(阶段五)
|
|
|
+```
|
|
|
+
|
|
|
+### 规则配置表 assessment_plan_rules
|
|
|
+
|
|
|
+**DB 迁移**:
|
|
|
+
|
|
|
+```sql
|
|
|
+CREATE TABLE IF NOT EXISTS assessment_plan_rules (
|
|
|
+ id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
|
|
+ dimension VARCHAR(30) NOT NULL COMMENT '测评维度: attention/focus/memory/logic/emotion',
|
|
|
+ score_min INT NOT NULL COMMENT '分数下限(含)',
|
|
|
+ score_max INT NOT NULL COMMENT '分数上限(含)',
|
|
|
+ template_id BIGINT NOT NULL COMMENT '关联TaskTemplatePackage ID',
|
|
|
+ priority INT DEFAULT 0 COMMENT '优先级',
|
|
|
+ is_active TINYINT(1) DEFAULT 1 COMMENT '是否启用',
|
|
|
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
|
+ updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
|
+ INDEX idx_dimension (dimension),
|
|
|
+ INDEX idx_score (score_min, score_max)
|
|
|
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='方案生成规则';
|
|
|
+```
|
|
|
+
|
|
|
+### 核心引擎 AssessmentPlanGenerator
|
|
|
+
|
|
|
+```java
|
|
|
+// 三步流程:
|
|
|
+// 1. collectScores(result): 从测评结果提取各维度得分
|
|
|
+// 2. matchRules(scores): 规则匹配 → 低分维度→对应训练模板包
|
|
|
+// 3. buildPlan(result, packages): 合并模板 → TaskPlanInstance
|
|
|
+
|
|
|
+// 关键逻辑:
|
|
|
+// - 匹配到多个模板时,取最长周期为主方案,其余合并
|
|
|
+// - 所有维度正常 → 生成维持型方案
|
|
|
+// - 方案状态为 generated(非直接 active)
|
|
|
+// - 方案关联 source_result_id 可追溯
|
|
|
+```
|
|
|
+
|
|
|
+### TaskPlanInstance 扩展
|
|
|
+
|
|
|
+**DB 迁移**:
|
|
|
+
|
|
|
+```sql
|
|
|
+ensureColumn("task_plan_instances", "source",
|
|
|
+ "VARCHAR(20) DEFAULT 'manual' COMMENT '方案来源: manual/assessment/template'");
|
|
|
+ensureColumn("task_plan_instances", "source_result_id",
|
|
|
+ "BIGINT COMMENT '关联测评结果ID(来源为assessment时)'");
|
|
|
+ensureColumn("task_plan_instances", "remark",
|
|
|
+ "TEXT COMMENT '方案备注(含指导意见摘要)'");
|
|
|
+```
|
|
|
+
|
|
|
+### 触发点
|
|
|
+
|
|
|
+| 触发点 | 位置 | 说明 |
|
|
|
+|--------|------|------|
|
|
|
+| 规划师提交结果 | `AssessmentService.recordResult()` | 结果 completed 时自动触发 |
|
|
|
+| 规划师确认家长上传报告 | `DanAssessmentController.confirmUpload()` | 确认后触发 |
|
|
|
+| AI 自动获取报告完成 | `ReportFetchProvider`(后续) | 占位 |
|
|
|
+
|
|
|
+### 预设训练模板
|
|
|
+
|
|
|
+在 `TaskTemplatePackage` 中预置(管理端创建):
|
|
|
+
|
|
|
+| 模板名称 | 维度 | 周期 | 任务示例 |
|
|
|
+|---------|------|------|---------|
|
|
|
+| 注意力基础训练(14天) | attention | 14天 | 舒尔特方格、静坐冥想、找不同 |
|
|
|
+| 注意力基础训练(7天) | attention | 7天 | 同上短周期 |
|
|
|
+| 注意力进阶训练(21天) | attention | 21天 | 舒尔特×2、冥想10分钟、拼图、阅读报告 |
|
|
|
+| 专注力基础训练(14天) | focus | 14天 | 番茄钟、单任务专注、干扰抑制 |
|
|
|
+| 记忆力训练(14天) | memory | 14天 | 数字记忆、图像记忆、故事复述 |
|
|
|
+| 逻辑力训练(14天) | logic | 14天 | 数独、逻辑推理、分类游戏 |
|
|
|
+| 综合维持方案(7天) | general | 7天 | 阅读、运动、情绪日记 |
|
|
|
+
|
|
|
+### 管理端规则配置
|
|
|
+
|
|
|
+新建 `cfc-web/views/admin/assessment-plan-rules.vue`:
|
|
|
+
|
|
|
+- 规则列表(维度/分数区间/关联模板/优先级/启用状态)
|
|
|
+- 规则 CRUD
|
|
|
+
|
|
|
+### 验证标准
|
|
|
+
|
|
|
+```
|
|
|
+□ 规则表可配置:维度 + 分数区间 → 训练模板
|
|
|
+□ 管理端有规则 CRUD 页面
|
|
|
+□ 规划师提交测评结果后自动调用生成器
|
|
|
+□ 匹配到多条规则时合并为一个方案
|
|
|
+□ 方案状态为 generated(非直接激活)
|
|
|
+□ 所有维度正常时生成维持型方案
|
|
|
+□ 方案关联 source_result_id,可追溯来源
|
|
|
+□ 方案 remark 包含指导意见摘要
|
|
|
+□ 规则不匹配时优雅降级
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 阶段五:方案审核→确认→执行跟踪
|
|
|
+
|
|
|
+### 状态机
|
|
|
+
|
|
|
+```
|
|
|
+generated → pending_review → active → completed
|
|
|
+ │ │ │
|
|
|
+ └──→ cancelled ←───────────┘
|
|
|
+ (任何状态可取消)
|
|
|
+ generated: 系统生成,待规划师审核
|
|
|
+ pending_review: 规划师已审核,待家长确认
|
|
|
+ active: 已确认,执行中
|
|
|
+ completed: 全部完成
|
|
|
+ cancelled: 取消
|
|
|
+```
|
|
|
+
|
|
|
+### TaskPlanInstance 扩展审核字段
|
|
|
+
|
|
|
+**DB 迁移**:
|
|
|
+
|
|
|
+```sql
|
|
|
+ensureColumn("task_plan_instances", "reviewed_by", "BIGINT COMMENT '审核人(规划师ID)'");
|
|
|
+ensureColumn("task_plan_instances", "reviewed_at", "DATETIME COMMENT '审核时间'");
|
|
|
+ensureColumn("task_plan_instances", "review_comment", "VARCHAR(500) COMMENT '审核意见'");
|
|
|
+ensureColumn("task_plan_instances", "confirmed_by", "BIGINT COMMENT '确认人(家长ID)'");
|
|
|
+ensureColumn("task_plan_instances", "confirmed_at", "DATETIME COMMENT '确认时间'");
|
|
|
+ensureColumn("task_plan_instances", "activated_at", "DATETIME COMMENT '激活时间'");
|
|
|
+```
|
|
|
+
|
|
|
+### API 清单
|
|
|
+
|
|
|
+| 端点 | 角色 | 说明 |
|
|
|
+|------|------|------|
|
|
|
+| `POST /api/guide/plans/pending-review` | 规划师 | 获取待审核方案列表 |
|
|
|
+| `POST /api/guide/plans/{id}/detail` | 规划师/家长 | 方案详情(含所有任务项) |
|
|
|
+| `POST /api/guide/plans/{id}/review` | 规划师 | 审核方案(approve/reject) |
|
|
|
+| `POST /api/guide/plans/{id}/items/adjust` | 规划师 | 调整方案任务项 |
|
|
|
+| `POST /api/plans/pending-confirm` | 家长 | 获取待确认方案列表 |
|
|
|
+| `POST /api/plans/{id}/confirm` | 家长 | 确认/退回方案 |
|
|
|
+| `POST /api/plans/{id}/progress` | 家长 | 方案执行进度 |
|
|
|
+| `POST /api/plans/{id}/pause` | 家长 | 暂停方案 |
|
|
|
+| `POST /api/plans/{id}/resume` | 家长 | 恢复方案 |
|
|
|
+| `POST /api/plans/{id}/complete` | 系统 | 完成方案(触发复测提醒)|
|
|
|
+
|
|
|
+### 每日任务生成
|
|
|
+
|
|
|
+```java
|
|
|
+// service/TaskGenerationService.java
|
|
|
+// generateTodayTasks(planId): 从 TaskPlanItem → 当日 Task 实例
|
|
|
+
|
|
|
+// task/PlanTaskGenerator.java (定时任务)
|
|
|
+// @Scheduled(cron = "0 30 5 * * ?")
|
|
|
+// 每天 5:30 生成所有活跃方案的当日任务
|
|
|
+```
|
|
|
+
|
|
|
+### 复测提醒
|
|
|
+
|
|
|
+方案完成时根据 `DanAssessmentResult.nextReviewDate` 发送提醒:
|
|
|
+
|
|
|
+```
|
|
|
+┌─ 🎉 方案已完成! ───────────────┐
|
|
|
+│ DAN专注力训练方案(14天) │
|
|
|
+│ 完成度: 100% │
|
|
|
+│ │
|
|
|
+│ 建议在 2026-08-10 前进行复测 │
|
|
|
+│ [立即预约复测] [稍后再说] │
|
|
|
+└──────────────────────────────────┘
|
|
|
+```
|
|
|
+
|
|
|
+### 前端页面清单
|
|
|
+
|
|
|
+| 页面 | 角色 | 说明 |
|
|
|
+|------|------|------|
|
|
|
+| `pages/guide/plan-review.vue` | 规划师 | 待审核方案列表 + 审核详情页 |
|
|
|
+| `pages/plans/pending-confirm.vue` | 家长 | 待确认方案列表 + 确认详情页 |
|
|
|
+| `pages/plans/dashboard.vue` | 家长 | 方案总览(进行中/已完成/待确认)|
|
|
|
+| `pages/plans/daily-view.vue` | 孩子 | 今日训练任务(执行入口)|
|
|
|
+| `pages/plans/weekly-view.vue` | 家长 | 周视图进度 |
|
|
|
+
|
|
|
+### 验证标准
|
|
|
+
|
|
|
+```
|
|
|
+□ 方案生成后状态为 generated,不直接激活
|
|
|
+□ 规划师可查看待审核方案列表和详情
|
|
|
+□ 规划师可调整方案任务项(增删改)
|
|
|
+□ 规划师审核通过→status=pending_review
|
|
|
+□ 家长确认→status=active,退回→返规划师
|
|
|
+□ 方案激活后自动生成当日任务
|
|
|
+□ 每日定时任务生成活跃方案的当日任务
|
|
|
+□ 方案执行进度可追踪
|
|
|
+□ 方案完成后触发复测提醒
|
|
|
+□ 可暂停和恢复执行中的方案
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 全五阶段文件清单
|
|
|
+
|
|
|
+### 新增文件
|
|
|
+
|
|
|
+| 阶段 | 后端 | 前端 |
|
|
|
+|:----:|------|------|
|
|
|
+| 一 | `AssessmentProduct.java`, `AssessmentProductMapper.java`, `AssessmentProductService.java`, `ProductCreateRequest.java` | `views/admin/assessment-products.vue` |
|
|
|
+| 二 | `AssessmentQuota.java`, `AssessmentExecution.java`, `AssessmentQuotaMapper.java`, `AssessmentExecutionMapper.java`, `AssessmentQuotaService.java`, `AssessmentExecutionService.java`, `AssessmentQuotaController.java`, `AssessmentQuotaVO.java` | `pages/assessment/quota.vue` |
|
|
|
+| 三 | `GrowthGuidance.java`, `GrowthGuidanceMapper.java`, `GrowthGuidanceService.java`, `FileStorageService.java` | `pages/assessment/upload-report.vue` |
|
|
|
+| 四 | `AssessmentPlanRule.java`, `AssessmentPlanRuleMapper.java`, `AssessmentPlanGenerator.java`, `AssessmentPlanRuleService.java`, `AdminPlanRuleController.java` | `views/admin/assessment-plan-rules.vue` |
|
|
|
+| 五 | `GuidePlanReviewController.java`, `PlanConfirmController.java`, `TaskGenerationService.java`, `PlanTaskGenerator.java` | `pages/guide/plan-review.vue`, `pages/plans/pending-confirm.vue`, `pages/plans/dashboard.vue`, `pages/plans/daily-view.vue`, `pages/plans/weekly-view.vue` |
|
|
|
+
|
|
|
+### 修改文件
|
|
|
+
|
|
|
+| 阶段 | 后端 | 前端 |
|
|
|
+|:----:|------|------|
|
|
|
+| 一 | `Product.java`, `AdminProductController.java`, `ProductOrderService.java` | `pages/shop/detail.vue` |
|
|
|
+| 二 | `ProductOrderService.java`, `AssessmentAppointmentController.java`, `AssessmentOrderController.java`, `DanAssessmentController.java` | `apply.vue`, `purchase.vue` |
|
|
|
+| 三 | `DanAssessmentResult.java`, `ReportParseService.java`, `DanAssessmentController.java` | `record.vue`, `results.vue` |
|
|
|
+| 四 | `AssessmentService.java`, `TaskPlanInstance.java`, `TaskPlanService.java`, `DanAssessmentController.java` | — |
|
|
|
+| 五 | `TaskPlanInstance.java`, `TaskPlanService.java` | — |
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## Sprint 建议
|
|
|
+
|
|
|
+```
|
|
|
+Sprint 1: 阶段一 + 阶段三(可并行)
|
|
|
+Sprint 2: 阶段二(依赖阶段一)+ 阶段五前端原型(与阶段四并行)
|
|
|
+Sprint 3: 阶段四 + 阶段五后端
|
|
|
+Sprint 4: 联调 + 测试 + 部署
|
|
|
+```
|