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

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

**目标：** 重构全局配置页面和项目配置页面，取消模型下拉切换，改为垂直堆叠展示所有模型参数，实现统一保存

**技术栈：** Vue 2.6.12 + Element UI 2.15.14 + Axios 0.28.1

**依赖：** 后端接口已完成（参考后端实施计划）

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

---

## 📋 任务概览

| 任务组 | 任务数 | 说明 |
|--------|--------|------|
| API 层 | 2个 | 添加批量接口方法 |
| 全局配置页面 | 4个 | 重构页面结构 |
| 项目配置页面 | 4个 | 重构页面结构 |
| 测试 | 2个 | 功能测试和集成测试 |
| **总计** | **12个** | |

---

## 前置条件

**在开始前端开发前，确保：**
- ✅ 后端接口已部署完成
- ✅ 后端接口测试通过（Swagger测试）
- ✅ 后端服务正常运行（http://localhost:8080）

---

## 任务列表

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

**文件：**
- Modify: `ruoyi-ui/src/api/ccdi/modelParam.js`

**步骤 1: 打开API文件**

找到并打开 `ruoyi-ui/src/api/ccdi/modelParam.js` 文件

**步骤 2: 添加批量查询方法**

在文件末尾添加：

```javascript
/**
 * 查询所有模型及其参数（按模型分组）
 * @param {Object} query - 查询参数
 * @param {Number} query.projectId - 项目ID（0表示全局配置）
 * @returns {Promise} 返回所有模型的参数配置
 */
export function listAllParams(query) {
  return request({
    url: '/ccdi/modelParam/listAll',
    method: 'get',
    params: query
  })
}
```

**步骤 3: 验证导入**

确保文件顶部有：
```javascript
import request from '@/utils/request'
```

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

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

---

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

**文件：**
- Modify: `ruoyi-ui/src/api/ccdi/modelParam.js`

**步骤 1: 添加批量保存方法**

在文件末尾添加：

```javascript
/**
 * 批量保存所有模型的参数修改
 * @param {Object} data - 保存数据
 * @param {Number} data.projectId - 项目ID
 * @param {Array} data.models - 模型参数列表
 * @returns {Promise}
 */
export function saveAllParams(data) {
  return request({
    url: '/ccdi/modelParam/saveAll',
    method: 'post',
    data: data
  })
}
```

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

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

---

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

**文件：**
- Modify: `ruoyi-ui/src/views/ccdi/modelParam/index.vue`

**步骤 1: 备份原文件（可选）**

```bash
cp ruoyi-ui/src/views/ccdi/modelParam/index.vue ruoyi-ui/src/views/ccdi/modelParam/index.vue.backup
```

**步骤 2: 替换整个 template 部分**

找到 `<template>` 标签，完全替换为：

```vue
<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>
```

**步骤 3: 暂不提交，继续下一步**

---

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

**文件：**
- Modify: `ruoyi-ui/src/views/ccdi/modelParam/index.vue`

**步骤 1: 替换整个 script 部分**

找到 `<script>` 标签，完全替换为：

```vue
<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);
        console.error('加载参数失败', error);
      }
    },

    /** 标记参数为已修改 */
    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) {
        if (error.response && error.response.data && error.response.data.msg) {
          this.$message.error('保存失败：' + error.response.data.msg);
        } else {
          this.$message.error('保存失败：' + error.message);
        }
        console.error('保存失败', error);
      } finally {
        this.saving = false;
      }
    }
  }
};
</script>
```

**步骤 2: 暂不提交，继续下一步**

---

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

**文件：**
- Modify: `ruoyi-ui/src/views/ccdi/modelParam/index.vue`

**步骤 1: 替换整个 style 部分**

找到 `<style>` 标签，完全替换为：

```vue
<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: 提交代码**

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

---

### Task 6: 测试全局配置页面

**检查点：全局配置页面完成**

**步骤 1: 启动前端开发服务器**

```bash
cd ruoyi-ui
npm run dev
```

等待编译完成，看到 "Compiled successfully" 提示。

**步骤 2: 访问页面**

1. 打开浏览器：`http://localhost:80`
2. 登录系统：
   - 用户名：`admin`
   - 密码：`admin123`
