fix(worker-platform): 拼单取消后可重入,大厅置顶始终优先

This commit is contained in:
yml2213
2026-10-25 13:08:19 +08:00
parent 7fdef88ba6
commit 81edf530db
7 changed files with 315 additions and 48 deletions
@@ -163,17 +163,63 @@ export function patchWorkerWorkOrderListEnvelope(
}
}
/** 无限下拉(大厅):第 1 页允许插入,其余页只做就地更新。 */
function readWorkOrderId(item: unknown): number {
return isRecord(item) ? toNumber(item.workOrderId) : 0
}
function readPinnedAtMs(item: unknown): number | null {
if (!isRecord(item)) return null
const pinnedAt = String(item.pinnedAt || '').trim()
if (!pinnedAt) return null
const parsed = Date.parse(pinnedAt)
// 有置顶标记但时间不可解析时仍算置顶,宁可排前面也不能被普通单挤下去。
return Number.isFinite(parsed) ? parsed : 0
}
/**
* 大厅排序必须与服务端一致:置顶单永远在最前(pinned_at DESC),其余按 id DESC。
* 实时事件把新单插入第 1 页后必须重排,否则新单会插到置顶单上面。
*/
export function sortWorkerHallItems(items: unknown[]): unknown[] {
return items.slice().sort((left, right) => {
const leftPinnedAt = readPinnedAtMs(left)
const rightPinnedAt = readPinnedAtMs(right)
if (leftPinnedAt !== null && rightPinnedAt === null) return -1
if (leftPinnedAt === null && rightPinnedAt !== null) return 1
if (leftPinnedAt !== null && rightPinnedAt !== null && leftPinnedAt !== rightPinnedAt) {
return rightPinnedAt - leftPinnedAt
}
return readWorkOrderId(right) - readWorkOrderId(left)
})
}
/** 无限下拉(大厅):第 1 页允许插入,其余页只做就地更新;最终按置顶优先重排。 */
export function patchWorkerWorkOrderInfiniteEnvelope(
current: unknown,
event: WorkerListEvent,
insert = false,
): unknown {
if (!isRecord(current) || !Array.isArray(current.pages)) return current
return {
...current,
pages: current.pages.map((page: unknown, index: number) =>
patchWorkerWorkOrderListEnvelope(page, event, insert && index === 0),
),
const pages = current.pages.map((page: unknown, index: number) =>
patchWorkerWorkOrderListEnvelope(page, event, insert && index === 0),
)
const lists: unknown[][] = []
for (const page of pages) {
if (!isRecord(page) || !isRecord(page.data) || !Array.isArray(page.data.items)) {
return { ...current, pages }
}
lists.push(page.data.items)
}
// 第 2 页之后被置顶的单也要提到第 1 页最前,所以跨页统一排序再按原页长度切回。
const sorted = sortWorkerHallItems(lists.flat())
let cursor = 0
const sortedPages = pages.map((page, index) => {
const length = lists[index]?.length || 0
const items = sorted.slice(cursor, cursor + length)
cursor += length
return isRecord(page) && isRecord(page.data) ? { ...page, data: { ...page.data, items } } : page
})
return { ...current, pages: sortedPages }
}
@@ -140,6 +140,84 @@ test('无限下拉:只有第 1 页允许插入,其余页只就地更新', ()
assert.equal(itemsOf(patched.pages[1]).length, 2, '第 2 页不得插入')
})
test('大厅新单插入后,置顶单必须仍在最前方', () => {
const current = {
pages: [
buildEnvelope([
buildRow({ workOrderId: 100, status: 'open', pinnedAt: '2026-10-25T10:00:00+08:00' }),
buildRow({ workOrderId: 200, status: 'open' }),
]),
],
pageParams: [1],
}
const patched = patchWorkerWorkOrderInfiniteEnvelope(
current,
{ operation: 'upsert', data: buildRow({ workOrderId: 300, status: 'open' }) },
true,
) as { pages: unknown[] }
assert.deepEqual(
itemsOf(patched.pages[0]).map((item) => item.workOrderId),
[100, 300, 200],
'新单必须排在置顶单之后,未置顶部分仍按 id 倒序',
)
})
test('多个置顶单之间按置顶时间倒序,且都排在普通单之前', () => {
const current = {
pages: [
buildEnvelope([
buildRow({ workOrderId: 100, status: 'open', pinnedAt: '2026-10-25T09:00:00+08:00' }),
buildRow({ workOrderId: 200, status: 'open' }),
buildRow({ workOrderId: 300, status: 'open', pinnedAt: '2026-10-25T11:00:00+08:00' }),
]),
],
pageParams: [1],
}
const patched = patchWorkerWorkOrderInfiniteEnvelope(
current,
{ operation: 'upsert', data: buildRow({ workOrderId: 400, status: 'open' }) },
true,
) as { pages: unknown[] }
assert.deepEqual(
itemsOf(patched.pages[0]).map((item) => item.workOrderId),
[300, 100, 400, 200],
)
})
test('第 2 页的工单被置顶后必须提到第 1 页最前', () => {
const current = {
pages: [
buildEnvelope([
buildRow({ workOrderId: 300, status: 'open' }),
buildRow({ workOrderId: 299, status: 'open' }),
]),
buildEnvelope([buildRow({ workOrderId: 100, status: 'open' })]),
],
pageParams: [1, 2],
}
const patched = patchWorkerWorkOrderInfiniteEnvelope(
current,
{
operation: 'upsert',
data: buildRow({
workOrderId: 100,
status: 'open',
pinnedAt: '2026-10-25T12:00:00+08:00',
}),
},
false,
) as { pages: unknown[] }
assert.deepEqual(
itemsOf(patched.pages[0]).map((item) => item.workOrderId),
[100, 300],
'置顶单要在第 1 页最前,被顶下去的普通单顺延到第 2 页',
)
assert.deepEqual(
itemsOf(patched.pages[1]).map((item) => item.workOrderId),
[299],
)
})
/**
* 「我的订单」状态页签的实时删行判定。
*