# 日级报表字段统计逻辑详细梳理（v4.0 - 完整版）

**更新日期**: 2026-05-16  
**版本**: v4.0 - 整体统计逻辑重构  
**状态**: ✅ 编译通过，逻辑已优化

---

## 核心改进

### 主要变化

1. **24H换单率重新定义**
   - ❌ 旧逻辑：`考核通过总数 / 高标签率应该换单数`（只考虑高标签率）
   - ✅ 新逻辑：`24H内完成数 / 当天应该换单数`（整体考虑，不区分标签率）

2. **移除了"考核通过率"**
   - 原因：与24H换单率重复，不需要单独维护

---

## SQL 字段出现顺序与统计逻辑

### 第1层：基础统计字段（从数据库直接查询）

#### 1.1 日期 (日期)
```sql
字段源: ArrivalRequests.到货时间 (UTC-5时区)
统计方式: DATE(CONVERT_TZ(到货时间, '+00:00', '-05:00'))
业务含义: 以到货时间为准的自然日
例子: 2026-05-16
```

#### 1.2 当日新增换单数 (当日新增换单数)
```sql
字段源: DailyBase 
统计方式: COUNT(DISTINCT 交接单号) WHERE 到货时间 = 当日
业务含义: 当天新进入系统的交接单数量
例子: 100
```

#### 1.3 当日换单失败数 (当日换单失败)
```sql
字段源: DailyFailedOrders
统计方式: COUNT(DISTINCT 订单号) WHERE 标记失败时间 = 当日
业务含义: 当天新增失败的订单数
例子: 5
```

#### 1.4 当日换单成功数 (当日换单成功数)
```sql
字段源: DailySuccessCount
统计方式: COUNT(DISTINCT 订单号) WHERE 首次成功时间 = 当日
业务含义: 当天首次成功扫描的订单数
例子: 85
```

#### 1.5 当日STOP数 (当日STOP数)
```sql
字段源: DailyScanMetrics
统计方式: COUNT(DISTINCT 订单号) WHERE STOP标记时间 = 当日
业务含义: 当天被标记为STOP（停止处理）的订单数
例子: 3
```

#### 1.6 16点前到仓包裹数 (16点前到仓包裹数)
```sql
字段源: DailyBase
统计方式: COUNT(DISTINCT 订单号) WHERE 到货时间 BETWEEN 当日00:00:00 AND 当日16:00:00
业务含义: 当天早上16点前到达仓库的订单数
例子: 60
```

#### 1.7 16点后到仓包裹数 (16点后到仓包裹数)
```sql
字段源: DailyBase
统计方式: COUNT(DISTINCT 订单号) WHERE 到货时间 BETWEEN 当日16:00:01 AND 当日23:59:59
业务含义: 当天下午16点后到达仓库的订单数
例子: 40
```

#### 1.8 当日完成数 (当日完成数)
```sql
字段源: DailyCompletedOrders
统计方式: COUNT(DISTINCT 订单号) WHERE 完成时间 = 当日
业务含义: 当天完成（所有流程结束）的订单数
例子: 88
```

#### 1.9 24H内完成数 (24H内完成数)
```sql
字段源: Daily24HCompletedOrders
统计方式: COUNT(DISTINCT 订单号) WHERE 完成时间 BETWEEN (昨日到货时间) AND (今日到货时间+24H)
业务含义: 24小时内完成的订单数（跨越两个自然日）
例子: 89
```

#### 1.10 当日标签推送数 (当日标签推送数)
```sql
字段源: DailyBase
统计方式: COUNT(DISTINCT 订单号) WHERE 标签推送时间 = 当日
业务含义: 当天新增推送的标签数
例子: 92
```

#### 1.11 当日扫描数 (当日扫描数)
```sql
字段源: DailyScanMetrics
统计方式: COUNT(DISTINCT 订单号) WHERE 首次扫描时间 = 当日
业务含义: 当天首次被扫描的订单数
例子: 86
```

