fix(consignment): 内部寄售匹配弹窗防点错

问题:弹窗里「走接单平台指派打手(冻结押金交付)」与「内部现货履约」两个按钮上下紧挨、
样式相近,而且只有"部分匹配"才弹确认——精确匹配时两个按钮点下去都立刻执行,
点错就得走「撤销寄售履约」才能退回来。

- 两个动作一律二次确认(不再只有部分匹配才确认),确认框写明:寄卖单号(可复制)、
  动作(给谁接单/是否冻结押金)、结果(立刻占用现货、其它订单不能再匹配、
  内部履约还会跳过「待打手提交资料」直接进冷却)、以及退回要走撤销寄售履约;
  部分匹配额外红字提示"不是精确匹配、无法自动回退"并把确认按钮降为 danger
- 按钮区改成独立的「选择履约方式」分区小卡片:两个按钮各占一行 block 铺满
  (点击目标更大、不再小按钮挨着)、间距 14px、各加图标(打手 TeamOutlined /
  库存 PushpinOutlined),每个按钮下方一句后果说明
This commit is contained in:
yml2213
2026-09-17 11:33:23 +08:00
parent 54f8a27e97
commit 47e09d72ce
2 changed files with 127 additions and 31 deletions
@@ -780,20 +780,61 @@ export default function WorkOrdersPanel() {
}
/** 非精确匹配(订单规格信息不全 / 高配充低配)必须人工确认,后端也会二次拦截 */
function confirmPartialMatch(matchType: string | undefined, onOk: () => void) {
if (matchType !== 'exact') {
modal.confirm({
title: '该现货不是精确匹配,确认继续?',
content:
'订单规格信息不全或这件现货高于订单要求(高配充低配)。继续履约后无法自动回退,请确认商品与买家订单一致。',
okText: '确认履约',
okButtonProps: { danger: true },
cancelText: '再想想',
onOk,
})
return
}
onOk()
/**
* 匹配弹窗里的两个动作**都会立刻占用现货**,点错就得走「撤销寄售履约」才能退回来,
* 而且两个按钮挨在一起很容易点错,所以一律二次确认,并把后果写清楚:
* 用哪个号占用、给谁、要不要冻结押金、能不能回退。
*/
function confirmConsignmentMatchAction(input: {
kind: 'assign_worker' | 'internal_stock'
matchType?: string
consignmentNo: string
workerName?: string
depositFen?: number | null
onOk: () => void
}) {
const isPartial = input.matchType !== 'exact'
const isAssignWorker = input.kind === 'assign_worker'
const depositText =
input.depositFen != null ? `履约押金 ¥${(input.depositFen / 100).toFixed(2)}` : '履约押金'
modal.confirm({
title: isAssignWorker ? '确认走接单平台指派打手?' : '确认用内部现货履约?',
width: 460,
content: (
<div style={{ fontSize: 13, lineHeight: 1.8 }}>
<div>
寄卖单号:
<Typography.Text strong copyable>
{input.consignmentNo}
</Typography.Text>
</div>
<div>
{isAssignWorker
? `动作:把订单指派给供货打手${input.workerName ? `「${input.workerName}」` : ''}接单,需冻结${depositText}`
: '动作:不向外部打手派单,直接用这件现货履约'}
</div>
<div>
{isAssignWorker
? '结果:立刻占用该现货,订单转入打手履约,其它订单不能再匹配它。'
: '结果:立刻占用该现货,跳过「待打手提交资料」直接进入赠送冷却期,其它订单不能再匹配它。'}
</div>
<div style={{ color: '#8c8c8c' }}>
退回需要走「撤销寄售履约」,请先核对商品与买家订单一致。
</div>
{isPartial ? (
<div style={{ color: '#d4380d' }}>
注意:这不是精确匹配(规格信息不全,或这件现货高于订单要求=高配充低配),
履约后无法自动回退。
</div>
) : null}
</div>
),
okText: isAssignWorker ? '确认指派打手' : '确认占用并履约',
okButtonProps: isPartial ? { danger: true } : undefined,
cancelText: '再想想',
onOk: input.onOk,
})
}
async function handleFulfillWithConsignment(inventoryId: number, allowPartial = false) {
@@ -3074,34 +3115,72 @@ export default function WorkOrdersPanel() {
</div>
</div>
<div style={{ marginLeft: 16 }}>
<Space direction="vertical" align="end" size={8}>
<div style={{ marginLeft: 16, width: 250, flexShrink: 0 }}>
<div
style={{
border: '1px solid #f0f0f0',
borderRadius: 8,
padding: '10px 12px',
backgroundColor: '#fff',
}}
>
<div style={{ fontSize: 11, color: '#8c8c8c', marginBottom: 8 }}>
选择履约方式(都会立刻占用该现货)
</div>
{inv.workerId ? (
<Button
type="primary"
style={{ backgroundColor: '#722ed1', borderColor: '#722ed1' }}
loading={consignmentInterceptModal.submitting}
onClick={() =>
confirmPartialMatch(m.matchType, () => {
void handleAssignWithConsignmentWorker(inv.id, inv.workerId, !isExact)
})
}
>
走接单平台指派打手(冻结押金交付)
</Button>
<>
<Button
block
type="primary"
icon={<TeamOutlined />}
style={{ backgroundColor: '#722ed1', borderColor: '#722ed1' }}
loading={consignmentInterceptModal.submitting}
onClick={() =>
confirmConsignmentMatchAction({
kind: 'assign_worker',
matchType: m.matchType,
consignmentNo: inv.sourceSubmissionNo || '客服手工入库',
workerName: inv.workerName,
depositFen: inv.depositAmountFen,
onOk: () => {
void handleAssignWithConsignmentWorker(
inv.id,
inv.workerId!,
!isExact,
)
},
})
}
>
走接单平台指派打手
</Button>
<div style={{ fontSize: 11, color: '#8c8c8c', margin: '4px 0 14px' }}>
由该供货打手接单,需冻结履约押金
</div>
</>
) : null}
<Button
block
type={inv.workerId ? 'default' : 'primary'}
icon={<PushpinOutlined />}
loading={consignmentInterceptModal.submitting}
onClick={() =>
confirmPartialMatch(m.matchType, () => {
void handleFulfillWithConsignment(inv.id, !isExact)
confirmConsignmentMatchAction({
kind: 'internal_stock',
matchType: m.matchType,
consignmentNo: inv.sourceSubmissionNo || '客服手工入库',
onOk: () => {
void handleFulfillWithConsignment(inv.id, !isExact)
},
})
}
>
内部现货履约
</Button>
</Space>
<div style={{ fontSize: 11, color: '#8c8c8c', marginTop: 4 }}>
不外派打手,直接用库存账号赠送
</div>
</div>
</div>
</div>
</Card>
+17
View File
@@ -21,6 +21,7 @@
| `632dddc4` | 上一轮:H5 渠道整体下线 + 凭据字段修复 + 状态机封闭(撤销守卫 / 库存绑定唯一性 / 生命周期解绑)+ 押金归属取台账 | 迁移 `079`、`consignment-*` 五个文件、`work-order-*` 三个仓库、两个前端面板 |
| `5d11bf20` | 批次 C+D:指派部分成功补偿、凭证核销如实反馈、空规格不放行 + 履约/指派服务端规格复检 | `consignment-fulfillment-service.ts`、`consignment-matching-service.ts`、`consignment-repo.ts`、履约路由、`WorkOrdersPanel.tsx` |
| `d6f6219f` | 批次 F1:内部现货履约停在「待加好友」,客服确认后才进赠送冷却 + 备注快捷项 | `work-order-gift-repo.ts`、履约服务、`WorkOrdersPanel.tsx`、`utils/gift-phase.ts` |
| 本批提交(批次 L,同一提交内含本文档,故不写自身 hash) | 批次 L:匹配弹窗两个动作一律二次确认 + 按钮分区/图标/后果说明,防点错 | `WorkOrdersPanel.tsx` |
| 本批提交(批次 K,同一提交内含本文档,故不写自身 hash) | 批次 K:匹配弹窗改用寄卖单号(候选查询补 join),客服界面不再展示内部仓库号 | `consignment-repo.ts`、`WorkOrdersPanel.tsx`、`ConsignmentInventoryPanel.tsx` |
| 本批提交(批次 J,同一提交内含本文档,故不写自身 hash) | 批次 J:凭证链可视化(提报凭证 + 赠送凭证),客服审核/仓库面板统一展示 | `consignment-admin-service.ts`、`consignment-repo.ts`、`ConsignmentSubmissionsPanel.tsx`、`ConsignmentInventoryPanel.tsx` |
| 本批提交(批次 I,同一提交内含本文档,故不写自身 hash) | 批次 I:提报单号为唯一寄卖单号(一件货一行)+ 统一状态机 + 卖家确认加好友/提交赠送截图 | `consignment-item-stage.ts`、`consignment-worker-service.ts`、`routes/worker/consignment.ts`、`ConsignmentInventoryPanel.tsx`、`WorkerConsignmentPage.tsx` |
@@ -281,6 +282,22 @@
前端在"部分匹配"候选上先 `modal.confirm` 危险确认,再带 `allowPartial: true` 重试,高配充低配的合法玩法保留但不可误触。
3. ⏳ 匹配下推 SQL + 批量匹配接口 + 工单列表角标(P2-8)未做:当前仍是"取全量在库 → 内存比对"。
### 批次 L · 匹配弹窗防点错(本轮)
**问题**:匹配弹窗里「走接单平台指派打手(冻结押金交付)」与「内部现货履约」两个按钮
上下紧挨、样式相近,而且**只有"部分匹配"才弹确认**——精确匹配时两个按钮点下去都立刻执行,
点错就要走「撤销寄售履约」才能退回来。
**改法**:
1. ✅ 两个动作**一律二次确认**(不再只有部分匹配才确认),确认框把后果写清楚:
寄卖单号(可复制)、动作(给谁/要不要冻结押金)、结果(立刻占用现货、其它订单不能再匹配它、
内部履约还会跳过「待打手提交资料」直接进冷却)、以及"退回要走撤销寄售履约";
部分匹配时额外红字提示"不是精确匹配、无法自动回退",并把确认按钮降为 danger。
2. ✅ 按钮区做成独立分区的「选择履约方式」小卡片:两个按钮各占一行、`block` 铺满(点击目标更大、
不再是小按钮挨着)、间距拉开到 14px、各加图标(打手=TeamOutlined,库存=PushpinOutlined),
每个按钮下方一句后果说明("由该供货打手接单,需冻结履约押金" / "不外派打手,直接用库存账号赠送")。
### 批次 K · 匹配弹窗也改用寄卖单号,内部仓库号只留内部(本轮)
**问题**:内部寄售库存匹配弹窗(发单时拦一下"有现货可直接履约"那个)显示的是