Files
ccdi/docs/plans/2026-03-06-model-param-config-optimization-split.md

32 KiB
Raw Blame History

模型参数配置页面优化实施计划(前后端分离版)

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 + Vue 2.6.12 + Element UI 2.15.14

设计文档: docs/plans/2026-03-06-model-param-config-optimization-design.md


📋 任务概览

阶段 任务范围 任务数 预计时间
阶段1后端开发 DTO/VO、Mapper、Service、Controller 16个任务 2-3小时
阶段2后端测试 Swagger接口测试 1个任务 30分钟
阶段3前端开发 API、页面重构 10个任务 2-3小时
阶段4前端测试 功能测试 3个任务 1小时
总计 30个任务 5-7小时

🔧 阶段1后端开发16个任务

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

文件:

  • Create: ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/dto/ModelParamAllQueryDTO.java

步骤 1: 创建类文件

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

import lombok.Data;

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

    /** 项目ID0表示全局配置>0表示项目配置 */
    private Long projectId;
}

步骤 2: 提交

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

Task 2: 创建模型分组VO

文件:

  • Create: ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/ModelGroupVO.java

步骤 1: 创建类文件

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: 提交

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

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

文件:

  • Create: ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/vo/ModelParamAllVO.java

步骤 1: 创建类文件

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

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

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

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

步骤 2: 提交

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

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

文件:

  • Create: ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/dto/ParamValueItem.java

步骤 1: 创建类文件

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

import lombok.Data;

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

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

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

步骤 2: 提交

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

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

文件:

  • Create: ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/dto/ModelParamGroupDTO.java

步骤 1: 创建类文件

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: 提交

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

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

文件:

  • Create: ccdi-project/src/main/java/com/ruoyi/ccdi/project/domain/dto/ModelParamSaveAllDTO.java

步骤 1: 创建类文件

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: 提交

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

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

文件:

  • Modify: ccdi-project/src/main/java/com/ruoyi/ccdi/project/mapper/CcdiModelParamMapper.java

步骤 1: 添加方法

在接口中添加:

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

步骤 2: 检查导入

确保包含:

import org.apache.ibatis.annotations.Param;
import java.util.List;

步骤 3: 提交

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

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

文件:

  • Modify: ccdi-project/src/main/resources/mapper/ccdi/project/CcdiModelParamMapper.xml

步骤 1: 添加SQL

<mapper> 标签内添加:

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

步骤 2: 提交

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

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

文件:

  • Modify: ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/ICcdiModelParamService.java

步骤 1: 添加方法签名

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

步骤 2: 添加导入

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

步骤 3: 提交

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

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

文件:

  • Modify: ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/ICcdiModelParamService.java

步骤 1: 添加方法签名

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

步骤 2: 添加导入

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

步骤 3: 提交

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

Task 11: 实现批量查询方法(第一部分 - 导入)

文件:

  • Modify: ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiModelParamServiceImpl.java

步骤 1: 添加导入语句

在文件顶部添加:

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: 提交

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

Task 12: 实现批量查询方法(第二部分 - 实现逻辑)

文件:

  • Modify: ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiModelParamServiceImpl.java

步骤 1: 实现 selectAllParams 方法

在类中添加:

@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: 提交

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

Task 13: 实现批量保存方法

文件:

  • Modify: ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiModelParamServiceImpl.java

步骤 1: 实现 saveAllParams 方法

在类中添加:

@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: 提交

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

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

文件:

  • Modify: ccdi-project/src/main/java/com/ruoyi/ccdi/project/controller/CcdiModelParamController.java

步骤 1: 添加导入

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: 添加接口方法

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

步骤 3: 提交

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

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

文件:

  • Modify: ccdi-project/src/main/java/com/ruoyi/ccdi/project/controller/CcdiModelParamController.java

步骤 1: 添加接口方法

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

步骤 2: 提交

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

🧪 阶段2后端测试1个任务

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

检查点:后端开发完成

步骤 1: 启动后端

# 提示用户手动启动
mvn spring-boot:run

步骤 2: 访问Swagger UI

