|
|
@@ -60,6 +60,9 @@ public class FiveDimensionSelfCheckService {
|
|
|
/** 15 题静态题库(书稿终章原文) */
|
|
|
private static final List<SelfCheckQuestionVO> QUESTION_BANK = buildQuestionBank();
|
|
|
|
|
|
+ /** 子维度附加题库(行6维 + 心·自驱力/自我概念 + 智·成长型思维 + 富·家族传承) */
|
|
|
+ private static final List<SelfCheckQuestionVO> SUB_DIMENSION_QUESTION_BANK = buildSubDimensionQuestionBank();
|
|
|
+
|
|
|
private static List<SelfCheckQuestionVO> buildQuestionBank() {
|
|
|
List<SelfCheckQuestionVO> bank = new ArrayList<>();
|
|
|
// 身(1-3)
|
|
|
@@ -115,6 +118,79 @@ public class FiveDimensionSelfCheckService {
|
|
|
return bank;
|
|
|
}
|
|
|
|
|
|
+ /** 子维度附加题库构建(对应五维内部子维度:行6维 + 心自驱力/自我概念 + 智成长型思维 + 富家族传承) */
|
|
|
+ private static List<SelfCheckQuestionVO> buildSubDimensionQuestionBank() {
|
|
|
+ List<SelfCheckQuestionVO> bank = new ArrayList<>();
|
|
|
+ // 行·亲子关系
|
|
|
+ bank.add(sq(101, "action", "actionParentChild",
|
|
|
+ "你每天有固定时间陪伴家人/孩子聊天吗?",
|
|
|
+ "A", "几乎每天", "B", "每周多次", "C", "偶尔", "D", "几乎没有"));
|
|
|
+ bank.add(sq(102, "action", "actionParentChild",
|
|
|
+ "家人/孩子愿意主动跟你分享心里话吗?",
|
|
|
+ "A", "总是愿意", "B", "经常", "C", "有时", "D", "很少开口"));
|
|
|
+ // 行·夫妻/同胞关系
|
|
|
+ bank.add(sq(103, "action", "actionMarital",
|
|
|
+ "你和伴侣有专属的二人交流时间吗?",
|
|
|
+ "A", "每周都有", "B", "每月几次", "C", "很少", "D", "几乎没有"));
|
|
|
+ bank.add(sq(104, "action", "actionSibling",
|
|
|
+ "你和兄弟姐妹相处融洽、能互相支持吗?",
|
|
|
+ "A", "非常融洽", "B", "比较和谐", "C", "一般", "D", "常有摩擦"));
|
|
|
+ // 行·父母/亲属关系
|
|
|
+ bank.add(sq(105, "action", "actionParental",
|
|
|
+ "你有定期探望或问候父母吗?",
|
|
|
+ "A", "每周都联系", "B", "每月数次", "C", "偶尔", "D", "很少联系"));
|
|
|
+ bank.add(sq(106, "action", "actionRelative",
|
|
|
+ "你与祖辈/其他长辈相处和睦、有沟通吗?",
|
|
|
+ "A", "非常和睦", "B", "比较和睦", "C", "一般", "D", "疏远"));
|
|
|
+ // 行·领导/师生关系
|
|
|
+ bank.add(sq(107, "action", "actionLeadership",
|
|
|
+ "你与上级/同事的协作关系顺畅吗?",
|
|
|
+ "A", "非常顺畅", "B", "比较顺畅", "C", "一般", "D", "常有冲突"));
|
|
|
+ bank.add(sq(108, "action", "actionTeacherStudent",
|
|
|
+ "你与老师/导师互动积极、关系良好吗?",
|
|
|
+ "A", "非常积极", "B", "比较积极", "C", "一般", "D", "很少互动"));
|
|
|
+ // 行·社会性
|
|
|
+ bank.add(sq(109, "action", "actionSociality",
|
|
|
+ "你积极参与朋友/同事/社区的社交活动吗?",
|
|
|
+ "A", "经常参与", "B", "偶尔参与", "C", "很少", "D", "几乎不参与"));
|
|
|
+ bank.add(sq(110, "action", "actionChildSociality",
|
|
|
+ "你乐于和同伴合作分享、遵守规则吗?",
|
|
|
+ "A", "总是如此", "B", "经常", "C", "有时", "D", "很少"));
|
|
|
+ // 行·人际韧性
|
|
|
+ bank.add(sq(111, "action", "actionInterpersonal",
|
|
|
+ "遇到人际冲突时你能冷静处理并修复关系吗?",
|
|
|
+ "A", "总能", "B", "经常能", "C", "有时能", "D", "常感无助"));
|
|
|
+ bank.add(sq(112, "action", "actionChildInterpersonal",
|
|
|
+ "受委屈时你能恰当表达并处理情绪吗?",
|
|
|
+ "A", "总能", "B", "经常能", "C", "有时能", "D", "常憋在心里"));
|
|
|
+ // 心·自驱力
|
|
|
+ bank.add(sq(113, "mind", "driveAutonomy",
|
|
|
+ "面对目标你能主动开始、不需他人催促吗?",
|
|
|
+ "A", "总是主动", "B", "经常主动", "C", "需要提醒", "D", "总要催"));
|
|
|
+ bank.add(sq(114, "mind", "driveCompetence",
|
|
|
+ "你对自己完成任务的能力有信心吗?",
|
|
|
+ "A", "非常有信心", "B", "比较有信心", "C", "有些不确定", "D", "常怀疑自己"));
|
|
|
+ bank.add(sq(115, "mind", "driveRelatedness",
|
|
|
+ "你对家庭/团队有强烈的归属感和认同感吗?",
|
|
|
+ "A", "非常强烈", "B", "比较强烈", "C", "一般", "D", "几乎没有"));
|
|
|
+ // 心·自我概念
|
|
|
+ bank.add(sq(116, "mind", "selfConceptOverall",
|
|
|
+ "你总体上接纳并喜欢现在的自己吗?",
|
|
|
+ "A", "非常接纳", "B", "比较接纳", "C", "一般", "D", "不太接纳"));
|
|
|
+ // 智·成长型思维
|
|
|
+ bank.add(sq(117, "wisdom", "wisdomGrowthMindset",
|
|
|
+ "遇到困难时你相信凭借努力可以提升和进步吗?",
|
|
|
+ "A", "非常相信", "B", "比较相信", "C", "不确定", "D", "觉得天赋决定一切"));
|
|
|
+ // 富·家族传承
|
|
|
+ bank.add(sq(118, "wealth", "wealthLegacy",
|
|
|
+ "你有为家庭做长期财务规划或传承安排吗?",
|
|
|
+ "A", "有系统规划", "B", "有初步想法", "C", "想过但没做", "D", "完全没想过"));
|
|
|
+ bank.add(sq(119, "wealth", "wealthChildLegacy",
|
|
|
+ "你会引导孩子养成储蓄和规划的理财习惯吗?",
|
|
|
+ "A", "经常引导", "B", "偶尔引导", "C", "很少", "D", "从未"));
|
|
|
+ return bank;
|
|
|
+ }
|
|
|
+
|
|
|
private static SelfCheckQuestionVO q(int id, String dimension, String text, String... opts) {
|
|
|
SelfCheckQuestionVO vo = new SelfCheckQuestionVO();
|
|
|
vo.setId(id);
|
|
|
@@ -135,11 +211,113 @@ public class FiveDimensionSelfCheckService {
|
|
|
return vo;
|
|
|
}
|
|
|
|
|
|
+ private static SelfCheckQuestionVO sq(int id, String dimension, String subDim, String text, String... opts) {
|
|
|
+ SelfCheckQuestionVO vo = q(id, dimension, text, opts);
|
|
|
+ vo.setSubDim(subDim);
|
|
|
+ return vo;
|
|
|
+ }
|
|
|
+
|
|
|
/** 获取题库(15题) */
|
|
|
public List<SelfCheckQuestionVO> getQuestions() {
|
|
|
return QUESTION_BANK;
|
|
|
}
|
|
|
|
|
|
+ /** 获取子维度附加题库 */
|
|
|
+ public List<SelfCheckQuestionVO> getSubDimensionQuestions() {
|
|
|
+ return SUB_DIMENSION_QUESTION_BANK;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 提交子维度自检问卷并计算子维度评分(0-100)
|
|
|
+ * 答案格式:A=100, B=66, C=33, D=0
|
|
|
+ * 结果以 sub_ 前缀存入 scoresJson(如 sub_actionParentChild: 75)
|
|
|
+ */
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public Map<String, Integer> submitSubDimensionCheck(SubmitSelfCheckDTO dto, Long userId) {
|
|
|
+ if (dto.getAnswers() == null || dto.getAnswers().isEmpty()) {
|
|
|
+ throw new IllegalArgumentException("答案不能为空");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 题目ID → 答案
|
|
|
+ Map<Integer, String> answerMap = new LinkedHashMap<>();
|
|
|
+ for (SubmitSelfCheckDTO.AnswerItem item : dto.getAnswers()) {
|
|
|
+ if (item.getQuestionId() == null || item.getAnswer() == null) continue;
|
|
|
+ answerMap.put(item.getQuestionId(), item.getAnswer().trim().toUpperCase());
|
|
|
+ }
|
|
|
+
|
|
|
+ // 逐子维度计分
|
|
|
+ Map<String, int[]> subDimScores = new LinkedHashMap<>(); // subDim → [sum, count]
|
|
|
+ for (SelfCheckQuestionVO qv : SUB_DIMENSION_QUESTION_BANK) {
|
|
|
+ String subDim = qv.getSubDim();
|
|
|
+ if (subDim == null) continue;
|
|
|
+ String ans = answerMap.get(qv.getId());
|
|
|
+ if (ans == null || "E".equals(ans)) continue;
|
|
|
+ int score = subScoreOf(ans);
|
|
|
+ subDimScores.computeIfAbsent(subDim, k -> new int[2]);
|
|
|
+ subDimScores.get(subDim)[0] += score;
|
|
|
+ subDimScores.get(subDim)[1]++;
|
|
|
+ }
|
|
|
+
|
|
|
+ Map<String, Integer> result = new LinkedHashMap<>();
|
|
|
+ for (Map.Entry<String, int[]> entry : subDimScores.entrySet()) {
|
|
|
+ int avg = entry.getValue()[1] > 0 ? entry.getValue()[0] / entry.getValue()[1] : 0;
|
|
|
+ result.put("sub_" + entry.getKey(), avg);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 保存到现有记录(复用 scoresJson,以 sub_ 前缀区分)
|
|
|
+ FiveDimensionSelfCheck record = new FiveDimensionSelfCheck();
|
|
|
+ record.setUserId(userId);
|
|
|
+ record.setFamilyMemberId(dto.getFamilyMemberId());
|
|
|
+ record.setAnswersJson(toJson(dto.getAnswers()));
|
|
|
+ // 合并到现有 scoresJson(保留 dimension 级 key + 新增 sub_ 前缀 key)
|
|
|
+ try {
|
|
|
+ Map<String, Object> merged = new LinkedHashMap<>();
|
|
|
+ String existingScoresJson = getLatestSubScores(userId);
|
|
|
+ if (existingScoresJson != null) {
|
|
|
+ Map<String, Object> existing = objectMapper.readValue(existingScoresJson, LinkedHashMap.class);
|
|
|
+ merged.putAll(existing);
|
|
|
+ }
|
|
|
+ merged.putAll(result);
|
|
|
+ record.setScoresJson(objectMapper.writeValueAsString(merged));
|
|
|
+ } catch (Exception e) {
|
|
|
+ record.setScoresJson(toJson(result));
|
|
|
+ }
|
|
|
+ record.setCreatedAt(new Date());
|
|
|
+ selfCheckMapper.insert(record);
|
|
|
+
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ /** 获取最新子维度得分JSON */
|
|
|
+ public String getLatestSubScores(Long userId) {
|
|
|
+ LambdaQueryWrapper<FiveDimensionSelfCheck> wrapper = new LambdaQueryWrapper<FiveDimensionSelfCheck>()
|
|
|
+ .eq(FiveDimensionSelfCheck::getUserId, userId)
|
|
|
+ .orderByDesc(FiveDimensionSelfCheck::getCreatedAt)
|
|
|
+ .last("LIMIT 1");
|
|
|
+ FiveDimensionSelfCheck record = selfCheckMapper.selectOne(wrapper);
|
|
|
+ if (record == null || record.getScoresJson() == null) return null;
|
|
|
+ // 仅返回 sub_ 前缀的 key
|
|
|
+ try {
|
|
|
+ Map<String, Object> all = objectMapper.readValue(record.getScoresJson(), LinkedHashMap.class);
|
|
|
+ Map<String, Object> sub = new LinkedHashMap<>();
|
|
|
+ for (Map.Entry<String, Object> e : all.entrySet()) {
|
|
|
+ if (e.getKey().startsWith("sub_")) {
|
|
|
+ sub.put(e.getKey().substring(4), e.getValue());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return sub.isEmpty() ? null : objectMapper.writeValueAsString(sub);
|
|
|
+ } catch (Exception e) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private int subScoreOf(String answer) {
|
|
|
+ if ("A".equals(answer)) return 100;
|
|
|
+ if ("B".equals(answer)) return 66;
|
|
|
+ if ("C".equals(answer)) return 33;
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 提交自检问卷并计算评分
|
|
|
*/
|