# 冻结标签率设计核心逻辑修正 - v3.0

**更新日期**: 2026-05-16  
**版本**: v3.0 - 关键考核规则澄清  
**状态**: ✅ 编译通过，文档已更新

---

## 核心修正点

### ⚠️ 发现的误区

在 v2.0 中，对 `DailyHighLabelRateShould` 和 `DailyLowLabelRateShould` 两个 CTE 的理解有误。

**错误理解**（v2.0）：
- 这两个 CTE 是用来分别统计"标签推送时间与扫描时间关系"中的高/低标签率包裹数
- 高标签率包裹单独处理，低标签率包裹单独处理

**用户指正**：
"如果冻结标签率是低于80%的，那么100个包裹都要按照完成即达标的规则处理，如果冻结标签率大于等于80%则按照到仓时间16点前后的规则处理"

### ✅ 正确理解（v3.0）

**冻结标签率的真实作用**：
- 冻结标签率是对**整个交接单**的标签率水平的评估
- 它决定了**这个交接单中的所有包裹**应该按什么规则处理
- **不是分别处理包裹，而是整体规则应用**

**考核规则的应用逻辑**：

```
IF 冻结标签率 >= 80% THEN
    ├─ 所有包裹都按照"到仓时间16点前后分段"规则处理
    └─ 高标签率应该换单数 += 这个交接单的全部包裹数
ELSE IF 冻结标签率 < 80% THEN
    ├─ 所有包裹都按照"完成即达标"规则处理
    └─ 低标签率应该换单数 += 这个交接单的全部包裹数
```

---

## 代码修正

### DailyHighLabelRateShould CTE 修正

**v2.0（错误）**：
```sql
WHERE earliest_times.earliest_scan_time > lrr.LabelRetrievedAt
-- 这样是在分别统计包裹，而不是统计交接单
```

**v3.0（正确）**：
```sql
FROM ArrivalRequests ar
INNER JOIN (
    SELECT DISTINCT BillOfLadingNumber, MasterPackageNumber
    FROM InterchangeUnitLabelRates
    WHERE label_rate_percent >= 80
) high_label_units ON ...
-- 统计所有冻结标签率 >= 80% 的交接单中的全部包裹数
```

### DailyLowLabelRateShould CTE 修正

**v2.0（错误）**：
```sql
WHERE earliest_times.earliest_scan_time <= lrr.LabelRetrievedAt
-- 这样是在分别统计包裹，而不是统计交接单
```

**v3.0（正确）**：
```sql
FROM ArrivalRequests ar
INNER JOIN (
    SELECT DISTINCT BillOfLadingNumber, MasterPackageNumber
    FROM InterchangeUnitLabelRates
    WHERE label_rate_percent < 80
) low_label_units ON ...
-- 统计所有冻结标签率 < 80% 的交接单中的全部包裹数
```

---

## 逻辑对比示例

### 场景：100个订单在同一交接单

**标签分布**：
- 30个订单：标签推送于09:00-10:00（早于作业开始）
- 50个订单：标签推送于10:00-11:00（同时作业开始）
- 20个订单：标签推送于11:00-12:00（晚于作业开始）

**冻结标签率**：`30/100 = 30%`

### v2.0 的错误理解

```
高标签率应该换单数 = 30（推送时间 > 扫描时间的包裹）
低标签率应该换单数 = 70（推送时间 <= 扫描时间的包裹）

那么：
- 30个包裹按高标签率规则处理（16点分段）
- 70个包裹按低标签率规则处理（完成即达标）
❌ 这样导致同一个交接单的包裹按不同规则处理！
```

### v3.0 的正确理解

```
冻结标签率 = 30% < 80%
→ 整个交接单（所有100个包裹）都按低标签率规则处理（完成即达标）

因此：
高标签率应该换单数 = 0（没有标签率≥80%的交接单）
低标签率应该换单数 = 100（整个交接单都按此规则处理）
✅ 这样才符合业务逻辑：同一个交接单的包裹按相同规则处理
```

---

## 关键原理

### 为什么要用冻结标签率作为整体判断标准？

1. **交接单是最小的考核单位**
   - 每个交接单都有一个统一的标签率水平
   - 不应该在同一个交接单内混合使用不同的考核规则

2. **标签率会随时间变化**
   - 某时刻的标签率可能低于80%，之后又升高
   - 冻结标签率通过"最早扫描时间"这一关键时刻点来定位
   - 代表"作业刚开始时的标签率情况"

3. **现场实际情况**
   - 作业人员在作业开始时面对的是一个固定的标签率
   - 这个"时刻的标签率"决定了他们的考核规则
   - 不会在作业过程中动态改变规则

### InterchangeUnitLabelRates 的双重用途

| 用途 | 含义 |
|------|------|
| 计算 `label_rate_percent` | 判断该交接单属于高还是低标签率 |
| 用于分类 | 通过 ≥80% 或 <80% 来分类全部交接单 |

---

## 文件变更

### 代码修改
- ✅ `src/DAL/Repositories/LabelReplaceRepository.cs`
  - DailyHighLabelRateShould CTE（第1048-1066行）
  - DailyLowLabelRateShould CTE（第1069-1083行）
  - 逻辑：从"分别统计包裹"改为"统计交接单中的全部包裹"

### 文档更新
- ✅ `frozen_label_rate_design.md`
  - 设计逻辑第三步：完全重写，强调整体规则应用
  - 验证场景：示例已更新
  - 字段映射：说明已澄清

- ✅ `frozen_label_rate_implementation_summary.md`
  - DailyHighLabelRateShould 和 DailyLowLabelRateShould 功能说明
  - 验证场景示例已更新

---

## 编译状态

✅ **编译成功**
- 命令：`dotnet build src/DAL/DAL.csproj --no-restore -v quiet`
- 结果：exit code 0
- 无编译错误

---

## 重要总结

### 冻结标签率的三层含义

| 层级 | 含义 | 用途 |
|------|------|------|
| 第1层 | 度量 | 测量特定时刻的标签率水平 |
| 第2层 | 分类 | 将交接单分为两类（≥80% 或 <80%） |
| 第3层 | 规则 | 决定整个交接单按什么考核规则处理 |

### 核心原则

✅ **DO**：
- 计算每个交接单的冻结标签率
- 根据冻结标签率对交接单分类
- 同一交接单内的所有包裹按相同规则处理

❌ **DON'T**：
- 在同一交接单内混合使用不同考核规则
- 对单个包裹分别应用高/低标签率规则
- 将包裹的"标签状态"与"整体考核规则"混淆

---

## 后续验证

1. ✅ 编译成功
2. 在测试环境中验证新逻辑
3. 对比新旧数据结果
4. 验证"成功数 < 考核通过数"的矛盾是否消除
