B["外层循环 i = 0..size-1"]
B --> C["内层循环 j = 0..size-1-i"]
C --> D{"users[j] 是 R6-R9?"}
D -- 否 --> C
D -- 是 --> E{"users[j+1] 是 R1-R5?"}
E -- 否 --> C
E -- 是 --> F{"users[j].RR > users[j+1].RR?"}
F -- 否 --> C
F -- 是 --> G{"users[j].BeJump < 15?"}
G -- 否 --> C
G -- 是 --> H{"users[j+1].NotConfirmNum < 4?"}
H -- 否 --> C
H -- 是 --> I["交换 users[j] 和 users[j+1]"]
I --> J["调用 DoJump 记录被插队信息"]
J --> C
```
### RR 微调触发条件
只有当以下条件同时成立时,后一个用户才能前移:
1. 前一个用户的 `RR ∈ [6, 9]`
2. 后一个用户的 `RR ∈ [1, 5]`
3. 前一个用户的 `RR > 后一个用户的 RR`
4. 前一个用户的 `BeJump < 15`
5. 后一个用户的 `NotConfirmNum < 4`
### RR 微调的副作用
- 发生交换后,原先在前面的用户会被视为“被插队”一次
- `DoJump` 会读取缓存 `lechat_jump_uids_`
- 如果同一个 `jumpUid` 已经插过队,则不重复增加 `BeJump`
- 如果是新的插队者,则:
- `BeJump += 1`
- 将 `jumpUid` 写回缓存
---
## 4. VIP 微调流程图
```mermaid
flowchart TD
A["进入 doQueueBaseVip"] --> B["外层循环 i = 0..size-1"]
B --> C["内层循环 j = 0..size-1-i"]
C --> D{"users[j].NotConfirmNum < 4?"}
D -- 否 --> C
D -- 是 --> E{"users[j] 不是 SSVIP?"}
E -- 否 --> C
E -- 是 --> F{"users[j+1] 是 SSVIP?"}
F -- 否 --> C
F -- 是 --> G{"users[j+1].UserGroup >= users[j].UserGroup?"}
G -- 否 --> C
G -- 是 --> H["交换 users[j] 和 users[j+1]"]
H --> C
```
### VIP 微调触发条件
后一个用户能凭 SSVIP 身份前移,必须同时满足:
1. 当前前面的用户 `NotConfirmNum < 4`
2. 当前前面的用户不是 SSVIP
3. 当前后面的用户是 SSVIP
4. 当前后面的用户 `UserGroup >= 当前前面的用户 UserGroup`
### UserGroup 含义
- `RR <= 5` 时,`UserGroup = 2`
- `RR > 5` 时,`UserGroup = 1`
所以这里的 `>=` 可以理解为:
- 同组 SSVIP 可以前移
- 更高组的 SSVIP 也可以前移
- 更低组的 SSVIP 不能越过更高组用户
---
## 5. 时序图
```mermaid
sequenceDiagram
participant Client as 调用方 / 前端
participant Controller as CustomerServiceQueue
participant Queue as Candidate Queue
participant CacheRR as RR缓存 lechat_
participant CacheJump as 插队缓存 lechat_jump_uids_
Client->>Controller: POST 请求 + candidate 列表
Controller->>Controller: BindJSON(req)
alt 请求非法
Controller-->>Client: 200 + InvalidArgument
else 请求合法
Controller->>Queue: GetRoughSortStore(queue)
loop 遍历每个用户
Queue->>Queue: 计算 RoughSortScore
end
Controller->>Queue: sort.Slice 按粗排分倒序
loop 遍历每个用户获取 RR
Controller->>CacheRR: GET lechat_
alt 命中且 rr_1p5 可解析
CacheRR-->>Controller: {"rr_1p5":"R3"}
Controller->>Queue: 设置 person.RR 和 UserGroup
else 未命中 / 解析失败
CacheRR-->>Controller: 空或异常数据
Controller->>Queue: RR 默认为 9, UserGroup=1
end
end
Controller->>Queue: doQueueBaseRR(queue)
loop 冒泡比较相邻用户
alt 命中 RR 交换条件
Queue->>Queue: 交换两个用户位置
Controller->>CacheJump: GET lechat_jump_uids_<被插队用户uid>
alt 当前 jumpUid 未出现过
CacheJump-->>Controller: 历史 jumpUid 列表
Controller->>Queue: 被插队用户 BeJump += 1
Controller->>CacheJump: SET 更新 jumpUid 列表
else 已被同一用户插过队
CacheJump-->>Controller: 已包含当前 jumpUid
end
end
end
Controller->>Queue: doQueueBaseVip(queue)
loop 冒泡比较相邻用户
alt 命中 VIP 交换条件
Queue->>Queue: 交换两个用户位置
end
end
Controller->>Controller: GetResult(req)
Controller-->>Client: 200 + 最终 queue 结果
end
```
---
## 6. 一句话总结
这段代码的执行顺序是:
**请求校验 → 粗排打分 → 粗排排序 → RR 缓存补全 → RR 冒泡纠偏 → VIP 冒泡纠偏 → 返回最终队列**。
它不是一次性总分排序,而是“**先形成基础顺序,再通过 RR 和 VIP 规则做局部前移**”。
">