fix(worker-platform): 按工单号搜不到彻底收口 —— 显式单号检索不再被任何排他筛选吞掉
## 修的是什么
线上反复复发的「后台接单平台按工单号搜不到、某些状态尤其明显」,根因不是一处,
而是同一类问题在 5 个地方各留了一半(历次修复都只补了一处,所以总复发):
1. 状态筛选走运营态派生:拼单母单一旦有人参与,open → in_progress /
pending_acceptance,于是「单号 + 待接单」永远为空(没人参与时反而搜得到),
这正是「有人接单后就搜不到」;非拼单单子被接单后同理。
2. 「单号 + 接单人员 / 分类 / 打手等级 / 创建时间」照样过滤掉目标单
(接单人员是 INNER JOIN 可见集合,不在集合里整行消失)。
d6523635 只在面板查询按钮里清了 状态/赠送阶段/验收模式,这三个没清。
3. 待办通知跳转(buildNotificationActionPath 带 ?workOrderId=)设下的
「定位工单」是 wo.id = X 排他条件,不手点「取消定位」就一直生效,
之后搜任何别的单号都是空 —— 这条路径历次修复从未涉及。
4. AdminLayout 把服务端 operation='remove' 直接判成 mismatch,
绕过了「显式单号不删行」的护栏。
5. 打手端「我的订单」默认页签固定「代练中」,搜索不联动页签、
实时补丁又拿状态当可证伪条件删行 → 打手端同类问题(此前只修了关键词匹配)。
## 修法(收口到单一真源,不再按按钮打补丁)
后端:
- 新增 isExplicitOrderNoLookupKeyword()(工单号 / 平台单号 / SUB·INV·AS·DT);
- 后台列表筛选抽成纯函数 resolveAdminWorkOrderListFilters():显式单号检索时
不下推 状态/VIP待补图/验收模式/赠送阶段/接单人员/分类/打手等级/创建时间/定位工单;
- 打手端 resolveWorkerMyOrderStatusFilter():只放掉状态与 VIP 待补图,
**严格保留 workerSharingId 可见范围**(否则打手能搜到别人的单)。
前端:
- admin-realtime-work-orders.ts:显式单号检索直接判 unknown(含服务端 remove),
remove 的短路移交给判定函数;
- WorkOrdersPanel:单号检索时清空全部排他筛选并提示「已按单号精准检索,自动忽略…」,
通知定位工单时也清掉其它筛选,避免残留;
- WorkerOrdersPage:单号检索自动切「全部订单」;WorkerLayout 走新的
resolveWorkerMyOrderRealtimeVerdict(),与后台同策。
刻意不改(避免越权/召回不可用单):抢单大厅(候选必须是 open)、
寄卖手动匹配候选(只做未接单整单)。
## 验证
后端 npm run check 全绿:682 pass / 3 skip(新增 6 项);
前端 npm run check 全绿:138 pass(新增 6 项,含「单号检索 + 实时事件不得删行」,
以及「服务端 remove 不得绕过单号护栏」的回归);format/lint/typecheck/build 通过。
无数据库迁移。
This commit is contained in:
@@ -2,6 +2,7 @@ import assert from 'node:assert/strict'
|
||||
import test from 'node:test'
|
||||
|
||||
import {
|
||||
isExplicitOrderNoLookupKeyword,
|
||||
isPlatformOrderIdLookupKeyword,
|
||||
isWorkOrderNoLookupKeyword,
|
||||
resolveRelatedWorkOrderLookupKind,
|
||||
@@ -59,3 +60,34 @@ test('关联单号识别不得误伤工单号、平台单号与普通关键词',
|
||||
assert.equal(resolveRelatedWorkOrderLookupKind(''), null)
|
||||
assert.equal(resolveRelatedWorkOrderLookupKind(null), null)
|
||||
})
|
||||
|
||||
/**
|
||||
* 显式单号检索的总判定。后端用它决定「不下推排他筛选」,前端用它决定「不删行」,
|
||||
* 两边覆盖的范围必须一致,否则又会出现「后台搜不到 / 行被删掉」这类只修一半的问题。
|
||||
*/
|
||||
test('显式单号检索覆盖工单号 / 平台单号 / 关联单号', () => {
|
||||
for (const orderNo of [
|
||||
'WO26101213031939',
|
||||
'wo26101213031939',
|
||||
' WO26101213031939 ',
|
||||
'WOb320ee0b39b9',
|
||||
'20247230034021572',
|
||||
'260915-091435834962130',
|
||||
'SUB26100301127318',
|
||||
'INV26092619393769',
|
||||
'ASde06bcb25aca',
|
||||
'DTb946808bcd5b',
|
||||
]) {
|
||||
assert.equal(isExplicitOrderNoLookupKeyword(orderNo), true, `${orderNo} 应识别为显式单号`)
|
||||
}
|
||||
})
|
||||
|
||||
test('显式单号检索不得误判商品名 / 昵称 / 短词', () => {
|
||||
for (const keyword of ['暗潮', '无限潮汐', '皮肤店', 'WO12', '12345', 'SUBWAY', '', null]) {
|
||||
assert.equal(
|
||||
isExplicitOrderNoLookupKeyword(keyword),
|
||||
false,
|
||||
`${String(keyword)} 不应识别为显式单号`,
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -15,6 +15,24 @@ export function isWorkOrderNoLookupKeyword(value: unknown): boolean {
|
||||
return /^WO[0-9a-zA-Z]{4,}$/i.test(trimmed)
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为「显式单号检索」——工单号 / 平台单号 / 关联单号(SUB/INV/AS/DT)。
|
||||
*
|
||||
* 语义:用户粘进来的是唯一单号,表达的是「我就要这一单」。
|
||||
* 前端(utils/admin-realtime-work-orders.ts 的 isExplicitOrderNoSearch)用它保证
|
||||
* 实时快照补丁不把正在看的行删掉;后端用它保证排他性筛选不把这单藏起来。
|
||||
* 两侧必须覆盖同一批形态,改这里就要同步改那边(反之亦然)。
|
||||
*/
|
||||
export function isExplicitOrderNoLookupKeyword(value: unknown): boolean {
|
||||
const trimmed = String(value || '').trim()
|
||||
if (!trimmed) return false
|
||||
return (
|
||||
isWorkOrderNoLookupKeyword(trimmed) ||
|
||||
isPlatformOrderIdLookupKeyword(trimmed) ||
|
||||
resolveRelatedWorkOrderLookupKind(trimmed) !== null
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 关联单号类型:号码本身不在 work_orders 上,必须经关联表反查工单 id。
|
||||
* - consignment_submission: 寄售线索号 SUB... → 产出的库存 → 被工单消耗后的工单
|
||||
|
||||
Reference in New Issue
Block a user