上传源代码版本

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,251 @@
# 24H换单率超过100% - 最终根本原因与修复计划
**日期**2026-05-16
**核心问题**24H换单率远超100%4745%等),根本原因是分母计算错误
---
## 业务逻辑最终澄清(用户确认)
### 包裹的属性关系
```
考核时间
决定者:作业时的标签率(交接单维度)
标签率(两种)
1. 作业时标签率(固定)
= 最早扫描时间之前的有标签包裹 / 该交接单所有包裹
用途决定考核时间、决定是否纳入24H换单率
2. 统计的标签率(最终)
= 当前有标签的包裹 / 该交接单所有包裹
用途:业务报表展示
```
### 标签率与考核时间的关系
```
对于交接单中的每个包裹:
- 作业时标签率≥80% → 有考核时间 → 需要在规定时间内完成
- 作业时标签率<80% → 无考核时间 → 完成即达标
关键:考核时间是交接单维度确定的,然后应用到该交接单的所有包裹
```
### 分母的精确定义(用户最终确认)
```
高标签率应该换单数 = 当日到货 且 作业时标签率≥80% 的交接单中的有标签包裹数
具体计算方式:
1. 找出当日到货的所有交接单
2. 对每个交接单:
a. 计算作业时标签率 = 最早扫描之前有标签的数 / 总数
b. 如果作业时标签率≥80%
→ 计算这个交接单有多少个有标签的包裹
→ 这些有标签包裹加入应该换单数
c. 如果作业时标签率<80%
→ 跳过这个交接单(不加入应该换单数)
3. 求和得到总的高标签率应该换单数
```
---
## 当前代码的根本问题
### 问题1InterchangeUnitLabelRatesAtFirstScan的计算
**当前代码**第761-791行
```sql
SELECT
l.BillOfLadingNumber,
l.MasterPackageNumber,
COUNT(DISTINCT l.Id) AS total_requests,
COUNT(DISTINCT CASE
WHEN l.Label IS NOT NULL AND l.Label != ''
AND l.LabelRetrievedAt < (...)
THEN l.Id
END) AS labeled_at_first_scan,
...
FROM label_replace_requests l
GROUP BY l.BillOfLadingNumber, l.MasterPackageNumber
```
**问题**
- COUNT(DISTINCT l.Id) 统计的是"所有包裹"的数量
- 但根据用户规则,应该统计的是"有标签的包裹"的数量
**正确做法**
- 分子应该是:最早扫描时间之前有标签的包裹数
- 分母应该是:该交接单所有有标签的包裹数(不是所有包裹)
### 问题2DailyHighLabelRateShould的计算
**当前代码**第1100-1117行
```sql
DailyHighLabelRateShould AS (
SELECT
DATE(CONVERT_TZ(ar.到货时间, '+00:00', '-05:00')) AS 日期,
COUNT(DISTINCT CONCAT(ar.BillOfLadingNumber, '|', ar.MasterPackageNumber))
AS 高标签率应该换单数
FROM ArrivalRequests ar
INNER JOIN InterchangeUnitLabelRatesAtFirstScan...
WHERE label_rate_at_first_scan >= 80
```
**问题**
- 这里统计的是交接单级别的计数
- 但应该统计的是"有标签的包裹"数量
- 如果一个交接单有10个包裹其中8个有标签标签率80%
- 应该换单数应该是8不是1
**导致的后果**
- 分母被严重低估每个交接单只算1而不是该交接单的有标签包裹数
- 分子/分母比率就会巨大
---
## 修复方案
### 第1步修正InterchangeUnitLabelRatesAtFirstScan
**改进思路**
- 保留交接单维度的标签率计算(用于决定考核时间)
- 但同时记录"有标签包裹数"用于分母计算
```sql
InterchangeUnitLabelRatesAtFirstScan AS (
SELECT
l.BillOfLadingNumber,
l.MasterPackageNumber,
-- 统计有标签的包裹数(用于后续分母计算)
COUNT(DISTINCT CASE
WHEN l.Label IS NOT NULL AND l.Label != ''
THEN l.Id
END) AS total_labeled_at_any_time,
-- 作业时有标签的包裹数
COUNT(DISTINCT CASE
WHEN l.Label IS NOT NULL AND l.Label != ''
AND l.LabelRetrievedAt < (
SELECT MIN(lsh.CreatedAt)
FROM label_scan_history lsh
WHERE lsh.NeutralWaybillNumber = l.NeutralWaybillNumber
)
THEN l.Id
END) AS labeled_at_first_scan,
-- 作业时标签率 = 作业时有标签数 / 所有有标签数
ROUND(
COUNT(DISTINCT CASE
WHEN l.Label IS NOT NULL AND l.Label != ''
AND l.LabelRetrievedAt < (
SELECT MIN(lsh.CreatedAt)
FROM label_scan_history lsh
WHERE lsh.NeutralWaybillNumber = l.NeutralWaybillNumber
)
THEN l.Id
END) * 100.0 /
COUNT(DISTINCT CASE
WHEN l.Label IS NOT NULL AND l.Label != ''
THEN l.Id
END),
2
) AS label_rate_at_first_scan
FROM label_replace_requests l
GROUP BY l.BillOfLadingNumber, l.MasterPackageNumber
)
```
### 第2步修正DailyHighLabelRateShould
**改进思路**
- 统计的是"有标签的包裹数",而不是交接单数
```sql
DailyHighLabelRateShould AS (
SELECT
DATE(CONVERT_TZ(ar.到货时间, '+00:00', '-05:00')) AS 日期,
-- 改为统计:有标签的包裹数
SUM(CASE
WHEN iulr_first.label_rate_at_first_scan >= 80
THEN iulr_first.total_labeled_at_any_time
ELSE 0
END) AS 高标签率应该换单数
FROM ArrivalRequests ar
INNER JOIN InterchangeUnitLabelRatesAtFirstScan iulr_first
ON ar.BillOfLadingNumber = iulr_first.BillOfLadingNumber
AND ar.MasterPackageNumber = iulr_first.MasterPackageNumber
WHERE ar.到货日期 IS NOT NULL
GROUP BY DATE(CONVERT_TZ(ar.到货时间, '+00:00', '-05:00'))
)
```
### 第3步确保分子与分母维度一致
**分子的逻辑**DailyBeforeNoonPassed + DailyAfternoonPassed
- 已经是按"订单"NeutralWaybillNumber计数
- 这是正确的
**但需要确保**
- 只统计有标签的订单
- 只统计作业时标签率≥80%的订单
- 只统计在考核时间内完成的订单
---
## 实施步骤
### 步骤1修改InterchangeUnitLabelRatesAtFirstScan CTE
- 位置第761-791行
- 任务添加total_labeled_at_any_time字段调整label_rate_at_first_scan计算逻辑
- 验证:确保新增字段计算正确
### 步骤2修改DailyHighLabelRateShould CTE
- 位置第1100-1117行
- 任务改为SUM统计有标签包裹数而不是COUNT交接单
- 验证:结果应该更大(因为统计包裹而不是交接单)
### 步骤3编译验证
- 运行:`dotnet build src/DAL/DAL.csproj`
- 预期:编译成功
### 步骤4测试和验证
**测试内容**不要求≤100%,因为这是可能的正常现象):
测试1验证分母计算逻辑
```sql
SELECT
日期,
高标签率应该换单数,
(SELECT COUNT(*) FROM ...) as 应该的包裹数
FROM DailyHighLabelRateShould
WHERE 日期 = '2026-05-15'
```
测试2验证分子分母是否合理对应
```sql
SELECT
日期,
(SELECT SUM(...) FROM DailyBeforeNoonPassed WHERE 日期='2026-05-15') as 分子_16点前,
(SELECT SUM(...) FROM DailyAfternoonPassed WHERE 日期='2026-05-15') as 分子_16点后,
(SELECT 高标签率应该换单数 FROM DailyHighLabelRateShould WHERE 日期='2026-05-15') as 分母
```
测试3验证数据是否能手工解释
- 选择某一天的数据
- 查看具体的订单数和包裹数
- 确认分子分母的计算逻辑是否符合业务规则
- **不要求分子≤分母或24H换单率≤100%,因为这是可能的正常现象**
---
## 预期结果
修复后:
- ✅ 分母正确反映"有标签包裹数"而不是"交接单数"
- ✅ 数据逻辑一致、可解释
- ✅ 24H换单率数据合理虽然可能>100%但不会是4745%这样极端的值)
- ✅ 分子分母的对应关系清晰