Просмотр исходного кода

feat: energy daily limit 数据库持久化 - 新增DimensionDailyLimit表及Controller读写

Ultrawwork with Sisyphus

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
asus 2 месяцев назад
Родитель
Сommit
c4c571d34b

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

@@ -3005,6 +3005,24 @@ log.info("已添加template_id列到tasks表");
 		} catch (Exception ex) {
 			log.warn("diet_preferences.must_eat 添加失败(可能已存在): " + ex.getMessage());
 		}
+		// 迁移255: 创建energy_daily_limit表(每日能量上限配置持久化)
+		try {
+			jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS energy_daily_limit (" +
+					"id BIGINT AUTO_INCREMENT PRIMARY KEY, " +
+					"dimension_code VARCHAR(20) NOT NULL COMMENT '维度代码: body/mind/wisdom/action/wealth', " +
+					"daily_limit INT NOT NULL DEFAULT 50 COMMENT '每日能量上限', " +
+					"created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
+					"updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, " +
+					"UNIQUE KEY uk_dimension_code (dimension_code)" +
+					") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='每日能量上限配置'");
+			log.info("已创建energy_daily_limit表");
+			// 插入默认数据(幂等)
+			jdbcTemplate.execute("INSERT IGNORE INTO energy_daily_limit (dimension_code, daily_limit) VALUES " +
+					"('body', 50), ('mind', 50), ('wisdom', 80), ('action', 60), ('wealth', 50)");
+			log.info("已插入energy_daily_limit默认数据");
+		} catch (Exception ex) {
+			log.warn("energy_daily_limit 表创建失败(可能已存在): " + ex.getMessage());
+		}
         ensureColumn("file_record", "file_type", "VARCHAR(50) DEFAULT NULL COMMENT '文件类型: image/pdf/video/audio/other'");
         ensureColumn("file_record", "description", "TEXT COMMENT '文件描述'");
 

+ 45 - 31
cfc-backend/src/main/java/com/etotem/cfc/controller/admin/AdminEnergyConfigController.java

@@ -2,7 +2,9 @@ package com.etotem.cfc.controller.admin;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.etotem.cfc.common.Result;
+import com.etotem.cfc.entity.DimensionDailyLimit;
 import com.etotem.cfc.entity.EnergySourceConfig;
+import com.etotem.cfc.mapper.DimensionDailyLimitMapper;
 import com.etotem.cfc.mapper.EnergySourceConfigMapper;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.tags.Tag;
