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

8.1 KiB
Raw Permalink Blame History

客户维度监控报表实现计划

一、需求分析

1.1 新报表概述

基于现有日级报表 GetDailyLabelStatsChineseAsync() 的逻辑,创建一个客户维度的监控报表

1.2 报表核心维度

  • 第一维度客户CustomerId / CustomerCode / CustomerName
  • 第二维度:日期(可选:按日期聚合)

1.3 新增数据字段

  1. 客户标签率:该客户的有标签订单数 / 总订单数
  2. 分段统计各客户在16点前后的到仓和考核通过情况
  3. 核心指标:每个客户的换单成功率、完成率等

1.4 数据粒度

  • 按客户日期统计粒度最细CustomerId + Date
  • 按客户汇总粗粒度CustomerId可选

二、现有系统分析

2.1 现有表结构涉及

  • label_replace_requests - 换单请求表包含CustomerId、Label等
  • arrival_handover_forms - 到货交接单表
  • label_scan_history - 扫描历史表

2.2 现有SQL逻辑复用

GetDailyLabelStatsChineseAsync() 中复用:

  • CustomerLabelRates CTE客户标签率计算
  • ArrivalRequests CTE考核时间逻辑
  • Daily24HCompletedOrders CTE考核通过判断
  • 16点分段统计逻辑

三、新报表DTO定义

3.1 新建DTO类

类名CustomerDailyLabelStatsDto

字段清单

// 基础信息
public int CustomerId { get; set; }
public string CustomerCode { get; set; }
public string CustomerName { get; set; }
public string Date { get; set; }  // yyyy-MM-dd

// 客户标签率相关
public string CustomerLabelRate { get; set; }  // "xx.xx%"
public int TotalRequests { get; set; }  // 该客户该日期的总订单数
public int LabeledRequests { get; set; }  // 有标签的订单数

// 到仓分布
public int BeforeNoonArrivedCount { get; set; }  // 16点前到仓
public int AfternoonArrivedCount { get; set; }  // 16点后到仓

// 考核通过
public int BeforeNoonPassedCount { get; set; }  // 16点前考核通过
public int AfternoonPassedCount { get; set; }  // 16点后考核通过

// 核心指标
public int DailyNewReplaceCount { get; set; }  // 当日新增换单数
public int DailySuccessCount { get; set; }  // 当日换单成功数
public int DailyFailureCount { get; set; }  // 当日换单失败
public int DailyCompletedCount { get; set; }  // 当日完成数

// 完成率
public string DailyCompletionRate { get; set; }  // "xx.xx%"
public string Rate24Hour { get; set; }  // 24小时完成率

// 其他
public DateTime DataFetchTime { get; set; }  // 数据拉取时间

四、新Repository方法实现

4.1 新增方法签名

/// <summary>
/// 获取客户维度的每日标签换单统计数据
/// </summary>
public async Task<List<CustomerDailyLabelStatsDto>> GetCustomerDailyLabelStatsAsync()

4.2 SQL结构设计

步骤1获取客户基础信息和标签率

CustomerInfo + CustomerLabelRates
├─ 客户ID、代码、名称
├─ 客户标签率 = 有标签订单数 / 总订单数
└─ 总订单数、有标签订单数

步骤2按客户日期分组的到仓统计

CustomerDailyArrival
├─ 按 CustomerId + DATE(ReceiptTime) 分组
├─ 16点前到仓数
└─ 16点后到仓数

步骤3按客户日期分组的考核通过统计

CustomerDailyBeforeNoonPassed
CustomerDailyAfternoonPassed
├─ 16点前考核通过数
└─ 16点后考核通过数

步骤4按客户日期分组的换单完成统计

CustomerDailyCompletion
├─ 当日新增换单数
├─ 当日成功数
├─ 当日失败数
└─ 当日完成数

步骤5最终聚合与输出

最终SELECT
├─ 关联CustomerInfo客户信息
├─ 关联CustomerDailyArrival到仓分布
├─ 关联CustomerDailyXxxPassed考核通过
├─ 关联CustomerDailyCompletion换单完成
├─ 计算完成率、24H率
└─ 输出所有字段

五、SQL查询框架

5.1 基础框架结构

WITH
-- 步骤1客户信息和标签率
CustomerInfo AS (
    SELECT CustomerId, CustomerCode, CustomerName, 
           标签率计算...
),