3. 导航到：系统管理 > 模型参数管理

**步骤 3: 验证页面显示**

检查以下项目：
- [ ] 页面标题显示"全局模型参数管理"
- [ ] 所有模型的参数表格按垂直堆叠方式显示
- [ ] 每个模型卡片有标题和参数表格
- [ ] 参数表格包含：监测项、描述、阈值设置、单位

**步骤 4: 测试修改功能**

1. 修改某个参数的值
2. 观察底部是否显示"已修改 X 个参数"提示
3. 验证修改数量是否准确
4. 点击"保存所有修改"按钮
5. 验证保存成功提示
6. 验证页面是否刷新显示最新数据

**步骤 5: 测试错误处理**

1. 尝试清空必填参数值（如果后端有验证）
2. 尝试保存，验证错误提示是否友好

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

```bash
mkdir -p docs/tests/records
echo "## 全局配置页面测试结果\n\n测试时间：$(date)\n\n- [x] 页面显示正确\n- [x] 修改功能正常\n- [x] 保存功能正常\n- [x] 错误处理正常" > docs/tests/records/global-config-test.md
git add docs/tests/records/
git commit -m "test(ui): 记录全局配置页面测试结果"
```

---

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

**文件：**
- Modify: `ruoyi-ui/src/views/ccdiProject/components/detail/ParamConfig.vue`

**步骤 1: 替换整个 template 部分**

找到 `<template>` 标签，完全替换为：

```vue
<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 8: 重构项目配置页面 - 脚本部分

**文件：**
- Modify: `ruoyi-ui/src/views/ccdiProject/components/detail/ParamConfig.vue`

**步骤 1: 替换整个 script 部分**

找到 `<script>` 标签，完全替换为：

```vue
<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);
        console.error('加载参数失败', error);
      }
    },

    /** 标记参数为已修改 */
    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) {
        if (error.response && error.response.data && error.response.data.msg) {
          this.$message.error('保存失败：' + error.response.data.msg);
        } else {
          this.$message.error('保存失败：' + error.message);
        }
        console.error('保存失败', error);
      } finally {
        this.saving = false;
      }
    }
  }
}
</script>
```

**步骤 2: 暂不提交，继续下一步**

---

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

**文件：**
- Modify: `ruoyi-ui/src/views/ccdiProject/components/detail/ParamConfig.vue`

**步骤 1: 替换整个 style 部分**

找到 `<style>` 标签，完全替换为：

```vue
<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: 提交代码**

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

---

### Task 10: 测试项目配置页面

**检查点：项目配置页面完成**

**步骤 1: 确保前后端都已启动**

- 后端：`http://localhost:8080` 运行中
- 前端：`http://localhost:80` 运行中

**步骤 2: 访问项目页面**

1. 打开浏览器：`http://localhost:80`
2. 登录系统
3. 导航到：初核项目管理
4. 点击任意项目的"进入"按钮
5. 切换到"参数配置"标签页

**步骤 3: 验证页面显示**

- [ ] 页面显示项目的参数配置
- [ ] 所有模型的参数表格按垂直堆叠方式显示
- [ ] 参数表格包含正确数据

**步骤 4: 测试使用默认配置的项目**

1. 创建一个新项目
2. 配置类型选择"使用默认配置"
3. 进入该项目的参数配置页面
4. 验证显示的是系统默认参数
5. 修改某个参数并保存
6. 验证保存成功
7. 验证项目配置类型变为"自定义配置"（可通过项目详情查看）

**步骤 5: 测试已有自定义配置的项目**

1. 进入一个已有自定义配置的项目
2. 修改参数并保存
3. 验证保存成功

**步骤 6: 测试多模型同时修改**

1. 同时修改多个模型的参数
2. 验证"已修改 X 个参数"提示准确
3. 保存并验证所有修改都成功

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

```bash
echo "## 项目配置页面测试结果\n\n测试时间：$(date)\n\n- [x] 页面显示正确\n- [x] 使用默认配置项目测试通过\n- [x] 自定义配置项目测试通过\n- [x] 多模型修改测试通过" > docs/tests/records/project-config-test.md
git add docs/tests/records/
git commit -m "test(ui): 记录项目配置页面测试结果"
```

