Эх сурвалжийг харах

feat: HealthPlan后端重构 - planJson/status字段+regenerate-section接口

Sisyphus 1 сар өмнө
parent
commit
aa839bdc49

+ 12 - 0
cfc-backend/src/main/java/com/etotem/cfc/config/DatabaseInitializer.java

@@ -2953,6 +2953,18 @@ log.info("已添加template_id列到tasks表");
         }
 
         // 迁移249: file_record 表添加 file_type 和 description 列(原迁移221/228误置于seedFullRegionData中,区域数据非空时永不执行)
+
+		// 迁移250: health_plans 添加 plan_json 和 status 列(支持结构化方案编辑)
+		try {
+			ensureColumn("health_plans", "plan_json", "JSON COMMENT '结构化方案内容(总览+营养+饮食+运动)'");
+		} catch (Exception e) {
+			log.warn("health_plans.plan_json 添加失败(可能已存在): " + e.getMessage());
+		}
+		try {
+			ensureColumn("health_plans", "status", "VARCHAR(20) DEFAULT 'draft' COMMENT '方案状态: draft(草稿)/confirmed(已确认)'");
+		} catch (Exception e) {
+			log.warn("health_plans.status 添加失败(可能已存在): " + e.getMessage());
+		}
         ensureColumn("file_record", "file_type", "VARCHAR(50) DEFAULT NULL COMMENT '文件类型: image/pdf/video/audio/other'");
         ensureColumn("file_record", "description", "TEXT COMMENT '文件描述'");
 

+ 40 - 5
cfc-backend/src/main/java/com/etotem/cfc/controller/HealthPlanController.java

@@ -6,6 +6,7 @@ import com.etotem.cfc.service.HealthPlanService;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.tags.Tag;
 import org.springframework.web.bind.annotation.*;
+
 import javax.annotation.Resource;
 import java.util.List;
 import java.util.Map;
@@ -19,7 +20,7 @@ public class HealthPlanController {
     @Resource
     private HealthPlanService healthPlanService;
 
-    @Operation(summary = "生成健康方案")
+    @Operation(summary = "生成健康方案(文本)")
     @PostMapping("/generate")
     public Result<String> generate(@RequestBody Map<String, Object> params,
                                    @RequestAttribute("userId") Long userId,
@@ -34,7 +35,23 @@ public class HealthPlanController {
         return Result.success(planContent);
     }
 
-    @Operation(summary = "保存健康方案")
+    @Operation(summary = "重新生成方案某一部分(营养/饮食/运动)")
+    @PostMapping("/regenerate-section")
+    public Result<String> regenerateSection(
+            @RequestBody Map<String, Object> params,
+            @RequestAttribute("userId") Long userId,
+            @RequestAttribute(value = "familyId", required = false) Long familyId) {
+        String section = (String) params.get("section");
+        String feedback = (String) params.get("feedback");
+        String planJsonStr = (String) params.get("planJson");
+        if (section == null || planJsonStr == null) {
+            return Result.error("section和planJson不能为空");
+        }
+        String result = healthPlanService.regenerateSection(familyId, section, feedback, planJsonStr);
+        return Result.success(result);
+    }
+
+    @Operation(summary = "保存/更新健康方案(支持结构化 planJson)")
     @PostMapping("/save")
     public Result<Long> save(@RequestBody Map<String, Object> params,
                              @RequestAttribute("userId") Long userId,
@@ -43,21 +60,39 @@ public class HealthPlanController {
         String dimensions = (String) params.get("dimensions");
         String goal = (String) params.get("goal");
         String planContent = (String) params.get("planContent");
+        String planJson = (String) params.get("planJson");
         String memberName = (String) params.get("memberName");
-        if (familyId == null || dimensions == null || goal == null || planContent == null) {
-            return Result.error("familyId, dimensions, goal, planContent不能为空");
+        Long planId = ParamUtils.getLong(params.get("planId"));
+        String status = (String) params.get("status");
+
+        if (familyId == null || dimensions == null || goal == null) {
+            return Result.error("familyId, dimensions, goal不能为空");
         }
         HealthPlan plan = new HealthPlan();
+        plan.setId(planId);
         plan.setFamilyId(familyId);
         plan.setMemberIds(memberIds != null ? memberIds : "");
         plan.setDimensions(dimensions);
         plan.setGoal(goal);
         plan.setPlanContent(planContent);
+        plan.setPlanJson(planJson);
         plan.setMemberName(memberName);
+        if (status != null) plan.setStatus(status);
         Long id = healthPlanService.savePlan(plan);
         return Result.success(id);
     }
 
+    @Operation(summary = "确认方案(提交后不可再编辑)")
+    @PostMapping("/confirm")
+    public Result<Long> confirm(@RequestBody Map<String, Object> params,
+                                @RequestAttribute("userId") Long userId,
+                                @RequestAttribute(value = "familyId", required = false) Long familyId) {
+        Long planId = ParamUtils.getLong(params.get("planId"));
+        if (planId == null) return Result.error("planId不能为空");
+        Long id = healthPlanService.confirmPlan(planId);
+        return Result.success(id);
+    }
+
     @Operation(summary = "查询历史方案列表")
     @PostMapping("/list")
     public Result<List<HealthPlan>> list(@RequestBody Map<String, Object> params,
@@ -77,4 +112,4 @@ public class HealthPlanController {
         if (plan == null) return Result.error("方案不存在");
         return Result.success(plan);
     }
-}
+}

+ 2 - 0
cfc-backend/src/main/java/com/etotem/cfc/entity/HealthPlan.java

@@ -19,5 +19,7 @@ public class HealthPlan implements Serializable {
     private String goal;
     @TableField("plan_content") private String planContent;
     @TableField("member_name") private String memberName;
+    @TableField("plan_json") private String planJson;
+    @TableField("status") private String status;
     @TableField("created_at") private Date createdAt;
 }

+ 3 - 1
cfc-backend/src/main/java/com/etotem/cfc/service/HealthPlanService.java

@@ -5,7 +5,9 @@ import java.util.List;
 
 public interface HealthPlanService {
     Long savePlan(HealthPlan plan);
+    Long confirmPlan(Long planId);
     List<HealthPlan> getPlanList(Long familyId);
     HealthPlan getPlanDetail(Long planId);
     String generatePlan(Long familyId, String memberIds, String dimensions, String goal);
-}
+    String regenerateSection(Long familyId, String section, String feedback, String planJsonStr);
+}

+ 2 - 0
cfc-backend/src/main/resources/schema.sql

@@ -4526,6 +4526,8 @@ CREATE TABLE IF NOT EXISTS health_plans (
     plan_content  TEXT         COMMENT 'LangGraph生成的方案内容',
     member_name   VARCHAR(50)  COMMENT '成员名称摘要',
     created_at    DATETIME DEFAULT CURRENT_TIMESTAMP,
+    plan_json     TEXT         COMMENT '结构化方案内容(JSON)',
+    status        VARCHAR(20)  DEFAULT 'draft' COMMENT '方案状态: draft(草稿)/confirmed(已确认)',
     INDEX idx_family (family_id),
     INDEX idx_created (created_at)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='健康方案汇总记录';