# 项目详情参数配置页面实施计划 > **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. **Goal:** 在项目详情页面实现参数配置功能,允许每个项目自定义模型参数,首次保存时自动从系统默认参数复制。 **Architecture:** 前端组件复用独立页面代码,后端修改 Service 根据 configType 返回对应参数,首次保存时自动复制默认参数并切换 configType。 **Tech Stack:** Spring Boot 3, MyBatis Plus, Vue.js 2, Element UI --- ## Task 1: 修改后端 Mapper 接口 **Files:** - Modify: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/mapper/CcdiModelParamMapper.java` **Step 1: 添加更新参数值方法** 在 `CcdiModelParamMapper.java` 接口中添加方法: ```java /** * 更新参数值 * * @param projectId 项目ID * @param modelCode 模型编码 * @param paramCode 参数编码 * @param paramValue 参数值 * @return 影响行数 */ int updateParamValue(@Param("projectId") Long projectId, @Param("modelCode") String modelCode, @Param("paramCode") String paramCode, @Param("paramValue") String paramValue); /** * 批量插入参数 * * @param params 参数列表 * @return 影响行数 */ int insertBatch(@Param("list") List params); ``` **Step 2: 提交** ```bash git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/mapper/CcdiModelParamMapper.java git commit -m "feat: 添加 Mapper 接口方法 updateParamValue 和 insertBatch" ``` --- ## Task 2: 修改后端 Mapper XML **Files:** - Modify: `ccdi-project/src/main/resources/mapper/ccdi/project/CcdiModelParamMapper.xml` **Step 1: 添加 updateParamValue SQL** 在 `` 标签之前添加: ```xml UPDATE ccdi_model_param SET param_value = #{paramValue}, update_time = NOW() WHERE project_id = #{projectId} AND model_code = #{modelCode} AND param_code = #{paramCode} INSERT INTO ccdi_model_param ( project_id, model_code, model_name, param_code, param_name, param_desc, param_value, param_unit, sort_order, remark, create_time, update_time ) VALUES ( #{item.projectId}, #{item.modelCode}, #{item.modelName}, #{item.paramCode}, #{item.paramName}, #{item.paramDesc}, #{item.paramValue}, #{item.paramUnit}, #{item.sortOrder}, #{item.remark}, NOW(), NOW() ) ``` **Step 2: 提交** ```bash git add ccdi-project/src/main/resources/mapper/ccdi/project/CcdiModelParamMapper.xml git commit -m "feat: 添加 Mapper XML SQL updateParamValue 和 insertBatch" ``` --- ## Task 3: 注入 ProjectMapper 依赖 **Files:** - Modify: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiModelParamServiceImpl.java` **Step 1: 添加 import 语句** 在文件顶部的 import 区域添加: ```java import com.ruoyi.ccdi.project.domain.CcdiProject; import com.ruoyi.ccdi.project.mapper.CcdiProjectMapper; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; ``` **Step 2: 添加 Logger** 在类开始处添加: ```java private static final Logger log = LoggerFactory.getLogger(CcdiModelParamServiceImpl.class); ``` **Step 3: 注入 ProjectMapper** 在 `@Resource private CcdiModelParamMapper modelParamMapper;` 之后添加: ```java @Resource private CcdiProjectMapper projectMapper; ``` **Step 4: 提交** ```bash git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiModelParamServiceImpl.java git commit -m "feat: 注入 CcdiProjectMapper 依赖" ``` --- ## Task 4: 修改 selectParamList 方法 **Files:** - Modify: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiModelParamServiceImpl.java:52-71` **Step 1: 替换 selectParamList 方法** 完全替换 `selectParamList` 方法: ```java @Override public List selectParamList(ModelParamQueryDTO queryDTO) { // 1. 参数验证 Long projectId = queryDTO.getProjectId(); if (projectId == null) { projectId = 0L; } // 2. 如果是项目查询(projectId > 0),需要根据 configType 决定查询哪组参数 Long effectiveProjectId = projectId; if (projectId > 0) { // 查询项目信息 CcdiProject project = projectMapper.selectById(projectId); if (project == null) { throw new ServiceException("项目不存在"); } // 根据 configType 决定查询哪组参数 if ("default".equals(project.getConfigType())) { // 使用系统默认参数 effectiveProjectId = 0L; } else { // 使用项目自定义参数 effectiveProjectId = projectId; } } // 3. 查询参数列表 List params = modelParamMapper.selectByProjectAndModel( effectiveProjectId, queryDTO.getModelCode() ); // 4. 转换为 VO List result = new ArrayList<>(); params.forEach(param -> { ModelParamVO vo = new ModelParamVO(); BeanUtils.copyProperties(param, vo); result.add(vo); }); return result; } ``` **Step 2: 提交** ```bash git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiModelParamServiceImpl.java git commit -m "feat: 修改 selectParamList 方法支持根据 configType 返回对应参数" ``` --- ## Task 5: 添加 copyDefaultParamsToProject 私有方法 **Files:** - Modify: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiModelParamServiceImpl.java` **Step 1: 添加复制参数方法** 在 `saveParams` 方法之后添加: ```java /** * 复制系统默认参数到项目 * * @param projectId 项目ID * @param modelCode 模型编码 * @return 复制的参数数量 */ private int copyDefaultParamsToProject(Long projectId, String modelCode) { // 查询系统默认参数 List defaultParams = modelParamMapper.selectByProjectAndModel(0L, modelCode); if (defaultParams.isEmpty()) { log.warn("系统默认参数为空,modelCode={}", modelCode); return 0; } // 复制到项目 List projectParams = defaultParams.stream() .map(param -> { CcdiModelParam newParam = new CcdiModelParam(); BeanUtils.copyProperties(param, newParam); newParam.setId(null); // 清空ID,让数据库自动生成 newParam.setProjectId(projectId); newParam.setCreateBy(null); // 清空审计字段,让 MyBatis Plus 自动填充 newParam.setCreateTime(null); newParam.setUpdateBy(null); newParam.setUpdateTime(null); return newParam; }) .collect(Collectors.toList()); // 批量插入 int count = modelParamMapper.insertBatch(projectParams); log.info("复制系统默认参数到项目成功,projectId={}, modelCode={}, count={}", projectId, modelCode, count); return count; } ``` **Step 2: 提交** ```bash git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiModelParamServiceImpl.java git commit -m "feat: 添加 copyDefaultParamsToProject 私有方法" ``` --- ## Task 6: 修改 saveParams 方法 **Files:** - Modify: `ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiModelParamServiceImpl.java:74-122` **Step 1: 替换 saveParams 方法** 完全替换 `saveParams` 方法: ```java @Override @Transactional(rollbackFor = Exception.class) public void saveParams(ModelParamSaveDTO saveDTO) { try { // 1. 参数验证 if (saveDTO.getProjectId() == null) { throw new ServiceException("项目ID不能为空"); } if (StringUtils.isBlank(saveDTO.getModelCode())) { throw new ServiceException("模型编码不能为空"); } if (saveDTO.getParams() == null || saveDTO.getParams().isEmpty()) { throw new ServiceException("参数列表不能为空"); } Long projectId = saveDTO.getProjectId(); // 2. 如果是项目保存(projectId > 0),需要检查是否首次保存 if (projectId > 0) { // 查询项目信息 CcdiProject project = projectMapper.selectById(projectId); if (project == null) { throw new ServiceException("项目不存在"); } // 3. 如果是首次保存(configType=default),需要复制系统默认参数 if ("default".equals(project.getConfigType())) { int copiedCount = copyDefaultParamsToProject(projectId, saveDTO.getModelCode()); if (copiedCount == 0) { log.warn("系统默认参数为空,projectId={}, modelCode={}", projectId, saveDTO.getModelCode()); } // 更新项目配置类型为 custom project.setConfigType("custom"); projectMapper.updateById(project); log.info("项目配置类型已更新为 custom,projectId={}", projectId); } } // 4. 更新参数值 String username = SecurityUtils.getUsername(); for (ModelParamSaveDTO.ParamValueItem item : saveDTO.getParams()) { int updated = modelParamMapper.updateParamValue( projectId, saveDTO.getModelCode(), item.getParamCode(), item.getParamValue() ); if (updated == 0) { log.warn("参数不存在或未更新,paramCode={}", item.getParamCode()); } } } catch (ServiceException e) { // 业务异常,直接抛出 throw e; } catch (Exception e) { // 系统异常,记录日志并抛出 log.error("保存模型参数失败", e); throw new ServiceException("保存模型参数失败:" + e.getMessage()); } } ``` **Step 2: 提交** ```bash git add ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiModelParamServiceImpl.java git commit -m "feat: 修改 saveParams 方法支持首次保存自动复制默认参数" ``` --- ## Task 7: 实现前端 ParamConfig 组件(模板部分) **Files:** - Modify: `ruoyi-ui/src/views/ccdiProject/components/detail/ParamConfig.vue` **Step 1: 替换模板部分** 完全替换文件内容: ```vue ``` **Step 2: 提交** ```bash git add ruoyi-ui/src/views/ccdiProject/components/detail/ParamConfig.vue git commit -m "feat: 实现 ParamConfig 组件模板部分" ``` --- ## Task 8: 实现前端 ParamConfig 组件(脚本部分) **Files:** - Modify: `ruoyi-ui/src/views/ccdiProject/components/detail/ParamConfig.vue` **Step 1: 添加脚本部分** 在 `` 之后添加: ```vue ``` **Step 2: 提交** ```bash git add ruoyi-ui/src/views/ccdiProject/components/detail/ParamConfig.vue git commit -m "feat: 实现 ParamConfig 组件脚本部分" ``` --- ## Task 9: 实现前端 ParamConfig 组件(样式部分) **Files:** - Modify: `ruoyi-ui/src/views/ccdiProject/components/detail/ParamConfig.vue` **Step 1: 添加样式部分** 在 `` 之后添加: ```vue ``` **Step 2: 提交** ```bash git add ruoyi-ui/src/views/ccdiProject/components/detail/ParamConfig.vue git commit -m "feat: 实现 ParamConfig 组件样式部分" ``` --- ## Task 10: 手动测试功能 **Step 1: 启动后端服务** 提示用户手动启动后端服务(不要自动运行)。 **Step 2: 启动前端服务** ```bash cd ruoyi-ui npm run dev ``` **Step 3: 访问测试页面** 1. 访问 `http://localhost:80` 2. 登录系统(admin/admin123) 3. 进入"项目管理"页面 4. 点击任意项目的"详情"按钮 5. 点击"参数配置"菜单 **Step 4: 测试场景 1 - 查看默认配置** **操作:** - 新项目查看参数配置 **预期结果:** - 显示系统默认参数 - 参数值与系统默认一致 **Step 5: 测试场景 2 - 首次保存参数** **操作:** - 修改参数值 - 点击"保存配置" **预期结果:** - 显示"保存成功"提示 - 项目的 `configType` 变为 `custom` - 再次查看参数显示修改后的值 **Step 6: 测试场景 3 - 切换模型** **操作:** - 切换到另一个模型 **预期结果:** - 参数列表正确切换 - 显示新模型的参数 **Step 7: 测试场景 4 - 不修改参数点击保存** **操作:** - 不修改任何参数 - 点击"保存配置" **预期结果:** - 显示"没有需要保存的修改"提示 **Step 8: 测试场景 5 - 清空参数值后保存** **操作:** - 清空某个参数值 - 点击"保存配置" **预期结果:** - 显示"请填写所有参数值"错误提示 - 不发起保存请求 **Step 9: 提交测试完成** ```bash git add . git commit -m "test: 项目详情参数配置功能手动测试完成" ``` --- ## 完成检查清单 - [ ] 后端 Mapper 接口已修改 - [ ] 后端 Mapper XML 已修改 - [ ] 后端 Service 已修改 - [ ] 前端 ParamConfig 组件已实现 - [ ] 所有测试场景通过 - [ ] 代码已提交到 git --- ## 注意事项 1. **不要自动启动后端服务** - 提示用户手动启动 2. **不需要后端单元测试** - 用户明确要求 3. **首次保存会触发复制** - 确保系统默认参数存在 4. **事务回滚** - 如果复制失败,事务会自动回滚 5. **前端验证优先** - 参数值验证在前端完成