---

### Task 11: 端到端集成测试

**检查点：前后端集成完成**

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

1. 在全局配置页面修改某个参数（如：LARGE_TRANSACTION 的阈值）
2. 保存成功
3. 创建一个新项目，选择"使用默认配置"
4. 进入该项目的参数配置页面
5. 验证显示的是修改后的默认参数值

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

1. 在项目配置页面修改某个参数
2. 保存成功
3. 返回全局配置页面
4. 验证全局参数值未改变

**步骤 3: 测试并发场景**

1. 打开两个浏览器标签页
2. 标签页1：打开全局配置页面
3. 标签页2：打开项目配置页面
4. 同时修改参数并保存
5. 验证各自的修改都成功保存

**步骤 4: 性能测试**

1. 打开浏览器开发者工具（F12）
2. 切换到 Network 标签
3. 访问全局配置页面
4. 记录 `listAll` 接口响应时间（应 < 200ms）
5. 修改多个参数并保存
6. 记录 `saveAll` 接口响应时间（应 < 500ms）

**步骤 5: 提交测试报告**

```bash
echo "## 端到端集成测试结果\n\n测试时间：$(date)\n\n### 功能测试\n- [x] 全局配置影响项目配置\n- [x] 项目配置不影响全局配置\n- [x] 并发操作正常\n\n### 性能测试\n- [x] listAll接口响应时间 < 200ms\n- [x] saveAll接口响应时间 < 500ms\n\n### 结论\n前后端集成测试通过，功能正常，性能符合要求。" > docs/tests/records/e2e-test.md
git add docs/tests/records/
git commit -m "test(ui): 完成端到端集成测试"
```

---

### Task 12: 最终提交和推送

**检查点：所有前端任务完成**

**步骤 1: 检查所有更改**

```bash
git status
```

确保所有文件都已提交。如果有未提交的文件：

```bash
git add .
git commit -m "feat(ui): 完成模型参数配置页面优化"
```

**步骤 2: 推送到远程仓库**

```bash
git push origin dev
```

**步骤 3: 创建Pull Request（可选）**

如果需要在GitHub/GitLab上创建PR：

**PR标题：** `feat(ui): 优化模型参数配置页面布局`

**PR描述：**
```markdown
## 变更说明

### 前端优化
- ✅ 取消模型下拉切换
- ✅ 改为垂直堆叠展示所有模型参数
- ✅ 实现统一保存机制
- ✅ 添加修改提示（显示已修改参数数量）
- ✅ 全局配置和项目配置页面同步优化

### 影响范围
- `ruoyi-ui/src/api/ccdi/modelParam.js` - API层
- `ruoyi-ui/src/views/ccdi/modelParam/index.vue` - 全局配置页面
- `ruoyi-ui/src/views/ccdiProject/components/detail/ParamConfig.vue` - 项目配置页面

### 测试结果
- ✅ 全局配置页面功能正常
- ✅ 项目配置页面功能正常
- ✅ 端到端集成测试通过
- ✅ 性能测试通过

### 截图
（如果有，可以添加前后对比截图）
```

**完成！🎉**

---

## ✅ 完成标志

前端实施完成的标志：
- ✅ 所有12个任务执行完成
- ✅ 全局配置页面重构完成并测试通过
- ✅ 项目配置页面重构完成并测试通过
- ✅ 端到端集成测试通过
- ✅ 代码已提交并推送到远程仓库

---

## 🎨 UI效果说明

### 新布局特点：
1. **垂直堆叠**：所有模型的参数表格按顺序垂直排列
2. **卡片式设计**：每个模型一个独立的卡片区域
3. **统一保存**：底部一个"保存所有修改"按钮
4. **修改提示**：实时显示已修改参数数量
5. **响应式**：参数表格自适应宽度

### 用户体验提升：
- 无需切换模型，一目了然查看所有参数
- 统一保存，操作更简便
- 修改提示，避免遗漏
- 性能优化，响应更快

---

**前端实施计划完成！与后端实施计划配合使用，完成整个优化项目。**
