Просмотр исходного кода

docs: 重构成长档案流程图 — 按阶段/分层/数据传递重绘

E2E Test Bot 1 месяц назад
Родитель
Сommit
3c4bfd146a
1 измененных файлов с 231 добавлено и 80 удалено
  1. 231 80
      docs/flows/growth-record-flow.md

+ 231 - 80
docs/flows/growth-record-flow.md

@@ -1,103 +1,254 @@
 # 用户使用流程图 — 成长档案
 
 > **端口说明**: 📱 小程序 | 🖥 管理后台 | 📋 规划师端 | ⚙️ 系统自动
+>
+> **分层说明**: 🏠 页面 → 🔗 API → ⚙️ Service → 📦 数据实体
+
+## 核心概念
+
+成长档案、成长计划、测评报告三者之间**不是一一对应关系**:
+
+- **成长档案** (GrowthRecord):孩子成长过程中的数据快照,可来自手动录入、PDF报告解析、外部系统同步
+- **成长计划** (GrowthPlan):由规划师基于测评分析制定的孩子成长方案,可引用某个测评报告的分析结果
+- **测评报告** (DanAssessmentResult):专业测评的结果数据,可被成长档案和成长计划引用
+
+> 一个孩子可以有多个成长档案、多个成长计划、多份测评报告。它们通过 `assessmentId` 相互引用,但不存在强制的一对一链式关系。
 
 ```mermaid
 flowchart TD
     %% ============ 颜色定义 ============
-    classDef actor fill:#e1f5fe,stroke:#0288d1,stroke-width:2px
-    classDef action fill:#fff3e0,stroke:#f57c00,stroke-width:1px
-    classDef system fill:#e8f5e9,stroke:#388e3c,stroke-width:1px
-    classDef decision fill:#fce4ec,stroke:#d32f2f,stroke-width:1px
-    classDef role fill:#f3e5f5,stroke:#7b1fa2,stroke-width:1px
-    classDef endpoint fill:#f5f5f5,stroke:#616161,stroke-width:1px
-    classDef portMiniApp fill:#e3f2fd,stroke:#1565c0,stroke-width:1px,stroke-dasharray:3 2
-    classDef portAdmin fill:#fce4ec,stroke:#c62828,stroke-width:1px,stroke-dasharray:3 2
-    classDef portGuide fill:#fff8e1,stroke:#f57f17,stroke-width:1px,stroke-dasharray:3 2
-    classDef portSystem fill:#f3e5f5,stroke:#6a1b9a,stroke-width:1px,stroke-dasharray:3 2
-
-    subgraph 成长档案创建
-        A1(("👤 家长")):::portMiniApp --> A2{📱 创建方式}:::portMiniApp
-        A2 -->|手动创建| A3[📱 创建成长档案 /record/create]:::portMiniApp
-        A2 -->|上传PDF报告| A4[📱 上传测评报告PDF /upload-and-parse]:::portMiniApp
-        A2 -->|创建并购买测评| A5[📱 创建档案+购买 /create-with-order]:::portMiniApp
-        A4 --> A6["⚙️ PDF解析引擎 (Stage 1)"]:::portSystem
-        A6 --> A7{⚙️ 是否重复?}:::portSystem
-        A7 -->|重复| A8[⚙️ 检查哈希去重 /check-duplicate]:::portSystem
-        A7 -->|新记录| A9["📱 创建成长档案 (Stage 2) /create-from-upload"]:::portMiniApp
-        A3 --> A10[📱 录入基础信息]:::portMiniApp
-        A9 --> A10
-    end
+    classDef page fill:#e3f2fd,stroke:#1565c0,stroke-width:2px
+    classDef api fill:#fff3e0,stroke:#f57c00,stroke-width:1px
+    classDef service fill:#e8f5e9,stroke:#388e3c,stroke-width:1px
+    classDef data fill:#f3e5f5,stroke:#7b1fa2,stroke-width:1px
+    classDef external fill:#fce4ec,stroke:#d32f2f,stroke-width:1px,stroke-dasharray:3 2
+    classDef actor fill:#e1f5fe,stroke:#0288d1,stroke-width:2px,stroke-dasharray:5 3
+
+    %% ============ 角色 ============
+    A0(("👤 家长")):::actor
+    B0(("📋 规划师")):::actor
+    C0(("👶 孩子")):::actor
+    D0(("⚙️ 系统/第三方")):::actor
+
+    %% ================================================================
+    %% 阶段一:数据采集 — 创建成长档案
+    %% ================================================================
+    subgraph 阶段一[阶段一:数据采集]
+        direction TB
+
+        P1["🏠 家长端:成长档案页<br>选择创建方式"]:::page
 
-    subgraph 补充材料
-        A10 --> B1[📱 创建补充记录 /supplement]:::portMiniApp
-        B1 --> B2[📱 获取补充记录列表 /:id/supplements]:::portMiniApp
+        P1 -->|手动录入| P1a["🏠 家长端:录入表单<br>childId, height, weight,<br>school, grade, photo"]:::page
+        P1a --> A1["🔗 POST /api/growth/record/create<br>body: {childId, height, weight,<br>school, grade, ...}"]:::api
+        A1 --> S1["⚙️ GrowthRecordService<br>.createRecord()"]:::service
+        S1 --> D1["📦 growth_records 表<br>写入一条记录"]:::data
+
+        P1 -->|上传PDF报告| P1b["🏠 家长端:选择PDF文件<br>拍照/相册选择"]:::page
+        P1b --> A1a["🔗 POST /api/growth/record/upload-and-parse<br>body: multipart file"]:::api
+        A1a --> S1a["⚙️ PDF解析引擎<br>Stage1: OCR + 结构化提取"]:::service
+        S1a --> D1a["📦 ParsedReport<br>{indicators, scores,<br>reportDate, ...}"]:::data
+        D1a --> A1b["🔗 POST /api/growth/record/check-duplicate<br>body: {fileHash}"]:::api
+        A1b --> S1b["⚙️ 哈希去重校验"]:::service
+        S1b -->|重复| D1b["📦 返回现有记录ID"]:::data
+        S1b -->|新记录| A1c["🔗 POST /api/growth/record/create-from-upload<br>body: {parsedReport}"]:::api
+        A1c --> S1c["⚙️ GrowthRecordService<br>.createFromUpload()"]:::service
+        S1c --> D1["📦 growth_records 表"]
+
+        P1 -->|创建档案+购买测评| P1c["🏠 家长端:选择测评套餐<br>guideId, packageId"]:::page
+        P1c --> A1d["🔗 POST /api/growth/record/create-with-order<br>body: {childId, guideId,<br>packageId, ...}"]:::api
+        A1d --> S1d["⚙️ 创建档案 + 创建测评订单<br>GrowthRecordService<br>+ AssessmentOrderService"]:::service
+        S1d --> D1c["📦 growth_records 表<br>+ assessment_orders 表"]:::data
     end
 
-    subgraph 外部数据同步
-        A10 --> C1[📱 外部系统测评同步 /external/sync]:::portMiniApp
-        C1 --> C2[⚙️ 数据融合]:::portSystem
+    %% ================================================================
+    %% 阶段二:补充材料与外部同步
+    %% ================================================================
+    subgraph 阶段二[阶段二:补充材料与外部同步]
+        D1 --> P2["🏠 家长端:档案详情页"]:::page
+        P2 -->|补充材料| P2a["🏠 家长端:补充记录表单"]:::page
+        P2a --> A2["🔗 POST /api/growth/record/supplement<br>body: {recordId, <br>supplementType, content}"]:::api
+        A2 --> S2["⚙️ GrowthRecordService<br>.addSupplement()"]:::service
+        S2 --> D2["📦 growth_record_supplements 表"]:::data
+
+        P2 -->|外部同步| P2b["🏠 家长端:选择外部系统"]:::page
+        P2b --> A2a["🔗 POST /api/growth/external/sync<br>body: {childId, source,<br>credentials}"]:::api
+        A2a --> S2a["⚙️ 外部数据同步引擎<br>对接第三方API"]:::service
+        S2a --> D2a["📦 融合后的数据写入<br>growth_records 表"]:::data
     end
 
-    subgraph 查询与管理
-        C2 --> D1[📱 获取家长的成长档案列表 /list]:::portMiniApp
-        D1 --> D2[📱 获取指定孩子的档案 /child/:childId]:::portMiniApp
-        D2 --> D3[📱 获取孩子的档案 /child-records]:::portMiniApp
-        D3 --> D4[📱 获取档案详情 /:id]:::portMiniApp
-        D4 --> D5[📱 删除成长档案 /:id/delete]:::portMiniApp
+    %% ================================================================
+    %% 阶段三:分析评估 — 查看测评结果
+    %% ================================================================
+    subgraph 阶段三[阶段三:分析评估]
+        D1 --> P3["🏠 家长端:档案列表页<br>GET /api/growth/record/list"]:::page
+        P3 --> P3a["🏠 家长端:档案详情<br>GET /api/growth/record/{id}"]:::page
+        P3a --> A3["🔗 GET /api/growth/record/{id}<br>返回: GrowthRecord +<br>关联的 assessmentSummary"]:::api
+        A3 --> S3["⚙️ GrowthRecordService<br>.getRecordDetail()<br>关联查询测评结果"]:::service
+        S3 --> D3["📦 GrowthRecord +<br>DanAssessmentResult<br>(通过 assessmentId 关联)"]:::data
+
+        D3 --> P3b["📋 规划师端:测评分析页<br>查看孩子的测评报告"]:::page
+        P3b --> A3a["🔗 GET /api/dan-assessment/my-results<br>或 /api/guide/assessment/child/{id}"]:::api
+        A3a --> S3a["⚙️ AssessmentService<br>.getChildResults()"]:::service
+        S3a --> D3a["📦 DanAssessmentResult<br>{dimensionScores,<br>structuredAnalysis, ...}"]:::data
     end
 
-    subgraph 生长记录
-        D1 --> E1[📱 获取生长记录列表 /list]:::portMiniApp
-        E1 --> E2[📱 获取生长记录详情 /detail]:::portMiniApp
-        E2 --> E3[📱 创建生长记录 /create]:::portMiniApp
-        E3 --> E4[📱 更新生长记录 /update]:::portMiniApp
-        E4 --> E5[📱 删除生长记录 /delete]:::portMiniApp
+    %% ================================================================
+    %% 阶段四:制定成长计划
+    %% ================================================================
+    subgraph 阶段四[阶段四:制定成长计划]
+        D3a --> P4["📋 规划师端:制定成长计划页<br>基于测评分析结果"]:::page
+        P4 --> A4["🔗 POST /api/growth/plan/create<br>body: {childId, assessmentId,<br>planTitle, planContent,<br>durationMonths, startDate}"]:::api
+        A4 --> S4["⚙️ GrowthPlanService<br>.createPlan()<br>设置 status='active'"]:::service
+        S4 --> D4["📦 growth_plans 表<br>一条计划记录"]:::data
+
+        D4 --> P4a["📋 规划师端:查看孩子计划列表<br>GET /api/growth/plan/child/{childId}"]:::page
+        P4a --> A4a["🔗 GET /api/growth/plan/child/{childId}<br>返回: GrowthPlan[]"]:::api
+        A4a --> S4a["⚙️ GrowthPlanService<br>.getByChildId()"]:::service
+
+        P4 -->|更新计划| P4b["📋 规划师端:编辑计划"]:::page
+        P4b --> A4b["🔗 POST /api/growth/plan/update<br>body: {id, planTitle,<br>planContent, ...}"]:::api
+        A4b --> S4b["⚙️ GrowthPlanService<br>.updatePlan()"]:::service
+        S4b --> D4
+
+        D4 --> P4c["📱 家长端:查看计划<br>GET /api/growth/plan/child/{childId}"]:::page
     end
 
-    subgraph 成长计划
-        E5 --> F1[📱 创建计划 /growth/plan/create]:::portMiniApp
-        F1 --> F2[📱 更新计划 /growth/plan/update]:::portMiniApp
-        F2 --> F3[📱 查看孩子计划 /growth/plan/child/:childId]:::portMiniApp
-        F3 --> F4[📱 激活计划 /growth/plan/child/:childId/active]:::portMiniApp
-        F4 --> F5[📱 计划详情 /growth/plan/:id]:::portMiniApp
-        F5 --> F6[📱 审核计划 /growth/plan/:id/review]:::portMiniApp
+    %% ================================================================
+    %% 阶段五:执行计划 + 记录成长
+    %% ================================================================
+    subgraph 阶段五[阶段五:执行计划与记录成长]
+        D4 --> P5["📱 家长端:查看活跃计划<br>GET /api/growth/plan/child/{childId}/active"]:::page
+        P5 --> P5a["🏠 家长端:执行计划任务<br>按计划内容进行日常活动"]:::page
+        P5a -->|执行中记录| P5b["📱 家长/孩子端:创建成长记录<br>记录身高/体重/学业/照片"]:::page
+        P5b --> A5["🔗 POST /api/health/growth/create<br>body: {childId, recordTitle,<br>height, weight, ...}"]:::api
+        A5 --> S5["⚙️ GrowthRecordService<br>.createRecord()<br>生长记录(非档案)"]:::service
+        S5 --> D5["📦 health_growth_records 表<br>日常生长记录"]:::data
+
+        P5a -->|定期更新档案| P5c["📱 家长端:更新成长档案<br>定期补充最新数据"]:::page
+        P5c --> A5a["🔗 POST /api/growth/record/create<br>body: {childId, assessmentSummary,<br>growthSuggestions, ...}"]:::api
+        A5a --> S5a["⚙️ GrowthRecordService<br>.createRecord()"]:::service
+        S5a --> D1["📦 growth_records 表"]
     end
 
-    R1(("👤 家长")):::actor
-    R2(("👶 孩子")):::role
-    R3(("📄 PDF解析引擎")):::system
+    %% ================================================================
+    %% 阶段六:复盘与评估
+    %% ================================================================
+    subgraph 阶段六[阶段六:复盘与评估]
+        D5 --> P6["📋 规划师端:查看执行记录<br>比较计划目标 vs 实际数据"]:::page
+        P6 --> A6["🔗 POST /api/growth/plan/{id}/review<br>body: {reviewNotes}"]:::api
+        A6 --> S6["⚙️ GrowthPlanService<br>.reviewPlan()<br>reviewCount++"]:::service
+        S6 --> D6["📦 growth_plans 表<br>reviewCount 更新"]:::data
+
+        D6 --> P6a["📋 规划师端:调整计划"]:::page
+        P6a --> A6a["🔗 POST /api/growth/plan/update<br>基于复盘结果调整<br>计划内容/时长"]:::api
+        A6a --> S6a["⚙️ GrowthPlanService<br>.updatePlan()"]:::service
+        S6a --> D4
+
+        D6 --> P6b["📱 家长端:查看复盘结果"]:::page
+    end
 
-    A1 -.- R1
-    D2 -.- R2
-    A6 -.- R3
+    %% ================================================================
+    %% 角色关联
+    %% ================================================================
+    A0 -.- P1
+    A0 -.- P2
+    A0 -.- P3
+    A0 -.- P4c
+    A0 -.- P5
+    A0 -.- P6b
+    B0 -.- P3b
+    B0 -.- P4
+    B0 -.- P6
+    C0 -.- P5a
+    D0 -.- S1a
+    D0 -.- S2a
 ```
 
 ## 端点明细
 
