# 项目管理页面改进设计文档 **日期:** 2026-02-27 **作者:** Claude Code **状态:** 待实施 --- ## 一、需求概述 项目管理页面存在以下三个问题需要改进: 1. **搜索框缺少搜索按钮** - 用户只能通过回车或清空触发搜索,缺少显式的搜索按钮 2. **标签页状态计数不准确** - 当前只统计当前页的数据,无法反映全局状态分布 3. **状态标签样式不够简约** - 当前使用带背景色的标签,视觉上较重 --- ## 二、技术方案 ### 2.1 方案选择 经过对比分析,选择 **方案1:独立统计接口 + 精准样式改造** **理由:** - 接口职责单一,易于维护 - 统计数据准确,不受分页影响 - 性能最优,统计数据量小(仅4个数字) - 符合 RESTful 设计规范 --- ## 三、后端设计 ### 3.1 新增统计接口 **接口定义** ``` GET /ccdi/project/statusCounts ``` **权限要求** ``` ccdi:project:list ``` **Controller 层实现** 文件:`ccdi-project/src/main/java/com/ruoyi/ccdi/project/controller/CcdiProjectController.java` ```java /** * 获取项目状态统计 */ @GetMapping("/statusCounts") @Operation(summary = "获取项目状态统计") @PreAuthorize("@ss.hasPermi('ccdi:project:list')") public AjaxResult getStatusCounts() { Map counts = projectService.getStatusCounts(); return AjaxResult.success(counts); } ``` **Service 层接口** 文件:`ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/ICcdiProjectService.java` ```java /** * 获取各状态的项目数量 * @return 返回格式:{"all": 总数, "0": 进行中数量, "1": 已完成数量, "2": 已归档数量} */ Map getStatusCounts(); ``` **Service 层实现** 文件:`ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectServiceImpl.java` ```java @Override public Map getStatusCounts() { Map counts = new HashMap<>(); // 使用 MyBatis Plus 分组查询 QueryWrapper wrapper = new QueryWrapper<>(); wrapper.select("status", "COUNT(*) as count") .groupBy("status"); List> results = baseMapper.selectMaps(wrapper); // 初始化各状态计数 Long totalCount = 0L; Long inProgressCount = 0L; Long completedCount = 0L; Long archivedCount = 0L; // 遍历结果统计 for (Map result : results) { String status = (String) result.get("status"); Long count = (Long) result.get("count"); totalCount += count; if ("0".equals(status)) { inProgressCount = count; } else if ("1".equals(status)) { completedCount = count; } else if ("2".equals(status)) { archivedCount = count; } } counts.put("all", totalCount); counts.put("0", inProgressCount); counts.put("1", completedCount); counts.put("2", archivedCount); return counts; } ``` **响应示例** ```json { "code": 200, "msg": "操作成功", "data": { "all": 15, "0": 8, "1": 5, "2": 2 } } ``` --- ## 四、前端设计 ### 4.1 API 接口定义 **文件:** `ruoyi-ui/src/api/ccdiProject.js` ```javascript // 获取项目状态统计 export function getProjectStatusCounts() { return request({ url: '/ccdi/project/statusCounts', method: 'get' }) } ``` ### 4.2 SearchBar 组件改造 **文件:** `ruoyi-ui/src/views/ccdiProject/components/SearchBar.vue` **改动说明:** - 使用 Element UI 的 slot 功能在输入框右侧添加搜索按钮 - 保持回车和清空触发搜索的功能 - 调整输入框宽度以容纳按钮 **实现代码:** ```vue ``` **样式调整:** ```scss .search-input { width: 300px; // 从 240px 调整为 300px height: 40px; } ``` ### 4.3 ProjectTable 组件改造 **文件:** `ruoyi-ui/src/views/ccdiProject/components/ProjectTable.vue` **改动说明:** - 替换 `` + `` 组合为简约的小圆点样式 - 使用不同颜色的小圆点标识不同状态 - 文字统一使用黑色,降低视觉干扰 **实现代码:** ```vue ``` **新增方法:** ```javascript getStatusText(status) { const statusMap = { '0': '进行中', '1': '已完成', '2': '已归档' } return statusMap[status] || '未知' } ``` **移除方法:** ```javascript // 删除不再使用的 getStatusType 方法 ``` **样式设计:** ```scss .status-badge { display: inline-flex; align-items: center; gap: 6px; .status-dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; } .status-text { color: #333; font-size: 14px; } // 进行中 - 蓝色 &.status-0 .status-dot { background-color: #1890ff; } // 已完成 - 绿色 &.status-1 .status-dot { background-color: #52c41a; } // 已归档 - 灰色 &.status-2 .status-dot { background-color: #8c8c8c; } } ``` ### 4.4 主页面集成 **文件:** `ruoyi-ui/src/views/ccdiProject/index.vue` **改动说明:** - 引入统计接口 - created 生命周期并发加载统计和列表数据 - 状态变更后同时刷新统计和列表 - 优雅的错误处理 **引入接口:** ```javascript import { listProject, getProjectStatusCounts } from '@/api/ccdiProject' ``` **新增方法:** ```javascript /** 获取状态统计 */ getStatusCounts() { return getProjectStatusCounts().then(response => { this.tabCounts = response.data }).catch(() => { // 统计接口失败时使用默认值,不影响列表显示 this.tabCounts = { all: 0, '0': 0, '1': 0, '2': 0 } }) } ``` **修改 created 生命周期:** ```javascript created() { // 并发加载统计和列表 Promise.all([ this.getStatusCounts(), this.getList() ]) } ``` **优化 calculateTabCounts 方法:** ```javascript /** 计算标签页数量 - 改为从统计接口获取 */ calculateTabCounts() { // 方法保留但不执行计算逻辑 // 统计数据已从接口获取,直接使用 this.tabCounts } ``` **修改状态变更处理:** ```javascript /** 确认归档 */ handleConfirmArchive(data) { console.log('确认归档:', data) this.$modal.msgSuccess('项目已归档') this.archiveDialogVisible = false // 同时刷新统计和列表 Promise.all([ this.getStatusCounts(), this.getList() ]) } /** 提交项目表单 */ handleSubmitProject(data) { this.addDialogVisible = false // 同时刷新统计和列表 Promise.all([ this.getStatusCounts(), this.getList() ]) } ``` **优化 getList 方法:** ```javascript /** 查询项目列表 */ getList() { this.loading = true listProject(this.queryParams).then(response => { this.projectList = response.rows this.total = response.total this.loading = false // 不再需要调用 calculateTabCounts }).catch(() => { this.loading = false this.$modal.msgError('加载项目列表失败') }) } ``` --- ## 五、数据流设计 ### 5.1 数据加载时机 | 场景 | 刷新统计 | 刷新列表 | 说明 | |------|---------|---------|------| | 页面首次加载 | ✓ | ✓ | 并发请求 | | 标签页切换 | - | ✓ | 仅列表变化 | | 搜索触发 | - | ✓ | 仅列表变化 | | 项目归档 | ✓ | ✓ | 状态变化 | | 新建项目 | ✓ | ✓ | 总数增加 | | 删除项目 | ✓ | ✓ | 总数减少 | | 重新分析 | - | ✓ | 状态不变 | ### 5.2 并发加载优化 ```javascript // 使用 Promise.all 并发请求,提升加载速度 Promise.all([ this.getStatusCounts(), // 统计接口 this.getList() // 列表接口 ]) ``` ### 5.3 错误处理策略 **统计接口失败:** - 不阻塞页面加载 - 标签页显示 0,但列表正常显示 - 控制台记录错误日志 **列表接口失败:** - 显示错误提示 - 保持现有数据不变 - Loading 状态正常关闭 --- ## 六、性能考虑 ### 6.1 接口性能 **统计接口:** - 使用 COUNT + GROUP BY,无需查询详细字段 - 数据量极小(仅4个数字) - 执行速度快,可在 100ms 内完成 **列表接口:** - 保持现有分页逻辑 - 不受统计接口影响 ### 6.2 前端性能 **并发请求:** - 统计和列表同时发起,不串行等待 - 总耗时 = max(统计耗时, 列表耗时) **缓存策略:** - 统计数据在前端内存中保留 - 仅在状态变更时重新获取 --- ## 七、测试要点 ### 7.1 后端测试 **单元测试:** - 测试统计接口返回数据格式 - 测试空数据情况(无项目时) - 测试各状态的数据准确性 **集成测试:** - 使用 Swagger 测试接口响应 - 验证权限控制 ### 7.2 前端测试 **功能测试:** - 搜索按钮点击触发搜索 - 回车键触发搜索 - 清空输入框触发搜索 - 标签页显示正确的统计数据 - 状态标签显示正确的颜色和文字 **UI 测试:** - 搜索按钮样式与输入框融合 - 状态标签小圆点样式正确 - 不同状态的颜色区分明显 **错误场景测试:** - 统计接口失败时页面正常显示 - 列表接口失败时错误提示正确 - 网络异常时的降级处理 --- ## 八、改动文件清单 ### 8.1 后端文件 1. `ccdi-project/src/main/java/com/ruoyi/ccdi/project/controller/CcdiProjectController.java` - 新增统计接口方法 2. `ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/ICcdiProjectService.java` - 新增服务方法定义 3. `ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectServiceImpl.java` - 实现统计逻辑 ### 8.2 前端文件 1. `ruoyi-ui/src/api/ccdiProject.js` - 新增统计接口调用 2. `ruoyi-ui/src/views/ccdiProject/components/SearchBar.vue` - 添加内嵌搜索按钮 - 调整输入框宽度 3. `ruoyi-ui/src/views/ccdiProject/components/ProjectTable.vue` - 改造状态标签样式 - 新增 getStatusText 方法 - 删除 getStatusType 方法 4. `ruoyi-ui/src/views/ccdiProject/index.vue` - 引入统计接口 - 修改 created 生命周期 - 新增 getStatusCounts 方法 - 优化状态变更处理 --- ## 九、实施计划 ### 9.1 实施顺序 1. **后端开发**(优先) - 实现统计接口 - Swagger 测试验证 2. **前端开发** - API 接口定义 - SearchBar 组件改造 - ProjectTable 组件改造 - 主页面集成 3. **联调测试** - 前后端联调 - 功能测试 - UI 测试 ### 9.2 预估工时 - 后端开发:1 小时 - 前端开发:2 小时 - 联调测试:1 小时 - **总计:4 小时** --- ## 十、风险评估 ### 10.1 技术风险 **风险:** 统计接口性能问题 **影响:** 中 **缓解措施:** - 使用 COUNT + GROUP BY 优化查询 - 添加数据库索引(status 字段) - 监控接口响应时间 **风险:** 前端样式兼容性 **影响:** 低 **缓解措施:** - 使用标准的 CSS 属性 - 测试主流浏览器 ### 10.2 业务风险 **风险:** 统计数据与实际不符 **影响:** 高 **缓解措施:** - 使用数据库事务保证一致性 - 状态变更时立即刷新统计 - 添加数据校验 --- ## 十一、后续优化 ### 11.1 短期优化 - 添加统计数据的本地缓存(5秒过期) - 优化错误提示文案 ### 11.2 长期优化 - 支持按时间范围统计 - 添加趋势图表 - 支持自定义状态 --- **设计完成日期:** 2026-02-27 **预计实施日期:** 待定