---

### 第2层：递推累计字段（需要上一日数据）

#### 2.1 累计要换的总单数 (累计要换的总单数)
```sql
计算公式:
  第1天: @running_total = 当日新增换单数
  第2天+: @running_total = MAX(0, 前一日累计 + 前一日新增 - 前一日完成)

业务含义: 当前还需要处理的交接单总数（待处理积压）
  - 当日新增: +100 (新加入的)
  - 前一日完成: -88 (完成的)
  - 前一日积压: +50 (上一天遗留的)
  - 结果: MAX(0, 50 + 100 - 88) = 62

例子: 62
说明: 注意使用 MAX(0, ...) 防止出现负数
```

#### 2.2 当天应该换单数 (当天应该换单数)
```sql
计算公式: 当天应该换单数 = 累计要换的总单数 + 当日新增换单数

业务含义: 当天应该完成/达标的目标订单数
  - 昨天积压: 50
  - 当日新增: +100
  - 目标: 150

例子: 150
说明: 这个数字用于计算当天和24H的完成率
```

#### 2.3 换单失败未完结订单 (换单失败未完结订单)
```sql
字段源: 
  - 历史数据: HistoryUnfinished (已结束日期的数据)
  - 当前日期: LatestUnfinished (最新日期的数据)

统计方式:
  IF 日期 = 最新日期 THEN
    使用 LatestUnfinished.换单失败未完结订单
  ELSE
    使用 HistoryUnfinished.换单失败未完结订单

业务含义: 因失败导致还未完成的订单数
例子: 2
说明: 这些订单可能需要人工介入或重新处理
```

---

### 第3层：考核维度字段

#### 3.1 16点前考核通过包裹数 (16点前考核通过包裹数)
```sql
字段源: DailyBeforeNoonPassed
统计方式: 
  COUNT(DISTINCT 订单号) WHERE
    1. 到货时间 < 16:00:00
    2. 首次成功时间 <= 考核时间
    3. 冻结标签率 >= 80%

考核时间规则 (16点前到仓，高标签率):
  考核时间 = 当日 16:00:00 ~ 次日 16:00:00
  
业务含义: 16点前到仓，标签率高（>=80%），且在规定时间内完成的订单
例子: 45
说明: 这类订单是优先级最高的考核对象
```

#### 3.2 16点后考核通过包裹数 (16点后考核通过包裹数)
```sql
字段源: DailyAfternoonPassed
统计方式:
  COUNT(DISTINCT 订单号) WHERE
    1. 到货时间 >= 16:00:00
    2. 首次成功时间 <= 考核时间
    3. 冻结标签率 >= 80%

考核时间规则 (16点后到仓，高标签率):
  考核时间 = 当日 16:00:00 ~ 次日 23:59:59
  (时间更宽松，因为到仓较晚)

业务含义: 16点后到仓，标签率高（>=80%），且在规定时间内完成的订单
例子: 30
说明: 比16点前的考核期限延长到晚上23:59:59
```

#### 3.3 低标签率考核通过包裹数 (低标签率考核通过包裹数)
```sql
字段源: DailyLowLabelRatePassed
统计方式:
  COUNT(DISTINCT 订单号) WHERE
    1. 冻结标签率 < 80%
    2. 曾成功 = 1

考核时间规则 (低标签率):
  考核时间 = NULL（完成即达标）
  只要首次成功就算通过考核

业务含义: 标签率低（<80%），只需要完成（首次成功）就算达标的订单
例子: 12
说明: 对这类订单的要求最低，完成就算通过
```

---

### 第4层：标签率维度字段

