# 模型参数配置优化 - 后端实施计划

> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.

**目标：** 实现模型参数批量查询和批量保存接口，支持前端统一展示和保存所有模型参数

**技术栈：** Spring Boot 3.5.8 + MyBatis Plus 3.0.5 + Java 21

**依赖模块：** ccdi-project

**预计时间：** 2-3小时

---

## 📋 任务概览

| 任务组 | 任务数 | 说明 |
|--------|--------|------|
| DTO/VO 创建 | 6个 | 数据传输对象 |
| Mapper 层 | 2个 | 数据访问层 |
| Service 层 | 5个 | 业务逻辑层 |
| Controller 层 | 2个 | API接口层 |
| 测试 | 1个 | Swagger测试 |
| **总计** | **16个** | |

---

## 任务列表

### Task 1: 创建批量查询请求DTO

**文件：**
- Create: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/dto/ModelParamAllQueryDTO.java`

**步骤 1: 创建类文件**

```java
package com.ruoyi.ccdi.project.domain.dto;

import lombok.Data;

/**
 * 批量查询所有模型参数DTO
 */
@Data
public class ModelParamAllQueryDTO {

    /** 项目ID（0表示全局配置，>0表示项目配置） */
    private Long projectId;
}
```

**步骤 2: 提交代码**

```bash
git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/dto/ModelParamAllQueryDTO.java
git commit -m "feat(ccdi-project): 添加批量查询所有模型参数DTO"
```

---

### Task 2: 创建模型分组VO

**文件：**
- Create: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/ModelGroupVO.java`

**步骤 1: 创建类文件**

```java
package com.ruoyi.ccdi.project.domain.vo;

import lombok.Data;
import java.util.List;

/**
 * 模型分组VO（用于按模型分组展示参数）
 */
@Data
public class ModelGroupVO {

    /** 模型编码 */
    private String modelCode;

    /** 模型名称 */
    private String modelName;

    /** 参数列表 */
    private List<ModelParamVO> params;
}
```

**步骤 2: 提交代码**

```bash
git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/ModelGroupVO.java
git commit -m "feat(ccdi-project): 添加模型分组VO"
```

---

### Task 3: 创建批量查询响应VO

**文件：**
- Create: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/ModelParamAllVO.java`

**步骤 1: 创建类文件**

```java
package com.ruoyi.ccdi.project.domain.vo;

import lombok.Data;
import java.util.List;

/**
 * 批量查询所有模型参数响应VO
 */
@Data
public class ModelParamAllVO {

    /** 模型列表（包含每个模型及其参数） */
    private List<ModelGroupVO> models;
}
```

**步骤 2: 提交代码**

```bash
git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/ModelParamAllVO.java
git commit -m "feat(ccdi-project): 添加批量查询所有模型参数响应VO"
```

---

### Task 4: 创建批量保存参数项DTO

**文件：**
- Create: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/dto/ParamValueItem.java`

**步骤 1: 创建类文件**

```java
package com.ruoyi.ccdi.project.domain.dto;

import lombok.Data;

/**
 * 参数值项DTO
 */
@Data
public class ParamValueItem {

    /** 参数编码 */
    private String paramCode;

    /** 参数值 */
    private String paramValue;
}
```

**步骤 2: 提交代码**

```bash
git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/dto/ParamValueItem.java
git commit -m "feat(ccdi-project): 添加参数值项DTO"
```

---

### Task 5: 创建批量保存模型参数组DTO

**文件：**
- Create: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/dto/ModelParamGroupDTO.java`

**步骤 1: 创建类文件**

```java
package com.ruoyi.ccdi.project.domain.dto;

import lombok.Data;
import java.util.List;

/**
 * 模型参数分组DTO（用于批量保存）
 */
@Data
public class ModelParamGroupDTO {

    /** 模型编码 */
    private String modelCode;

    /** 该模型下修改过的参数 */
    private List<ParamValueItem> params;
}
```

**步骤 2: 提交代码**

```bash
git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/dto/ModelParamGroupDTO.java
git commit -m "feat(ccdi-project): 添加模型参数分组DTO"
```

---

### Task 6: 创建批量保存请求DTO

**文件：**
- Create: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/dto/ModelParamSaveAllDTO.java`

**步骤 1: 创建类文件**

```java
package com.ruoyi.ccdi.project.domain.dto;

import lombok.Data;
import java.util.List;

/**
 * 批量保存所有模型参数DTO
 */
@Data
public class ModelParamSaveAllDTO {

    /** 项目ID */
    private Long projectId;

    /** 所有模型的参数修改（只包含修改过的参数） */
    private List<ModelParamGroupDTO> models;
}
```

