add:新增同一个工单同一人可以多次拼单:拼单后按钮固定显示「再拼一次」

This commit is contained in:
2026-10-23 16:37:59 +08:00
parent 2befb57ef8
commit 7e1e1f7075
7 changed files with 159 additions and 18 deletions
@@ -435,6 +435,9 @@ function applyWorkerHallCachePatch(
current,
{ ...event, data: workerSnapshot, operation },
shouldInsert,
// 大厅广播是「所有打手通用」的快照,不含当前打手自己的份额;
// 覆盖行时必须保留,否则「再拼一次」会被冲回「拼单 ¥x/份」。
['myShare', 'myShares'],
),
)
}
@@ -635,6 +635,8 @@ export default function WorkerHallPage() {
const disabledReason = resolveGrabDisabledReason(order, worker, remainingSlots)
const productName = resolveHallProductName(order) || '未命名商品'
const sharingRemaining = resolveSharingRemaining(order)
/** 已参与过就用固定文案「再拼一次」,拼几次都不再改按钮文字(需求)。 */
const myShareSummary = resolveMyShareSummary(order)
return (
<article key={order.workOrderId} className="worker-hall-mobile-card">
@@ -717,12 +719,15 @@ export default function WorkerHallPage() {
size="middle"
className="worker-hall-sharing-button"
disabled={Boolean(disabledReason)}
title={
myShareSummary.count > 0
? `已参与 ${myShareSummary.count} 次 · 共 ${myShareSummary.quantity} 份`
: undefined
}
onClick={() => openSharingModal(order)}
>
{resolveMyShareSummary(order).count > 0
? `已参与 ${resolveMyShareSummary(order).count} 次 · 共 ${
resolveMyShareSummary(order).quantity
} 份 / 再拼`
{myShareSummary.count > 0
? '再拼一次'
: `拼单 ${formatMoney(order.sharing.unitReward)}/份`}
</Button>
) : null}
@@ -1073,6 +1078,8 @@ export default function WorkerHallPage() {
const disabledReason = resolveGrabDisabledReason(order, worker, remainingSlots)
const productName = resolveHallProductName(order) || '未命名商品'
const sharingRemaining = resolveSharingRemaining(order)
/** 已参与过就用固定文案「再拼一次」,拼几次都不再改按钮文字(需求)。 */
const myShareSummary = resolveMyShareSummary(order)
const depositAmount = resolveHallDepositAmount(order)
const rewardAmount = resolveHallRewardAmount(order)
@@ -1169,12 +1176,15 @@ export default function WorkerHallPage() {
size="large"
className="worker-hall-sharing-button"
disabled={Boolean(disabledReason)}
title={
myShareSummary.count > 0
? `已参与 ${myShareSummary.count} 次 · 共 ${myShareSummary.quantity} 份`
: undefined
}
onClick={() => openSharingModal(order)}
>
{resolveMyShareSummary(order).count > 0
? `已参与 ${resolveMyShareSummary(order).count} 次 · 共 ${
resolveMyShareSummary(order).quantity
} 份 / 再拼`
{myShareSummary.count > 0
? '再拼一次'
: `拼单 ${formatMoney(order.sharing.unitReward)}/份`}
</Button>
) : null}
@@ -121,6 +121,13 @@ export function patchWorkerWorkOrderListEnvelope(
current: unknown,
event: WorkerListEvent,
insert = false,
/**
* 就地更新时,快照里没有的「本打手私有字段」保留旧值。
*
* 大厅广播是发给所有打手的通用快照,天然没有 `myShare`/`myShares`(那是每个打手自己的份额)。
* 整行替换会把「再拼一次」冲回「拼单 ¥x/份」,所以覆盖行时必须保留。
*/
preserveFields: readonly string[] = [],
): unknown {
if (!isRecord(current) || !isRecord(current.data) || !Array.isArray(current.data.items)) {
return current
@@ -140,7 +147,14 @@ export function patchWorkerWorkOrderListEnvelope(
(entry) => toNumber((entry as { workOrderId?: unknown })?.workOrderId) === id,
)
if (index >= 0) {
nextItems = items.map((entry, itemIndex) => (itemIndex === index ? event.data : entry))
const existing = items[index]
const merged: Record<string, unknown> = { ...data }
if (isRecord(existing)) {
for (const field of preserveFields) {
if (!(field in merged)) merged[field] = existing[field]
}
}
nextItems = items.map((entry, itemIndex) => (itemIndex === index ? merged : entry))
} else if (insert) {
nextItems = [event.data, ...items]
} else {
@@ -173,12 +187,13 @@ export function patchWorkerWorkOrderInfiniteEnvelope(
current: unknown,
event: WorkerListEvent,
insert = false,
preserveFields: readonly string[] = [],
): 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),
patchWorkerWorkOrderListEnvelope(page, event, insert && index === 0, preserveFields),
),
}
}