#### 4.1 高标签率应该换单数 (高标签率应该换单数)
```sql
字段源: DailyHighLabelRateShould
统计方式:
  COUNT(DISTINCT 订单号) FROM ArrivalRequests ar WHERE
    冻结标签率 >= 80%
  按到货时间分组统计

冻结标签率计算:
  冻结标签率 = (最早扫描时间 > 标签推送时间的包裹数) / 总包裹数 × 100%
  
  其中:
  - 最早扫描时间 = MIN(label_scan_history.CreatedAt for 交接单内所有包裹)
  - 标签推送时间 = label_replace_requests.LabelRetrievedAt
  - 最早扫描时间 > 标签推送时间 => 标签已可用

业务含义: 整个交接单的标签率达到或超过80%的订单总数
         （这个交接单中的所有包裹都按高标签率规则处理）
例子: 87
说明: 这些订单需要按16点前/后分段规则处理
```

#### 4.2 低标签率应该换单数 (低标签率应该换单数)
```sql
字段源: DailyLowLabelRateShould
统计方式:
  COUNT(DISTINCT 订单号) FROM ArrivalRequests ar WHERE
    冻结标签率 < 80%
  按到货时间分组统计

业务含义: 整个交接单的标签率低于80%的订单总数
         （这个交接单中的所有包裹都按完成即达标规则处理）
例子: 13
说明: 这些订单只要完成就算通过，无需区分16点前后
      高标签率应该换单数 + 低标签率应该换单数 = 100
```

---

### 第5层：衍生计算字段

#### 5.1 考核通过总数 (考核通过总数)
```sql
计算公式:
  考核通过总数 = 16点前考核通过包裹数 + 16点后考核通过包裹数 + 低标签率考核通过包裹数

业务含义: 所有通过考核（达到目标）的订单总数，不区分考核方式
例子: 45 + 30 + 12 = 87
说明: 这是最关键的达成指标之一
```

#### 5.2 当天换单完成率 (当天换单完成率)
```sql
计算公式:
  当天换单完成率 = 当日完成数 / 当天应该换单数 × 100%
  
  分子: 当日完成数 = 88
  分母: 当天应该换单数 = 150
  结果: 88 / 150 × 100% = 58.67%

业务含义: 当天的完成达成率（只考虑当日完成的订单）
例子: 58.67%
说明: 衡量当天的工作效率
```

#### 5.3 24H换单率 ✨ (24H换单率)
```sql
计算公式:
  24H换单率 = 24H内完成数 / 当天应该换单数 × 100%
  
  分子: 24H内完成数 = 89 (包括昨天到货但今天完成的)
  分母: 当天应该换单数 = 150
  结果: 89 / 150 × 100% = 59.33%

业务含义: 24小时周期内的完成达成率（涵盖跨天的订单）
例子: 59.33%
说明: 关键KPI，衡量整体履约能力（不区分高低标签率）
      为什么不用"考核通过总数"？
      因为考核通过总数只统计满足考核条件的订单，
      不包括在考核期限外完成的订单。
      而24H换单率更全面，包含所有在24小时内完成的订单。
```

#### 5.4 数据拉取时间（UTC-5） (数据拉取时间（UTC_5）)
```sql
计算公式: UTC_TIMESTAMP() - INTERVAL 5 HOUR
业务含义: 报表数据生成的时刻（UTC-5时区）
例子: 2026-05-16 19:30:45
说明: 用于追踪报表的新鲜度
```

---

## 完整数据流示例

### 场景：100个订单，冻结标签率=30% (<80%)