**步骤 2: 提交代码**

```bash
git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/dto/ModelParamSaveAllDTO.java
git commit -m "feat(ccdi-project): 添加批量保存所有模型参数DTO"
```

---

### Task 7: 在Mapper接口中添加批量查询方法

**文件：**
- Modify: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/mapper/CcdiModelParamMapper.java`

**步骤 1: 添加方法签名**

在接口中添加：

```java
/**
 * 根据项目ID查询所有模型参数
 *
 * @param projectId 项目ID
 * @return 参数列表
 */
List<CcdiModelParam> selectByProjectId(@Param("projectId") Long projectId);
```

**步骤 2: 检查导入**

确保包含必要的导入：
```java
import org.apache.ibatis.annotations.Param;
import java.util.List;
```

**步骤 3: 提交代码**

```bash
git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/mapper/CcdiModelParamMapper.java
git commit -m "feat(ccdi-project): 在Mapper接口中添加批量查询方法"
```

---

### Task 8: 在Mapper XML中添加SQL查询

**文件：**
- Modify: `ccdi-project/src/main/resources/mapper/ccdi/project/CcdiModelParamMapper.xml`

**步骤 1: 添加SQL语句**

在 `<mapper>` 标签内添加：

```xml
<!-- 根据项目ID查询所有模型参数 -->
<select id="selectByProjectId" resultType="CcdiModelParam">
    SELECT * FROM ccdi_model_param
    WHERE project_id = #{projectId}
    ORDER BY model_code, sort_order
</select>
```

**步骤 2: 提交代码**

```bash
git add ccdi-project/src/main/resources/mapper/ccdi/project/CcdiModelParamMapper.xml
git commit -m "feat(ccdi-project): 在Mapper XML中添加批量查询SQL"
```

---

### Task 9: 在Service接口中添加批量查询方法

**文件：**
- Modify: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/ICcdiModelParamService.java`

**步骤 1: 添加方法签名**

```java
/**
 * 查询所有模型及其参数（按模型分组）
 *
 * @param projectId 项目ID（0表示全局配置）
 * @return 所有模型的参数配置
 */
ModelParamAllVO selectAllParams(Long projectId);
```

**步骤 2: 添加导入**

```java
import com.ruoyi.ccdi.project.domain.vo.ModelParamAllVO;
```

**步骤 3: 提交代码**

```bash
git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/ICcdiModelParamService.java
git commit -m "feat(ccdi-project): 在Service接口中添加批量查询方法"
```

---

### Task 10: 在Service接口中添加批量保存方法

**文件：**
- Modify: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/ICcdiModelParamService.java`

**步骤 1: 添加方法签名**

```java
/**
 * 批量保存所有模型的参数修改
 *
 * @param saveAllDTO 所有模型的参数修改数据
 */
void saveAllParams(ModelParamSaveAllDTO saveAllDTO);
```

**步骤 2: 添加导入**

```java
import com.ruoyi.ccdi.project.domain.dto.ModelParamSaveAllDTO;
```

**步骤 3: 提交代码**

```bash
git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/ICcdiModelParamService.java
git commit -m "feat(ccdi-project): 在Service接口中添加批量保存方法"
```

---

### Task 11: 添加Service实现所需的导入语句

**文件：**
- Modify: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiModelParamServiceImpl.java`

**步骤 1: 添加导入语句**

在文件顶部导入区域添加：

```java
import com.ruoyi.ccdi.project.domain.dto.ModelParamSaveAllDTO;
import com.ruoyi.ccdi.project.domain.dto.ModelParamGroupDTO;
import com.ruoyi.ccdi.project.domain.dto.ParamValueItem;
import com.ruoyi.ccdi.project.domain.vo.ModelParamAllVO;
import com.ruoyi.ccdi.project.domain.vo.ModelGroupVO;
import java.util.Comparator;
```

**步骤 2: 提交代码**

```bash
git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiModelParamServiceImpl.java
git commit -m "feat(ccdi-project): 添加批量操作所需的导入语句"
```

---

### Task 12: 实现批量查询方法

