Files
LabelChange-server/.trae/documents/metrics_dashboard_improvement_plan.md
2026-06-01 16:30:29 +08:00

13 KiB
Raw Blame History

指标查询系统改进计划 - 一页式完整汇总

📌 需求分析

用户痛点

需要多个查询页面拼凑指标 用户体验不佳,操作复杂 无法一次性看到所有关键指标

改进目标

用户只需选择一个日期 自动展示该日期的所有关键指标 一个仪表盘页面展现完整数据 无需手动计算和拼凑


🎯 实现方案

第一步:改进 metrics-dashboard.html

方案1: 简化为"一键查询"模式

文件: metrics-dashboard.html (修改)

改进内容:

  1. 移除 5 个独立查询模块
  2. 保留 唯一的输入:日期选择
  3. 新增 "查询汇总"按钮
  4. 显示 完整的指标卡片组件

展示指标 (20+个):

当天新增换单数、累计要换的总单数、当日应该换单数
当日换单完成数、当日STOP数、当日标签推送数
当日换单完成率、24小时完成率
16点前到仓数、16点后到仓数、16点前完成数、16点后完成数
当日失败数、当日成功数、当日未完结失败数
当日扫描数、累计积压数
等等...

UI 结构:

┌─────────────────────────────────────┐
│  📊 订单指标日汇总查询系统          │
│  选择日期: [日期选择器] [查询按钮] │
└────────────┬────────────────────────┘
             ↓
┌─────────────────────────────────────┐
│  📈 关键指标一览                     │
│  ├─ 新增/完成/应换 (3个大卡片)      │
│  ├─ 完成率指标 (2个卡片)            │
│  └─ 其他指标 (表格 + 卡片)          │
└─────────────────────────────────────┘

第二步:后端 API 优化

方案: 前端合并或后端聚合

选项 A: 前端合并 (简单快速)

  • 前端一次调用 getDailySummary API
  • API 返回所有 20+ 个指标
  • 前端直接展示

选项 B: 后端聚合 (推荐)

  • 新增 API: GET /api/metrics/daily-dashboard
  • 后端一次性返回完整汇总
  • 包含所有必要指标

第三步JSP 代理增强

修改: metrics-proxy.jsp

新增操作:

action: getDailyDashboard
- 参数: date (日期)
- 返回: 完整的日汇总数据结构

返回数据示例:

{
  "date": "2026-05-17",
  "summary": {
    "dailyNewReplaceCount": 150,
    "dailyShouldReplaceCount": 150,
    "dailySuccessCount": 145,
    "dailyCompletionRate": "96.67%",
    "rate24Hour": "96.67%"
  },
  "breakdown": {
    "beforeNoon": {
      "arrived": 80,
      "passed": 78,
      "rate": "97.50%"
    },
    "afternoon": {
      "arrived": 70,
      "passed": 67,
      "rate": "95.71%"
    }
  },
  "details": {
    "cumulativeTotal": 500,
    "dailyStop": 25,
    "dailyLabelPush": 160,
    "dailyScanCount": 200,
    "dailyFailure": 5
  }
}

📊 仪表盘设计

顶部信息区

┌─────────────────────────────────────┐
│ 📊 2026-05-17 订单处理指标汇总       │
│ 刷新时间: 14:30:45 (UTC-5)         │
└─────────────────────────────────────┘

指标展示区 (四层级)

一级: 核心指标 (3个大卡片)

┌──────────────┐  ┌──────────────┐  ┌──────────────┐
│ 当天新增     │  │ 应该换单数   │  │ 已完成       │
│    150       │  │    150       │  │    145       │
└──────────────┘  └──────────────┘  └──────────────┘

二级: 完成率 (2个卡片)

┌──────────────┐  ┌──────────────┐
│ 当日完成率   │  │ 24小时完成率 │
│   96.67%     │  │   96.67%     │
└──────────────┘  └──────────────┘

三级: 分时段统计 (表格)

┌────────┬───────┬───────┬────────┐
│ 时段   │ 到仓数 │ 完成数 │ 完成率 │
├────────┼───────┼───────┼────────┤
│ 16点前 │  80   │  78   │ 97.50% │
│ 16点后 │  70   │  67   │ 95.71% │
└────────┴───────┴───────┴────────┘