打开:http://localhost:8080/swagger-ui/index.html

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

  1. 找到 GET /ccdi/modelParam/listAll
  2. 点击 "Try it out"
  3. 输入:projectId = 0
  4. 点击 "Execute"
  5. 验证响应200包含 models 数组

预期结果:

{
  "code": 200,
  "msg": "操作成功",
  "data": {
    "models": [
      {
        "modelCode": "LARGE_TRANSACTION",
        "modelName": "大额交易模型",
        "params": [...]
      }
    ]
  }
}

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

  1. 找到 POST /ccdi/modelParam/saveAll
  2. 点击 "Try it out"
  3. 输入请求体:
{
  "projectId": 0,
  "models": [
    {
      "modelCode": "LARGE_TRANSACTION",
      "params": [
        {
          "paramCode": "THRESHOLD_AMOUNT",
          "paramValue": "60000"
        }
      ]
    }
  ]
}
  1. 点击 "Execute"
  2. 验证200"保存成功"

步骤 5: 提交测试记录

git add docs/test-records/
git commit -m "test: 记录后端接口测试结果"

🎨 阶段3前端开发10个任务

Task 17: 在API层添加批量查询方法

文件:

  • Modify: ruoyi-ui/src/api/ccdi/modelParam.js

步骤 1: 添加方法

/**
 * 查询所有模型及其参数(按模型分组)
 */
export function listAllParams(query) {
  return request({
    url: '/ccdi/modelParam/listAll',
    method: 'get',
    params: query
  })
}

步骤 2: 提交

git add ruoyi-ui/src/api/ccdi/modelParam.js
git commit -m "feat: 在API层添加批量查询方法"

Task 18: 在API层添加批量保存方法

文件:

  • Modify: ruoyi-ui/src/api/ccdi/modelParam.js

步骤 1: 添加方法

/**
 * 批量保存所有模型的参数修改
 */
export function saveAllParams(data) {
  return request({
    url: '/ccdi/modelParam/saveAll',
    method: 'post',
    data: data
  })
}

步骤 2: 提交

git add ruoyi-ui/src/api/ccdi/modelParam.js
git commit -m "feat: 在API层添加批量保存方法"

Task 19: 重构全局配置页面 - 模板部分

文件:

  • Modify: ruoyi-ui/src/views/ccdi/modelParam/index.vue

步骤 1: 替换 template 部分

<template>
  <div class="param-config-container">
    <!-- 页面标题 -->
    <div class="page-header">
      <h2>全局模型参数管理</h2>
    </div>

    <!-- 模型参数卡片组垂直堆叠 -->
    <div class="model-cards-container">
      <div
        v-for="model in modelGroups"
        :key="model.modelCode"
        class="model-card"
      >
        <!-- 模型标题 -->
        <div class="model-header">
          <h3>{{ model.modelName }}</h3>
        </div>

        <!-- 参数表格 -->
        <el-table :data="model.params" border style="width: 100%">
          <el-table-column label="监测项" prop="paramName" width="200" />
          <el-table-column label="描述" prop="paramDesc" />
          <el-table-column label="阈值设置" width="200">
            <template #default="{ row }">
              <el-input
                v-model="row.paramValue"
                placeholder="请输入阈值"
                @input="markAsModified(model.modelCode, row)"
              />
            </template>
          </el-table-column>
          <el-table-column label="单位" prop="paramUnit" width="120" />
        </el-table>
      </div>
    </div>

    <!-- 统一保存按钮 -->
    <div class="button-section">
      <el-button type="primary" @click="handleSaveAll" :loading="saving">
        保存所有修改
      </el-button>
      <span v-if="modifiedCount > 0" class="modified-tip">
        已修改 {{ modifiedCount }} 个参数
      </span>
    </div>
  </div>
</template>

步骤 2: 暂不提交


Task 20: 重构全局配置页面 - 脚本部分

文件:

  • Modify: ruoyi-ui/src/views/ccdi/modelParam/index.vue

步骤 1: 替换 script 部分

<script>
import { listAllParams, saveAllParams } from "@/api/ccdi/modelParam";