**文件：**
- Modify: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiModelParamServiceImpl.java`

**步骤 1: 实现 selectAllParams 方法**

在 `CcdiModelParamServiceImpl` 类中添加方法：

```java
@Override
public ModelParamAllVO selectAllParams(Long projectId) {
    // 1. 参数验证
    if (projectId == null) {
        projectId = 0L;
    }

    // 2. 如果是项目查询，根据 configType 决定查询哪组参数
    Long effectiveProjectId = projectId;
    if (projectId > 0) {
        CcdiProject project = projectMapper.selectById(projectId);
        if (project == null) {
            throw new ServiceException("项目不存在");
        }
        if ("default".equals(project.getConfigType())) {
            effectiveProjectId = 0L;
        }
    }

    // 3. 查询所有模型的参数
    List<CcdiModelParam> allParams = modelParamMapper.selectByProjectId(effectiveProjectId);

    // 4. 按模型分组
    Map<String, List<CcdiModelParam>> groupedParams = allParams.stream()
        .collect(Collectors.groupingBy(CcdiModelParam::getModelCode));

    // 5. 转换为VO
    ModelParamAllVO result = new ModelParamAllVO();
    List<ModelGroupVO> models = new ArrayList<>();

    groupedParams.forEach((modelCode, params) -> {
        ModelGroupVO groupVO = new ModelGroupVO();
        groupVO.setModelCode(modelCode);
        groupVO.setModelName(params.get(0).getModelName());

        List<ModelParamVO> paramVOs = params.stream()
            .map(param -> {
                ModelParamVO vo = new ModelParamVO();
                BeanUtils.copyProperties(param, vo);
                return vo;
            })
            .collect(Collectors.toList());

        groupVO.setParams(paramVOs);
        models.add(groupVO);
    });

    // 6. 按模型编码排序（保证固定顺序）
    models.sort(Comparator.comparing(ModelGroupVO::getModelCode));

    result.setModels(models);
    return result;
}
```

**步骤 2: 提交代码**

```bash
git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiModelParamServiceImpl.java
git commit -m "feat(ccdi-project): 实现批量查询所有模型参数方法"
```

---

### Task 13: 实现批量保存方法

**文件：**
- Modify: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiModelParamServiceImpl.java`

**步骤 1: 实现 saveAllParams 方法**

在 `CcdiModelParamServiceImpl` 类中添加方法：

```java
@Override
@Transactional(rollbackFor = Exception.class)
public void saveAllParams(ModelParamSaveAllDTO saveAllDTO) {
    try {
        // 1. 参数验证
        if (saveAllDTO.getProjectId() == null) {
            throw new ServiceException("项目ID不能为空");
        }
        if (saveAllDTO.getModels() == null || saveAllDTO.getModels().isEmpty()) {
            throw new ServiceException("参数列表不能为空");
        }

        Long projectId = saveAllDTO.getProjectId();

        // 2. 如果是项目保存，检查是否需要复制默认参数
        if (projectId > 0) {
            CcdiProject project = projectMapper.selectById(projectId);
            if (project == null) {
                throw new ServiceException("项目不存在");
            }

            // 如果是首次保存（configType=default），需要复制所有模型的系统默认参数
            if ("default".equals(project.getConfigType())) {
                for (ModelParamGroupDTO modelGroup : saveAllDTO.getModels()) {
                    copyDefaultParamsToProject(projectId, modelGroup.getModelCode());
                }

                // 更新项目配置类型为 custom
                project.setConfigType("custom");
                projectMapper.updateById(project);
            }
        }

        // 3. 批量更新所有模型的参数值
        for (ModelParamGroupDTO modelGroup : saveAllDTO.getModels()) {
            for (ParamValueItem item : modelGroup.getParams()) {
                int updated = modelParamMapper.updateParamValue(
                    projectId,
                    modelGroup.getModelCode(),
                    item.getParamCode(),
                    item.getParamValue()
                );
                if (updated == 0) {
                    log.warn("参数不存在或未更新，modelCode={}, paramCode={}",
                        modelGroup.getModelCode(), item.getParamCode());
                }
            }
        }

    } catch (ServiceException e) {
        throw e;
    } catch (Exception e) {
        log.error("批量保存模型参数失败", e);
        throw new ServiceException("批量保存模型参数失败：" + e.getMessage());
    }
}
```

**步骤 2: 提交代码**

```bash
git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiModelParamServiceImpl.java
git commit -m "feat(ccdi-project): 实现批量保存所有模型参数方法"
```

---

### Task 14: 在Controller中添加批量查询接口

**文件：**
- Modify: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/controller/CcdiModelParamController.java`

**步骤 1: 添加导入语句**

在文件顶部添加：

```java
import com.ruoyi.ccdi.project.domain.dto.ModelParamAllQueryDTO;
import com.ruoyi.ccdi.project.domain.dto.ModelParamSaveAllDTO;
import com.ruoyi.ccdi.project.domain.vo.ModelParamAllVO;
```

**步骤 2: 添加接口方法**

在 `CcdiModelParamController` 类中添加：

```java
/**
 * 查询所有模型及其参数（按模型分组）
 */
