上传源代码版本

This commit is contained in:
Im-Jenisson
2026-06-01 16:30:29 +08:00
commit b2a9b7d3c2
462 changed files with 104365 additions and 0 deletions

View File

@@ -0,0 +1,296 @@
# 客户维度监控报表实现计划
## 一、需求分析
### 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`
**字段清单**
```csharp
// 基础信息
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 新增方法签名
```csharp
/// <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 基础框架结构
```sql
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 客户标签率计算
```sql
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 按客户分组的到仓统计
```sql
-- 需要关联 ArrivalRequests 以获取 CustomerId
-- 按 CustomerId + DATE(到货时间) 分组
-- 统计16点前后到仓数量去重
```
### 6.3 按客户分组的考核通过统计
```sql
-- 复用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. ✅ 实现总结文档