# 五维手动填分 + MBTI 完整体系 实施计划 > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** 实现"只填结果"的五维手动填分功能(0-100 分,家长可给家庭成员填),以及 MBTI 完整体系(标准版 ~30题测评 + 16型人格百科 + 五维联动解读)。 **Architecture:** 后端新增两组 Controller/Service/Mapper/Entity;前端新增 5 个页面 + 1 个管理端页面;数据库 3 张新表(mbti_questions, mbti_results, mbti_profiles)通过 DatabaseInitializer 迁移;种子数据脚本初始化题库与 16 型画像。 **Tech Stack:** Java 8 + Spring Boot 2.7.18 + MyBatis-Plus / uni-app Vue 2 (微信小程序) / Vue 2 + Element UI (Web 管理端) / MySQL 8.0 **Spec:** 本计划基于前期 brainstorming 确认的设计,包含 Part 1(手动填分)与 Part 2(MBTI 体系)两大模块。 --- ## Global Constraints - 统一 `@PostMapping`,禁止 `@GetMapping/@PutMapping/@DeleteMapping` - 响应包装 `Result` (code/message/data) - JWT Bearer Token 认证,`JwtInterceptor` 拦截 `/api/**` - DI 使用 `@Resource`,字段名必须与 Bean Name 一致 - MyBatis-Plus `@TableName` + `@TableId(type = IdType.AUTO)` - 小程序限制:禁止 `?.`、CSS Grid、`:key` 表达式、`new Date(string)`(用 `parseDate()`) - 数据库迁移唯一入口:`DatabaseInitializer.runMigrations()`,使用 `ensureColumn` / try-catch 幂等 - 每次迁移必须同步更新 `schema.sql` 对应 `CREATE TABLE` - 新增接口前必须查阅 `docs/superpowers/api/API_REFERENCE.md` 确认无重复 - Bean 命名冲突检查:新增 Controller/Service 确保类名不重复 - 编译验证:`mvn clean compile` 唯一验证方式 --- ## 文件结构映射 ### 后端新增/修改文件 | 文件 | 类型 | 说明 | |------|------|------| | `entity/MbtiQuestion.java` | 新增 | MBTI 题库实体 | | `entity/MbtiResult.java` | 新增 | 用户 MBTI 测评结果实体 | | `entity/MbtiProfile.java` | 新增 | 16型人格画像库实体 | | `mapper/MbtiQuestionMapper.java` | 新增 | 题库 Mapper | | `mapper/MbtiResultMapper.java` | 新增 | 结果 Mapper | | `mapper/MbtiProfileMapper.java` | 新增 | 画像 Mapper | | `service/MbtiService.java` | 新增 | MBTI 业务接口 | | `service/impl/MbtiServiceImpl.java` | 新增 | MBTI 业务实现 | | `controller/family/MbtiController.java` | 新增 | `/api/family/mbti` 接口 | | `controller/family/ManualDimensionScoreController.java` | 新增 | `/api/family/manual-score` 接口 | | `service/ManualDimensionScoreService.java` | 新增 | 手动填分业务接口 | | `service/impl/ManualDimensionScoreServiceImpl.java` | 新增 | 手动填分业务实现 | | `dto/MbtiQuestionVO.java` | 新增 | 题目 VO | | `dto/MbtiResultVO.java` | 新增 | 结果 VO | | `dto/MbtiProfileVO.java` | 新增 | 画像 VO | | `dto/ManualScoreSubmitDTO.java` | 新增 | 手动提交 DTO | | `dto/ManualScoreVO.java` | 新增 | 手动填分 VO | | `config/DatabaseInitializer.java` | 修改 | 添加 3 表迁移 | ### 前端新增/修改文件 | 文件 | 类型 | 说明 | |------|------|------| | `pages/family/manual-score-entry.vue` | 新增 | 手动填分录入页 | | `pages/family/mbti-entry.vue` | 新增 | MBTI 入口页(选成员) | | `pages/family/mbti-test.vue` | 新增 | MBTI 答题页 | | `pages/family/mbti-result.vue` | 新增 | MBTI 结果页 | | `pages/family/mbti-profile.vue` | 新增 | MBTI 16型百科页 | | `pages/family/self-check-entry.vue` | 修改 | 增加"直接填分"按钮 + MBTI 卡片入口 | | `utils/api.js` | 修改 | 新增 10+ API 封装 | | `pages.json` | 修改 | 注册 5 个新页面 | ### 管理端新增文件 | 文件 | 类型 | 说明 | |------|------|------| | `src/views/admin/MbtiProfiles.vue` | 新增 | 16 型配置管理页 | | `src/api/mbti.js` | 新增 | 管理端 MBTI API | | `src/router/index.js` | 修改 | 新增路由 | --- ## 任务分解 ### Phase 0: 数据库迁移与种子数据 #### Task 0.1: DatabaseInitializer 添加 3 表迁移 **Files:** - Modify: `cfc-backend/src/main/java/com/etotem/cfc/config/DatabaseInitializer.java` (搜索 `// 迁移` 找到最新编号) - Modify: `cfc-backend/src/main/resources/schema.sql` (追加 3 表 CREATE TABLE) **Interfaces:** - Produces: 3 张表结构在数据库中可用 ```markdown - [ ] **Step 1: 在 DatabaseInitializer.runMigrations() 末尾添加 3 个迁移块** ```java // 迁移XXX: 创建 mbti_questions 表 try { jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS mbti_questions (" + "id BIGINT AUTO_INCREMENT PRIMARY KEY, " + "dimension CHAR(1) NOT NULL COMMENT 'E/I/S/N/T/F/J/P', " + "question_text TEXT NOT NULL COMMENT '题目文本', " + "option_a TEXT NOT NULL COMMENT '选项 A(正向)', " + "option_b TEXT NOT NULL COMMENT '选项 B(反向)', " + "weight DECIMAL(3,2) DEFAULT 1.0 COMMENT '权重', " + "sort_order INT DEFAULT 0, " + "is_active TINYINT DEFAULT 1, " + "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " + "INDEX idx_dim_active (dimension, is_active)" + ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='MBTI 测评题库'"); log.info("已创建 mbti_questions 表"); } catch (Exception e) { /* 忽略 */ } // 迁移XXX+1: 创建 mbti_results 表 try { jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS mbti_results (" + "id BIGINT AUTO_INCREMENT PRIMARY KEY, " + "user_id BIGINT NOT NULL COMMENT '答题人用户ID', " + "family_member_id BIGINT COMMENT '关联家庭成员ID', " + "answers_json TEXT COMMENT '用户答案JSON', " + "type_code CHAR(4) NOT NULL COMMENT 'MBTI 类型', " + "ei_score INT COMMENT 'E/I 原始分', " + "sn_score INT COMMENT 'S/N 原始分', " + "tf_score INT COMMENT 'T/F 原始分', " + "jp_score INT COMMENT 'J/P 原始分', " + "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " + "INDEX idx_user (user_id), " + "INDEX idx_member (family_member_id)" + ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='MBTI 测评结果'"); log.info("已创建 mbti_results 表"); } catch (Exception e) { /* 忽略 */ } // 迁移XXX+2: 创建 mbti_profiles 表 try { jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS mbti_profiles (" + "id BIGINT AUTO_INCREMENT PRIMARY KEY, " + "type_code CHAR(4) NOT NULL UNIQUE COMMENT '类型代码', " + "name VARCHAR(50) COMMENT '中文名称', " + "description TEXT COMMENT '核心特质描述', " + "strengths TEXT COMMENT '优势', " + "weaknesses TEXT COMMENT '挑战', " + "career_tendency TEXT COMMENT '职业倾向', " + "family_style TEXT COMMENT '家庭/育儿风格', " + "pairing_notes TEXT COMMENT '伴侣/孩子类型搭配建议', " + "energy_suggestion JSON COMMENT '五维能量联动建议', " + "is_active TINYINT DEFAULT 1, " + "created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " + "updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" + ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='MBTI 人格画像库'"); log.info("已创建 mbti_profiles 表"); } catch (Exception e) { /* 忽略 */ } ``` - [ ] **Step 2: 同步追加到 schema.sql 末尾** ```sql -- 与上面 3 个 CREATE TABLE IF NOT EXISTS 完全一致 ``` - [ ] **Step 3: 编译验证** ```bash cd cfc-backend && mvn clean compile ``` #### Task 0.2: MBTI 种子数据 SQL 脚本 **Files:** - Create: `cfc-backend/src/main/resources/migration_mbti_seed_data.sql` **Interfaces:** - Produces: 30 题题库 + 16 型基础画像数据 ```markdown - [ ] **Step 1: 编写种子数据脚本** 包含: - mbti_questions: 30 题(E/I 8题, S/N 8题, T/F 7题, J/P 7题),每题 dimension + question_text + option_a/option_b + weight + sort_order - mbti_profiles: 16 条记录(INTJ/INTP/ENTJ/ENTP/INFJ/INFP/ENFJ/ENFP/ISTJ/ISFJ/ESTJ/ESFJ/ISTP/ISFP/ESTP/ESFP),每条含 name/description/strengths/weaknesses/career_tendency/family_style/pairing_notes/energy_suggestion(JSON) - [ ] **Step 2: 在 DatabaseInitializer 执行种子数据** ```java // 迁移XXX+3: MBTI 种子数据初始化 try { String seedSql = FileUtils.readFileToString(new File("src/main/resources/migration_mbti_seed_data.sql"), "UTF-8"); for (String stmt : seedSql.split(";")) { String trimmed = stmt.trim(); if (!trimmed.isEmpty()) { jdbcTemplate.execute(trimmed); } } log.info("MBTI 种子数据初始化完成"); } catch (Exception e) { log.warn("MBTI 种子数据初始化失败(可能已存在): {}", e.getMessage()); } ``` - [ ] **Step 3: 编译验证** ```bash cd cfc-backend && mvn clean compile ``` --- ### Phase 1: 后端手动填分模块 #### Task 1.1: ManualDimensionScore 实体、Mapper、DTO **Files:** - Create: `entity/ManualDimensionScore.java` (可复用 FiveDimensionScore,仅 source_type='manual' 区分,无需新表) - Create: `dto/ManualScoreSubmitDTO.java` - Create: `dto/ManualScoreVO.java` ```markdown - [ ] **Step 1: ManualScoreSubmitDTO** ```java package com.etotem.cfc.dto; import lombok.Data; import java.math.BigDecimal; import java.util.Map; @Data public class ManualScoreSubmitDTO { private Long memberId; // 必填 private Map scores; // 必填: {"body":80,"mind":60,"wisdom":70,"action":50,"wealth":90} private String note; // 可选备注 } ``` - [ ] **Step 2: ManualScoreVO (返回前端)** ```java package com.etotem.cfc.dto; import lombok.Data; import java.util.Date; import java.util.List; @Data public class ManualScoreVO { private Long id; // five_dimension_scores.id private Long memberId; private String memberName; private Map scores; // 5维度分数 private Integer totalScore; // 5维总和 private Date createdAt; } ``` - [ ] **Step 3: 编译验证** #### Task 1.2: ManualDimensionScoreService 接口与实现 **Files:** - Create: `service/ManualDimensionScoreService.java` - Create: `service/impl/ManualDimensionScoreServiceImpl.java` ```markdown - [ ] **Step 1: 接口定义** ```java package com.etotem.cfc.service; import com.etotem.cfc.dto.ManualScoreSubmitDTO; import com.etotem.cfc.dto.ManualScoreVO; import java.util.List; public interface ManualDimensionScoreService { ManualScoreVO submit(ManualScoreSubmitDTO dto, Long userId); ManualScoreVO getLatest(Long userId, Long memberId); List getHistory(Long userId, Long memberId, int limit); } ``` - [ ] **Step 2: 实现类** ```java @Service public class ManualDimensionScoreServiceImpl implements ManualDimensionScoreService { @Resource private FiveDimensionScoreMapper fiveDimensionScoreMapper; @Resource private FiveDimensionSelfCheckMapper selfCheckMapper; @Resource private FamilyMemberMapper familyMemberMapper; @Resource private UserMapper userMapper; @Resource private FiveDimensionScoreService fiveDimensionScoreService; private final ObjectMapper objectMapper = new ObjectMapper(); @Transactional(rollbackFor = Exception.class) public ManualScoreVO submit(ManualScoreSubmitDTO dto, Long userId) { // 1. 校验 memberId 存在且属于当前用户家庭 // 2. 校验 5 维度键全为 body/mind/wisdom/action/wealth,值 0-100,至少一项>0 // 3. 写入 five_dimension_scores (source_type='manual', source_id=自增ID) // 4. 写入 five_dimension_self_checks (scores_json 存 0-100 映射,totalScore=5维总和,questionIdsJson=[]) // 5. 返回 VO } public ManualScoreVO getLatest(Long userId, Long memberId) { // 查 five_dimension_scores 最近一条 source_type='manual' } public List getHistory(Long userId, Long memberId, int limit) { // 查历史 } } ``` - [ ] **Step 3: 编译验证** #### Task 1.3: ManualDimensionScoreController **Files:** - Create: `controller/family/ManualDimensionScoreController.java` ```markdown - [ ] **Step 1: Controller 实现** ```java @Tag(name = "五维手动填分", description = "直接填写 0-100 分,跳过问卷") @RestController @RequestMapping("/api/family/manual-score") public class ManualDimensionScoreController { @Resource private ManualDimensionScoreService manualScoreService; @PostMapping("/submit") public Result submit(@RequestBody ManualScoreSubmitDTO dto, @RequestAttribute("userId") Long userId) { // 校验 userId, 调用 service, 返回 Result } @PostMapping("/latest") public Result latest(@RequestBody(required=false) Map body, @RequestAttribute("userId") Long userId) { Long memberId = ParamUtils.getLong(body?.get("memberId")); // 调用 service } @PostMapping("/history") public Result> history(@RequestBody(required=false) Map body, @RequestAttribute("userId") Long userId) { Long memberId = ParamUtils.getLong(body?.get("memberId")); Integer limit = body?.get("limit") != null ? Integer.valueOf(body.get("limit").toString()) : 20; // 调用 service } } ``` - [ ] **Step 2: 编译验证** --- ### Phase 2: 后端 MBTI 模块 #### Task 2.1: MBTI 实体、Mapper **Files:** - Create: `entity/MbtiQuestion.java` - Create: `entity/MbtiResult.java` - Create: `entity/MbtiProfile.java` - Create: `mapper/MbtiQuestionMapper.java` - Create: `mapper/MbtiResultMapper.java` - Create: `mapper/MbtiProfileMapper.java` ```markdown - [ ] **Step 1: MbtiQuestion 实体** ```java @Data @TableName("mbti_questions") public class MbtiQuestion implements Serializable { @TableId(type=IdType.AUTO) private Long id; private String dimension; // E/I/S/N/T/F/J/P private String questionText; private String optionA; private String optionB; private BigDecimal weight; private Integer sortOrder; private Integer isActive; private Date createdAt; } ``` - [ ] **Step 2: MbtiResult 实体** ```java @Data @TableName("mbti_results") public class MbtiResult implements Serializable { @TableId(type=IdType.AUTO) private Long id; private Long userId; private Long familyMemberId; private String answersJson; private String typeCode; // INTJ 等 private Integer eiScore; private Integer snScore; private Integer tfScore; private Integer jpScore; private Date createdAt; } ``` - [ ] **Step 3: MbtiProfile 实体** ```java @Data @TableName("mbti_profiles") public class MbtiProfile implements Serializable { @TableId(type=IdType.AUTO) private Long id; private String typeCode; // INTJ 等,唯一 private String name; // 架构师 private String description; private String strengths; private String weaknesses; private String careerTendency; private String familyStyle; private String pairingNotes; private String energySuggestion; // JSON 字符串 private Integer isActive; private Date createdAt; private Date updatedAt; } ``` - [ ] **Step 4: 3 个 Mapper 接口** (extends BaseMapper) - [ ] **Step 5: 编译验证** #### Task 2.2: MBTI DTO/VO **Files:** - Create: `dto/MbtiQuestionVO.java` - Create: `dto/MbtiResultVO.java` - Create: `dto/MbtiProfileVO.java` - Create: `dto/SubmitMbtiDTO.java` ```markdown - [ ] **Step 1: MbtiQuestionVO** (题目含选项 A/B) ```java @Data public class MbtiQuestionVO { private Long id; private String dimension; // E/I/S/N/T/F/J/P private String questionText; private OptionVO optionA; private OptionVO optionB; @Data static class OptionVO { String value; String label; } } ``` - [ ] **Step 2: SubmitMbtiDTO** ```java @Data public class SubmitMbtiDTO { private Long familyMemberId; private List answers; @Data static class AnswerItem { Long questionId; String answer; } // answer: "A" 或 "B" } ``` - [ ] **Step 3: MbtiResultVO** (结果含 4 维度分 + 类型代码) ```java @Data public class MbtiResultVO { private Long id; private String typeCode; private String typeName; // 中文名 private Integer eiScore; private Integer snScore; private Integer tfScore; private Integer jpScore; private String eiType; // "E" 或 "I" private String snType; // "S" 或 "N" private String tfType; // "T" 或 "F" private String jpType; // "J" 或 "P" private MbtiProfileVO profile; // 画像详情 private Date createdAt; } ``` - [ ] **Step 4: MbtiProfileVO** (画像详情) ```java @Data public class MbtiProfileVO { private String typeCode; private String name; private String description; private String strengths; private String weaknesses; private String careerTendency; private String familyStyle; private String pairingNotes; private Map energySuggestion; // 5维度建议 } ``` - [ ] **Step 5: 编译验证** #### Task 2.3: MbtiService 接口与实现 **Files:** - Create: `service/MbtiService.java` - Create: `service/impl/MbtiServiceImpl.java` ```markdown - [ ] **Step 1: 接口** ```java public interface MbtiService { List getQuestions(); MbtiResultVO submit(SubmitMbtiDTO dto, Long userId); MbtiResultVO getLatest(Long userId, Long memberId); MbtiProfileVO getProfile(String typeCode); List getHistory(Long userId, Long memberId, int limit); } ``` - [ ] **Step 2: 实现核心计算逻辑** ```java @Service public class MbtiServiceImpl implements MbtiService { @Resource private MbtiQuestionMapper questionMapper; @Resource private MbtiResultMapper resultMapper; @Resource private MbtiProfileMapper profileMapper; @Resource private FamilyMemberMapper familyMemberMapper; private final ObjectMapper objectMapper = new ObjectMapper(); public List getQuestions() { // 查 is_active=1,按 dimension+sort_order 排序,转 VO } @Transactional(rollbackFor = Exception.class) public MbtiResultVO submit(SubmitMbtiDTO dto, Long userId) { // 1. 校验 memberId // 2. 加载题库 Map // 3. 遍历 answers,累加 4 维度分: // dimension='E' -> eiScore += (answer=="A"? weight : -weight) // dimension='I' -> eiScore -= (answer=="A"? weight : -weight) // 反向 // S/N、T/F、J/P 同理 // 4. 判定 4 字母:eiScore>0?"E":"I" 等 // 5. typeCode = ei+sn+tf+jp // 6. 查 profileMapper.selectByTypeCode(typeCode) // 7. 写入 mbti_results // 8. 组装 VO 返回 } // getLatest, getProfile, getHistory 均为简单查询 } ``` - [ ] **Step 3: 编译验证** #### Task 2.4: MbtiController **Files:** - Create: `controller/family/MbtiController.java` ```markdown - [ ] **Step 1: Controller 实现** ```java @Tag(name = "MBTI 人格测评", description = "标准版 ~30题 + 16型画像 + 五维联动") @RestController @RequestMapping("/api/family/mbti") public class MbtiController { @Resource private MbtiService mbtiService; @PostMapping("/questions") public Result> questions(@RequestAttribute("userId") Long userId) { return Result.success(mbtiService.getQuestions()); } @PostMapping("/submit") public Result submit(@RequestBody SubmitMbtiDTO dto, @RequestAttribute("userId") Long userId) { return Result.success(mbtiService.submit(dto, userId)); } @PostMapping("/latest") public Result latest(@RequestBody(required=false) Map body, @RequestAttribute("userId") Long userId) { Long memberId = ParamUtils.getLong(body?.get("memberId")); return Result.success(mbtiService.getLatest(userId, memberId)); } @PostMapping("/profile/{typeCode}") public Result profile(@PathVariable String typeCode, @RequestAttribute("userId") Long userId) { return Result.success(mbtiService.getProfile(typeCode.toUpperCase())); } @PostMapping("/history") public Result> history(@RequestBody(required=false) Map body, @RequestAttribute("userId") Long userId) { Long memberId = ParamUtils.getLong(body?.get("memberId")); Integer limit = body?.get("limit") != null ? Integer.valueOf(body.get("limit").toString()) : 20; return Result.success(mbtiService.getHistory(userId, memberId, limit)); } } ``` - [ ] **Step 2: 编译验证** --- ### Phase 3: 前端手动填分页面 #### Task 3.1: manual-score-entry.vue **Files:** - Create: `cfc-frontend/pages/family/manual-score-entry.vue` ```markdown - [ ] **Step 1: 页面结构** - 顶部:成员选择器(横向滑动卡片,显示头像+昵称+角色标签,复用 getFamilyMemberList) - 中部:5 个维度滑块(Slider 组件或自定义拖拽条),每维度 0-100,实时显示数值 - 底部:提交按钮(主色调渐变),提交后跳转 self-check-result.vue (复用结果页,传参 source=manual) - [ ] **Step 2: 逻辑** - onLoad 调用 getFamilyMemberList({visibleOnly:true}) 获取成员列表 - 默认选中当前用户自己 - scores 对象响应式绑定 5 维度 - 提交调用 submitManualScore({memberId, scores}) → 跳转结果页 - [ ] **Step 3: 样式遵循现有设计 Token (--color-primary, --bg, --shadow-clay 等)** #### Task 3.2: 修改 self-check-entry.vue 入口 **Files:** - Modify: `cfc-frontend/pages/family/self-check-entry.vue` ```markdown - [ ] **Step 1: 底部按钮区域增加两个按钮** ```html ``` - [ ] **Step 2: methods 新增跳转** ```javascript goManualScore() { uni.navigateTo({ url: '/pages/family/manual-score-entry' }) }, goMbti() { uni.navigateTo({ url: '/pages/family/mbti-entry' }) } ``` --- ### Phase 4: 前端 MBTI 页面 (4 个页面) #### Task 4.1: mbti-entry.vue (入口选成员) **Files:** - Create: `cfc-frontend/pages/family/mbti-entry.vue` ```markdown - [ ] 成员横向选择卡片 (复用 manual-score-entry 逻辑) - 大字标题:"MBTI 人格测评" + 副标题"发现你的天赋型,获得专属育儿建议" - "开始测评" 按钮 → navigateTo mbti-test.vue?memberId=xxx ``` #### Task 4.2: mbti-test.vue (答题页) **Files:** - Create: `cfc-frontend/pages/family/mbti-test.vue` ```markdown - [ ] 单题卡片模式 (类似 self-check.vue) - 进度条:当前题号 / 总题数 - 题目文本 + 两个选项按钮 (A/B),左右分布 - 选中高亮,可点击切换 - 底部:上一题 / 下一题 (最后一题显示"提交") - 答案暂存本地数组 answers[] - 提交调用 submitMbti({familyMemberId, answers}) → navigateTo mbti-result.vue?id=xxx ``` #### Task 4.3: mbti-result.vue (结果页) **Files:** - Create: `cfc-frontend/pages/family/mbti-result.vue` ```markdown - [ ] 大字展示类型代码 (如 INTJ) + 中文名 (架构师) + 动画入场 - 4 维度雷达图 (Canvas 2D,复用 self-check-result 雷达逻辑,4 轴 E/I S/N T/F J/P) - 画像卡片:核心特质 / 优势 / 挑战 / 职业倾向 / 家庭风格 / 搭配建议 - 五维能量联动建议卡片 (从 profile.energySuggestion 读取,展示 5 个维度建议) - 底部按钮:查看百科、分享、重新测评 ``` #### Task 4.4: mbti-profile.vue (16 型百科) **Files:** - Create: `cfc-frontend/pages/family/mbti-profile.vue` ```markdown - [ ] 4x4 网格卡片 (16 种类型),每卡片显示类型代码 + 中文名 + 1 行标签 - 点击卡片 → 调用 getMbtiProfile(typeCode) → 弹窗或新页展示完整画像 - 顶部搜索/筛选:按 E/I、S/N、T/F、J/P 筛选 ``` --- ### Phase 5: 管理端 MBTI 配置 #### Task 5.1: 管理端 API 与页面 **Files:** - Create: `cfc-web/src/api/mbti.js` - Create: `cfc-web/src/views/admin/MbtiProfiles.vue` - Modify: `cfc-web/src/router/index.js` ```markdown - [ ] **Step 1: API 封装** (mbti.js) ```js export function getMbtiProfileList() { return request('/api/admin/mbti/profile/list', 'POST') } export function saveMbtiProfile(data) { return request('/api/admin/mbti/profile/save', 'POST', data) } export function deleteMbtiProfile(id) { return request('/api/admin/mbti/profile/delete', 'POST', {id}) } export function initMbtiSeedData() { return request('/api/admin/mbti/seed/init', 'POST') } ``` - [ ] **Step 2: MbtiProfiles.vue** (Element UI Table + Dialog 编辑) - 列表展示 16 行:type_code, name, is_active, 操作(编辑/删除) - 编辑弹窗:所有字段可编辑,energy_suggestion 用 JSON 编辑器 (textarea + 格式化) - "初始化种子数据"按钮调用 initMbtiSeedData() - [ ] **Step 3: 路由注册** (admin 子路由) ``` #### Task 5.2: 管理端 Controller (可选,若需后端增删改) **Files:** - Create: `controller/admin/MbtiProfileController.java` (若管理端走后端 CRUD) - 或直接在 MbtiService 暴露 admin 方法,MbtiController 复用 ```markdown - [ ] 视情况新增或复用,编译验证 ``` --- ### Phase 6: API 文档同步与验收 #### Task 6.1: 更新 API_REFERENCE.md **Files:** - Modify: `docs/superpowers/api/API_REFERENCE.md` ```markdown - [ ] 在 Controller 总览表新增: | ManualDimensionScoreController | /api/family/manual-score | 五维手动填分 | — | | MbtiController | /api/family/mbti | MBTI 人格测评 | — | | MbtiProfileController | /api/admin/mbti/profile | MBTI 画像管理(管理端) | — | - [ ] 详细记录每个接口的请求/响应示例 ``` #### Task 6.2: 全量编译 + 功能自测 ```markdown - [ ] cd cfc-backend && mvn clean compile - [ ] 启动后端,用 Postman/curl 测试 8 个新接口 - [ ] 微信开发者工具预览 5 个新页面流程 - [ ] 管理端 npm run serve 验证 MBTI 配置页 ``` --- ## 验收标准 (Definition of Done) 1. **手动填分**:家长可在 self-check-entry 点"直接填分" → 选成员 → 5 个滑块 0-100 → 提交 → 结果页显示雷达图/总分,能量沙盘实时更新 2. **MBTI 测评**:入口 → 选成员 → 30 题答完 → 显示类型代码+画像+4维雷达+五维建议 → 可查百科 3. **管理端**:16 型画像可增删改,种子数据一键初始化 4. **数据库**:3 表结构正确,迁移幂等,schema.sql 同步 5. **编译**:`mvn clean compile` 通过,无 Lint 报错 --- ## 执行建议 **推荐 Subagent-Driven 并行执行** (7 个独立子任务可并行): | 并行组 | 任务 | 预计耗时 | |---------|------|----------| | A | Task 0.1+0.2 (DB迁移+种子) | 30 min | | B | Task 1.1-1.3 (手动填分后端) | 45 min | | C | Task 2.1-2.4 (MBTI 后端) | 60 min | | D | Task 3.1-3.2 (前端手动填分) | 45 min | | E | Task 4.1-4.4 (前端 MBTI 4页) | 90 min | | F | Task 5.1-5.2 (管理端) | 45 min | | G | Task 6.1-6.2 (文档+验收) | 30 min | **两阶段 Review:** 每组完成后暂停,人工确认无冲突再合并。 --- **Plan complete and saved to `docs/superpowers/plans/2026-09-10-manual-dimension-mbti-plan.md`. Two execution options:** **1. Subagent-Driven (recommended)** - I dispatch a fresh subagent per task group, review between groups, fast iteration **2. Inline Execution** - Execute tasks in this session using executing-plans, batch execution with checkpoints **Which approach?**