-- 步骤2客户日期的到仓分布
CustomerDailyArrival AS (
    SELECT CustomerId, DATE(ReceiptTime) AS 日期,
           COUNT(CASE WHEN HOUR(ReceiptTime) < 16...)
           COUNT(CASE WHEN HOUR(ReceiptTime) >= 16...)
),

-- 步骤3客户日期的16点前考核通过
CustomerDailyBeforeNoonPassed AS (
    SELECT CustomerId, 日期, COUNT(...)
),

-- 步骤4客户日期的16点后考核通过
CustomerDailyAfternoonPassed AS (
    SELECT CustomerId, 日期, COUNT(...)
),

-- 步骤5客户日期的换单完成统计
CustomerDailyCompletion AS (
    SELECT CustomerId, 日期, 
           COUNT(新增), COUNT(成功), COUNT(失败), COUNT(完成)
),

-- 步骤6最终聚合
最终SELECT

六、关键SQL逻辑

6.1 客户标签率计算

CustomerLabelRate = 
  (SELECT COUNT(DISTINCT id) 
   FROM label_replace_requests l 
   WHERE l.CustomerId = ci.CustomerId AND l.Label IS NOT NULL AND l.Label != '')
  /
  (SELECT COUNT(DISTINCT id) 
   FROM label_replace_requests l 
   WHERE l.CustomerId = ci.CustomerId)
  * 100

6.2 按客户分组的到仓统计

-- 需要关联 ArrivalRequests 以获取 CustomerId
-- 按 CustomerId + DATE(到货时间) 分组
-- 统计16点前后到仓数量去重

6.3 按客户分组的考核通过统计

-- 复用Daily24HCompletedOrders的逻辑
-- 额外按 CustomerId 分组
-- 分别统计16点前和16点后的通过数

七、实现步骤

步骤1创建新DTO类

文件d:\EPproject\LabelReplaceServer\src\MDL\DTOs\CustomerDailyLabelStatsDto.cs

  • 定义所有字段
  • 添加SugarColumn注解

步骤2在Repository中新增方法

文件d:\EPproject\LabelReplaceServer\src\DAL\Repositories\LabelReplaceRepository.cs

  • 新增 GetCustomerDailyLabelStatsAsync() 方法
  • 实现完整SQL查询
  • 添加reader映射逻辑

步骤3创建对应的Service方法可选

文件BLL/Services/ 中的相关Service

  • 封装数据处理逻辑
  • 提供业务层接口

步骤4创建Controller端点可选

文件CONTROLLER/Controllers/ 中的相关Controller

  • 新增API端点
  • 处理请求参数如客户ID、日期范围

步骤5验证与测试

  • SQL语法检查
  • 编译无错误
  • 数据准确性验证

八、关键技术点

8.1 去重问题

  • 客户标签率需要用 COUNT(DISTINCT l.Id) 避免重复计算
  • 到仓分布需要用 COUNT(DISTINCT ar.RequestId) 避免重复
  • 完成数需要用 COUNT(DISTINCT NeutralWaybillNumber) 去重

8.2 时区处理

  • 所有时间比较保持一致的UTC-5时区
  • 到仓时间:a.ReceiptTime已是UTC-5
  • 完成时间:CONVERT_TZ(oss.首次成功时间, '+00:00', '-05:00')

8.3 考核时间逻辑复用

  • 从现有SQL中复用CustomerLabelRates CTE
  • 从现有SQL中复用考核时间计算逻辑
  • 从现有SQL中复用Daily24HCompletedOrders判断逻辑

8.4 性能优化

  • 添加索引:label_replace_requests(CustomerId)
  • 避免多次相同的子查询
  • 使用CTE提高查询可读性

九、输出样例

CustomerId CustomerCode CustomerName Date CustomerLabelRate BeforeNoonArrived ...
1 CUST001 客户A 2026-05-16 95.50% 10 ...
1 CUST001 客户A 2026-05-17 95.50% 8 ...
2 CUST002 客户B 2026-05-16 78.30% 15 ...

十、风险与考虑

10.1 潜在风险

  1. 数据一致性:客户信息是否会变更?
  2. 性能:大量客户下的查询性能?
  3. 时间范围:查询是否需要日期范围参数?

10.2 扩展考虑

  • 支持日期范围查询参数
  • 支持按客户ID筛选
  • 支持按标签率范围筛选
  • 支持导出到Excel

十一、预期交付物

  1. CustomerDailyLabelStatsDto.cs - DTO类
  2. Repository新方法 - GetCustomerDailyLabelStatsAsync()
  3. 完整SQL查询脚本
  4. 编译无错误
  5. 实现总结文档