# 用户使用流程图 — 勋章与微行动 > **端口说明**: 📱 小程序 | 🖥 管理后台 | 📋 规划师端 | ⚙️ 系统自动 > > **分层说明**: 🏠 页面 → 🔗 API → ⚙️ Service → 📦 数据实体 ```mermaid flowchart TD %% ============ 颜色定义 ============ 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 %% ============ 角色 ============ ROLE_PARENT(("👤 家长")):::actor ROLE_CHILD(("👶 孩子")):::actor ROLE_ADMIN(("🔧 管理员")):::actor %% ================================================================ %% 阶段一:勋章浏览 %% ================================================================ subgraph 阶段一[阶段一:勋章浏览] direction TB P1["🏠 小程序:勋章列表页"]:::page P1 -->|"查看所有启用勋章"| A1["🔗 POST /api/badges/list"]:::api A1 -->|"无参数"| S1["⚙️ BadgeService.getActiveBadges()"]:::service S1 -->|"查询isActive=1, 按sortOrder排序"| S1a["⚙️ BadgeMapper.selectList()"]:::service S1a -->|"Badge列表"| D1["📦 badge 表"]:::data P1 -->|"查看勋章详情"| P1a["🏠 勋章详情页"]:::page P1a -->|"id"| A2["🔗 POST /api/badges/detail"]:::api A2 -->|"id"| S2["⚙️ BadgeService.getBadgeById()"]:::service S2 -->|"按主键查询"| S2a["⚙️ BadgeMapper.selectById()"]:::service S2a -->|"Badge详情"| D1 P1 -->|"收藏/取消收藏"| P1b["🏠 收藏按钮"]:::page P1b -->|"childId, badgeId"| A3["🔗 POST /api/badges/favorite"]:::api A3 -->|"childId, badgeId"| S3["⚙️ BadgeService.toggleFavorite()"]:::service S3 -->|"查询child_badge记录, 翻转isFavorite"| S3a["⚙️ ChildBadgeMapper.updateById()"]:::service S3a -->|"child_badge记录"| D2["📦 child_badge 表"]:::data end %% ================================================================ %% 阶段二:勋章获得与统计 %% ================================================================ subgraph 阶段二[阶段二:勋章获得与统计] D2 -->|"childId"| P2["🏠 小程序:孩子勋章页"]:::page P2 -->|"查看孩子勋章列表"| A4["🔗 POST /api/badges/child/list"]:::api A4 -->|"childId"| S4["⚙️ BadgeService.getActiveChildBadges()"]:::service S4 -->|"查询status=1, 按收藏/获得时间排序"| S4a["⚙️ ChildBadgeMapper.selectList()"]:::service S4a -->|"ChildBadge列表"| D2 S4 -->|"关联Badge定义"| S4b["⚙️ BadgeMapper.selectById()"]:::service S4b -->|"Badge详情"| D1 S4b -->|"合并后返回"| D3["📦 {childBadge, badge}(返回前端)"]:::data P2 -->|"勋章统计"| P2a["🏠 勋章统计面板"]:::page P2a -->|"childId"| A5["🔗 POST /api/badges/statistics/child"]:::api A5 -->|"childId"| S5["⚙️ BadgeService.getChildBadgeStats()"]:::service S5 -->|"统计总数/活跃/过期/撤销"| S5a["⚙️ 按status筛选"]:::service S5a -->|"分类统计+等级统计"| S5b["⚙️ ChildBadgeMapper.selectCategoryStats/selectLevelStats"]:::service S5b -->|"聚合统计结果"| D4["📦 {total, active, expired, revoked, categoryStats, levelStats}"]:::data P2 -->|"家庭内勋章排行"| P2b["🏠 家庭勋章排行页"]:::page P2b -->|"familyId"| A6["🔗 POST /api/badges/ranking/family"]:::api A6 -->|"familyId"| S6["⚙️ BadgeService.getFamilyRanking()"]:::service S6 -->|"按家庭内孩子统计勋章数排序"| S6a["⚙️ ChildBadgeMapper.selectFamilyRanking()"]:::service S6a -->|"排行列表(childId, total)"| D5["📦 排行数据(返回前端)"]:::data end %% ================================================================ %% 阶段三:管理后台勋章管理 %% ================================================================ subgraph 阶段三[阶段三:管理后台勋章管理] P3["🏠 管理后台:勋章管理页"]:::page P3 -->|"查看所有勋章(含未启用)"| A7["🔗 POST /api/badges/all"]:::api A7 -->|"无参数"| S7["⚙️ BadgeService.getAllBadges()"]:::service S7 -->|"全部勋章按sortOrder排序"| D1 P3 -->|"创建勋章"| P3a["🏠 创建表单"]:::page P3a -->|"Badge对象"| A8["🔗 POST /api/badges/create"]:::api A8 -->|"Badge对象"| S8["⚙️ BadgeService.createBadge()"]:::service S8 -->|"设置创建/更新时间"| S8a["⚙️ BadgeMapper.insert()"]:::service S8a -->|"新Badge记录"| D1 P3 -->|"编辑勋章"| P3b["🏠 编辑表单"]:::page P3b -->|"Badge对象(含id)"| A9["🔗 POST /api/badges/update"]:::api A9 -->|"Badge对象"| S9["⚙️ BadgeService.updateBadge()"]:::service S9 -->|"更新字段"| D1 P3 -->|"删除勋章"| P3c["🏠 删除确认弹窗"]:::page P3c -->|"id"| A10["🔗 POST /api/badges/delete"]:::api A10 -->|"id"| S10["⚙️ BadgeService.deleteBadge()"]:::service S10 -->|"按id删除"| D1 P3 -->|"手动授予勋章"| P3d["🏠 授勋弹窗:选择孩子"]:::page P3d -->|"childId, badgeId"| A11["🔗 POST /api/badges/grant"]:::api A11 -->|"childId, badgeId"| S11["⚙️ BadgeService.grantBadge()"]:::service S11 -->|"检查是否已授予(去重)"| S11a["⚙️ 查ChildBadgeMapper"]:::service S11a -->|"已授予则跳过"| P3d S11 -->|"创建ChildBadge记录"| S11b["⚙️ ChildBadgeMapper.insert()"]:::service S11b -->|"child_badge记录(初始状态=1)"| D2 end %% ================================================================ %% 阶段四:微行动 %% ================================================================ subgraph 阶段四[阶段四:微行动] P4["🏠 小程序:微行动页"]:::page P4 -->|"查看所有微行动"| A12["🔗 POST /api/micro-action/list"]:::api A12 -->|"无参数"| S12["⚙️ MicroActionService.getAllActions()"]:::service S12 -->|"查询status=1, 按sortOrder排序"| S12a["⚙️ MicroActionMapper.selectList()"]:::service S12a -->|"MicroAction列表"| D6["📦 micro_actions 表"]:::data P4 -->|"获取今日推荐"| P4a["🏠 今日推荐卡片"]:::page P4a -->|"childId"| A13["🔗 POST /api/micro-action/today"]:::api A13 -->|"userId, childId"| S13["⚙️ MicroActionService.getTodayAction()"]:::service S13 -->|"按日期取模随机选择一个行动"| S13a["⚙️ 日期取模算法"]:::service S13a -->|"MicroAction/null(当日已完成)"| D6 S13 -->|"检查当日是否已完成"| S13b["⚙️ MicroActionService.getTodayRecord()"]:::service S13b -->|"已有记录返回true"| D7["📦 micro_action_records 表"]:::data S13b -->|"completed=true/false"| D8["📦 {action, completed}(返回前端)"]:::data P4a -->|"完成微行动"| P4b["🏠 完成按钮"]:::page P4b -->|"childId, actionId"| A14["🔗 POST /api/micro-action/complete"]:::api A14 -->|"userId, childId, actionId"| S14["⚙️ MicroActionService.completeAction()"]:::service S14 -->|"校验: 今日未完成、未健康打卡"| S14a["⚙️ 互斥校验"]:::service S14a -->|"校验失败抛出RuntimeException"| P4b S14 -->|"验证微行动存在且启用"| S14b["⚙️ MicroActionMapper.selectById()"]:::service S14b -->|"MicroAction"| D6 S14 -->|"创建完成记录"| S14c["⚙️ MicroActionRecordMapper.insert()"]:::service S14c -->|"记录(earnedEnergy=1)"| D7 S14 -->|"自动创建任务+积分+能量"| S14d["⚙️ TaskMapper.insert() + PointsLog + EnergyService.awardEnergy()"]:::service S14d -->|"task记录 + points_log记录"| D9["📦 tasks + points_logs 表"]:::data S14 -->|"触发新手引导+成长任务"| S14e["⚙️ OnboardingService + GrowthTaskService"]:::service S14e -->|"进度更新"| D10["📦 状态更新"]:::data P4 -->|"检查今日是否已完成"| P4c["🏠 加载时自动检查"]:::page P4c -->|"childId"| A15["🔗 POST /api/micro-action/check-today"]:::api A15 -->|"childId"| S15["⚙️ MicroActionService.hasCompletedToday()"]:::service S15 -->|"按childId+今日日期查询记录"| D7 S15 -->|"completed=true/false"| D8 end %% ================================================================ %% 角色关联 %% ================================================================ ROLE_PARENT -.- P1 ROLE_PARENT -.- P2 ROLE_CHILD -.- P1 ROLE_CHILD -.- P2 ROLE_CHILD -.- P4 ROLE_ADMIN -.- P3 ``` ## 端点明细 ### 勋章(用户端) | 端点 | 说明 | 端口 | 请求数据 | 响应数据 | |------|------|------|---------|---------| | `POST /api/badges/list` | 获取启用的勋章列表 | 📱小程序 | — | `List`(仅isActive=1) | | `POST /api/badges/detail` | 获取勋章详情 | 📱小程序 | `{id}` | `Badge`(含描述、图标、等级、稀有度等) | | `POST /api/badges/favorite` | 收藏/取消收藏勋章 | 📱小程序 | `{childId, badgeId}` | `String` | | `POST /api/badges/child/list` | 获取孩子获得的勋章列表 | 📱小程序 | `{childId}` | `List<{childBadge, badge}>` | | `POST /api/badges/statistics/child` | 孩子勋章统计 | 📱小程序 | `{childId}` | `{total, active, expired, revoked, categoryStats[], levelStats[]}` | | `POST /api/badges/ranking/family` | 家庭内勋章排行 | 📱小程序 | `{familyId}` | `List<{childId, total}>` | ### 勋章(管理后台) | 端点 | 说明 | 端口 | 请求数据 | 响应数据 | |------|------|------|---------|---------| | `POST /api/badges/all` | 获取全部勋章(含未启用) | 🖥管理后台 | — | `List` | | `POST /api/badges/create` | 创建勋章 | 🖥管理后台 | `Badge`对象 | `String` | | `POST /api/badges/update` | 更新勋章 | 🖥管理后台 | `Badge`对象(含id) | `String` | | `POST /api/badges/delete` | 删除勋章 | 🖥管理后台 | `{id}` | `String` | | `POST /api/badges/grant` | 手动授予勋章 | 🖥管理后台 | `{childId, badgeId}` | `String` | ### 微行动 | 端点 | 说明 | 端口 | 请求数据 | 响应数据 | |------|------|------|---------|---------| | `POST /api/micro-action/list` | 获取所有微行动列表 | 📱小程序 | — | `List` | | `POST /api/micro-action/today` | 获取今日推荐微行动 | 📱小程序 | `{childId}` | `{action, completed}` | | `POST /api/micro-action/complete` | 完成微行动 | 📱小程序 | `{childId, actionId}` | `MicroActionRecord` | | `POST /api/micro-action/check-today` | 检查今日是否已完成 | 📱小程序 | `{childId}` | `{completed}` | ## 数据实体关系 ```mermaid erDiagram Badge ||--o{ ChildBadge : "一个勋章可授予多个孩子" Child ||--o{ ChildBadge : "一个孩子可获多个勋章" MicroAction ||--o{ MicroActionRecord : "一个行动有多次完成记录" Child ||--o{ MicroActionRecord : "一个孩子可有多次记录" User ||--o{ MicroActionRecord : "一个用户可操作多次" Badge { Long id PK string badgeId "逻辑编码" string name string description string icon string category "分类" string level "等级" string rarity "稀有度" string triggerType "触发类型" int threshold "阈值" bool needApproval "需审批" int expireDays "有效期天数" int sortOrder int isActive "1启用 0禁用" datetime createdAt datetime updatedAt } ChildBadge { Long id PK Long childId FK Long badgeId FK datetime earnedAt "获得时间" datetime expireAt "过期时间" int status "1活跃 0过期 -1撤销" bool isFavorite "是否收藏" datetime createdAt datetime updatedAt } MicroAction { Long id PK string code "DRINK_WATER, DEEP_BREATH" string name "喝一杯水" string icon string description int sortOrder int status "1启用 0禁用" datetime createdAt } MicroActionRecord { Long id PK Long userId FK "操作人" Long childId FK "执行孩子" Long actionId FK date completedDate "完成日期" int earnedEnergy "获得能量值" string note datetime createdAt } ``` ## 完整性分析 | # | 维度 | 评估 | 说明 | |---|------|------|------| | 1 | **流程完整性** | ✅ 完整 | 覆盖勋章浏览/收藏、孩子勋章查询/统计/排行、管理后台CRUD/授勋、微行动列表/今日推荐/完成/检查4个阶段 | | 2 | **异常路径** | ⚠️ 部分覆盖 | 微行动与健康打卡互斥逻辑(当日只能选择一种)、行动已下架校验、勋章重复授予跳过在图中体现;勋章自动触发(triggerType/threshold)的自动授勋逻辑未画入(当前仅支持手动授予) | | 3 | **端点覆盖** | ✅ 完整 | 15个端点全部映射到流程图中,与代码实际暴露的BadgeController(11个)、MicroActionController(4个)一致 | | 4 | **角色覆盖** | ✅ 完整 | 家长和孩子可浏览勋章和微行动;管理员在后管端进行勋章CRUD和手动授勋 | | 5 | **数据实体** | ✅ 完整 | badge表、child_badge表、micro_actions表、micro_action_records表、tasks表、points_logs表均在图中映射 | | 6 | **一致性** | ✅ 与代码一致 | 所有端点路径与实际Controller中的`@PostMapping`匹配,Service方法名与BadgeService、MicroActionService一致 |