@@ -23,6 +25,9 @@ public class AdminEnergyConfigController {
     @Resource
     private EnergySourceConfigMapper energySourceConfigMapper;
 
+    @Resource
+    private DimensionDailyLimitMapper dimensionDailyLimitMapper;
+
     /**
      * 能量来源配置列表
      */
@@ -95,27 +100,49 @@ public class AdminEnergyConfigController {
     }
 
     /**
-     * 获取每日能量限制(V1 返回硬编码值)
+     * 获取每日能量限制(数据库持久化)
      */
     @Operation(summary = "获取每日能量限制")
     @PostMapping("/daily-limits")
     public Result<List<DimensionDailyLimit>> dailyLimits(@RequestBody Map<String, Object> params) {
-        List<DimensionDailyLimit> limits = new ArrayList<>();
-        limits.add(new DimensionDailyLimit("body", 50));
-        limits.add(new DimensionDailyLimit("mind", 50));
-        limits.add(new DimensionDailyLimit("wisdom", 80));
-        limits.add(new DimensionDailyLimit("action", 60));
-        limits.add(new DimensionDailyLimit("wealth", 50));
+        List<DimensionDailyLimit> limits = dimensionDailyLimitMapper.selectList(
+            new LambdaQueryWrapper<DimensionDailyLimit>()
+                .orderByAsc(DimensionDailyLimit::getDimensionCode)
+        );
         return Result.success(limits);
     }
 
     /**
-     * 保存每日能量限制(V1 仅返回成功,实际存储待后续迁移)
+     * 保存每日能量限制(数据库持久化)
      */
     @Operation(summary = "保存每日能量限制")
     @PostMapping("/daily-limit-save")
     public Result<String> dailyLimitSave(@RequestBody DailyLimitSaveRequest request) {
-        // V1: 仅返回成功,实际存储待后续迁移到数据库
+        if (request.getLimits() == null || request.getLimits().isEmpty()) {
+            return Result.error("limits不能为空");
+        }
+        Date now = new Date();
+        for (DimensionDailyLimit dto : request.getLimits()) {
+            String code = dto.getDimensionCode();
+            Integer limit = dto.getDailyLimit();
+            if (code == null || limit == null) {
+                return Result.error("dimensionCode和dailyLimit不能为空");
+            }
+            DimensionDailyLimit existing = dimensionDailyLimitMapper.selectOne(
+                new LambdaQueryWrapper<DimensionDailyLimit>().eq(DimensionDailyLimit::getDimensionCode, code));
+            if (existing != null) {
+                existing.setDailyLimit(limit);
+                existing.setUpdatedAt(now);
+                dimensionDailyLimitMapper.updateById(existing);
+            } else {
+                DimensionDailyLimit entity = new DimensionDailyLimit();
+                entity.setDimensionCode(code);
+                entity.setDailyLimit(limit);
+                entity.setCreatedAt(now);
+                entity.setUpdatedAt(now);
+                dimensionDailyLimitMapper.insert(entity);
+            }
+        }
         return Result.success("保存成功");
     }
 
@@ -162,13 +189,16 @@ public class AdminEnergyConfigController {
         Map<String, Object> data = new HashMap<>();
         data.put("sources", sources);
 
-        // 每日限制
+        // 每日限制(从数据库读取)
         List<Map<String, Object>> dailyLimits = new ArrayList<>();
-        dailyLimits.add(limitMap("body", 50));
-        dailyLimits.add(limitMap("mind", 50));
-        dailyLimits.add(limitMap("wisdom", 80));
-        dailyLimits.add(limitMap("action", 60));
-        dailyLimits.add(limitMap("wealth", 50));
+        List<DimensionDailyLimit> limitsFromDb = dimensionDailyLimitMapper.selectList(
+            new LambdaQueryWrapper<DimensionDailyLimit>().orderByAsc(DimensionDailyLimit::getDimensionCode));
+        for (DimensionDailyLimit limit : limitsFromDb) {
+            Map<String, Object> m = new HashMap<>();
+            m.put("dimensionCode", limit.getDimensionCode());
+            m.put("dailyLimit", limit.getDailyLimit());
+            dailyLimits.add(m);
+        }
         data.put("dailyLimits", dailyLimits);
 
         return Result.success(data);
@@ -212,22 +242,6 @@ public class AdminEnergyConfigController {
         public void setRatio(Integer ratio) { this.ratio = ratio; }
     }
 
-    public static class DimensionDailyLimit {
-        private String dimensionCode;
-        private Integer dailyLimit;
-
-        public DimensionDailyLimit() {}
-        public DimensionDailyLimit(String dimensionCode, Integer dailyLimit) {
-            this.dimensionCode = dimensionCode;
-            this.dailyLimit = dailyLimit;
-        }
-
-        public String getDimensionCode() { return dimensionCode; }
-        public void setDimensionCode(String dimensionCode) { this.dimensionCode = dimensionCode; }
-        public Integer getDailyLimit() { return dailyLimit; }
-        public void setDailyLimit(Integer dailyLimit) { this.dailyLimit = dailyLimit; }
-    }
-
     public static class DailyLimitSaveRequest {
         private List<DimensionDailyLimit> limits;
 

+ 27 - 0
cfc-backend/src/main/java/com/etotem/cfc/entity/DimensionDailyLimit.java

@@ -0,0 +1,27 @@
+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.io.Serializable;
+import java.util.Date;
+
+@Data
+@TableName("energy_daily_limit")
+public class DimensionDailyLimit implements Serializable {
+
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    /** 维度代码: body/mind/wisdom/action/wealth */
+    private String dimensionCode;
+
+    /** 每日能量上限 */
+    private Integer dailyLimit;
+
+    private Date createdAt;
+
+    private Date updatedAt;
+}

+ 9 - 0
cfc-backend/src/main/java/com/etotem/cfc/mapper/DimensionDailyLimitMapper.java

@@ -0,0 +1,9 @@
+package com.etotem.cfc.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.etotem.cfc.entity.DimensionDailyLimit;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface DimensionDailyLimitMapper extends BaseMapper<DimensionDailyLimit> {
+}

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

@@ -5115,3 +5115,13 @@ CREATE TABLE IF NOT EXISTS profile_history (
     INDEX idx_member_date (member_id, snapshot_date),
     INDEX idx_date (snapshot_date)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户画像历史快照';
+
+-- 每日能量上限配置(迁移255)
+CREATE TABLE IF NOT EXISTS energy_daily_limit (
+    id BIGINT AUTO_INCREMENT PRIMARY KEY,
+    dimension_code VARCHAR(20) NOT NULL COMMENT '维度代码: body/mind/wisdom/action/wealth',
+    daily_limit INT NOT NULL DEFAULT 50 COMMENT '每日能量上限',
+    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
+    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+    UNIQUE KEY uk_dimension_code (dimension_code)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='每日能量上限配置';