export default {
  name: "ModelParam",
  data() {
    return {
      modelGroups: [],
      modifiedParams: new Map(),
      saving: false
    };
  },
  computed: {
    modifiedCount() {
      let count = 0;
      this.modifiedParams.forEach(params => {
        count += params.size;
      });
      return count;
    }
  },
  created() {
    this.loadAllParams();
  },
  methods: {
    async loadAllParams() {
      try {
        const res = await listAllParams({ projectId: 0 });
        this.modelGroups = res.data.models;
        this.modifiedParams.clear();
      } catch (error) {
        this.$message.error('加载参数失败:' + error.message);
      }
    },

    markAsModified(modelCode, row) {
      if (!this.modifiedParams.has(modelCode)) {
        this.modifiedParams.set(modelCode, new Set());
      }
      this.modifiedParams.get(modelCode).add(row.paramCode);
    },

    async handleSaveAll() {
      if (this.modifiedCount === 0) {
        this.$message.info('没有需要保存的修改');
        return;
      }

      const saveDTO = {
        projectId: 0,
        models: []
      };

      this.modifiedParams.forEach((paramCodes, modelCode) => {
        const modelGroup = this.modelGroups.find(m => m.modelCode === modelCode);
        const modifiedParamList = modelGroup.params
          .filter(p => paramCodes.has(p.paramCode))
          .map(p => ({
            paramCode: p.paramCode,
            paramValue: p.paramValue
          }));

        if (modifiedParamList.length > 0) {
          saveDTO.models.push({
            modelCode: modelCode,
            params: modifiedParamList
          });
        }
      });

      this.saving = true;
      try {
        await saveAllParams(saveDTO);
        this.$modal.msgSuccess('保存成功');
        this.modifiedParams.clear();
        await this.loadAllParams();
      } catch (error) {
        this.$message.error('保存失败:' + (error.response?.data?.msg || error.message));
      } finally {
        this.saving = false;
      }
    }
  }
};
</script>

步骤 2: 暂不提交


Task 21: 重构全局配置页面 - 样式部分

文件:

  • Modify: ruoyi-ui/src/views/ccdi/modelParam/index.vue

步骤 1: 替换 style 部分

<style scoped lang="scss">
.param-config-container {
  padding: 20px;
  background-color: #f5f5f5;
  min-height: 100vh;
}

.page-header {
  margin-bottom: 20px;
  padding: 15px;
  background: #fff;
  border-radius: 4px;

  h2 {
    font-size: 18px;
    font-weight: bold;
    color: #333;
    margin: 0;
  }
}

.model-cards-container {
  margin-bottom: 20px;
}

.model-card {
  background: #fff;
  border-radius: 4px;
  padding: 20px;
  margin-bottom: 20px;
  border: 1px solid #e4e7ed;

  .model-header {
    margin-bottom: 15px;

    h3 {
      font-size: 16px;
      font-weight: bold;
      color: #333;
      margin: 0;
    }
  }
}

.button-section {
  padding: 15px;
  background: #fff;
  border-radius: 4px;
  text-align: left;

  .modified-tip {
    margin-left: 15px;
    color: #909399;
    font-size: 14px;
  }
}
</style>

步骤 2: 提交

git add ruoyi-ui/src/views/ccdi/modelParam/index.vue
git commit -m "feat: 重构全局模型参数配置页面"

Task 22: 测试全局配置页面

检查点:全局配置页面完成

步骤 1: 启动前端

cd ruoyi-ui
npm run dev

步骤 2: 访问页面

  • 打开:http://localhost:80
  • 登录admin / admin123
  • 导航到:系统管理 > 模型参数管理

步骤 3: 验证功能

  • 页面标题正确
  • 所有模型垂直堆叠显示
  • 参数表格数据正确
  • 修改参数后显示"已修改 X 个参数"
  • 保存功能正常
  • 错误提示友好

步骤 4: 提交测试记录

git add docs/test-records/
git commit -m "test: 记录全局配置页面测试结果"

Task 23: 重构项目配置页面 - 模板部分

文件:

  • Modify: ruoyi-ui/src/views/ccdiProject/components/detail/ParamConfig.vue

步骤 1: 替换 template 部分