```
【输入】
┌─────────────────────────────────────┐
│ DailyBase (原始交接单数据)          │
│ ├─ 当日新增换单数: 100              │
│ ├─ 16点前到仓: 60                   │
│ ├─ 16点后到仓: 40                   │
│ └─ 当日标签推送: 92                 │
│                                      │
│ DailySuccessCount (成功数据)         │
│ └─ 当日换单成功数: 85                │
│                                      │
│ Daily24HCompletedOrders (24H完成)   │
│ ├─ 当日完成数: 88                    │
│ └─ 24H内完成数: 89                   │
│                                      │
│ InterchangeUnitLabelRates (标签率)  │
│ ├─ 冻结标签率: 30%                   │
│ └─ (30个:最早扫描>标签推送时间)     │
└─────────────────────────────────────┘

【计算过程】
1️⃣ 冻结标签率判断
   冻结标签率 = 30% < 80% → 低标签率

2️⃣ 标签率维度统计
   高标签率应该换单数: 0 (没有标签率>=80%的交接单)
   低标签率应该换单数: 100 (所有100个都按低标签率处理)

3️⃣ 考核统计
   因为冻结标签率 < 80%，所有订单按"完成即达标"规则
   
   16点前考核通过包裹数: 0 (高标签率规则不适用)
   16点后考核通过包裹数: 0 (高标签率规则不适用)
   低标签率考核通过包裹数: 82 (成功的订单中的一部分)
   考核通过总数: 0 + 0 + 82 = 82

4️⃣ 累计计算（假设前一日数据）
   前一日累计: 50
   前一日新增: 100
   前一日完成: 88
   
   累计要换的总单数 = MAX(0, 50 + 100 - 88) = 62
   当天应该换单数 = 62 + 100 = 162

5️⃣ 完成率计算
   当天换单完成率 = 88 / 162 × 100% = 54.32%
   24H换单率 = 89 / 162 × 100% = 54.94%

【输出】
┌─────────────────────────────────────┐
│ 日期                    2026-05-16  │
│ 当日新增换单数              100    │
│ 累计要换的总单数             62    │
│ 当天应该换单数              162    │
│ 换单失败未完结订单            2    │
│ 当日换单失败                 5    │
│ 当日换单成功数              85    │
│ 当日STOP数                  3    │
│ 16点前到仓包裹数            60    │
│ 16点后到仓包裹数            40    │
│ 16点前考核通过包裹数         0    │
│ 16点后考核通过包裹数         0    │
│ 低标签率考核通过包裹数       82    │
│ 高标签率应该换单数            0    │
│ 低标签率应该换单数          100    │
│ 当日完成数                 88    │
│ 24H内完成数                89    │
│ 考核通过总数               82    │
│ 当天换单完成率            54.32%  │
│ 24H换单率                54.94%  │
│ 当日标签推送数             92    │
│ 当日扫描数                86    │
│ 数据拉取时间（UTC-5）19:30:45│
└─────────────────────────────────────┘
```

---

## 关键逻辑梳理

### 冻结标签率的作用流程

```
1. 计算每个交接单的冻结标签率
   ↓
2. 根据冻结标签率判断：>= 80% 还是 < 80%
   ↓
3. 如果 >= 80% 
   ├─ 高标签率应该换单数 += 100
   ├─ 按16点前/后分段处理
   └─ 使用考核时间判断是否通过
   ↓
4. 如果 < 80%
   ├─ 低标签率应该换单数 += 100
   ├─ 按"完成即达标"处理
   └─ 只要成功就算通过
```

### 为什么24H换单率用"24H内完成数"而不用"考核通过总数"？

| 对比项 | 24H内完成数 | 考核通过总数 |
|-------|----------|----------|
| 计数对象 | 所有24小时内完成的订单 | 满足考核条件的订单 |
| 是否受限制 | 不受考核时间限制 | 受16点分段等限制 |
| 反映维度 | 整体履约能力 | 考核规则下的达成 |
| 业务价值 | 对客户更有说服力 | 对内部考核更重要 |

**示例**：
- 订单A：16点后到仓，标签率高，23:00完成 → 考核不通过（超期），但24H完成
- 使用考核通过总数：不计入 (无法获得完整的24小时履约情况)
- 使用24H完成数：计入 ✓ (客观反映24小时内的完成情况)

---

## 编译状态

✅ **编译成功**
- 所有字段逻辑已完整梳理
- 24H换单率已重新定义
- 无编译错误

