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 规则做局部前移**”。 ">