<template>
  <div class="param-config-container">
    <!-- 模型参数卡片组垂直堆叠 -->
    <div class="model-cards-container">
      <div
        v-for="model in modelGroups"
        :key="model.modelCode"
        class="model-card"
      >
        <!-- 模型标题 -->
        <div class="model-header">
          <h3>{{ model.modelName }}</h3>
        </div>

        <!-- 参数表格 -->
        <el-table :data="model.params" border style="width: 100%">
          <el-table-column label="监测项" prop="paramName" width="200" />
          <el-table-column label="描述" prop="paramDesc" />
          <el-table-column label="阈值设置" width="200">
            <template #default="{ row }">
              <el-input
                v-model="row.paramValue"
                placeholder="请输入阈值"
                @input="markAsModified(model.modelCode, row)"
              />
            </template>
          </el-table-column>
          <el-table-column label="单位" prop="paramUnit" width="120" />
        </el-table>
      </div>
    </div>

    <!-- 统一保存按钮 -->
    <div class="button-section">
      <el-button type="primary" @click="handleSaveAll" :loading="saving">
        保存所有修改
      </el-button>
      <span v-if="modifiedCount > 0" class="modified-tip">
        已修改 {{ modifiedCount }} 个参数
      </span>
    </div>
  </div>
</template>

步骤 2: 暂不提交


Task 24: 重构项目配置页面 - 脚本部分

文件:

  • Modify: ruoyi-ui/src/views/ccdiProject/components/detail/ParamConfig.vue

步骤 1: 替换 script 部分

<script>
import { listAllParams, saveAllParams } from "@/api/ccdi/modelParam";

export default {
  name: 'ParamConfig',
  props: {
    projectId: {
      type: [String, Number],
      required: true
    },
    projectInfo: {
      type: Object,
      default: () => ({})
    }
  },
  data() {
    return {
      modelGroups: [],
      modifiedParams: new Map(),
      saving: false
    }
  },
  computed: {
    modifiedCount() {
      let count = 0;
      this.modifiedParams.forEach(params => {
        count += params.size;
      });
      return count;
    }
  },
  watch: {
    projectId(newVal) {
      if (newVal) {
        this.loadAllParams();
      }
    }
  },
  created() {
    if (this.projectId) {
      this.loadAllParams();
    }
  },
  methods: {
    async loadAllParams() {
      try {
        const res = await listAllParams({ projectId: this.projectId });
        this.modelGroups = res.data.models;
        this.modifiedParams.clear();
      } catch (error) {
        this.$message.error('加载参数失败:' + error.message);
      }
    },

    markAsModified(modelCode, row) {
      if (!this.modifiedParams.has(modelCode)) {
        this.modifiedParams.set(modelCode, new Set());
      }
      this.modifiedParams.get(modelCode).add(row.paramCode);
    },

    async handleSaveAll() {
      if (this.modifiedCount === 0) {
        this.$message.info('没有需要保存的修改');
        return;
      }

      const saveDTO = {
        projectId: this.projectId,
        models: []
      };

      this.modifiedParams.forEach((paramCodes, modelCode) => {
        const modelGroup = this.modelGroups.find(m => m.modelCode === modelCode);
        const modifiedParamList = modelGroup.params
          .filter(p => paramCodes.has(p.paramCode))
          .map(p => ({
            paramCode: p.paramCode,
            paramValue: p.paramValue
          }));

        if (modifiedParamList.length > 0) {
          saveDTO.models.push({
            modelCode: modelCode,
            params: modifiedParamList
          });
        }
      });

      this.saving = true;
      try {
        await saveAllParams(saveDTO);
        this.$message.success('保存成功');
        this.modifiedParams.clear();
        await this.loadAllParams();
      } catch (error) {
        this.$message.error('保存失败:' + (error.response?.data?.msg || error.message));
      } finally {
        this.saving = false;
      }
    }
  }
}
</script>

步骤 2: 暂不提交


Task 25: 重构项目配置页面 - 样式部分

文件:

  • Modify: ruoyi-ui/src/views/ccdiProject/components/detail/ParamConfig.vue

步骤 1: 替换 style 部分

<style scoped lang="scss">
.param-config-container {
  padding: 20px;
  background-color: #fff;
  min-height: 400px;
}

.model-cards-container {
  margin-bottom: 20px;
}

