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: 将知心益家 (ZXYJ) 从家庭教育任务管理小程序升级为溪福俱乐部 — 身/心/智/行四维主动健康管理平台,集成Lilishop电商。
Architecture: 增量重构(非重建),保留现有ZXYJ代码作为智(Wisdom)域基础,围绕其新增身(Body)/心(Mind)/行(Action)三个域。前端首页改为四象限矩阵入口,后端按域新增controller包和entity。Lilishop作为独立微服务通过REST API集成。
Tech Stack:
| # | 决策点 | 选择 | 理由 |
|---|---|---|---|
| 1 | Entity组织 | A) flat entity/ + 域前缀命名 (BodyHealthMetric, MindMoodLog) | 现有49个实体全平铺,最小破坏性,MyBatis-Plus不关心包路径 |
| 2 | Controller包 | B) 新增域包,旧包保留 (新增controller/body/, controller/mind/, controller/action/) | 不打断现有功能,增量迁移 |
| 3 | 前端导航 | 4-tab: 首页(四象限) / 智(任务+成长) / 行(活动+商城) / 我的 | 微信tabBar最多5项,4项最简洁;身/心通过首页象限入口进入 |
| 4 | 数据库策略 | A) DatabaseInitializer.java | 遵循"不建索引,不建约束,不建自定义SQL"约束,保持现有模式 |
| 5 | 积分系统 | 跨域共享PointsService + PointsLog增加domain字段 | 积分来源扩展到四域,统一管理避免碎片化 |
| 6 | Lilishop集成 | C) 混合模式 — 服务账号(商品浏览) + 委托认证(购物车/结算) | 浏览无需用户上下文,交易需用户身份 |
| 7 | 构建顺序 | 框架→行→身→心→电商 | 行域有部分代码可扩展,身域较简单,心域最复杂,电商独立最后加 |
| 功能 | 说明 | 新entity |
|---|---|---|
| 健康指标记录 | 体重/血压/心率/睡眠 | BodyHealthMetric |
| 水营养追踪 | 每日饮水/营养素摄入 | BodyNutritionLog |
| 抗衰评估 | 细胞抗衰测评+报告 | BodyAntiAgingAssessment |
| 运动追踪 | 运动记录+步数 | BodyExerciseLog |
| 功能 | 说明 | 新entity |
|---|---|---|
| 情绪日志 | 每日心情记录+标签 | MindMoodLog |
| 心理测评 | 专业心理评估问卷 | MindPsychologicalAssessment |
| 家庭氛围指数 | 家庭关系评估 | MindFamilyAtmosphereIndex |
| 冥想/放松 | 引导式冥想计时 | MindMeditationSession |
| 功能 | 现有entity | 状态 |
|---|---|---|
| 任务管理 | Task, TaskTemplate, TaskPlanInstance | ✅ 已完成 |
| 积分系统 | PointsLog, StreakMilestone | ✅ 已完成 |
| 奖励体系 | Reward, Wish, RewardWishlist | ✅ 已完成 |
| 成长档案 | GrowthRecord, GrowthPlan | ✅ 已完成 |
| DAN测评 | DanAssessmentResult, AssessmentOrder | ✅ 已完成 |
| 小游戏 | MiniGame | ✅ 已完成 |
| 规划师 | Guide, GuidePackage, GuideFamily | ✅ 已完成 |
| 功能 | 说明 | 新entity |
|---|---|---|
| 活动/事件 | 线上线下活动组织 | ActionActivity, ActionActivityRegistration |
| 内容科普 | 文章/视频/知识库 | ActionArticle, ActionArticleCategory |
| 长者关怀 | 养老计划+关怀记录 | ActionElderCarePlan, ActionElderCareLog |
| 家庭实践 | 关系践行任务(区别于智域学习任务) | ActionPracticeTask |
| 社区互动 | 家庭间交流 | ActionCommunityPost, ActionCommunityComment |
cfc-backend/src/main/java/com/etotem/cfc/
├── controller/
│ ├── body/ # NEW
│ │ ├── BodyHealthController.java
│ │ ├── BodyNutritionController.java
│ │ ├── BodyAntiAgingController.java
│ │ └── BodyExerciseController.java
│ ├── mind/ # NEW
│ │ ├── MindMoodController.java
│ │ ├── MindAssessmentController.java
│ │ ├── MindFamilyAtmosphereController.java
│ │ └── MindMeditationController.java
│ ├── action/ # NEW
│ │ ├── ActionController.java
│ │ ├── ActionArticleController.java
│ │ ├── ActionElderCareController.java
│ │ └── ActionCommunityController.java
│ └── commerce/ # NEW (Phase 5)
│ └── CommerceController.java
├── entity/
│ ├── BodyHealthMetric.java # NEW
│ ├── BodyNutritionLog.java # NEW
│ ├── BodyAntiAgingAssessment.java # NEW
│ ├── BodyExerciseLog.java # NEW
│ ├── MindMoodLog.java # NEW
│ ├── MindPsychologicalAssessment.java # NEW
│ ├── MindFamilyAtmosphereIndex.java # NEW
│ ├── MindMeditationSession.java # NEW
│ ├── ActionActivity.java # NEW
│ ├── ActionActivityRegistration.java # NEW
│ ├── ActionArticle.java # NEW
│ ├── ActionArticleCategory.java # NEW
│ ├── ActionElderCarePlan.java # NEW
│ ├── ActionElderCareLog.java # NEW
│ ├── ActionPracticeTask.java # NEW
│ ├── ActionCommunityPost.java # NEW
│ └── ActionCommunityComment.java # NEW
├── service/
│ ├── BodyHealthService.java # NEW
│ ├── BodyNutritionService.java # NEW
│ ├── BodyAntiAgingService.java # NEW
│ ├── BodyExerciseService.java # NEW
│ ├── MindMoodService.java # NEW
│ ├── MindAssessmentService.java # NEW
│ ├── MindFamilyAtmosphereService.java # NEW
│ ├── MindMeditationService.java # NEW
│ ├── ActionActivityService.java # NEW
│ ├── ActionArticleService.java # NEW
│ ├── ActionElderCareService.java # NEW
│ ├── ActionPracticeService.java # NEW
│ ├── ActionCommunityService.java # NEW
│ └── LilishopApiClient.java # NEW (Phase 5)
└── mapper/
├── BodyHealthMetricMapper.java # NEW
├── BodyNutritionLogMapper.java # NEW
├── BodyAntiAgingAssessmentMapper.java # NEW
├── BodyExerciseLogMapper.java # NEW
├── MindMoodLogMapper.java # NEW
├── MindPsychologicalAssessmentMapper.java # NEW
├── MindFamilyAtmosphereIndexMapper.java # NEW
├── MindMeditationSessionMapper.java # NEW
├── ActionActivityMapper.java # NEW
├── ActionActivityRegistrationMapper.java # NEW
├── ActionArticleMapper.java # NEW
├── ActionArticleCategoryMapper.java # NEW
├── ActionElderCarePlanMapper.java # NEW
├── ActionElderCareLogMapper.java # NEW
├── ActionPracticeTaskMapper.java # NEW
├── ActionCommunityPostMapper.java # NEW
└── ActionCommunityCommentMapper.java # NEW
cfc-frontend/
├── pages/
│ ├── index/
│ │ ├── index.vue # MODIFY - 四象限首页
│ │ ├── parent-index.vue # MODIFY - 增加四象限入口
│ │ └── child-index.vue # MODIFY - 增加四象限入口
│ ├── body/ # NEW
│ │ ├── index.vue # 身域首页
│ │ ├── health-metric.vue # 健康指标记录
│ │ ├── nutrition-log.vue # 水营养追踪
│ │ ├── anti-aging.vue # 抗衰评估
│ │ └── exercise-log.vue # 运动追踪
│ ├── mind/ # NEW
│ │ ├── index.vue # 心域首页
│ │ ├── mood-log.vue # 情绪日志
│ │ ├── assessment.vue # 心理测评
│ │ ├── family-atmosphere.vue # 家庭氛围
│ │ └── meditation.vue # 冥想
│ ├── action/ # NEW
│ │ ├── index.vue # 行域首页
│ │ ├── activity-list.vue # 活动列表
│ │ ├── activity-detail.vue # 活动详情
│ │ ├── article-list.vue # 文章/科普列表
│ │ ├── article-detail.vue # 文章详情
│ │ ├── elder-care.vue # 长者关怀
│ │ └── community.vue # 社区互动
│ ├── commerce/ # NEW (Phase 5)
│ │ ├── product-list.vue # 商品列表
│ │ ├── product-detail.vue # 商品详情
│ │ ├── cart.vue # 购物车
│ │ └── order-list.vue # 订单列表
│ └── ... # 现有页面保留
├── pages.json # MODIFY - 新增页面注册 + tabBar调整
├── utils/
│ └── api.js # MODIFY - 新增域API封装
└── store/
└── index.js # MODIFY - 增加 domain state
目标: 建立四域框架,替换首页为四象限入口,创建所有新entity/mapper/service骨架,调整导航结构。此阶段完成后,用户可以看到四象限首页,点击进入各域,但各域功能为空壳。
Files:
cfc-backend/src/main/java/com/etotem/cfc/entity/BodyHealthMetric.javacfc-backend/src/main/java/com/etotem/cfc/entity/BodyNutritionLog.javacfc-backend/src/main/java/com/etotem/cfc/entity/BodyAntiAgingAssessment.javaCreate: cfc-backend/src/main/java/com/etotem/cfc/entity/BodyExerciseLog.java
[ ] Step 1: 创建 BodyHealthMetric entity
package com.etotem.cfc.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@Data
@TableName("body_health_metrics")
public class BodyHealthMetric {
@TableId(type = IdType.AUTO)
private Long id;
private Long familyId;
private Long userId;
private BigDecimal weight;
private Integer bloodPressureSystolic;
private Integer bloodPressureDiastolic;
private Integer heartRate;
private Integer sleepHours;
private Integer sleepQuality;
private String note;
private LocalDateTime recordDate;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}
[ ] Step 2: 创建 BodyNutritionLog entity
package com.etotem.cfc.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@Data
@TableName("body_nutrition_logs")
public class BodyNutritionLog {
@TableId(type = IdType.AUTO)
private Long id;
private Long familyId;
private Long userId;
private Integer waterMl;
private Integer calorieIntake;
private BigDecimal proteinG;
private BigDecimal vitaminC;
private BigDecimal vitaminD;
private String mealType;
private String note;
private LocalDateTime recordDate;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}
[ ] Step 3: 创建 BodyAntiAgingAssessment entity
package com.etotem.cfc.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@TableName("body_anti_aging_assessments")
public class BodyAntiAgingAssessment {
@TableId(type = IdType.AUTO)
private Long id;
private Long familyId;
private Long userId;
private Long guideId;
private String assessmentType;
private Integer cellularAge;
private Integer biologicalAge;
private String resultSummary;
private String resultDetail;
private String reportUrl;
private String status;
private LocalDateTime assessmentDate;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}
[ ] Step 4: 创建 BodyExerciseLog entity
package com.etotem.cfc.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@TableName("body_exercise_logs")
public class BodyExerciseLog {
@TableId(type = IdType.AUTO)
private Long id;
private Long familyId;
private Long userId;
private String exerciseType;
private Integer durationMinutes;
private Integer steps;
private Integer caloriesBurned;
private Integer intensity;
private String note;
private LocalDateTime exerciseDate;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}
[ ] Step 5: 编译验证
Run: cd cfc-backend && mvn compile -q
Expected: BUILD SUCCESS
Files:
cfc-backend/src/main/java/com/etotem/cfc/entity/MindMoodLog.javacfc-backend/src/main/java/com/etotem/cfc/entity/MindPsychologicalAssessment.javacfc-backend/src/main/java/com/etotem/cfc/entity/MindFamilyAtmosphereIndex.javaCreate: cfc-backend/src/main/java/com/etotem/cfc/entity/MindMeditationSession.java
[ ] Step 1: 创建 MindMoodLog entity
package com.etotem.cfc.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@TableName("mind_mood_logs")
public class MindMoodLog {
@TableId(type = IdType.AUTO)
private Long id;
private Long familyId;
private Long userId;
private Integer moodScore;
private String moodLabel;
private String tags;
private String note;
private String weather;
private LocalDateTime recordDate;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}
[ ] Step 2: 创建 MindPsychologicalAssessment entity
package com.etotem.cfc.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@TableName("mind_psychological_assessments")
public class MindPsychologicalAssessment {
@TableId(type = IdType.AUTO)
private Long id;
private Long familyId;
private Long userId;
private Long guideId;
private String assessmentType;
private Integer totalScore;
private String resultLevel;
private String resultSummary;
private String resultDetail;
private String reportUrl;
private String status;
private LocalDateTime assessmentDate;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}
[ ] Step 3: 创建 MindFamilyAtmosphereIndex entity
package com.etotem.cfc.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@TableName("mind_family_atmosphere_indices")
public class MindFamilyAtmosphereIndex {
@TableId(type = IdType.AUTO)
private Long id;
private Long familyId;
private Integer communicationScore;
private Integer emotionalScore;
private Integer supportScore;
private Integer conflictScore;
private Integer overallScore;
private String note;
private LocalDateTime recordDate;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}
[ ] Step 4: 创建 MindMeditationSession entity
package com.etotem.cfc.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@TableName("mind_meditation_sessions")
public class MindMeditationSession {
@TableId(type = IdType.AUTO)
private Long id;
private Long familyId;
private Long userId;
private String meditationType;
private Integer durationMinutes;
private Integer completionRate;
private String audioUrl;
private String note;
private LocalDateTime sessionDate;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}
[ ] Step 5: 编译验证
Run: cd cfc-backend && mvn compile -q
Expected: BUILD SUCCESS
Files:
cfc-backend/src/main/java/com/etotem/cfc/entity/ActionActivity.javacfc-backend/src/main/java/com/etotem/cfc/entity/ActionActivityRegistration.javacfc-backend/src/main/java/com/etotem/cfc/entity/ActionArticle.javacfc-backend/src/main/java/com/etotem/cfc/entity/ActionArticleCategory.javacfc-backend/src/main/java/com/etotem/cfc/entity/ActionElderCarePlan.javacfc-backend/src/main/java/com/etotem/cfc/entity/ActionElderCareLog.javacfc-backend/src/main/java/com/etotem/cfc/entity/ActionPracticeTask.javacfc-backend/src/main/java/com/etotem/cfc/entity/ActionCommunityPost.javaCreate: cfc-backend/src/main/java/com/etotem/cfc/entity/ActionCommunityComment.java
[ ] Step 1: 创建 ActionActivity entity
package com.etotem.cfc.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@Data
@TableName("action_activities")
public class ActionActivity {
@TableId(type = IdType.AUTO)
private Long id;
private Long creatorId;
private String title;
private String description;
private String coverUrl;
private String activityType;
private String location;
private BigDecimal latitude;
private BigDecimal longitude;
private LocalDateTime startTime;
private LocalDateTime endTime;
private Integer maxParticipants;
private Integer currentParticipants;
private BigDecimal fee;
private String status;
private Integer pointsReward;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}
[ ] Step 2: 创建 ActionActivityRegistration entity
package com.etotem.cfc.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@TableName("action_activity_registrations")
public class ActionActivityRegistration {
@TableId(type = IdType.AUTO)
private Long id;
private Long activityId;
private Long userId;
private Long familyId;
private String status;
private String note;
private LocalDateTime registeredAt;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}
[ ] Step 3: 创建 ActionArticle entity
package com.etotem.cfc.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@TableName("action_articles")
public class ActionArticle {
@TableId(type = IdType.AUTO)
private Long id;
private Long authorId;
private Long categoryId;
private String title;
private String summary;
private String content;
private String coverUrl;
private String articleType;
private Integer viewCount;
private Integer likeCount;
private String status;
private LocalDateTime publishedAt;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}
[ ] Step 4: 创建 ActionArticleCategory entity
package com.etotem.cfc.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@TableName("action_article_categories")
public class ActionArticleCategory {
@TableId(type = IdType.AUTO)
private Long id;
private String name;
private String icon;
private String description;
private Integer sortOrder;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}
[ ] Step 5: 创建 ActionElderCarePlan entity
package com.etotem.cfc.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@TableName("action_elder_care_plans")
public class ActionElderCarePlan {
@TableId(type = IdType.AUTO)
private Long id;
private Long familyId;
private Long creatorId;
private String elderName;
private Integer elderAge;
private String healthCondition;
private String careLevel;
private String careItems;
private String emergencyContact;
private String emergencyPhone;
private String status;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}
[ ] Step 6: 创建 ActionElderCareLog entity
package com.etotem.cfc.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@TableName("action_elder_care_logs")
public class ActionElderCareLog {
@TableId(type = IdType.AUTO)
private Long id;
private Long planId;
private Long familyId;
private Long caregiverId;
private String careItem;
private String careDetail;
private String careResult;
private LocalDateTime careDate;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}
[ ] Step 7: 创建 ActionPracticeTask entity
package com.etotem.cfc.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@TableName("action_practice_tasks")
public class ActionPracticeTask {
@TableId(type = IdType.AUTO)
private Long id;
private Long familyId;
private Long creatorId;
private Long assigneeId;
private String title;
private String description;
private String practiceType;
private Integer pointsReward;
private String status;
private LocalDateTime deadline;
private LocalDateTime completedAt;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}
[ ] Step 8: 创建 ActionCommunityPost entity
package com.etotem.cfc.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@TableName("action_community_posts")
public class ActionCommunityPost {
@TableId(type = IdType.AUTO)
private Long id;
private Long userId;
private Long familyId;
private String title;
private String content;
private String imageUrl;
private String postType;
private Integer viewCount;
private Integer likeCount;
private Integer commentCount;
private String status;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}
[ ] Step 9: 创建 ActionCommunityComment entity
package com.etotem.cfc.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@TableName("action_community_comments")
public class ActionCommunityComment {
@TableId(type = IdType.AUTO)
private Long id;
private Long postId;
private Long userId;
private Long parentId;
private String content;
private Integer likeCount;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}
[ ] Step 10: 编译验证
Run: cd cfc-backend && mvn compile -q
Expected: BUILD SUCCESS
Files:
Create: 17 mapper files (每个entity对应一个Mapper)
[ ] Step 1: 创建 Body 域 Mapper
// cfc-backend/src/main/java/com/etotem/cfc/mapper/BodyHealthMetricMapper.java
package com.etotem.cfc.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.etotem.cfc.entity.BodyHealthMetric;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface BodyHealthMetricMapper extends BaseMapper<BodyHealthMetric> {}
// cfc-backend/src/main/java/com/etotem/cfc/mapper/BodyNutritionLogMapper.java
package com.etotem.cfc.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.etotem.cfc.entity.BodyNutritionLog;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface BodyNutritionLogMapper extends BaseMapper<BodyNutritionLog> {}
// cfc-backend/src/main/java/com/etotem/cfc/mapper/BodyAntiAgingAssessmentMapper.java
package com.etotem.cfc.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.etotem.cfc.entity.BodyAntiAgingAssessment;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface BodyAntiAgingAssessmentMapper extends BaseMapper<BodyAntiAgingAssessment> {}
// cfc-backend/src/main/java/com/etotem/cfc/mapper/BodyExerciseLogMapper.java
package com.etotem.cfc.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.etotem.cfc.entity.BodyExerciseLog;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface BodyExerciseLogMapper extends BaseMapper<BodyExerciseLog> {}
[ ] Step 2: 创建 Mind 域 Mapper
// cfc-backend/src/main/java/com/etotem/cfc/mapper/MindMoodLogMapper.java
package com.etotem.cfc.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.etotem.cfc.entity.MindMoodLog;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface MindMoodLogMapper extends BaseMapper<MindMoodLog> {}
// cfc-backend/src/main/java/com/etotem/cfc/mapper/MindPsychologicalAssessmentMapper.java
package com.etotem.cfc.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.etotem.cfc.entity.MindPsychologicalAssessment;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface MindPsychologicalAssessmentMapper extends BaseMapper<MindPsychologicalAssessment> {}
// cfc-backend/src/main/java/com/etotem/cfc/mapper/MindFamilyAtmosphereIndexMapper.java
package com.etotem.cfc.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.etotem.cfc.entity.MindFamilyAtmosphereIndex;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface MindFamilyAtmosphereIndexMapper extends BaseMapper<MindFamilyAtmosphereIndex> {}
// cfc-backend/src/main/java/com/etotem/cfc/mapper/MindMeditationSessionMapper.java
package com.etotem.cfc.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.etotem.cfc.entity.MindMeditationSession;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface MindMeditationSessionMapper extends BaseMapper<MindMeditationSession> {}
[ ] Step 3: 创建 Action 域 Mapper
// cfc-backend/src/main/java/com/etotem/cfc/mapper/ActionActivityMapper.java
package com.etotem.cfc.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.etotem.cfc.entity.ActionActivity;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface ActionActivityMapper extends BaseMapper<ActionActivity> {}
// cfc-backend/src/main/java/com/etotem/cfc/mapper/ActionActivityRegistrationMapper.java
package com.etotem.cfc.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.etotem.cfc.entity.ActionActivityRegistration;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface ActionActivityRegistrationMapper extends BaseMapper<ActionActivityRegistration> {}
// cfc-backend/src/main/java/com/etotem/cfc/mapper/ActionArticleMapper.java
package com.etotem.cfc.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.etotem.cfc.entity.ActionArticle;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface ActionArticleMapper extends BaseMapper<ActionArticle> {}
// cfc-backend/src/main/java/com/etotem/cfc/mapper/ActionArticleCategoryMapper.java
package com.etotem.cfc.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.etotem.cfc.entity.ActionArticleCategory;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface ActionArticleCategoryMapper extends BaseMapper<ActionArticleCategory> {}
// cfc-backend/src/main/java/com/etotem/cfc/mapper/ActionElderCarePlanMapper.java
package com.etotem.cfc.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.etotem.cfc.entity.ActionElderCarePlan;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface ActionElderCarePlanMapper extends BaseMapper<ActionElderCarePlan> {}
// cfc-backend/src/main/java/com/etotem/cfc/mapper/ActionElderCareLogMapper.java
package com.etotem.cfc.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.etotem.cfc.entity.ActionElderCareLog;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface ActionElderCareLogMapper extends BaseMapper<ActionElderCareLog> {}
// cfc-backend/src/main/java/com/etotem/cfc/mapper/ActionPracticeTaskMapper.java
package com.etotem.cfc.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.etotem.cfc.entity.ActionPracticeTask;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface ActionPracticeTaskMapper extends BaseMapper<ActionPracticeTask> {}
// cfc-backend/src/main/java/com/etotem/cfc/mapper/ActionCommunityPostMapper.java
package com.etotem.cfc.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.etotem.cfc.entity.ActionCommunityPost;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface ActionCommunityPostMapper extends BaseMapper<ActionCommunityPost> {}
// cfc-backend/src/main/java/com/etotem/cfc/mapper/ActionCommunityCommentMapper.java
package com.etotem.cfc.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.etotem.cfc.entity.ActionCommunityComment;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface ActionCommunityCommentMapper extends BaseMapper<ActionCommunityComment> {}
[ ] Step 4: 编译验证
Run: cd cfc-backend && mvn compile -q
Expected: BUILD SUCCESS
Files:
Modify: cfc-backend/src/main/java/com/etotem/cfc/config/DatabaseInitializer.java
[ ] Step 1: 在 DatabaseInitializer 中添加 17 张新表的 CREATE TABLE 语句
在 DatabaseInitializer 的 init 方法中(现有建表语句之后),添加以下新表创建逻辑。遵循现有模式:CREATE TABLE IF NOT EXISTS + 基本字段 + created_at/updated_at。
// === Body 域表 ===
createTableIfNotExists("body_health_metrics", "CREATE TABLE IF NOT EXISTS `body_health_metrics` (" +
"`id` BIGINT PRIMARY KEY AUTO_INCREMENT," +
"`family_id` BIGINT NOT NULL," +
"`user_id` BIGINT NOT NULL," +
"`weight` DECIMAL(5,1) DEFAULT NULL COMMENT '体重kg'," +
"`blood_pressure_systolic` INT DEFAULT NULL COMMENT '收缩压'," +
"`blood_pressure_diastolic` INT DEFAULT NULL COMMENT '舒张压'," +
"`heart_rate` INT DEFAULT NULL COMMENT '心率'," +
"`sleep_hours` INT DEFAULT NULL COMMENT '睡眠时长(小时)'," +
"`sleep_quality` INT DEFAULT NULL COMMENT '睡眠质量1-5'," +
"`note` VARCHAR(500) DEFAULT NULL," +
"`record_date` DATETIME NOT NULL," +
"`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP," +
"`updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='健康指标记录'");
createTableIfNotExists("body_nutrition_logs", "CREATE TABLE IF NOT EXISTS `body_nutrition_logs` (" +
"`id` BIGINT PRIMARY KEY AUTO_INCREMENT," +
"`family_id` BIGINT NOT NULL," +
"`user_id` BIGINT NOT NULL," +
"`water_ml` INT DEFAULT NULL COMMENT '饮水量ml'," +
"`calorie_intake` INT DEFAULT NULL COMMENT '热量摄入kcal'," +
"`protein_g` DECIMAL(5,1) DEFAULT NULL COMMENT '蛋白质g'," +
"`vitamin_c` DECIMAL(5,1) DEFAULT NULL COMMENT '维生素C mg'," +
"`vitamin_d` DECIMAL(5,1) DEFAULT NULL COMMENT '维生素D ug'," +
"`meal_type` VARCHAR(20) DEFAULT NULL COMMENT '餐次(breakfast/lunch/dinner/snack)'," +
"`note` VARCHAR(500) DEFAULT NULL," +
"`record_date` DATETIME NOT NULL," +
"`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP," +
"`updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='水营养记录'");
createTableIfNotExists("body_anti_aging_assessments", "CREATE TABLE IF NOT EXISTS `body_anti_aging_assessments` (" +
"`id` BIGINT PRIMARY KEY AUTO_INCREMENT," +
"`family_id` BIGINT NOT NULL," +
"`user_id` BIGINT NOT NULL," +
"`guide_id` BIGINT DEFAULT NULL COMMENT '规划师ID'," +
"`assessment_type` VARCHAR(50) DEFAULT NULL COMMENT '评估类型'," +
"`cellular_age` INT DEFAULT NULL COMMENT '细胞年龄'," +
"`biological_age` INT DEFAULT NULL COMMENT '生物学年龄'," +
"`result_summary` VARCHAR(500) DEFAULT NULL," +
"`result_detail` TEXT DEFAULT NULL," +
"`report_url` VARCHAR(500) DEFAULT NULL," +
"`status` VARCHAR(20) DEFAULT 'pending' COMMENT 'pending/completed'," +
"`assessment_date` DATETIME NOT NULL," +
"`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP," +
"`updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='抗衰评估'");
createTableIfNotExists("body_exercise_logs", "CREATE TABLE IF NOT EXISTS `body_exercise_logs` (" +
"`id` BIGINT PRIMARY KEY AUTO_INCREMENT," +
"`family_id` BIGINT NOT NULL," +
"`user_id` BIGINT NOT NULL," +
"`exercise_type` VARCHAR(50) NOT NULL COMMENT '运动类型'," +
"`duration_minutes` INT DEFAULT NULL COMMENT '时长(分钟)'," +
"`steps` INT DEFAULT NULL COMMENT '步数'," +
"`calories_burned` INT DEFAULT NULL COMMENT '消耗卡路里'," +
"`intensity` INT DEFAULT NULL COMMENT '强度1-5'," +
"`note` VARCHAR(500) DEFAULT NULL," +
"`exercise_date` DATETIME NOT NULL," +
"`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP," +
"`updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='运动记录'");
// === Mind 域表 ===
createTableIfNotExists("mind_mood_logs", "CREATE TABLE IF NOT EXISTS `mind_mood_logs` (" +
"`id` BIGINT PRIMARY KEY AUTO_INCREMENT," +
"`family_id` BIGINT NOT NULL," +
"`user_id` BIGINT NOT NULL," +
"`mood_score` INT NOT NULL COMMENT '心情分数1-10'," +
"`mood_label` VARCHAR(20) DEFAULT NULL COMMENT '心情标签(happy/sad/anxious/calm/angry)'," +
"`tags` VARCHAR(200) DEFAULT NULL COMMENT '自定义标签,分隔'," +
"`note` VARCHAR(500) DEFAULT NULL," +
"`weather` VARCHAR(20) DEFAULT NULL COMMENT '天气'," +
"`record_date` DATETIME NOT NULL," +
"`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP," +
"`updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='情绪日志'");
createTableIfNotExists("mind_psychological_assessments", "CREATE TABLE IF NOT EXISTS `mind_psychological_assessments` (" +
"`id` BIGINT PRIMARY KEY AUTO_INCREMENT," +
"`family_id` BIGINT NOT NULL," +
"`user_id` BIGINT NOT NULL," +
"`guide_id` BIGINT DEFAULT NULL COMMENT '规划师ID'," +
"`assessment_type` VARCHAR(50) NOT NULL COMMENT '评估类型(SCL90/SDS/SAS等)'," +
"`total_score` INT DEFAULT NULL," +
"`result_level` VARCHAR(20) DEFAULT NULL COMMENT 'normal/mild/moderate/severe'," +
"`result_summary` VARCHAR(500) DEFAULT NULL," +
"`result_detail` TEXT DEFAULT NULL," +
"`report_url` VARCHAR(500) DEFAULT NULL," +
"`status` VARCHAR(20) DEFAULT 'pending'," +
"`assessment_date` DATETIME NOT NULL," +
"`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP," +
"`updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='心理测评'");
createTableIfNotExists("mind_family_atmosphere_indices", "CREATE TABLE IF NOT EXISTS `mind_family_atmosphere_indices` (" +
"`id` BIGINT PRIMARY KEY AUTO_INCREMENT," +
"`family_id` BIGINT NOT NULL," +
"`communication_score` INT DEFAULT NULL COMMENT '沟通评分1-100'," +
"`emotional_score` INT DEFAULT NULL COMMENT '情感评分1-100'," +
"`support_score` INT DEFAULT NULL COMMENT '支持评分1-100'," +
"`conflict_score` INT DEFAULT NULL COMMENT '冲突评分1-100(越高越好=冲突处理越好)'," +
"`overall_score` INT DEFAULT NULL COMMENT '综合评分1-100'," +
"`note` VARCHAR(500) DEFAULT NULL," +
"`record_date` DATETIME NOT NULL," +
"`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP," +
"`updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='家庭氛围指数'");
createTableIfNotExists("mind_meditation_sessions", "CREATE TABLE IF NOT EXISTS `mind_meditation_sessions` (" +
"`id` BIGINT PRIMARY KEY AUTO_INCREMENT," +
"`family_id` BIGINT NOT NULL," +
"`user_id` BIGINT NOT NULL," +
"`meditation_type` VARCHAR(30) DEFAULT NULL COMMENT '冥想类型(breathing/body-scan/guided)'," +
"`duration_minutes` INT NOT NULL COMMENT '时长(分钟)'," +
"`completion_rate` INT DEFAULT NULL COMMENT '完成率0-100'," +
"`audio_url` VARCHAR(500) DEFAULT NULL COMMENT '引导音频URL'," +
"`note` VARCHAR(500) DEFAULT NULL," +
"`session_date` DATETIME NOT NULL," +
"`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP," +
"`updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='冥想记录'");
// === Action 域表 ===
createTableIfNotExists("action_activities", "CREATE TABLE IF NOT EXISTS `action_activities` (" +
"`id` BIGINT PRIMARY KEY AUTO_INCREMENT," +
"`creator_id` BIGINT NOT NULL COMMENT '创建人ID'," +
"`title` VARCHAR(200) NOT NULL," +
"`description` TEXT DEFAULT NULL," +
"`cover_url` VARCHAR(500) DEFAULT NULL COMMENT '封面图'," +
"`activity_type` VARCHAR(30) DEFAULT NULL COMMENT 'online/offline/hybrid'," +
"`location` VARCHAR(200) DEFAULT NULL COMMENT '地点'," +
"`latitude` DECIMAL(10,7) DEFAULT NULL," +
"`longitude` DECIMAL(10,7) DEFAULT NULL," +
"`start_time` DATETIME NOT NULL," +
"`end_time` DATETIME NOT NULL," +
"`max_participants` INT DEFAULT NULL COMMENT '最大参与人数'," +
"`current_participants` INT DEFAULT 0," +
"`fee` DECIMAL(10,2) DEFAULT 0 COMMENT '费用'," +
"`status` VARCHAR(20) DEFAULT 'draft' COMMENT 'draft/published/cancelled/ended'," +
"`points_reward` INT DEFAULT 0 COMMENT '参与奖励积分'," +
"`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP," +
"`updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='活动'");
createTableIfNotExists("action_activity_registrations", "CREATE TABLE IF NOT EXISTS `action_activity_registrations` (" +
"`id` BIGINT PRIMARY KEY AUTO_INCREMENT," +
"`activity_id` BIGINT NOT NULL," +
"`user_id` BIGINT NOT NULL," +
"`family_id` BIGINT NOT NULL," +
"`status` VARCHAR(20) DEFAULT 'registered' COMMENT 'registered/cancelled/attended'," +
"`note` VARCHAR(500) DEFAULT NULL," +
"`registered_at` DATETIME DEFAULT CURRENT_TIMESTAMP," +
"`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP," +
"`updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='活动报名'");
createTableIfNotExists("action_articles", "CREATE TABLE IF NOT EXISTS `action_articles` (" +
"`id` BIGINT PRIMARY KEY AUTO_INCREMENT," +
"`author_id` BIGINT NOT NULL," +
"`category_id` BIGINT DEFAULT NULL," +
"`title` VARCHAR(200) NOT NULL," +
"`summary` VARCHAR(500) DEFAULT NULL," +
"`content` LONGTEXT DEFAULT NULL," +
"`cover_url` VARCHAR(500) DEFAULT NULL," +
"`article_type` VARCHAR(30) DEFAULT 'article' COMMENT 'article/video/infographic'," +
"`view_count` INT DEFAULT 0," +
"`like_count` INT DEFAULT 0," +
"`status` VARCHAR(20) DEFAULT 'draft' COMMENT 'draft/published/archived'," +
"`published_at` DATETIME DEFAULT NULL," +
"`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP," +
"`updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文章/科普'");
createTableIfNotExists("action_article_categories", "CREATE TABLE IF NOT EXISTS `action_article_categories` (" +
"`id` BIGINT PRIMARY KEY AUTO_INCREMENT," +
"`name` VARCHAR(50) NOT NULL," +
"`icon` VARCHAR(50) DEFAULT NULL," +
"`description` VARCHAR(200) DEFAULT NULL," +
"`sort_order` INT DEFAULT 0," +
"`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP," +
"`updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文章分类'");
createTableIfNotExists("action_elder_care_plans", "CREATE TABLE IF NOT EXISTS `action_elder_care_plans` (" +
"`id` BIGINT PRIMARY KEY AUTO_INCREMENT," +
"`family_id` BIGINT NOT NULL," +
"`creator_id` BIGINT NOT NULL," +
"`elder_name` VARCHAR(50) NOT NULL COMMENT '长者姓名'," +
"`elder_age` INT DEFAULT NULL," +
"`health_condition` VARCHAR(500) DEFAULT NULL COMMENT '健康状况'," +
"`care_level` VARCHAR(20) DEFAULT NULL COMMENT 'care-level-1/2/3'," +
"`care_items` TEXT DEFAULT NULL COMMENT '关怀项目JSON'," +
"`emergency_contact` VARCHAR(50) DEFAULT NULL COMMENT '紧急联系人'," +
"`emergency_phone` VARCHAR(20) DEFAULT NULL COMMENT '紧急联系电话'," +
"`status` VARCHAR(20) DEFAULT 'active' COMMENT 'active/completed/archived'," +
"`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP," +
"`updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='长者关怀计划'");
createTableIfNotExists("action_elder_care_logs", "CREATE TABLE IF NOT EXISTS `action_elder_care_logs` (" +
"`id` BIGINT PRIMARY KEY AUTO_INCREMENT," +
"`plan_id` BIGINT NOT NULL," +
"`family_id` BIGINT NOT NULL," +
"`caregiver_id` BIGINT NOT NULL COMMENT '照护人ID'," +
"`care_item` VARCHAR(100) NOT NULL COMMENT '关怀项目'," +
"`care_detail` TEXT DEFAULT NULL COMMENT '照护详情'," +
"`care_result` VARCHAR(200) DEFAULT NULL COMMENT '照护结果'," +
"`care_date` DATETIME NOT NULL," +
"`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP," +
"`updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='长者关怀日志'");
createTableIfNotExists("action_practice_tasks", "CREATE TABLE IF NOT EXISTS `action_practice_tasks` (" +
"`id` BIGINT PRIMARY KEY AUTO_INCREMENT," +
"`family_id` BIGINT NOT NULL," +
"`creator_id` BIGINT NOT NULL," +
"`assignee_id` BIGINT DEFAULT NULL COMMENT '执行人ID'," +
"`title` VARCHAR(200) NOT NULL," +
"`description` VARCHAR(500) DEFAULT NULL," +
"`practice_type` VARCHAR(30) DEFAULT NULL COMMENT 'relationship/parenting/elder-care/community'," +
"`points_reward` INT DEFAULT 0 COMMENT '完成积分奖励'," +
"`status` VARCHAR(20) DEFAULT 'pending' COMMENT 'pending/completed/cancelled'," +
"`deadline` DATETIME DEFAULT NULL," +
"`completed_at` DATETIME DEFAULT NULL," +
"`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP," +
"`updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='践行任务'");
createTableIfNotExists("action_community_posts", "CREATE TABLE IF NOT EXISTS `action_community_posts` (" +
"`id` BIGINT PRIMARY KEY AUTO_INCREMENT," +
"`user_id` BIGINT NOT NULL," +
"`family_id` BIGINT DEFAULT NULL," +
"`title` VARCHAR(200) NOT NULL," +
"`content` TEXT NOT NULL," +
"`image_url` VARCHAR(500) DEFAULT NULL COMMENT '图片URL,分隔多张'," +
"`post_type` VARCHAR(30) DEFAULT 'sharing' COMMENT 'sharing/question/experience'," +
"`view_count` INT DEFAULT 0," +
"`like_count` INT DEFAULT 0," +
"`comment_count` INT DEFAULT 0," +
"`status` VARCHAR(20) DEFAULT 'published' COMMENT 'published/hidden/deleted'," +
"`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP," +
"`updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='社区帖子'");
createTableIfNotExists("action_community_comments", "CREATE TABLE IF NOT EXISTS `action_community_comments` (" +
"`id` BIGINT PRIMARY KEY AUTO_INCREMENT," +
"`post_id` BIGINT NOT NULL," +
"`user_id` BIGINT NOT NULL," +
"`parent_id` BIGINT DEFAULT NULL COMMENT '父评论ID(回复)'," +
"`content` VARCHAR(500) NOT NULL," +
"`like_count` INT DEFAULT 0," +
"`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP," +
"`updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='社区评论'");
在 DatabaseInitializer 的现有 points_log 表创建之后,添加 ALTER 语句:
// PointsLog 扩展:增加 domain 字段支持四域积分来源
try {
jdbcTemplate.execute("ALTER TABLE points_log ADD COLUMN `domain` VARCHAR(20) DEFAULT 'wisdom' COMMENT '积分来源域(body/mind/wisdom/action)'");
} catch (Exception e) {
// 字段已存在,忽略
log.info("points_log.domain already exists");
}
Run: cd cfc-backend && mvn spring-boot:run (确认启动不报错,新表自动创建)
Expected: Application starts successfully, logs show new tables created
Files:
Create: 13 service files (每个域核心service)
[ ] Step 1: 创建 Body 域 Service
// cfc-backend/src/main/java/com/etotem/cfc/service/BodyHealthService.java
package com.etotem.cfc.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.etotem.cfc.entity.BodyHealthMetric;
import com.etotem.cfc.mapper.BodyHealthMetricMapper;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
@Service
public class BodyHealthService {
@Resource
private BodyHealthMetricMapper bodyHealthMetricMapper;
public BodyHealthMetric createRecord(BodyHealthMetric record) {
bodyHealthMetricMapper.insert(record);
return record;
}
public List<BodyHealthMetric> getRecords(Long userId, Integer limit) {
return bodyHealthMetricMapper.selectList(
new LambdaQueryWrapper<BodyHealthMetric>()
.eq(BodyHealthMetric::getUserId, userId)
.orderByDesc(BodyHealthMetric::getRecordDate)
.last("LIMIT " + limit)
);
}
public BodyHealthMetric getLatestRecord(Long userId) {
return bodyHealthMetricMapper.selectOne(
new LambdaQueryWrapper<BodyHealthMetric>()
.eq(BodyHealthMetric::getUserId, userId)
.orderByDesc(BodyHealthMetric::getRecordDate)
.last("LIMIT 1")
);
}
}
// cfc-backend/src/main/java/com/etotem/cfc/service/BodyNutritionService.java
package com.etotem.cfc.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.etotem.cfc.entity.BodyNutritionLog;
import com.etotem.cfc.mapper.BodyNutritionLogMapper;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
@Service
public class BodyNutritionService {
@Resource
private BodyNutritionLogMapper bodyNutritionLogMapper;
public BodyNutritionLog createLog(BodyNutritionLog log) {
bodyNutritionLogMapper.insert(log);
return log;
}
public List<BodyNutritionLog> getLogs(Long userId, Integer limit) {
return bodyNutritionLogMapper.selectList(
new LambdaQueryWrapper<BodyNutritionLog>()
.eq(BodyNutritionLog::getUserId, userId)
.orderByDesc(BodyNutritionLog::getRecordDate)
.last("LIMIT " + limit)
);
}
}
// cfc-backend/src/main/java/com/etotem/cfc/service/BodyAntiAgingService.java
package com.etotem.cfc.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.etotem.cfc.entity.BodyAntiAgingAssessment;
import com.etotem.cfc.mapper.BodyAntiAgingAssessmentMapper;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
@Service
public class BodyAntiAgingService {
@Resource
private BodyAntiAgingAssessmentMapper bodyAntiAgingAssessmentMapper;
public BodyAntiAgingAssessment createAssessment(BodyAntiAgingAssessment assessment) {
bodyAntiAgingAssessmentMapper.insert(assessment);
return assessment;
}
public List<BodyAntiAgingAssessment> getAssessments(Long userId) {
return bodyAntiAgingAssessmentMapper.selectList(
new LambdaQueryWrapper<BodyAntiAgingAssessment>()
.eq(BodyAntiAgingAssessment::getUserId, userId)
.orderByDesc(BodyAntiAgingAssessment::getAssessmentDate)
);
}
}
// cfc-backend/src/main/java/com/etotem/cfc/service/BodyExerciseService.java
package com.etotem.cfc.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.etotem.cfc.entity.BodyExerciseLog;
import com.etotem.cfc.mapper.BodyExerciseLogMapper;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
@Service
public class BodyExerciseService {
@Resource
private BodyExerciseLogMapper bodyExerciseLogMapper;
public BodyExerciseLog createLog(BodyExerciseLog log) {
bodyExerciseLogMapper.insert(log);
return log;
}
public List<BodyExerciseLog> getLogs(Long userId, Integer limit) {
return bodyExerciseLogMapper.selectList(
new LambdaQueryWrapper<BodyExerciseLog>()
.eq(BodyExerciseLog::getUserId, userId)
.orderByDesc(BodyExerciseLog::getExerciseDate)
.last("LIMIT " + limit)
);
}
}
[ ] Step 2: 创建 Mind 域 Service
// cfc-backend/src/main/java/com/etotem/cfc/service/MindMoodService.java
package com.etotem.cfc.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.etotem.cfc.entity.MindMoodLog;
import com.etotem.cfc.mapper.MindMoodLogMapper;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
@Service
public class MindMoodService {
@Resource
private MindMoodLogMapper mindMoodLogMapper;
public MindMoodLog createLog(MindMoodLog log) {
mindMoodLogMapper.insert(log);
return log;
}
public List<MindMoodLog> getLogs(Long userId, Integer limit) {
return mindMoodLogMapper.selectList(
new LambdaQueryWrapper<MindMoodLog>()
.eq(MindMoodLog::getUserId, userId)
.orderByDesc(MindMoodLog::getRecordDate)
.last("LIMIT " + limit)
);
}
}
// cfc-backend/src/main/java/com/etotem/cfc/service/MindAssessmentService.java
package com.etotem.cfc.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.etotem.cfc.entity.MindPsychologicalAssessment;
import com.etotem.cfc.mapper.MindPsychologicalAssessmentMapper;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
@Service
public class MindAssessmentService {
@Resource
private MindPsychologicalAssessmentMapper mindPsychologicalAssessmentMapper;
public MindPsychologicalAssessment createAssessment(MindPsychologicalAssessment assessment) {
mindPsychologicalAssessmentMapper.insert(assessment);
return assessment;
}
public List<MindPsychologicalAssessment> getAssessments(Long userId) {
return mindPsychologicalAssessmentMapper.selectList(
new LambdaQueryWrapper<MindPsychologicalAssessment>()
.eq(MindPsychologicalAssessment::getUserId, userId)
.orderByDesc(MindPsychologicalAssessment::getAssessmentDate)
);
}
}
// cfc-backend/src/main/java/com/etotem/cfc/service/MindFamilyAtmosphereService.java
package com.etotem.cfc.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.etotem.cfc.entity.MindFamilyAtmosphereIndex;
import com.etotem.cfc.mapper.MindFamilyAtmosphereIndexMapper;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
@Service
public class MindFamilyAtmosphereService {
@Resource
private MindFamilyAtmosphereIndexMapper mindFamilyAtmosphereIndexMapper;
public MindFamilyAtmosphereIndex createIndex(MindFamilyAtmosphereIndex index) {
mindFamilyAtmosphereIndexMapper.insert(index);
return index;
}
public List<MindFamilyAtmosphereIndex> getIndices(Long familyId) {
return mindFamilyAtmosphereIndexMapper.selectList(
new LambdaQueryWrapper<MindFamilyAtmosphereIndex>()
.eq(MindFamilyAtmosphereIndex::getFamilyId, familyId)
.orderByDesc(MindFamilyAtmosphereIndex::getRecordDate)
);
}
}
// cfc-backend/src/main/java/com/etotem/cfc/service/MindMeditationService.java
package com.etotem.cfc.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.etotem.cfc.entity.MindMeditationSession;
import com.etotem.cfc.mapper.MindMeditationSessionMapper;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
@Service
public class MindMeditationService {
@Resource
private MindMeditationSessionMapper mindMeditationSessionMapper;
public MindMeditationSession createSession(MindMeditationSession session) {
mindMeditationSessionMapper.insert(session);
return session;
}
public List<MindMeditationSession> getSessions(Long userId, Integer limit) {
return mindMeditationSessionMapper.selectList(
new LambdaQueryWrapper<MindMeditationSession>()
.eq(MindMeditationSession::getUserId, userId)
.orderByDesc(MindMeditationSession::getSessionDate)
.last("LIMIT " + limit)
);
}
}
[ ] Step 3: 创建 Action 域 Service
// cfc-backend/src/main/java/com/etotem/cfc/service/ActionActivityService.java
package com.etotem.cfc.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.etotem.cfc.entity.ActionActivity;
import com.etotem.cfc.entity.ActionActivityRegistration;
import com.etotem.cfc.mapper.ActionActivityMapper;
import com.etotem.cfc.mapper.ActionActivityRegistrationMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.List;
@Service
public class ActionActivityService {
@Resource
private ActionActivityMapper actionActivityMapper;
@Resource
private ActionActivityRegistrationMapper actionActivityRegistrationMapper;
public ActionActivity createActivity(ActionActivity activity) {
actionActivityMapper.insert(activity);
return activity;
}
public List<ActionActivity> getPublishedActivities(Integer limit) {
return actionActivityMapper.selectList(
new LambdaQueryWrapper<ActionActivity>()
.eq(ActionActivity::getStatus, "published")
.orderByDesc(ActionActivity::getStartTime)
.last("LIMIT " + limit)
);
}
public ActionActivity getById(Long id) {
return actionActivityMapper.selectById(id);
}
@Transactional
public ActionActivityRegistration register(Long activityId, Long userId, Long familyId) {
ActionActivityRegistration registration = new ActionActivityRegistration();
registration.setActivityId(activityId);
registration.setUserId(userId);
registration.setFamilyId(familyId);
registration.setStatus("registered");
actionActivityRegistrationMapper.insert(registration);
// Increment current_participants
ActionActivity activity = actionActivityMapper.selectById(activityId);
if (activity != null) {
activity.setCurrentParticipants(activity.getCurrentParticipants() + 1);
actionActivityMapper.updateById(activity);
}
return registration;
}
}
// cfc-backend/src/main/java/com/etotem/cfc/service/ActionArticleService.java
package com.etotem.cfc.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.etotem.cfc.entity.ActionArticle;
import com.etotem.cfc.mapper.ActionArticleMapper;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
@Service
public class ActionArticleService {
@Resource
private ActionArticleMapper actionArticleMapper;
public ActionArticle createArticle(ActionArticle article) {
actionArticleMapper.insert(article);
return article;
}
public List<ActionArticle> getPublishedArticles(Long categoryId, Integer limit) {
LambdaQueryWrapper<ActionArticle> wrapper = new LambdaQueryWrapper<ActionArticle>()
.eq(ActionArticle::getStatus, "published")
.orderByDesc(ActionArticle::getPublishedAt)
.last("LIMIT " + limit);
if (categoryId != null) {
wrapper.eq(ActionArticle::getCategoryId, categoryId);
}
return actionArticleMapper.selectList(wrapper);
}
public ActionArticle getById(Long id) {
return actionArticleMapper.selectById(id);
}
}
// cfc-backend/src/main/java/com/etotem/cfc/service/ActionElderCareService.java
package com.etotem.cfc.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.etotem.cfc.entity.ActionElderCarePlan;
import com.etotem.cfc.entity.ActionElderCareLog;
import com.etotem.cfc.mapper.ActionElderCarePlanMapper;
import com.etotem.cfc.mapper.ActionElderCareLogMapper;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
@Service
public class ActionElderCareService {
@Resource
private ActionElderCarePlanMapper actionElderCarePlanMapper;
@Resource
private ActionElderCareLogMapper actionElderCareLogMapper;
public ActionElderCarePlan createPlan(ActionElderCarePlan plan) {
actionElderCarePlanMapper.insert(plan);
return plan;
}
public List<ActionElderCarePlan> getPlans(Long familyId) {
return actionElderCarePlanMapper.selectList(
new LambdaQueryWrapper<ActionElderCarePlan>()
.eq(ActionElderCarePlan::getFamilyId, familyId)
.orderByDesc(ActionElderCarePlan::getCreatedAt)
);
}
public ActionElderCareLog createCareLog(ActionElderCareLog log) {
actionElderCareLogMapper.insert(log);
return log;
}
public List<ActionElderCareLog> getCareLogs(Long planId) {
return actionElderCareLogMapper.selectList(
new LambdaQueryWrapper<ActionElderCareLog>()
.eq(ActionElderCareLog::getPlanId, planId)
.orderByDesc(ActionElderCareLog::getCareDate)
);
}
}
// cfc-backend/src/main/java/com/etotem/cfc/service/ActionPracticeService.java
package com.etotem.cfc.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.etotem.cfc.entity.ActionPracticeTask;
import com.etotem.cfc.mapper.ActionPracticeTaskMapper;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
@Service
public class ActionPracticeService {
@Resource
private ActionPracticeTaskMapper actionPracticeTaskMapper;
public ActionPracticeTask createTask(ActionPracticeTask task) {
actionPracticeTaskMapper.insert(task);
return task;
}
public List<ActionPracticeTask> getTasks(Long familyId) {
return actionPracticeTaskMapper.selectList(
new LambdaQueryWrapper<ActionPracticeTask>()
.eq(ActionPracticeTask::getFamilyId, familyId)
.orderByDesc(ActionPracticeTask::getCreatedAt)
);
}
}
// cfc-backend/src/main/java/com/etotem/cfc/service/ActionCommunityService.java
package com.etotem.cfc.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.etotem.cfc.entity.ActionCommunityPost;
import com.etotem.cfc.entity.ActionCommunityComment;
import com.etotem.cfc.mapper.ActionCommunityPostMapper;
import com.etotem.cfc.mapper.ActionCommunityCommentMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.List;
@Service
public class ActionCommunityService {
@Resource
private ActionCommunityPostMapper actionCommunityPostMapper;
@Resource
private ActionCommunityCommentMapper actionCommunityCommentMapper;
public ActionCommunityPost createPost(ActionCommunityPost post) {
actionCommunityPostMapper.insert(post);
return post;
}
public List<ActionCommunityPost> getPosts(Integer limit) {
return actionCommunityPostMapper.selectList(
new LambdaQueryWrapper<ActionCommunityPost>()
.eq(ActionCommunityPost::getStatus, "published")
.orderByDesc(ActionCommunityPost::getCreatedAt)
.last("LIMIT " + limit)
);
}
public ActionCommunityComment createComment(ActionCommunityComment comment) {
actionCommunityCommentMapper.insert(comment);
// Increment post comment count
ActionCommunityPost post = actionCommunityPostMapper.selectById(comment.getPostId());
if (post != null) {
post.setCommentCount(post.getCommentCount() + 1);
actionCommunityPostMapper.updateById(post);
}
return comment;
}
public List<ActionCommunityComment> getComments(Long postId) {
return actionCommunityCommentMapper.selectList(
new LambdaQueryWrapper<ActionCommunityComment>()
.eq(ActionCommunityComment::getPostId, postId)
.orderByAsc(ActionCommunityComment::getCreatedAt)
);
}
}
[ ] Step 4: 编译验证
Run: cd cfc-backend && mvn compile -q
Expected: BUILD SUCCESS
Files:
cfc-backend/src/main/java/com/etotem/cfc/controller/body/BodyHealthController.javacfc-backend/src/main/java/com/etotem/cfc/controller/mind/MindMoodController.javacfc-backend/src/main/java/com/etotem/cfc/controller/action/ActionController.javaCreate: cfc-backend/src/main/java/com/etotem/cfc/controller/action/ActionArticleController.java
[ ] Step 1: 创建 BodyHealthController
package com.etotem.cfc.controller.body;
import com.etotem.cfc.common.Result;
import com.etotem.cfc.entity.BodyHealthMetric;
import com.etotem.cfc.service.BodyHealthService;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/body/health")
public class BodyHealthController {
@Resource
private BodyHealthService bodyHealthService;
@PostMapping("/create")
public Result<BodyHealthMetric> createRecord(@RequestBody BodyHealthMetric record) {
return Result.success(bodyHealthService.createRecord(record));
}
@PostMapping("/list")
public Result<List<BodyHealthMetric>> getRecords(@RequestBody Map<String, Object> params) {
Long userId = Long.valueOf(params.get("userId").toString());
Integer limit = params.containsKey("limit") ? Integer.valueOf(params.get("limit").toString()) : 30;
return Result.success(bodyHealthService.getRecords(userId, limit));
}
@PostMapping("/latest")
public Result<BodyHealthMetric> getLatestRecord(@RequestBody Map<String, Object> params) {
Long userId = Long.valueOf(params.get("userId").toString());
return Result.success(bodyHealthService.getLatestRecord(userId));
}
}
[ ] Step 2: 创建 MindMoodController
package com.etotem.cfc.controller.mind;
import com.etotem.cfc.common.Result;
import com.etotem.cfc.entity.MindMoodLog;
import com.etotem.cfc.service.MindMoodService;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/mind/mood")
public class MindMoodController {
@Resource
private MindMoodService mindMoodService;
@PostMapping("/create")
public Result<MindMoodLog> createLog(@RequestBody MindMoodLog log) {
return Result.success(mindMoodService.createLog(log));
}
@PostMapping("/list")
public Result<List<MindMoodLog>> getLogs(@RequestBody Map<String, Object> params) {
Long userId = Long.valueOf(params.get("userId").toString());
Integer limit = params.containsKey("limit") ? Integer.valueOf(params.get("limit").toString()) : 30;
return Result.success(mindMoodService.getLogs(userId, limit));
}
}
[ ] Step 3: 创建 ActionController (活动+社区)
package com.etotem.cfc.controller.action;
import com.etotem.cfc.common.Result;
import com.etotem.cfc.entity.ActionActivity;
import com.etotem.cfc.entity.ActionActivityRegistration;
import com.etotem.cfc.service.ActionActivityService;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/action/activity")
public class ActionController {
@Resource
private ActionActivityService actionActivityService;
@PostMapping("/create")
public Result<ActionActivity> createActivity(@RequestBody ActionActivity activity) {
return Result.success(actionActivityService.createActivity(activity));
}
@PostMapping("/list")
public Result<List<ActionActivity>> getActivities(@RequestBody Map<String, Object> params) {
Integer limit = params.containsKey("limit") ? Integer.valueOf(params.get("limit").toString()) : 20;
return Result.success(actionActivityService.getPublishedActivities(limit));
}
@PostMapping("/detail")
public Result<ActionActivity> getDetail(@RequestBody Map<String, Object> params) {
Long id = Long.valueOf(params.get("id").toString());
return Result.success(actionActivityService.getById(id));
}
@PostMapping("/register")
public Result<ActionActivityRegistration> register(@RequestBody Map<String, Object> params) {
Long activityId = Long.valueOf(params.get("activityId").toString());
Long userId = Long.valueOf(params.get("userId").toString());
Long familyId = Long.valueOf(params.get("familyId").toString());
return Result.success(actionActivityService.register(activityId, userId, familyId));
}
}
[ ] Step 4: 创建 ActionArticleController
package com.etotem.cfc.controller.action;
import com.etotem.cfc.common.Result;
import com.etotem.cfc.entity.ActionArticle;
import com.etotem.cfc.service.ActionArticleService;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/action/article")
public class ActionArticleController {
@Resource
private ActionArticleService actionArticleService;
@PostMapping("/create")
public Result<ActionArticle> createArticle(@RequestBody ActionArticle article) {
return Result.success(actionArticleService.createArticle(article));
}
@PostMapping("/list")
public Result<List<ActionArticle>> getArticles(@RequestBody Map<String, Object> params) {
Long categoryId = params.containsKey("categoryId") ? Long.valueOf(params.get("categoryId").toString()) : null;
Integer limit = params.containsKey("limit") ? Integer.valueOf(params.get("limit").toString()) : 20;
return Result.success(actionArticleService.getPublishedArticles(categoryId, limit));
}
@PostMapping("/detail")
public Result<ActionArticle> getDetail(@RequestBody Map<String, Object> params) {
Long id = Long.valueOf(params.get("id").toString());
return Result.success(actionArticleService.getById(id));
}
}
[ ] Step 5: 编译验证
Run: cd cfc-backend && mvn compile -q
Expected: BUILD SUCCESS
Files:
Modify: cfc-backend/src/main/java/com/etotem/cfc/entity/PointsLog.java
[ ] Step 1: 在 PointsLog.java 中增加 domain 字段
在现有 PointsLog 实体中添加:
private String domain; // 积分来源域: body/mind/wisdom/action,默认 "wisdom"
Run: cd cfc-backend && mvn compile -q
Expected: BUILD SUCCESS
Files:
cfc-frontend/pages/index/index.vuecfc-frontend/pages/index/parent-index.vuecfc-frontend/pages/index/child-index.vuecfc-frontend/pages.jsoncfc-frontend/utils/api.jsModify: cfc-frontend/store/index.js
[ ] Step 1: 修改 pages.json — 注册新页面路径 + 调整tabBar
在 pages 数组中新增(在现有页面之后):
{
"path": "pages/body/index",
"style": { "navigationBarTitleText": "身·细胞抗衰" }
},
{
"path": "pages/body/health-metric",
"style": { "navigationBarTitleText": "健康指标" }
},
{
"path": "pages/body/nutrition-log",
"style": { "navigationBarTitleText": "水营养追踪" }
},
{
"path": "pages/body/anti-aging",
"style": { "navigationBarTitleText": "抗衰评估" }
},
{
"path": "pages/body/exercise-log",
"style": { "navigationBarTitleText": "运动记录" }
},
{
"path": "pages/mind/index",
"style": { "navigationBarTitleText": "心·心理情绪" }
},
{
"path": "pages/mind/mood-log",
"style": { "navigationBarTitleText": "情绪日志" }
},
{
"path": "pages/mind/assessment",
"style": { "navigationBarTitleText": "心理测评" }
},
{
"path": "pages/mind/family-atmosphere",
"style": { "navigationBarTitleText": "家庭氛围" }
},
{
"path": "pages/mind/meditation",
"style": { "navigationBarTitleText": "冥想放松" }
},
{
"path": "pages/action/index",
"style": { "navigationBarTitleText": "行·关系践行" }
},
{
"path": "pages/action/activity-list",
"style": { "navigationBarTitleText": "活动列表" }
},
{
"path": "pages/action/activity-detail",
"style": { "navigationBarTitleText": "活动详情" }
},
{
"path": "pages/action/article-list",
"style": { "navigationBarTitleText": "文章科普" }
},
{
"path": "pages/action/article-detail",
"style": { "navigationBarTitleText": "文章详情" }
},
{
"path": "pages/action/elder-care",
"style": { "navigationBarTitleText": "长者关怀" }
},
{
"path": "pages/action/community",
"style": { "navigationBarTitleText": "社区互动" }
}
修改 tabBar(保留4-tab,调整"任务"和"心愿单"为域入口):
"tabBar": {
"color": "#999999",
"selectedColor": "#4A90D9",
"backgroundColor": "#ffffff",
"borderStyle": "black",
"list": [
{
"pagePath": "pages/index/index",
"text": "首页",
"iconPath": "static/tab-home.png",
"selectedIconPath": "static/tab-home-active.png"
},
{
"pagePath": "pages/tasks/tasks",
"text": "智·成长",
"iconPath": "static/tab-wisdom.png",
"selectedIconPath": "static/tab-wisdom-active.png"
},
{
"pagePath": "pages/rewards/rewards",
"text": "行·实践",
"iconPath": "static/tab-action.png",
"selectedIconPath": "static/tab-action-active.png"
},
{
"pagePath": "pages/profile/profile",
"text": "我的",
"iconPath": "static/tab-me.png",
"selectedIconPath": "static/tab-me-active.png"
}
]
}
在 parent-index.vue 和 child-index.vue 的模板中,在现有内容上方添加四象限矩阵区域:
<!-- 四象限入口 -->
<view class="domain-matrix">
<view class="domain-title">溪福俱乐部 · 身心智行</view>
<view class="domain-grid">
<view class="domain-item domain-body" @click="navigateToDomain('body')">
<view class="domain-icon">🧬</view>
<view class="domain-name">身 · 细胞抗衰</view>
<view class="domain-desc">健康指标·运动·抗衰</view>
</view>
<view class="domain-item domain-mind" @click="navigateToDomain('mind')">
<view class="domain-icon">🧠</view>
<view class="domain-name">心 · 心理情绪</view>
<view class="domain-desc">情绪·测评·冥想</view>
</view>
<view class="domain-item domain-wisdom" @click="navigateToDomain('wisdom')">
<view class="domain-icon">📚</view>
<view class="domain-name">智 · 教育成长</view>
<view class="domain-desc">任务·积分·测评</view>
</view>
<view class="domain-item domain-action" @click="navigateToDomain('action')">
<view class="domain-icon">🤝</view>
<view class="domain-name">行 · 关系践行</view>
<view class="domain-desc">活动·科普·关怀</view>
</view>
</view>
</view>
在 parent-index.vue 和 child-index.vue 的 methods 中添加:
navigateToDomain(domain) {
const routes = {
body: '/pages/body/index',
mind: '/pages/mind/index',
wisdom: '/pages/tasks/tasks',
action: '/pages/action/index'
};
const url = routes[domain];
if (domain === 'wisdom') {
uni.switchTab({ url });
} else {
uni.navigateTo({ url });
}
}
在 style 中添加:
.domain-matrix {
padding: 20rpx 30rpx;
background: linear-gradient(135deg, #f5f7fa 0%, #e8ecf1 100%);
border-radius: 20rpx;
margin: 20rpx;
}
.domain-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
text-align: center;
margin-bottom: 20rpx;
}
.domain-grid {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.domain-item {
width: 48%;
padding: 30rpx 20rpx;
border-radius: 16rpx;
margin-bottom: 16rpx;
text-align: center;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.06);
}
.domain-body {
background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);
}
.domain-mind {
background: linear-gradient(135deg, #a18cd1 0%, #fbc2eb 100%);
}
.domain-wisdom {
background: linear-gradient(135deg, #fccb90 0%, #d57eeb 100%);
}
.domain-action {
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
}
.domain-icon {
font-size: 60rpx;
margin-bottom: 10rpx;
}
.domain-name {
font-size: 28rpx;
font-weight: bold;
color: #fff;
margin-bottom: 6rpx;
}
.domain-desc {
font-size: 22rpx;
color: rgba(255, 255, 255, 0.85);
}
创建以下空壳页面(每个域首页只含标题和功能列表入口):
pages/body/index.vue:
<template>
<view class="domain-page">
<view class="domain-header domain-header-body">
<view class="domain-header-icon">🧬</view>
<view class="domain-header-title">身 · 细胞抗衰</view>
</view>
<view class="feature-list">
<view class="feature-item" @click="navigateTo('/pages/body/health-metric')">
<text class="feature-name">健康指标记录</text>
<text class="feature-arrow">›</text>
</view>
<view class="feature-item" @click="navigateTo('/pages/body/nutrition-log')">
<text class="feature-name">水营养追踪</text>
<text class="feature-arrow">›</text>
</view>
<view class="feature-item" @click="navigateTo('/pages/body/anti-aging')">
<text class="feature-name">抗衰评估</text>
<text class="feature-arrow">›</text>
</view>
<view class="feature-item" @click="navigateTo('/pages/body/exercise-log')">
<text class="feature-name">运动记录</text>
<text class="feature-arrow">›</text>
</view>
</view>
</view>
</template>
<script>
export default {
methods: {
navigateTo(url) {
uni.navigateTo({ url });
}
}
}
</script>
<style scoped>
.domain-page { padding: 0; }
.domain-header { padding: 40rpx; text-align: center; color: #fff; }
.domain-header-body { background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%); }
.domain-header-icon { font-size: 80rpx; }
.domain-header-title { font-size: 36rpx; font-weight: bold; margin-top: 10rpx; }
.feature-list { padding: 20rpx 30rpx; }
.feature-item { display: flex; justify-content: space-between; align-items: center; padding: 30rpx; background: #fff; border-radius: 12rpx; margin-bottom: 16rpx; box-shadow: 0 2rpx 8rpx rgba(0,0,0,0.04); }
.feature-name { font-size: 30rpx; color: #333; }
.feature-arrow { font-size: 36rpx; color: #ccc; }
</style>
pages/mind/index.vue: 同上结构,domain-header-mind 样式为 background: linear-gradient(135deg, #a18cd1 0%, #fbc2eb 100%),功能列表为情绪日志/心理测评/家庭氛围/冥想放松。
pages/action/index.vue: 同上结构,domain-header-action 样式为 background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%),功能列表为活动列表/文章科普/长者关怀/社区互动。
为每个域的功能页面创建最小占位 vue 文件(仅含标题文本),确保 pages.json 注册的路径都有对应文件。
每个占位页面结构统一:
<template>
<view class="page-container">
<view class="placeholder">
<text class="placeholder-text">【功能名称】 — 即将上线</text>
</view>
</view>
</template>
<script>
export default {}
</script>
<style scoped>
.page-container { display: flex; justify-content: center; align-items: center; height: 100vh; background: #f5f7fa; }
.placeholder { text-align: center; }
.placeholder-text { font-size: 28rpx; color: #999; }
</style>
需要创建的占位文件:
pages/body/health-metric.vue → "健康指标记录"pages/body/nutrition-log.vue → "水营养追踪"pages/body/anti-aging.vue → "抗衰评估"pages/body/exercise-log.vue → "运动记录"pages/mind/mood-log.vue → "情绪日志"pages/mind/assessment.vue → "心理测评"pages/mind/family-atmosphere.vue → "家庭氛围"pages/mind/meditation.vue → "冥想放松"pages/action/activity-list.vue → "活动列表"pages/action/activity-detail.vue → "活动详情"pages/action/article-list.vue → "文章科普"pages/action/article-detail.vue → "文章详情"pages/action/elder-care.vue → "长者关怀"pages/action/community.vue → "社区互动"
[ ] Step 5: 修改 api.js — 增加域 API 封装
在 cfc-frontend/utils/api.js 末尾添加:
// === Body 域 API ===
export const createBodyHealthMetric = (data) => request('/body/health/create', data);
export const getBodyHealthMetrics = (data) => request('/body/health/list', data);
export const getLatestBodyHealthMetric = (data) => request('/body/health/latest', data);
export const createBodyNutritionLog = (data) => request('/body/nutrition/create', data);
export const getBodyNutritionLogs = (data) => request('/body/nutrition/list', data);
export const createBodyAntiAgingAssessment = (data) => request('/body/anti-aging/create', data);
export const getBodyAntiAgingAssessments = (data) => request('/body/anti-aging/list', data);
export const createBodyExerciseLog = (data) => request('/body/exercise/create', data);
export const getBodyExerciseLogs = (data) => request('/body/exercise/list', data);
// === Mind 域 API ===
export const createMindMoodLog = (data) => request('/mind/mood/create', data);
export const getMindMoodLogs = (data) => request('/mind/mood/list', data);
export const createMindAssessment = (data) => request('/mind/assessment/create', data);
export const getMindAssessments = (data) => request('/mind/assessment/list', data);
export const createMindFamilyAtmosphere = (data) => request('/mind/atmosphere/create', data);
export const getMindFamilyAtmosphere = (data) => request('/mind/atmosphere/list', data);
export const createMindMeditation = (data) => request('/mind/meditation/create', data);
export const getMindMeditations = (data) => request('/mind/meditation/list', data);
// === Action 域 API ===
export const createActionActivity = (data) => request('/action/activity/create', data);
export const getActionActivities = (data) => request('/action/activity/list', data);
export const getActionActivityDetail = (data) => request('/action/activity/detail', data);
export const registerActionActivity = (data) => request('/action/activity/register', data);
export const createActionArticle = (data) => request('/action/article/create', data);
export const getActionArticles = (data) => request('/action/article/list', data);
export const getActionArticleDetail = (data) => request('/action/article/detail', data);
export const createActionElderCarePlan = (data) => request('/action/elder-care/create', data);
export const getActionElderCarePlans = (data) => request('/action/elder-care/list', data);
export const createActionPracticeTask = (data) => request('/action/practice/create', data);
export const getActionPracticeTasks = (data) => request('/action/practice/list', data);
export const createActionCommunityPost = (data) => request('/action/community/create-post', data);
export const getActionCommunityPosts = (data) => request('/action/community/posts', data);
export const createActionCommunityComment = (data) => request('/action/community/create-comment', data);
export const getActionCommunityComments = (data) => request('/action/community/comments', data);
在 Vuex state 中添加:
currentDomain: null, // 'body' | 'mind' | 'wisdom' | 'action' — 当前活跃域
在 mutations 中添加:
setCurrentDomain(state, domain) {
state.currentDomain = domain;
}
[ ] Step 7: 提交 Phase 1 框架代码
git add -A
git commit -m "feat: 溪福俱乐部四域框架搭建 - 17个新entity/mapper/service - 四象限首页 - 域导航骨架"
目标: 完善行域所有功能页面(活动、文章、长者关怀、社区、践行任务),建立域内完整业务闭环。
注: Phase 2-4 每个域的具体功能实现计划将在 Phase 1 完成后细化。每个域需要:
- 完善后端 Controller + Service 业务逻辑(CRUD + 业务规则)
- 实现前端功能页面(替换占位页面)
- 接入积分系统(域内行为可获积分)
- 管理端页面(cfc-web 内容管理)
| 功能 | 后端Controller | 前端页面 | 优先级 |
|---|---|---|---|
| 活动发布/列表/报名/详情 | ActionController | activity-list, activity-detail | P0 |
| 文章发布/列表/详情 | ActionArticleController | article-list, article-detail | P0 |
| 长者关怀计划/日志 | ActionElderCareController(新增) | elder-care | P1 |
| 社区帖子/评论 | ActionCommunityController(新增) | community | P1 |
| 践行任务CRUD | ActionPracticeController(新增) | - (首页卡片) | P1 |
目标: 完善身域所有功能页面(健康指标、水营养、抗衰评估、运动记录),建立健康管理闭环。
| 功能 | 后端Controller | 前端页面 | 优先级 |
|---|---|---|---|
| 健康指标CRUD + 趋势图 | BodyHealthController | health-metric | P0 |
| 水营养追踪 + 统计 | BodyNutritionController(新增) | nutrition-log | P0 |
| 抗衰评估 + 报告 | BodyAntiAgingController(新增) | anti-aging | P1 |
| 运动记录 + 步数 | BodyExerciseController(新增) | exercise-log | P1 |
目标: 完善心域所有功能页面(情绪日志、心理测评、家庭氛围、冥想),建立心理健康管理闭环。
| 功能 | 后端Controller | 前端页面 | 优先级 |
|---|---|---|---|
| 情绪日志CRUD + 趋势 | MindMoodController | mood-log | P0 |
| 心理测评问卷+报告 | MindAssessmentController(新增) | assessment | P0 |
| 家庭氛围评估 | MindFamilyAtmosphereController(新增) | family-atmosphere | P1 |
| 冥想计时+引导音频 | MindMeditationController(新增) | meditation | P1 |
目标: 通过 REST API 集成 Lilishop 电商功能,实现商品浏览、购物车、下单结算。
| 功能 | 后端实现 | 前端页面 | 优先级 |
|---|---|---|---|
| LilishopApiClient | LilishopApiClient.java (RestTemplate) | - | P0 |
| 商品浏览/搜索 | CommerceController → Lilishop buyer-api | product-list, product-detail | P0 |
| 购物车 | CommerceController → Lilishop buyer-api | cart | P0 |
| 下单/支付 | CommerceController → Lilishop buyer-api | checkout | P1 |
| 订单管理 | CommerceController → Lilishop buyer-api | order-list | P1 |
| 商品管理(管理端) | CommerceAdminController → Lilishop seller-api | cfc-web 商品管理页 | P2 |
在 application.yml 中添加:
lilishop:
buyer-api: http://localhost:8888
seller-api: http://localhost:8889
manager-api: http://localhost:8887
service-account:
username: cfc_service
password: ${LILISHOP_SERVICE_PASSWORD}
token-cache-minutes: 50
目标: 在 Web 管理端新增四域内容管理页面。
| 路由 | 页面 | 功能 |
|---|---|---|
| /body/health | BodyHealth.vue | 健康指标数据管理 |
| /body/anti-aging | BodyAntiAging.vue | 抗衰评估管理 |
| /mind/assessment | MindAssessment.vue | 心理测评管理 |
| /mind/atmosphere | MindAtmosphere.vue | 家庭氛围数据 |
| /action/activity | ActionActivity.vue | 活动发布管理 |
| /action/article | ActionArticle.vue | 文章内容管理 |
| /action/community | ActionCommunity.vue | 社区内容审核 |
| /commerce/products | CommerceProducts.vue | 商品管理(Lilishop) |
| /commerce/orders | CommerceOrders.vue | 订单管理(Lilishop) |