四级: 详细指标 (信息卡片组)

当日STOP数: 25
当日标签推送: 160
当日扫描数: 200
当日失败数: 5
累计积压数: 500

🔧 技术实现细节

第一步: 修改 metrics-dashboard.html

删除的代码:

  • 移除 5 个独立查询模块的 HTML 结构
  • 移除对应的 AJAX 查询函数

新增的代码:

  1. 单一日期选择器
  2. "查询汇总"按钮
  3. 统一的展示容器
  4. 完整的指标卡片组件

新增的 JavaScript (使用 JSONP 方式,对齐 batch_query.html):

// 定义回调函数容器
var dashboardCallbacks = {};

// 单一查询函数(使用 JSONP
function queryDailyDashboard() {
    const date = document.getElementById('dashboardDate').value;
    if (!date) {
        showError('请选择日期');
        return;
    }
    
    // 生成唯一的回调函数名称
    const callbackName = 'dashboardCallback_' + new Date().getTime();
    
    // 定义回调处理函数
    window[callbackName] = function(response) {
        handleDashboardResponse(response);
        // 清理
        delete window[callbackName];
    };
    
    // 构建 JSONP 请求 URL
    const url = `metrics-proxy.jsp?action=getDailyDashboard&date=${date}&callback=${callbackName}&env=${getEnvironment()}`;
    
    // 使用 JSONP 请求
    jsonpRequest(url, callbackName);
}

// JSONP 请求函数(参考 batch_query.html
function jsonpRequest(url, callbackName) {
    const script = document.createElement('script');
    script.src = url;
    script.type = 'text/javascript';
    
    // 超时处理
    const timeout = setTimeout(() => {
        script.remove();
        delete window[callbackName];
        showError('请求超时,请重试');
    }, 10000);
    
    script.onload = () => {
        clearTimeout(timeout);
        script.remove();
    };
    
    script.onerror = () => {
        clearTimeout(timeout);
        script.remove();
        delete window[callbackName];
        showError('请求失败,请检查网络连接');
    };
    
    document.head.appendChild(script);
}

// 处理响应数据
function handleDashboardResponse(response) {
    if (response.success) {
        displayDashboard(response.data);
    } else {
        showError(response.error || '查询失败');
    }
}

// 展示完整指标仪表盘
function displayDashboard(data) {
    // 构建完整的指标展示 HTML
    // ... 具体实现
}

第二步: 修改 metrics-proxy.jsp

获取 callback 参数:

String callback = request.getParameter("callback");
String format = request.getParameter("format");
if (format == null) {
    format = (callback != null && !callback.isEmpty()) ? "jsonp" : "json";
}

新增操作:

else if ("getDailyDashboard".equals(action)) {
    // 调用新的聚合 API
    apiUrl = baseUrl + "/api/metrics/daily-dashboard?date=" + URLEncoder.encode(date, "UTF-8");
}

返回格式处理 (响应使用 JSONP 包装):

// 如果是 JSONP 格式,使用 callback 包装
if ("jsonp".equals(format) && callback != null && !callback.isEmpty()) {
    // 验证 callback 名称安全
    if (callback.matches("^[a-zA-Z_$][a-zA-Z0-9_$]*$")) {
        out.print(callback + "(" + resultJson.toString() + ");");
    } else {
        out.print("jsonp_error({\"error\": \"Invalid callback name\"});");
    }
} else {
    out.print(resultJson.toString());
}

第三步: 后端 API (可选但推荐)

新增 Controller 方法:

[HttpGet("daily-dashboard")]
public async Task<IActionResult> GetDailyDashboard([FromQuery] string date)
{
    // 调用 GetDailySummaryAsync
    // 返回格式化的完整汇总
}

📈 指标优先级

必显示 (一级重要)

  • 当天新增换单数
  • 当天应该换单数
  • 当日换单完成数
  • 当日完成率
  • 24小时完成率

次要显示 (二级重要)

  • 16点前到仓数
  • 16点前完成数
  • 16点后到仓数
  • 16点后完成数