@Operation(summary = "查询所有模型及其参数")
@GetMapping("/listAll")
public AjaxResult listAll(@Validated ModelParamAllQueryDTO queryDTO) {
    ModelParamAllVO result = modelParamService.selectAllParams(queryDTO.getProjectId());
    return success(result);
}
```

**步骤 3: 提交代码**

```bash
git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/controller/CcdiModelParamController.java
git commit -m "feat(ccdi-project): 在Controller中添加批量查询接口"
```

---

### Task 15: 在Controller中添加批量保存接口

**文件：**
- Modify: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/controller/CcdiModelParamController.java`

**步骤 1: 添加接口方法**

在 `CcdiModelParamController` 类中添加：

```java
/**
 * 批量保存所有模型的参数修改
 */
@Operation(summary = "批量保存所有模型参数")
@Log(title = "模型参数配置", businessType = BusinessType.UPDATE)
@PostMapping("/saveAll")
public AjaxResult saveAll(@Validated @RequestBody ModelParamSaveAllDTO saveAllDTO) {
    modelParamService.saveAllParams(saveAllDTO);
    return success("保存成功");
}
```

**步骤 2: 提交代码**

```bash
git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/controller/CcdiModelParamController.java
git commit -m "feat(ccdi-project): 在Controller中添加批量保存接口"
```

---

### Task 16: 使用Swagger测试后端接口

**检查点：后端开发完成**

**步骤 1: 启动后端应用**

提示用户手动启动：
```bash
mvn spring-boot:run
```

**步骤 2: 访问Swagger UI**

打开浏览器：`http://localhost:8080/swagger-ui/index.html`

**步骤 3: 测试批量查询接口**

1. 找到"模型参数配置"分组
2. 找到 `GET /ccdi/modelParam/listAll` 接口
3. 点击 "Try it out"
4. 输入参数：`projectId: 0`
5. 点击 "Execute"
6. 验证响应：
   - 状态码：200
   - 返回数据包含 `models` 数组
   - 每个模型包含 `modelCode`, `modelName`, `params`

**预期结果：**
```json
{
  "code": 200,
  "msg": "操作成功",
  "data": {
    "models": [
      {
        "modelCode": "LARGE_TRANSACTION",
        "modelName": "大额交易模型",
        "params": [
          {
            "paramCode": "THRESHOLD_AMOUNT",
            "paramName": "单笔交易金额阈值",
            "paramDesc": "单笔交易金额超过此值触发预警",
            "paramValue": "50000",
            "paramUnit": "元"
          }
        ]
      }
    ]
  }
}
```

**步骤 4: 测试批量保存接口**

1. 找到 `POST /ccdi/modelParam/saveAll` 接口
2. 点击 "Try it out"
3. 输入请求体：
```json
{
  "projectId": 0,
  "models": [
    {
      "modelCode": "LARGE_TRANSACTION",
      "params": [
        {
          "paramCode": "THRESHOLD_AMOUNT",
          "paramValue": "60000"
        }
      ]
    }
  ]
}
```
4. 点击 "Execute"
5. 验证响应：状态码 200，msg 为 "保存成功"

**步骤 5: 测试其他场景**

- 测试项目配置查询（projectId > 0）
- 测试首次保存参数复制
- 测试多模型同时保存

**步骤 6: 提交测试记录**

```bash
mkdir -p docs/test-records
git add docs/test-records/
git commit -m "test(ccdi-project): 记录后端接口测试结果"
```

---

## ✅ 完成标志

后端实施完成的标志：
- ✅ 所有16个任务执行完成
- ✅ Swagger接口测试通过
- ✅ 代码已提交到git
- ✅ 可以响应前端的批量查询和保存请求

## 📝 后端API说明

### 批量查询接口
- **URL**: `GET /ccdi/modelParam/listAll?projectId=0`
- **返回**: 所有模型的参数配置（按模型分组）

### 批量保存接口
- **URL**: `POST /ccdi/modelParam/saveAll`
- **请求体**:
```json
{
  "projectId": 0,
  "models": [
    {
      "modelCode": "MODEL_CODE",
      "params": [
        {
          "paramCode": "PARAM_CODE",
          "paramValue": "NEW_VALUE"
        }
      ]
    }
  ]
}
```
- **返回**: `{"code": 200, "msg": "保存成功"}`

---

**后端实施计划完成！准备前端开发时，使用前端实施计划。**
