Merge branch 'dev1023' into dev
This commit is contained in:
@@ -440,6 +440,24 @@ export function formatWorkOrderEvent(event: WorkOrderEvent): EventNodeStyle {
|
||||
color: 'red',
|
||||
}
|
||||
}
|
||||
case 'sharing_part_cancelled': {
|
||||
const cancelledQuantity = readPayloadAmount(event, 'cancelledQuantity')
|
||||
const totalQuantityAfter = readPayloadAmount(event, 'totalQuantityAfter')
|
||||
const releasedDepositAmount = readPayloadAmount(event, 'releasedDepositAmount')
|
||||
const refundAmount = readPayloadAmount(event, 'refundAmount')
|
||||
const details = [
|
||||
cancelledQuantity > 0 ? `取消 ${cancelledQuantity} 份未验收份数` : '',
|
||||
totalQuantityAfter > 0 ? `保留 ${totalQuantityAfter} 份已验收` : '整单已取消',
|
||||
releasedDepositAmount > 0 ? `退还押金 ${formatFenAmount(releasedDepositAmount)}` : '',
|
||||
refundAmount > 0 ? `登记退款 ${formatFenAmount(refundAmount)}` : '',
|
||||
note ? `原因:${note}` : '',
|
||||
].filter(Boolean)
|
||||
return {
|
||||
title: '取消拼单未验收部分',
|
||||
description: details.length > 0 ? details.join(';') : undefined,
|
||||
color: 'red',
|
||||
}
|
||||
}
|
||||
case 'pending_deposit_deducted':
|
||||
return { title: '扣减了待解冻押金', color: 'default' }
|
||||
case 'voucher_backfilled':
|
||||
|
||||
@@ -56,6 +56,7 @@ import {
|
||||
cancelAdminWorkOrder,
|
||||
cancelAdminWorkOrderShare,
|
||||
cancelAdminWorkOrderSharing,
|
||||
cancelAdminWorkOrderSharingPart,
|
||||
completeAdminWorkOrderGiftCooldown,
|
||||
confirmAdminWorkOrderFriend,
|
||||
deductAdminWorkOrderPendingDeposit,
|
||||
@@ -185,6 +186,11 @@ type CancelSharingFormValues = {
|
||||
reason?: string
|
||||
}
|
||||
|
||||
type CancelSharingPartFormValues = {
|
||||
refundAmount?: number
|
||||
reason?: string
|
||||
}
|
||||
|
||||
/** 工单 `material.consignment`(寄售履约信息);没有寄售履约信息时返回 null。 */
|
||||
function getConsignmentFulfillment(row: WorkOrder): ConsignmentFulfillmentInfo | null {
|
||||
const consignment = asRecord((row.material as Record<string, unknown> | undefined)?.consignment)
|
||||
@@ -311,6 +317,7 @@ export default function WorkOrdersPanel() {
|
||||
const [problemShare, setProblemShare] = useState<WorkOrderShare | null>(null)
|
||||
const [disposeShare, setDisposeShare] = useState<WorkOrderShare | null>(null)
|
||||
const [cancelSharingOrder, setCancelSharingOrder] = useState<WorkOrder | null>(null)
|
||||
const [cancelSharingPartOrder, setCancelSharingPartOrder] = useState<WorkOrder | null>(null)
|
||||
const [assignOrder, setAssignOrder] = useState<WorkOrder | null>(null)
|
||||
const [assignWorkerId, setAssignWorkerId] = useState<number | undefined>(undefined)
|
||||
const [editOrder, setEditOrder] = useState<WorkOrder | null>(null)
|
||||
@@ -329,6 +336,7 @@ export default function WorkOrdersPanel() {
|
||||
note?: string
|
||||
}>()
|
||||
const [cancelSharingForm] = Form.useForm<CancelSharingFormValues>()
|
||||
const [cancelSharingPartForm] = Form.useForm<CancelSharingPartFormValues>()
|
||||
const [deductForm] = Form.useForm<{ amount?: number; note?: string }>()
|
||||
const [editForm] = Form.useForm<{
|
||||
productName?: string
|
||||
@@ -551,6 +559,18 @@ export default function WorkOrdersPanel() {
|
||||
['joined', 'submitted'].includes(share.status),
|
||||
)
|
||||
const hasAcceptedSharingShares = sharingShares.some((share) => share.status === 'accepted')
|
||||
const cancelSharingPartTotalQuantity = Math.max(
|
||||
1,
|
||||
Number(cancelSharingPartOrder?.sharing?.totalQuantity || 1),
|
||||
)
|
||||
const cancelSharingPartAcceptedQuantity = Math.max(
|
||||
0,
|
||||
Number(cancelSharingPartOrder?.sharingProgress?.acceptedQuantity || 0),
|
||||
)
|
||||
const cancelSharingPartCancelledQuantity = Math.max(
|
||||
0,
|
||||
cancelSharingPartTotalQuantity - cancelSharingPartAcceptedQuantity,
|
||||
)
|
||||
const assignWorkersQuery = useQuery({
|
||||
queryKey: ['admin-worker-platform-workers', 'assign', assignWorkerKeyword],
|
||||
queryFn: () =>
|
||||
@@ -821,6 +841,48 @@ export default function WorkOrdersPanel() {
|
||||
cancelSharingForm.resetFields()
|
||||
}
|
||||
|
||||
/** 打开「取消部分」:默认按实付金额比例预填退款金额。 */
|
||||
function openCancelSharingPartModal(order: WorkOrder) {
|
||||
const totalQuantity = Math.max(1, Number(order.sharing?.totalQuantity || 1))
|
||||
const acceptedQuantity = Math.max(0, Number(order.sharingProgress?.acceptedQuantity || 0))
|
||||
const cancelledQuantity = Math.max(0, totalQuantity - acceptedQuantity)
|
||||
const paidAmountFen = Math.max(0, Number(order.sourceOrderAmount || 0))
|
||||
setCancelSharingPartOrder(order)
|
||||
cancelSharingPartForm.setFieldsValue({
|
||||
refundAmount:
|
||||
totalQuantity > 0
|
||||
? Math.round((paidAmountFen * cancelledQuantity) / totalQuantity) / 100
|
||||
: 0,
|
||||
reason: '',
|
||||
})
|
||||
}
|
||||
|
||||
async function submitCancelSharingPart(values: CancelSharingPartFormValues) {
|
||||
if (!cancelSharingPartOrder) return
|
||||
const workOrderId = cancelSharingPartOrder.workOrderId
|
||||
const refundAmount = values.refundAmount
|
||||
const succeeded = await runAction(
|
||||
() =>
|
||||
cancelAdminWorkOrderSharingPart(workOrderId, {
|
||||
...(refundAmount === undefined || refundAmount === null
|
||||
? {}
|
||||
: { refundAmount: Number(refundAmount) }),
|
||||
reason: String(values.reason || '').trim(),
|
||||
}),
|
||||
(result) =>
|
||||
`已取消 ${result.data.cancelledQuantity} 份未验收份数,退还押金 ${formatMoney(
|
||||
result.data.releasedDepositAmount,
|
||||
)},登记退款 ${formatMoney(result.data.refundAmount)}`,
|
||||
)
|
||||
if (!succeeded) return
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: ['admin-worker-platform-order-sharing', workOrderId],
|
||||
})
|
||||
setCancelSharingPartOrder(null)
|
||||
setSharingOrder(null)
|
||||
cancelSharingPartForm.resetFields()
|
||||
}
|
||||
|
||||
async function refreshAll() {
|
||||
await Promise.all([
|
||||
queryClient.invalidateQueries({
|
||||
@@ -3114,6 +3176,7 @@ export default function WorkOrdersPanel() {
|
||||
setCancelShare(null)
|
||||
setReduceShare(null)
|
||||
setCancelSharingOrder(null)
|
||||
setCancelSharingPartOrder(null)
|
||||
sharingForm.resetFields()
|
||||
cancelShareForm.resetFields()
|
||||
reduceShareForm.resetFields()
|
||||
@@ -3201,6 +3264,26 @@ export default function WorkOrdersPanel() {
|
||||
</Form>
|
||||
|
||||
<Card size="small" title="拼单明细">
|
||||
{sharingOrder.capabilities?.canCancelSharingPart ? (
|
||||
<Space
|
||||
direction="vertical"
|
||||
size={8}
|
||||
className="full-width"
|
||||
style={{ marginBottom: 12 }}
|
||||
>
|
||||
<Alert
|
||||
showIcon
|
||||
type="warning"
|
||||
message="取消部分会取消所有未验收份数(进行中 + 待接单)"
|
||||
description="已验收份额保留;取消的份额退还押金。退款金额只登记,实际退款请在来源平台操作。"
|
||||
/>
|
||||
<div>
|
||||
<Button danger onClick={() => openCancelSharingPartModal(sharingOrder)}>
|
||||
取消部分
|
||||
</Button>
|
||||
</div>
|
||||
</Space>
|
||||
) : null}
|
||||
{sharingQuery.isLoading ? (
|
||||
<Typography.Text type="secondary">加载中...</Typography.Text>
|
||||
) : (sharingQuery.data?.data.shares || []).length === 0 ? (
|
||||
@@ -3782,6 +3865,60 @@ export default function WorkOrdersPanel() {
|
||||
) : null}
|
||||
</Modal>
|
||||
|
||||
<Modal
|
||||
title={`取消部分 · ${getDisplayOrderNo(cancelSharingPartOrder)}`}
|
||||
open={Boolean(cancelSharingPartOrder)}
|
||||
onCancel={() => {
|
||||
setCancelSharingPartOrder(null)
|
||||
cancelSharingPartForm.resetFields()
|
||||
}}
|
||||
onOk={() => cancelSharingPartForm.submit()}
|
||||
okText="确认取消"
|
||||
okButtonProps={{ danger: true }}
|
||||
destroyOnHidden
|
||||
>
|
||||
{cancelSharingPartOrder ? (
|
||||
<Form form={cancelSharingPartForm} layout="vertical" onFinish={submitCancelSharingPart}>
|
||||
<Alert
|
||||
showIcon
|
||||
type="warning"
|
||||
message="只保留已验收份额,其余份数全部取消"
|
||||
description={
|
||||
cancelSharingPartAcceptedQuantity > 0
|
||||
? '取消后母单总量收敛为已验收份数,并直接转为已验收;取消的份额会退还押金。'
|
||||
: '本单没有已验收份额,提交后整张订单会被取消;取消的份额会退还押金。'
|
||||
}
|
||||
style={{ marginBottom: 16 }}
|
||||
/>
|
||||
<Descriptions size="small" column={1} bordered style={{ marginBottom: 16 }}>
|
||||
<Descriptions.Item label="当前总量">
|
||||
{cancelSharingPartTotalQuantity} 份
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="已验收(保留)">
|
||||
{cancelSharingPartAcceptedQuantity} 份
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="将取消">
|
||||
{cancelSharingPartCancelledQuantity} 份(进行中 + 待接单)
|
||||
</Descriptions.Item>
|
||||
</Descriptions>
|
||||
<Form.Item
|
||||
label="退款金额"
|
||||
name="refundAmount"
|
||||
extra="默认按订单实付金额 × 取消份数 / 原总量计算,可手工修改;本系统只登记金额。"
|
||||
>
|
||||
<InputNumber min={0} precision={2} addonAfter="元" style={{ width: '100%' }} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="取消原因"
|
||||
name="reason"
|
||||
rules={[{ required: true, whitespace: true, message: '请填写取消原因' }]}
|
||||
>
|
||||
<Input.TextArea rows={3} placeholder="如:剩余份数不再需要,按实付比例退款" />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
) : null}
|
||||
</Modal>
|
||||
|
||||
{/* 内部寄售库存匹配拦截弹窗 */}
|
||||
<Modal
|
||||
title={
|
||||
|
||||
@@ -942,6 +942,24 @@ export function cancelAdminWorkOrderSharing(
|
||||
}>(`/api/v1/admin/worker-platform/orders/${workOrderId}/sharing/cancel`, payload)
|
||||
}
|
||||
|
||||
/** 取消部分:保留已验收份额,取消进行中份额与待接单剩余份数,退还取消份额的押金。 */
|
||||
export function cancelAdminWorkOrderSharingPart(
|
||||
workOrderId: number,
|
||||
payload: {
|
||||
/** 退款金额(元);不传则后端按实付比例算 */
|
||||
refundAmount?: number
|
||||
reason: string
|
||||
},
|
||||
) {
|
||||
return apiPost<{
|
||||
order: WorkOrder
|
||||
cancelledShareCount: number
|
||||
cancelledQuantity: number
|
||||
releasedDepositAmount: number
|
||||
refundAmount: number
|
||||
}>(`/api/v1/admin/worker-platform/orders/${workOrderId}/sharing/cancel-part`, payload)
|
||||
}
|
||||
|
||||
export function acceptAdminWorkOrders(workOrderIds: number[]) {
|
||||
return apiPost<{ orders: WorkOrder[] }>('/api/v1/admin/worker-platform/orders/accept-batch', {
|
||||
workOrderIds,
|
||||
|
||||
@@ -648,6 +648,8 @@ export type WorkOrder = {
|
||||
canPublish: boolean
|
||||
canCancel: boolean
|
||||
canCancelSharing?: boolean
|
||||
/** 取消部分:保留已验收份额,取消进行中份额与待接单剩余份数。 */
|
||||
canCancelSharingPart?: boolean
|
||||
canResolveProblem: boolean
|
||||
canDeduct: boolean
|
||||
canConfirmFriend?: boolean
|
||||
@@ -655,6 +657,8 @@ export type WorkOrder = {
|
||||
canResetGiftFlow?: boolean
|
||||
}
|
||||
rewardAmount: number
|
||||
/** 来源订单实付金额(分):取消部分时用于预填退款金额。 */
|
||||
sourceOrderAmount?: number
|
||||
/** 当前打手生效的免押额度,仅打手端订单数据返回。 */
|
||||
depositFreeAmount?: number
|
||||
requiredDepositAmount?: number
|
||||
@@ -668,6 +672,10 @@ export type WorkOrder = {
|
||||
joinedQuantity: number
|
||||
pendingSubmissionCount: number
|
||||
remainingQuantity?: number
|
||||
/** 已验收份额的份数合计 */
|
||||
acceptedQuantity?: number
|
||||
/** 可取消的未验收份数 = 进行中 + 待接单 */
|
||||
cancellableQuantity?: number
|
||||
filled?: boolean
|
||||
}
|
||||
pendingUnfreezeAmount?: number
|
||||
|
||||
Reference in New Issue
Block a user