# 24小时换单率修复 - 完成总结 **修复完成日期**:2026-05-16 **编译状态**:✅ 成功(exit code: 0) --- ## 修复概述 根据用户的最终业务逻辑澄清,已完成24小时换单率的根本性修复。核心改进:**使用作业时标签率(基于最早扫描时间)替代现在标签率**,确保分子分母维度一致。 --- ## 核心问题与解决方案 ### 问题:为什么超过100%? **根本原因**: 1. **分子按完成日期分组**:某天完成的包裹(可能来自多天到货) 2. **分母按到货日期分组**:某天到货的应该完成的包裹 3. **导致分子 >> 分母**:例如分子=130,分母=50 → 260% **更深层问题**: - 用的是"现在的标签率"判断,而不是"作业时的标签率" - 作业决策在最早扫描时刻做的,此时的标签率是固定的 - 用错误的标签率判断导致错误的包裹被纳入24H统计 --- ## 实施的三大关键修改 ### 修改1:创建"作业时标签率" CTE **新增CTE**:`InterchangeUnitLabelRatesAtFirstScan`(第760-791行) ```sql 作业时标签率 = 最早扫描时间之前推送的标签数 / 总包裹数 ``` **原理**: - 最早扫描时间 = 任何Result值的最早扫描记录 - 在这个时刻,标签率是"冻结"的 - 这个标签率决定了包裹是否纳入24H考核 --- ### 修改2:修改考核时间逻辑 **位置**:ArrivalRequests CTE(第802-843行) **改变**: ```sql 原来:用现在的标签率判断 (label_rate_percent) 现在:用作业时标签率判断 (label_rate_at_first_scan) ``` **含义**: - 作业时标签率≥80% → 设定考核时间(16点前后不同) - 作业时标签率<80% → 无考核时间(完成即达标) **结果**:每个包裹的考核方式由其作业时的标签率决定,而不是最终标签率 --- ### 修改3:分子分母维度对齐 **分母改为使用作业时标签率**(第1113-1115行): ```sql FROM InterchangeUnitLabelRatesAtFirstScan WHERE label_rate_at_first_scan >= 80 ``` **分子改为按到货日期分组**(第1047、1066行): ```sql GROUP BY DATE(CONVERT_TZ(ar.到货时间, '+00:00', '-05:00')) ``` **结果**: - 分子:某天到货、作业时标签率≥80%、已完成的包裹 - 分母:某天到货、作业时标签率≥80%的全部包裹 - **维度一致,分子 ≤ 分母** --- ## 修复前后对比 ### 修复前(有问题) ``` DailyBeforeNoonPassed(分子): └─ GROUP BY 首次成功日期 DailyAfternoonPassed(分子): └─ GROUP BY 首次成功日期 DailyHighLabelRateShould(分母): └─ GROUP BY 到货日期 结果:日期维度不同,导致分子 >> 分母 → 超过100% ``` ### 修复后(正确) ``` DailyBeforeNoonPassed(分子): ├─ GROUP BY 到货日期 ✓ ├─ WHERE 作业时标签率≥80% ✓ └─ AND 完成时间 <= 考核时间 ✓ DailyAfternoonPassed(分子): ├─ GROUP BY 到货日期 ✓ ├─ WHERE 作业时标签率≥80% ✓ └─ AND 完成时间 <= 考核时间 ✓ DailyHighLabelRateShould(分母): ├─ GROUP BY 到货日期 ✓ ├─ FROM InterchangeUnitLabelRatesAtFirstScan └─ WHERE 作业时标签率≥80% ✓ 结果:日期维度一致,分子 ≤ 分母 → 0-100% ``` --- ## 修改的具体代码位置 | 操作 | 文件 | 行号 | 内容 | |------|------|------|------| | 新增CTE | LabelReplaceRepository.cs | 760-791 | InterchangeUnitLabelRatesAtFirstScan | | 修改ArrivalRequests | LabelReplaceRepository.cs | 802-843 | 新增作业时标签率字段,修改考核时间逻辑 | | 修改DailyHighLabelRateShould | LabelReplaceRepository.cs | 1100-1117 | 改用作业时标签率判断 | | 修改DailyBeforeNoonPassed | LabelReplaceRepository.cs | 1033-1050 | 改按到货日期分组 | | 修改DailyAfternoonPassed | LabelReplaceRepository.cs | 1052-1069 | 改按到货日期分组 | --- ## 预期效果 修复后24H换单率应该表现为: ``` 24H换单率 = (该天到货、作业时标签率≥80%、已完成的包裹) / (该天到货、作业时标签率≥80%的全部包裹) × 100% 特性: ✅ 0% ≤ 24H换单率 ≤ 100% ✅ 分子 ≤ 分母(数学上正确) ✅ 可以手工验证(选一天数据验证) ✅ 符合业务含义(该天到货订单24小时内完成率) ``` --- ## 测试建议 ### 第1步:查询某一天的统计数据 ```sql SELECT 日期, 高标签率应该换单数 AS 分母, 16点前考核通过包裹数 + 16点后考核通过包裹数 AS 分子, 24H换单率 FROM 日级报表 WHERE 日期 = '2026-05-15' ``` 验证:分子 ≤ 分母,24H换单率 ≤ 100% ### 第2步:检查作业时标签率vs现在标签率 某些订单的标签率会在作业时间之后继续增加,导致: - 作业时标签率 < 80% → 按完成即达标处理 - 现在标签率 ≥ 80% → 但不会被纳入24H考核(因为作业时没有达到80%) 这是**正确行为**,因为决策是在作业开始时做的。 ### 第3步:验证边界情况 测试以下场景: - 某天到货100个订单,作业时79% → 应该2-48小时内完成 - 某天到货100个订单,作业时80% → 应该按16点前后分别设定考核时间 --- ## 关键设计理念 ### "冻结"的标签率 ``` 时间线: ┌─ 标签推送 → 标签率: 50% │ ├─ 最早扫描 ← 作业时标签率冻结在这个时刻 │ (标签率: 60%) │ ├─ 继续扫描和标签推送 → 标签率: 70% → 85% │ (但不影响作业策略,已经确定要按60%处理) │ └─ 首次成功 → 完成时间确定 决策依据:作业时标签率(60%)而不是最终标签率(85%) ``` ### 两种场景的处理 **场景A:作业时标签率≥80%** - 需要在规定时间内完成 - 完成时间 ≤ 考核时间 → 考核通过 - 完成时间 > 考核时间 → 考核不通过 **场景B:作业时标签率<80%** - 无需在特定时间内完成 - 完成即达标,不需要考核时间 --- ## 编译验证 ✅ **编译成功** - 命令:`dotnet build src/DAL/DAL.csproj` - 结果:exit code 0 - 时间:2026-05-16 --- ## 后续行动 1. **部署到测试环境**:运行修复后的查询 2. **数据验证**:确认24H换单率 ≤ 100% 3. **手工抽查**:选择3-5个日期,手工验证分子分母 4. **监控**:上线后监测是否有异常数据 --- ## 文档参考 - 修复计划:[fix_24h_rate_based_on_first_scan_plan.md](fix_24h_rate_based_on_first_scan_plan.md) - 之前诊断:[24h_rate_numerator_denominator_diagnosis.md](24h_rate_numerator_denominator_diagnosis.md) - 代码位置:[LabelReplaceRepository.cs](file:///d:\EPproject\LabelReplaceServer\src\DAL\Repositories\LabelReplaceRepository.cs#L709)