|
|
@@ -183,7 +183,7 @@ public class EnergyService {
|
|
|
dto.setMindScore(calcParentMind(parent));
|
|
|
dto.setWisdomScore(calcParentWisdom(parent));
|
|
|
dto.setActionScore(calcParentAction(parent));
|
|
|
- dto.setWealthScore(calcParentWealth(parent));
|
|
|
+ dto.setWealthScore(calcParentWealth(parent, dto));
|
|
|
|
|
|
int overall = (safeScore(dto.getBodyScore()) + safeScore(dto.getMindScore())
|
|
|
+ safeScore(dto.getWisdomScore()) + safeScore(dto.getActionScore())
|
|
|
@@ -249,17 +249,36 @@ public class EnergyService {
|
|
|
Arrays.asList("习惯", "好习惯", "自律", "家务", "自理", "作息"), 365);
|
|
|
}
|
|
|
|
|
|
- /** 家长 富 — 积分积累效率 */
|
|
|
- private int calcParentWealth(User parent) {
|
|
|
+ /** 家长 富 — 三子维度加权 */
|
|
|
+ private int calcParentWealth(User parent, MemberEnergyDTO dto) {
|
|
|
+ int income = calcParentWealthIncome(parent);
|
|
|
+ int achievement = calcParentWealthAchievement(parent);
|
|
|
+ int network = calcParentWealthNetwork(parent);
|
|
|
+ dto.setWealthIncome(income);
|
|
|
+ dto.setWealthAchievement(achievement);
|
|
|
+ dto.setWealthNetwork(network);
|
|
|
+ return (int) Math.round(income * 0.5 + achievement * 0.3 + network * 0.2);
|
|
|
+ }
|
|
|
+
|
|
|
+ /** 家长富-金钱收入:积分总量/500 */
|
|
|
+ private int calcParentWealthIncome(User parent) {
|
|
|
Integer totalPoints = parent.getTotalPoints();
|
|
|
if (totalPoints == null) totalPoints = 0;
|
|
|
-
|
|
|
- // 参考上限:假设 500 积分为满分
|
|
|
int refMax = 500;
|
|
|
int score = Math.min(totalPoints * 100 / Math.max(refMax, 1), 100);
|
|
|
return Math.max(score, 0);
|
|
|
}
|
|
|
|
|
|
+ /** 家长富-社会成就:第一阶段返回0占位 */
|
|
|
+ private int calcParentWealthAchievement(User parent) {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ /** 家长富-资源网络:第一阶段返回0占位 */
|
|
|
+ private int calcParentWealthNetwork(User parent) {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
// ==================== 孩子能量计算 ====================
|
|
|
|
|
|
private MemberEnergyDTO calcChildEnergy(FamilyMember child) {
|
|
|
@@ -269,11 +288,15 @@ public class EnergyService {
|
|
|
dto.setName(child.getNickname());
|
|
|
dto.setAvatar(null); // 孩子没有独立头像,用默认
|
|
|
|
|
|
- dto.setBodyScore(calcChildBody(child));
|
|
|
+ int bodyScore = calcChildBody(child);
|
|
|
+ dto.setBodyScore(bodyScore);
|
|
|
dto.setMindScore(calcChildMind(child));
|
|
|
dto.setWisdomScore(calcChildWisdom(child));
|
|
|
dto.setActionScore(calcChildAction(child));
|
|
|
- dto.setWealthScore(calcChildWealth(child));
|
|
|
+ dto.setWealthScore(calcChildWealth(child, dto));
|
|
|
+
|
|
|
+ // 身克富杠杆
|
|
|
+ applyBodyWealthRestraint(bodyScore, dto.getWealthScore(), dto);
|
|
|
|
|
|
int overall = (safeScore(dto.getBodyScore()) + safeScore(dto.getMindScore())
|
|
|
+ safeScore(dto.getWisdomScore()) + safeScore(dto.getActionScore())
|
|
|
@@ -513,11 +536,56 @@ public class EnergyService {
|
|
|
return Math.min((int) Math.round(streakScore * 0.4 + habitScore * 0.6), 100);
|
|
|
}
|
|
|
|
|
|
- /** 孩子 富 — 积分获取效率 */
|
|
|
- private int calcChildWealth(FamilyMember child) {
|
|
|
+ /** 孩子 富 — 三子维度加权 */
|
|
|
+ private int calcChildWealth(FamilyMember child, MemberEnergyDTO dto) {
|
|
|
+ int edu = calcChildWealthEducation(child);
|
|
|
+ int social = calcChildWealthSocial(child);
|
|
|
+ int points = calcChildWealthPoints(child);
|
|
|
+ dto.setWealthEducation(edu);
|
|
|
+ dto.setWealthSocial(social);
|
|
|
+ dto.setWealthPoints(points);
|
|
|
+ return (int) Math.round(edu * 0.3 + social * 0.2 + points * 0.5);
|
|
|
+ }
|
|
|
+
|
|
|
+ /** 孩子富-学业成绩:DAN测评最近3次综合分+进步趋势 */
|
|
|
+ private int calcChildWealthEducation(FamilyMember child) {
|
|
|
Long childId = child.getId();
|
|
|
+ LambdaQueryWrapper<DanAssessmentResult> qw = new LambdaQueryWrapper<DanAssessmentResult>()
|
|
|
+ .eq(DanAssessmentResult::getChildId, childId)
|
|
|
+ .eq(DanAssessmentResult::getStatus, "completed")
|
|
|
+ .orderByDesc(DanAssessmentResult::getAssessmentDate)
|
|
|
+ .last("LIMIT 3");
|
|
|
+ List<DanAssessmentResult> results = danAssessmentResultMapper.selectList(qw);
|
|
|
+ if (results.isEmpty()) return 0;
|
|
|
+
|
|
|
+ double avg = results.stream()
|
|
|
+ .filter(r -> r.getOverallScore() != null)
|
|
|
+ .mapToInt(DanAssessmentResult::getOverallScore)
|
|
|
+ .average()
|
|
|
+ .orElse(0);
|
|
|
+
|
|
|
+ // 进步趋势:最近一次 vs 前面平均
|
|
|
+ if (results.size() >= 2 && results.get(0).getOverallScore() != null && results.get(1).getOverallScore() != null) {
|
|
|
+ int latest = results.get(0).getOverallScore();
|
|
|
+ double prevAvg = results.subList(1, results.size()).stream()
|
|
|
+ .filter(r -> r.getOverallScore() != null)
|
|
|
+ .mapToInt(DanAssessmentResult::getOverallScore)
|
|
|
+ .average()
|
|
|
+ .orElse(latest);
|
|
|
+ double trend = (latest - prevAvg) / Math.max(prevAvg, 1) * 10;
|
|
|
+ avg += trend;
|
|
|
+ }
|
|
|
+ return clamp((int) Math.round(avg), 0, 100);
|
|
|
+ }
|
|
|
|
|
|
- // 已获得积分: points_log 中正向入账
|
|
|
+ /** 孩子富-社交筹码:活动参与次数(第一阶段返回0) */
|
|
|
+ private int calcChildWealthSocial(FamilyMember child) {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ /** 孩子富-规则博弈:积分获取效率 */
|
|
|
+ private int calcChildWealthPoints(FamilyMember child) {
|
|
|
+ Long childId = child.getId();
|
|
|
Calendar cal = Calendar.getInstance();
|
|
|
cal.add(Calendar.YEAR, -1);
|
|
|
Date oneYearAgo = cal.getTime();
|
|
|
@@ -531,7 +599,6 @@ public class EnergyService {
|
|
|
.mapToInt(pl -> pl.getAmount() != null ? pl.getAmount() : 0)
|
|
|
.sum();
|
|
|
|
|
|
- // 参考上限: 同期可获得的积分上限
|
|
|
LambdaQueryWrapper<Task> taskWrapper = new LambdaQueryWrapper<Task>()
|
|
|
.eq(Task::getChildId, childId)
|
|
|
.ne(Task::getIsTemplate, 1)
|
|
|
@@ -546,6 +613,37 @@ public class EnergyService {
|
|
|
return Math.max(score, 0);
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 身克富杠杆:身体底盘制约财富能量
|
|
|
+ * - 身 < 40: penalty → wealth *= (0.5 + 0.5 * body/100)
|
|
|
+ * - 身 < 50 && 富 > 身+20: overdraw(透支预警,不下调)
|
|
|
+ * - else: normal
|
|
|
+ */
|
|
|
+ private void applyBodyWealthRestraint(Integer bodyScore, Integer wealthScore, MemberEnergyDTO dto) {
|
|
|
+ int body = safeScore(bodyScore);
|
|
|
+ int wealth = safeScore(wealthScore);
|
|
|
+
|
|
|
+ if (body < 40) {
|
|
|
+ dto.setBodyWealthStatus("penalty");
|
|
|
+ double factor = 0.5 + 0.5 * body / 100.0;
|
|
|
+ int adjusted = (int) Math.round(wealth * factor);
|
|
|
+ dto.setWealthScore(Math.max(adjusted, 0));
|
|
|
+ dto.setBodyWealthMessage("健康正在稀释财富能量,建议优先关注身体健康");
|
|
|
+ } else if (body < 50 && wealth > body + 20) {
|
|
|
+ dto.setBodyWealthStatus("overdraw");
|
|
|
+ dto.setWealthScore(wealth);
|
|
|
+ dto.setBodyWealthMessage("财富能量超出身体承受范围,注意劳逸结合");
|
|
|
+ } else {
|
|
|
+ dto.setBodyWealthStatus("normal");
|
|
|
+ dto.setWealthScore(wealth);
|
|
|
+ if (body >= 70) {
|
|
|
+ dto.setBodyWealthMessage("身体底盘稳固,财富能量充沛");
|
|
|
+ } else {
|
|
|
+ dto.setBodyWealthMessage("");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
// ==================== 通用方法 ====================
|
|
|
|
|
|
/**
|