.model-card {
  background: #fff;
  border-radius: 4px;
  padding: 20px;
  margin-bottom: 20px;
  border: 1px solid #e4e7ed;

  .model-header {
    margin-bottom: 15px;

    h3 {
      font-size: 16px;
      font-weight: bold;
      color: #333;
      margin: 0;
    }
  }
}

.button-section {
  padding: 15px;
  background: #fff;
  border-radius: 4px;
  text-align: left;

  .modified-tip {
    margin-left: 15px;
    color: #909399;
    font-size: 14px;
  }
}
</style>

步骤 2: 提交

git add ruoyi-ui/src/views/ccdiProject/components/detail/ParamConfig.vue
git commit -m "feat: 重构项目内模型参数配置页面"

Task 26: 测试项目配置页面

检查点:项目配置页面完成

步骤 1: 确保前后端启动

步骤 2: 访问项目页面

  • 导航到:初核项目管理 > 进入项目 > 参数配置标签页

步骤 3: 验证功能

  • 参数正确显示
  • 使用默认配置的项目显示系统参数
  • 首次保存后配置类型变为"自定义"
  • 多模型同时修改保存成功

步骤 4: 提交测试记录

git add docs/test-records/
git commit -m "test: 记录项目配置页面测试结果"

阶段4集成测试4个任务

Task 27: 端到端功能测试

步骤 1: 测试全局配置影响项目配置

  1. 全局配置页面修改参数
  2. 创建新项目(使用默认配置)
  3. 验证项目显示修改后的参数

步骤 2: 测试项目配置不影响全局配置

  1. 项目配置页面修改参数
  2. 返回全局配置页面
  3. 验证全局参数未改变

步骤 3: 提交测试记录

git add docs/test-records/
git commit -m "test: 完成端到端功能测试"

Task 28: 性能测试

步骤 1: 测试页面加载性能

  • 验证 listAll 接口响应时间 < 200ms

步骤 2: 测试保存性能

  • 验证 saveAll 接口响应时间 < 500ms

步骤 3: 测试渲染性能

  • 验证首次渲染 < 300ms
  • 验证交互响应 < 100ms

步骤 4: 提交测试记录

git add docs/test-records/
git commit -m "test: 完成性能测试"

Task 29: 更新API文档

文件:

  • Create: docs/api-docs/model-param-batch-api.md

步骤 1: 创建文档

# 模型参数批量操作API文档

## 批量查询所有模型参数

**接口地址:** `GET /ccdi/modelParam/listAll`

**请求参数:**

| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| projectId | Long | 否 | 项目ID0或不传表示全局配置 |

**响应示例:**

\`\`\`json
{
  "code": 200,
  "msg": "操作成功",
  "data": {
    "models": [...]
  }
}
\`\`\`

## 批量保存所有模型参数

**接口地址:** `POST /ccdi/modelParam/saveAll`

**请求体示例:**

\`\`\`json
{
  "projectId": 1,
  "models": [
    {
      "modelCode": "LARGE_TRANSACTION",
      "params": [
        {
          "paramCode": "THRESHOLD_AMOUNT",
          "paramValue": "60000"
        }
      ]
    }
  ]
}
\`\`\`

步骤 2: 提交

git add docs/api-docs/model-param-batch-api.md
git commit -m "docs: 添加模型参数批量操作API文档"

Task 30: 最终提交和推送

检查点:所有任务完成

步骤 1: 检查所有更改

git status

步骤 2: 推送到远程

git push origin dev

步骤 3: 创建Pull Request可选

  • 标题:feat: 优化模型参数配置页面布局
  • 描述:
    • 取消模型下拉切换
    • 改为垂直堆叠展示所有模型参数
    • 统一保存机制
    • 全局配置和项目配置页面同步修改

完成!🎉


📊 总结

完成的功能:

  • 后端批量查询和保存接口
  • 前端全局配置页面重构
  • 前端项目配置页面重构
  • 统一保存机制
  • 修改提示
  • 完整测试

技术亮点:

  • 垂直堆叠布局,用户体验更好
  • 批量操作减少HTTP请求
  • 只保存修改过的参数
  • 保留向后兼容

后续优化建议:

  • 添加"重置为默认值"功能
  • 添加参数修改历史记录
  • 添加参数导入导出功能