详情显示 (三级信息)

  • 当日STOP数
  • 当日标签推送数
  • 当日扫描数
  • 当日失败数
  • 累计积压数

🎨 UI 改进

设计原则

  1. 一屏即得 - 不需要滚动看所有指标
  2. 视觉优先级 - 重要数据更大更突出
  3. 颜色编码 - 好/一般/差用不同颜色
  4. 实时刷新 - 支持手动刷新最新数据

色彩编码

  • 🟢 绿色: 完成率 >= 95%
  • 🟡 黄色: 完成率 85-95%
  • 🔴 红色: 完成率 < 85%

📝 实现步骤表

步骤 操作 文件 优先级
1 重设计仪表盘布局 metrics-dashboard.html
2 新增日期+查询UI metrics-dashboard.html
3 新增汇总展示容器 metrics-dashboard.html
4 编写查询函数 metrics-dashboard.html
5 更新 JSP 代理 metrics-proxy.jsp
6 新增后端 API (可选) MetricsController.cs

验收标准

  • 用户选择日期后,一次调用获取所有指标
  • 所有 20+ 个指标在一个仪表盘展示
  • 无需多个查询和手动计算
  • 指标分层展示,易于查看
  • 支持日期范围快速选择 (今天、昨天、本周等)
  • 支持数据刷新按钮

📊 预期效果

改进前

用户: 我想看 2026-05-17 的指标
流程: 
1. 选择日期查标签率
2. 再查订单评估
3. 再查每日汇总
4. 手动拼凑计算
时间: 5 分钟+

改进后

用户: 我想看 2026-05-17 的指标
流程:
1. 选择日期
2. 点击查询
时间: 2-3 秒
结果: 完整汇总一屏显示 ✅

🎯 整体方案架构

┌──────────────────────────────────────┐
│  改进版仪表盘 (新)                   │
│  ├─ 日期选择器 (单一入口)            │
│  ├─ 查询汇总按钮                     │
│  └─ 完整指标展示                     │
│     ├─ 核心指标卡片 (3个)            │
│     ├─ 完成率卡片 (2个)              │
│     ├─ 分时段统计 (表格)             │
│     └─ 详细指标卡片 (4个)            │
└──────────────────────────────────────┘
         ↓ 调用
┌──────────────────────────────────────┐
│  metrics-proxy.jsp (改进版)          │
│  ├─ 新增 getDailyDashboard 操作      │
│  └─ 返回聚合后的完整数据             │
└──────────────────────────────────────┘
         ↓ 调用
┌──────────────────────────────────────┐
│  MetricsController (可选)            │
│  └─ 新增 /daily-dashboard API        │
└──────────────────────────────────────┘

💡 核心改进点

  1. 入口简化 - 从 5 个查询模块 → 1 个日期选择
  2. 数据聚合 - 从多次调用 → 1 次 API 调用
  3. 展示完整 - 从分散显示 → 一屏汇总
  4. 用户友好 - 从复杂操作 → 一键查询
  5. JSONP 支持 - 采用与 batch_query.html 相同的 JSONP 方式调用

🔗 JSONP 调用示例

请求 URL

metrics-proxy.jsp?action=getDailyDashboard&date=2026-05-17&callback=dashboardCallback_1234567890&env=test

响应格式

dashboardCallback_1234567890({
  "success": true,
  "data": {
    "date": "2026-05-17",
    "summary": {
      "dailyNewReplaceCount": 150,
      "dailyShouldReplaceCount": 150,
      "dailySuccessCount": 145,
      "dailyCompletionRate": "96.67%",
      "rate24Hour": "96.67%"
    },
    "breakdown": {
      "beforeNoon": { "arrived": 80, "passed": 78, "rate": "97.50%" },
      "afternoon": { "arrived": 70, "passed": 67, "rate": "95.71%" }
    },
    "details": {
      "cumulativeTotal": 500,
      "dailyStop": 25,
      "dailyLabelPush": 160,
      "dailyScanCount": 200,
      "dailyFailure": 5
    }
  }
});

前端处理

// 自动执行回调,接收数据
function handleDashboardResponse(response) {
    if (response.success) {
        displayDashboard(response.data);
    } else {
        showError(response.error || '查询失败');
    }
}