From 2d80127b08df345286b5d22e9157041dbc8ef3d5 Mon Sep 17 00:00:00 2001 From: kang Date: Fri, 26 Jun 2026 15:19:17 +0800 Subject: [PATCH] =?UTF-8?q?fix(funds):=20=E7=BB=93=E7=AE=97=E5=B9=82?= =?UTF-8?q?=E7=AD=89=E9=94=AE=E5=A4=8D=E7=94=A8=E4=B8=8E=E8=BD=AC=E8=B4=A6?= =?UTF-8?q?=E5=86=B2=E6=AD=A3=E6=8C=89=E9=92=AE=E5=AF=B9=E9=BD=90=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 账单收付/补差幂等键在首次操作时生成并复用至成功 - 冲正按钮仅当 API 返回 can_reverse=true 时展示 --- src/lib/wallet-transfer-actions.ts | 2 +- src/modules/settlement/agent-bill-detail.tsx | 27 ++++++++++++++++++-- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/lib/wallet-transfer-actions.ts b/src/lib/wallet-transfer-actions.ts index 6df1ee8..cf3a756 100644 --- a/src/lib/wallet-transfer-actions.ts +++ b/src/lib/wallet-transfer-actions.ts @@ -11,7 +11,7 @@ export type TransferOrderActionRow = { }; export function canReverseTransferOrder(row: TransferOrderActionRow, canWriteWallet: boolean): boolean { - return canWriteWallet && (row.can_reverse ?? row.status === "pending_reconcile"); + return canWriteWallet && row.can_reverse === true; } export function canCompleteTransferInCredit(row: TransferOrderActionRow, canWriteWallet: boolean): boolean { diff --git a/src/modules/settlement/agent-bill-detail.tsx b/src/modules/settlement/agent-bill-detail.tsx index 488f97f..afb86b0 100644 --- a/src/modules/settlement/agent-bill-detail.tsx +++ b/src/modules/settlement/agent-bill-detail.tsx @@ -67,8 +67,23 @@ export function AgentBillDetail({ const [advancedOpen, setAdvancedOpen] = useState(false); const confirmRef = useRef(null); const paymentRef = useRef(null); + const paymentIdempotencyKeyRef = useRef(null); + const adjustmentIdempotencyKeyRef = useRef(null); const { request: requestConfirm, ConfirmDialog, busy: confirmBusy } = useConfirmAction(); + const createIdempotencyKey = useCallback((prefix: string): string => { + const random = + typeof crypto !== "undefined" && typeof crypto.randomUUID === "function" + ? crypto.randomUUID() + : Math.random().toString(36).slice(2, 10); + return `${prefix}-${billId}-${Date.now()}-${random}`; + }, [billId]); + + useEffect(() => { + paymentIdempotencyKeyRef.current = null; + adjustmentIdempotencyKeyRef.current = null; + }, [billId]); + const load = useCallback(async () => { setLoading(true); setLoadErr(null); @@ -202,7 +217,10 @@ export function AgentBillDetail({ return; } - const idempotencyKey = `pay-${billId}-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`; + if (!paymentIdempotencyKeyRef.current) { + paymentIdempotencyKeyRef.current = createIdempotencyKey("pay"); + } + const idempotencyKey = paymentIdempotencyKeyRef.current; requestConfirm({ title: t("settlementBills.paymentConfirmTitle", { defaultValue: "确认登记收付?" }), description: t("settlementBills.paymentConfirmDescription", { @@ -218,6 +236,7 @@ export function AgentBillDetail({ proof: payProof.trim() || undefined, idempotency_key: idempotencyKey, }); + paymentIdempotencyKeyRef.current = null; await load(); await onUpdated?.(); toast.success(t("settlementBills.paid", { defaultValue: "已登记收付" })); @@ -273,7 +292,10 @@ export function AgentBillDetail({ return; } - const idempotencyKey = `adj-${billId}-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`; + if (!adjustmentIdempotencyKeyRef.current) { + adjustmentIdempotencyKeyRef.current = createIdempotencyKey("adj"); + } + const idempotencyKey = adjustmentIdempotencyKeyRef.current; requestConfirm({ title: t("settlementBills.adjustmentConfirmTitle", { defaultValue: "确认创建补差/冲正单?" }), description: t("settlementBills.adjustmentConfirmDescription", { @@ -289,6 +311,7 @@ export function AgentBillDetail({ reason, idempotency_key: idempotencyKey, }); + adjustmentIdempotencyKeyRef.current = null; setAdjustAmount(""); setAdjustReason(""); toast.success(t("settlementBills.adjustmentCreated", { defaultValue: "已创建补差单" }));