add:新增同一个工单同一人可以多次拼单:抢单大厅优化
This commit is contained in:
@@ -116,6 +116,39 @@ export function resolveWorkerMyOrderRealtimeVerdict(input: {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 大厅行的实时排序:与后端列表 SQL(pinnedFirst 时 `pinned_at DESC NULLS LAST, id DESC`)
|
||||
* 保持同一口径。大厅广播是「就地覆盖 + 第 1 页顶部插入」的缓存补丁,快照来自事件
|
||||
* 而不是重新查询,行会带着事件发生时的快字段停在缓存里;排序只影响展示位置。
|
||||
*
|
||||
* 这里必须带置顶维度:广播快照的 pinnedAt 参与不了 SQL 排序,若只按 workOrderId 排,
|
||||
* 每次广播变更(拼单进度、材料更新等)都会把置顶行挤到未置顶行后面 ——
|
||||
* 表现为「进大厅过一会儿,排名靠后的订单跑到前面去」。
|
||||
*/
|
||||
export function compareWorkerHallOrderRows(left: unknown, right: unknown): number {
|
||||
const leftPinnedAtMs = resolveHallPinnedAtMs(left)
|
||||
const rightPinnedAtMs = resolveHallPinnedAtMs(right)
|
||||
if (leftPinnedAtMs !== rightPinnedAtMs) {
|
||||
// 有一方置顶即置顶行在前;双方都置顶时按置顶时间倒序(同列表 SQL 的 NULLS LAST)。
|
||||
if (leftPinnedAtMs !== null && rightPinnedAtMs !== null) {
|
||||
return rightPinnedAtMs - leftPinnedAtMs
|
||||
}
|
||||
return leftPinnedAtMs !== null ? -1 : 1
|
||||
}
|
||||
// 双方置顶状态一致:按工单号倒序(与列表 SQL 的 `id DESC` 一致)。
|
||||
return (
|
||||
toNumber((right as { workOrderId?: unknown })?.workOrderId) -
|
||||
toNumber((left as { workOrderId?: unknown })?.workOrderId)
|
||||
)
|
||||
}
|
||||
|
||||
/** 置顶行的时间戳;未置顶返回 null(对应 SQL 的 NULLS LAST)。 */
|
||||
function resolveHallPinnedAtMs(item: unknown): number | null {
|
||||
if (!isRecord(item)) return null
|
||||
const parsed = Date.parse(String(item.pinnedAt || ''))
|
||||
return Number.isFinite(parsed) ? parsed : null
|
||||
}
|
||||
|
||||
/** 按工单号原地增删行,并同步分页总数(结构同后端 `{ data: { items, pagination } }`)。 */
|
||||
export function patchWorkerWorkOrderListEnvelope(
|
||||
current: unknown,
|
||||
@@ -128,6 +161,15 @@ export function patchWorkerWorkOrderListEnvelope(
|
||||
* 整行替换会把「再拼一次」冲回「拼单 ¥x/份」,所以覆盖行时必须保留。
|
||||
*/
|
||||
preserveFields: readonly string[] = [],
|
||||
/**
|
||||
* 插行后的行内排序比较器。
|
||||
*
|
||||
* 插入的新行(大厅广播的 upsert)落在第 1 页顶部,如果大厅缓存里已有置顶行,
|
||||
* 只按「插到最前面」处理会把新行插到置顶行前面;传入比较器可以按大厅的
|
||||
* 排序口径(置顶优先,然后工单号倒序)重新排一次。「我的订单」等按服务端
|
||||
* 顺序追加的列表不传该参数,保持原行为。
|
||||
*/
|
||||
sortCompare?: (left: unknown, right: unknown) => number,
|
||||
): unknown {
|
||||
if (!isRecord(current) || !isRecord(current.data) || !Array.isArray(current.data.items)) {
|
||||
return current
|
||||
@@ -161,6 +203,7 @@ export function patchWorkerWorkOrderListEnvelope(
|
||||
return current
|
||||
}
|
||||
}
|
||||
if (sortCompare) nextItems = [...nextItems].sort(sortCompare)
|
||||
|
||||
const delta = nextItems.length - items.length
|
||||
const pagination = isRecord(current.data.pagination) ? current.data.pagination : null
|
||||
@@ -188,12 +231,19 @@ export function patchWorkerWorkOrderInfiniteEnvelope(
|
||||
event: WorkerListEvent,
|
||||
insert = false,
|
||||
preserveFields: readonly string[] = [],
|
||||
sortCompare?: (left: unknown, right: unknown) => number,
|
||||
): 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, preserveFields),
|
||||
patchWorkerWorkOrderListEnvelope(
|
||||
page,
|
||||
event,
|
||||
insert && index === 0,
|
||||
preserveFields,
|
||||
sortCompare,
|
||||
),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user