-| 端点 | 说明 | 端口 |
-|------|------|------|
-| `/api/growth/record/create` | 创建成长档案 | 📱小程序 |
-| `/api/growth/record/create-with-order` | 创建档案并购买测评 | 📱小程序 |
-| `/api/growth/record/list` | 获取家长的档案列表 | 📱小程序 |
-| `/api/growth/record/child/{childId}` | 获取指定孩子档案 | 📱小程序 |
-| `/api/growth/record/child-records` | 获取孩子的成长档案 | 📱小程序 |
-| `/api/growth/record/{id}` | 获取档案详情 | 📱小程序 |
-| `/api/growth/record/{id}/delete` | 删除成长档案 | 📱小程序 |
-| `/api/growth/external/sync` | 外部系统同步 | 📱小程序 |
-| `/api/growth/record/upload-and-parse` | 上传并解析PDF | 📱小程序 |
-| `/api/growth/record/create-from-upload` | 创建成长档案(从上传) | 📱小程序 |
-| `/api/growth/record/supplement` | 创建补充记录 | 📱小程序 |
-| `/api/growth/record/check-duplicate` | 检查重复记录 | ⚙️系统自动 |
-| `/api/growth/record/{id}/supplements` | 获取补充记录 | 📱小程序 |
-| `/api/health/growth/list` | 获取生长记录列表 | 📱小程序 |
-| `/api/health/growth/detail` | 获取生长记录详情 | 📱小程序 |
-| `/api/health/growth/create` | 创建生长记录 | 📱小程序 |
-| `/api/health/growth/update` | 更新生长记录 | 📱小程序 |
-| `/api/health/growth/delete` | 删除生长记录 | 📱小程序 |
-| `/api/growth/plan/create` | 创建成长计划 | 📱小程序 |
-| `/api/growth/plan/update` | 更新成长计划 | 📱小程序 |
-| `/api/growth/plan/child/{childId}` | 查看孩子成长计划 | 📱小程序 |
-| `/api/growth/plan/child/{childId}/active` | 激活孩子成长计划 | 📱小程序 |
-| `/api/growth/plan/{id}` | 查看计划详情 | 📱小程序 |
-| `/api/growth/plan/{id}/review` | 审核成长计划 | 📱小程序 |
+### 成长档案
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/growth/record/create` | 创建成长档案 | 📱小程序 | `{childId, height, weight, school, grade, assessmentSummary, ...}` | `GrowthRecord` |
+| `POST /api/growth/record/create-with-order` | 创建档案并购买测评 | 📱小程序 | `{childId, guideId, packageId, ...}` | `GrowthRecord + AssessmentOrder` |
+| `POST /api/growth/record/upload-and-parse` | 上传并解析PDF | 📱小程序 | `multipart file` | `ParsedReport` |
+| `POST /api/growth/record/create-from-upload` | 从解析结果创建档案 | 📱小程序 | `{parsedReport}` | `GrowthRecord` |
+| `POST /api/growth/record/check-duplicate` | 检查重复记录 | ⚙️系统 | `{fileHash}` | `{isDuplicate, existingId}` |
+| `GET /api/growth/record/list` | 获取家长档案列表 | 📱小程序 | `{page, size}` | `Page<GrowthRecord>` |
+| `GET /api/growth/record/child/{childId}` | 获取指定孩子档案 | 📱小程序 | path: `childId` | `List<GrowthRecord>` |
+| `GET /api/growth/record/child-records` | 获取孩子的成长档案 | 📱小程序 | `{childId}` | `List<GrowthRecord>` |
+| `GET /api/growth/record/{id}` | 获取档案详情 | 📱小程序 | path: `id` | `GrowthRecord + 关联数据` |
+| `DELETE /api/growth/record/{id}/delete` | 删除成长档案 | 📱小程序 | path: `id` | `boolean` |
+| `POST /api/growth/record/supplement` | 创建补充记录 | 📱小程序 | `{recordId, supplementType, content}` | `Supplement` |
+| `GET /api/growth/record/{id}/supplements` | 获取补充记录 | 📱小程序 | path: `id` | `List<Supplement>` |
+| `POST /api/growth/external/sync` | 外部系统同步 | 📱小程序 | `{childId, source, credentials}` | `GrowthRecord` |
+
+### 生长记录(日常追踪)
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `GET /api/health/growth/list` | 获取生长记录列表 | 📱小程序 | `{childId, page, size}` | `Page<HealthGrowthRecord>` |
+| `GET /api/health/growth/detail` | 获取生长记录详情 | 📱小程序 | `{id}` | `HealthGrowthRecord` |
+| `POST /api/health/growth/create` | 创建生长记录 | 📱小程序 | `{childId, recordTitle, height, weight, ...}` | `HealthGrowthRecord` |
+| `POST /api/health/growth/update` | 更新生长记录 | 📱小程序 | `{id, ...}` | `boolean` |
+| `DELETE /api/health/growth/delete` | 删除生长记录 | 📱小程序 | `{id}` | `boolean` |
+
+### 成长计划
+
+| 端点 | 说明 | 端口 | 请求数据 | 响应数据 |
+|------|------|------|---------|---------|
+| `POST /api/growth/plan/create` | 创建成长计划 | 📋规划师端 | `{childId, assessmentId, planTitle, planContent, durationMonths, startDate}` | `GrowthPlan` |
+| `POST /api/growth/plan/update` | 更新成长计划 | 📋规划师端 | `{id, planTitle, planContent, durationMonths, ...}` | `boolean` |
+| `GET /api/growth/plan/child/{childId}` | 查看孩子计划列表 | 📱📋 | path: `childId` | `List<GrowthPlan>` |
+| `GET /api/growth/plan/child/{childId}/active` | 获取当前活跃计划 | 📱📋 | path: `childId` | `GrowthPlan` |
+| `GET /api/growth/plan/{id}` | 查看计划详情 | 📱📋 | path: `id` | `GrowthPlan` |
+| `POST /api/growth/plan/{id}/review` | 复盘成长计划 | 📋规划师端 | path: `id`, body: `{reviewNotes}` | `boolean` |
+
+## 数据实体关系
+
+```mermaid
+erDiagram
+    GrowthRecord ||--o{ DanAssessmentResult : "assessmentId 引用"
+    GrowthPlan ||--o{ DanAssessmentResult : "assessmentId 引用"
+    GrowthRecord ||--o{ Supplement : "一条记录多个补充"
+    Child ||--o{ GrowthRecord : "一个孩子多个档案"
+    Child ||--o{ GrowthPlan : "一个孩子多个计划"
+    Child ||--o{ DanAssessmentResult : "一个孩子多份报告"
+
+    GrowthRecord {
+        Long id PK
+        Long childId FK
+        Long assessmentId FK "nullable"
+        string recordTitle
+        string height
+        string weight
+        string school
+        int grade
+        string assessmentSummary
+        int overallScore
+        string growthSuggestions
+    }
+
+    GrowthPlan {
+        Long id PK
+        Long childId FK
+        Long teacherId FK
+        Long assessmentId FK "nullable"
+        string planTitle
+        string planContent
+        int durationMonths
+        string status "active/inactive"
+        date startDate
+        date endDate
+        int reviewCount
+    }
+
+    DanAssessmentResult {
+        Long id PK
+        Long childId FK
+        string dimensionScores
+        string structuredAnalysis
+        string source
+    }
+```