From 2ecb66c4c92acac275bfe5a2430e3facf9385af9 Mon Sep 17 00:00:00 2001 From: wkc <978997012@qq.com> Date: Fri, 27 Feb 2026 15:25:56 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E6=B7=BB=E5=8A=A0=E9=A1=B9=E7=9B=AE?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E9=A1=B5=E9=9D=A2=E6=94=B9=E8=BF=9B=E8=AE=BE?= =?UTF-8?q?=E8=AE=A1=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 搜索框添加内嵌搜索按钮 - 标签页状态计数改为后端统计接口 - 状态标签改为简约小圆点样式 --- ...-project-management-improvements-design.md | 586 ++++++++++++++++++ 1 file changed, 586 insertions(+) create mode 100644 docs/plans/2026-02-27-project-management-improvements-design.md diff --git a/docs/plans/2026-02-27-project-management-improvements-design.md b/docs/plans/2026-02-27-project-management-improvements-design.md new file mode 100644 index 0000000..1b707bd --- /dev/null +++ b/docs/plans/2026-02-27-project-management-improvements-design.md @@ -0,0 +1,586 @@ +# 项目管理页面改进设计文档 + +**日期:** 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 +**预计实施日期:** 待定