587 lines
12 KiB
Markdown
587 lines
12 KiB
Markdown
|
|
# 项目管理页面改进设计文档
|
|||
|
|
|
|||
|
|
**日期:** 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<String, Long> 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<String, Long> getStatusCounts();
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Service 层实现**
|
|||
|
|
|
|||
|
|
文件:`ccdi-project/src/main/java/com/ruoyi/ccdi/project/service/impl/CcdiProjectServiceImpl.java`
|
|||
|
|
|
|||
|
|
```java
|
|||
|
|
@Override
|
|||
|
|
public Map<String, Long> getStatusCounts() {
|
|||
|
|
Map<String, Long> counts = new HashMap<>();
|
|||
|
|
|
|||
|
|
// 使用 MyBatis Plus 分组查询
|
|||
|
|
QueryWrapper<CcdiProject> wrapper = new QueryWrapper<>();
|
|||
|
|
wrapper.select("status", "COUNT(*) as count")
|
|||
|
|
.groupBy("status");
|
|||
|
|
|
|||
|
|
List<Map<String, Object>> results = baseMapper.selectMaps(wrapper);
|
|||
|
|
|
|||
|
|
// 初始化各状态计数
|
|||
|
|
Long totalCount = 0L;
|
|||
|
|
Long inProgressCount = 0L;
|
|||
|
|
Long completedCount = 0L;
|
|||
|
|
Long archivedCount = 0L;
|
|||
|
|
|
|||
|
|
// 遍历结果统计
|
|||
|
|
for (Map<String, Object> 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
|
|||
|
|
<el-input
|
|||
|
|
v-model="searchKeyword"
|
|||
|
|
placeholder="请输入关键词搜索项目"
|
|||
|
|
clearable
|
|||
|
|
size="small"
|
|||
|
|
class="search-input"
|
|||
|
|
@keyup.enter.native="handleSearch"
|
|||
|
|
@clear="handleSearch"
|
|||
|
|
>
|
|||
|
|
<el-button
|
|||
|
|
slot="append"
|
|||
|
|
icon="el-icon-search"
|
|||
|
|
@click="handleSearch"
|
|||
|
|
/>
|
|||
|
|
</el-input>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**样式调整:**
|
|||
|
|
|
|||
|
|
```scss
|
|||
|
|
.search-input {
|
|||
|
|
width: 300px; // 从 240px 调整为 300px
|
|||
|
|
height: 40px;
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4.3 ProjectTable 组件改造
|
|||
|
|
|
|||
|
|
**文件:** `ruoyi-ui/src/views/ccdiProject/components/ProjectTable.vue`
|
|||
|
|
|
|||
|
|
**改动说明:**
|
|||
|
|
- 替换 `<el-tag>` + `<dict-tag>` 组合为简约的小圆点样式
|
|||
|
|
- 使用不同颜色的小圆点标识不同状态
|
|||
|
|
- 文字统一使用黑色,降低视觉干扰
|
|||
|
|
|
|||
|
|
**实现代码:**
|
|||
|
|
|
|||
|
|
```vue
|
|||
|
|
<!-- 状态列 -->
|
|||
|
|
<el-table-column
|
|||
|
|
prop="status"
|
|||
|
|
label="状态"
|
|||
|
|
width="120"
|
|||
|
|
align="center"
|
|||
|
|
>
|
|||
|
|
<template slot-scope="scope">
|
|||
|
|
<span class="status-badge" :class="'status-' + scope.row.status">
|
|||
|
|
<span class="status-dot"></span>
|
|||
|
|
<span class="status-text">{{ getStatusText(scope.row.status) }}</span>
|
|||
|
|
</span>
|
|||
|
|
</template>
|
|||
|
|
</el-table-column>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**新增方法:**
|
|||
|
|
|
|||
|
|
```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
|
|||
|
|
**预计实施日期:** 待定
|