/** * 确认人工履约弹窗(订单列表 / 订单详情共用)。 * * 口径(2026-10-24): * * 渠道与消耗积分在成本中心提前配好,客服不选、不填; * * 固定成本 → 直接确认; * * 成本不固定(消耗积分 = 0)→ 只填本次实际成本; * * 确认后扣对应平台积分/备用金并写成本快照。 * * 原「人工履约待办」页面已下线,入口收敛到订单界面。 */ import { CheckOutlined } from '@ant-design/icons' import { Alert, App, Form, Input, InputNumber, Modal, Select, Space, Statistic, Tag, Typography, } from 'antd' import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' import { useEffect, useState } from 'react' import { confirmAdminManualFulfillment, fetchAdminFundAccounts, fetchAdminManualFulfillmentPending, fetchAdminPlatformCreditOwners, } from '@/services/admin' import type { ManualConfiguredChannel, ManualFulfillmentPendingItem } from '@/types/admin' import { getAdminRole, getAdminUserId } from '@/utils/admin-auth' type ConfirmFormValues = { costYuan?: number payeeName?: string note?: string } const PLATFORM_TAG_COLORS: Record = { nanhang: 'blue', lewan: 'purple', rock: 'cyan', fund_cash: 'orange', } export type ManualFulfillmentConfirmModalProps = { open: boolean orderId: number | null initialOrderItemId?: number | null onClose: () => void onConfirmed?: () => void } export function ManualFulfillmentConfirmModal({ open, orderId, initialOrderItemId = null, onClose, onConfirmed, }: ManualFulfillmentConfirmModalProps) { const { message } = App.useApp() const queryClient = useQueryClient() const [form] = Form.useForm() const [selectedId, setSelectedId] = useState(null) const [selectedPlatformKey, setSelectedPlatformKey] = useState(null) const [fundAccountId, setFundAccountId] = useState(null) const [creditOwnerAdminUserId, setCreditOwnerAdminUserId] = useState(null) const role = getAdminRole() const privileged = role !== 'support' const currentUserId = getAdminUserId() const pendingQuery = useQuery({ queryKey: ['admin-manual-fulfillment-pending', 'order', orderId], queryFn: () => fetchAdminManualFulfillmentPending({ orderId: orderId || undefined, status: 'pending', page: 1, pageSize: 20, }), enabled: open && Boolean(orderId), }) const items = pendingQuery.data?.data.items || [] const selected = items.find((item) => item.orderItemId === selectedId) || items.find((item) => item.orderItemId === initialOrderItemId) || items[0] || null const configuredChannels = selected?.channels || [] const selectedChannel: ManualConfiguredChannel | null = configuredChannels.find((channel) => channel.platformKey === selectedPlatformKey) || configuredChannels[0] || null const fundAccountsQuery = useQuery({ queryKey: ['admin-manual-confirm-fund-accounts'], queryFn: () => fetchAdminFundAccounts({ page: 1, pageSize: 100 }), enabled: open && privileged && selectedChannel?.isFundCash === true, retry: false, }) const creditOwnersQuery = useQuery({ queryKey: ['admin-manual-confirm-credit-owners'], queryFn: () => fetchAdminPlatformCreditOwners(), enabled: open && privileged && Boolean(selectedChannel) && selectedChannel?.isFundCash !== true && selectedChannel?.isOnAccount !== true, retry: false, }) useEffect(() => { if (!open) return setSelectedId(initialOrderItemId || null) setSelectedPlatformKey(null) form.resetFields() }, [open, initialOrderItemId, form]) useEffect(() => { if (!open || !selected) return setSelectedPlatformKey((current) => { if (current && selected.channels.some((channel) => channel.platformKey === current)) { return current } return selected.channels[0]?.platformKey || selected.platformKey || null }) }, [open, selected?.orderItemId, selected?.channels, selected?.platformKey]) // 代录时默认选本人账户;客服没有代录权限,不展示选择。 useEffect(() => { if (!open || !privileged) return if (selectedChannel?.isFundCash) { const accounts = (fundAccountsQuery.data?.data.items || []).filter( (item) => item.accountType === 'agent' && item.status === 'active', ) const own = accounts.find((item) => item.ownerAdminUserId === currentUserId) setFundAccountId(own?.id ?? null) return } if (selectedChannel?.isOnAccount) { setCreditOwnerAdminUserId(null) setFundAccountId(null) return } const owners = creditOwnersQuery.data?.data.items || [] const own = owners.find((item) => item.id === currentUserId) setCreditOwnerAdminUserId(own?.id ?? null) }, [ open, privileged, selected?.orderItemId, selectedChannel?.isFundCash, selectedChannel?.isOnAccount, currentUserId, fundAccountsQuery.data, creditOwnersQuery.data, ]) const confirmMutation = useMutation({ mutationFn: (values: ConfirmFormValues) => confirmAdminManualFulfillment({ orderItemId: selected?.orderItemId || 0, platformKey: selectedChannel?.platformKey || selected?.platformKey || '', costFen: values.costYuan === undefined ? undefined : Math.round(values.costYuan * 100), payeeName: values.payeeName || '', note: values.note || '', ...(privileged && selectedChannel?.isFundCash && fundAccountId ? { fundAccountId } : {}), ...(privileged && selectedChannel && !selectedChannel.isFundCash && !selectedChannel.isOnAccount && creditOwnerAdminUserId ? { creditOwnerAdminUserId } : {}), }), onSuccess: (response) => { const result = response.data message.success( result.onAccountBillId ? `履约已确认,已生成统一结算虚拟账单 ¥${(result.costFen / 100).toFixed(2)}` : `履约已确认,扣 ${result.creditQuantity} 积分,成本 ¥${(result.costFen / 100).toFixed(2)}`, ) void queryClient.invalidateQueries({ queryKey: ['admin-manual-fulfillment-pending'] }) void queryClient.invalidateQueries({ queryKey: ['admin-order-detail'] }) void queryClient.invalidateQueries({ queryKey: ['admin-orders'] }) void queryClient.invalidateQueries({ queryKey: ['admin-fund-my'] }) void queryClient.invalidateQueries({ queryKey: ['admin-fund-accounts'] }) void queryClient.invalidateQueries({ queryKey: ['admin-platform-credit-accounts'] }) void queryClient.invalidateQueries({ queryKey: ['admin-platform-credit-entries'] }) onConfirmed?.() onClose() }, onError: (error) => { message.error(error instanceof Error ? error.message : '确认履约失败') }, }) const showCostInput = selectedChannel?.costFen === null const costRequired = showCostInput && selectedChannel?.isOnAccount !== true return ( , disabled: !selected || !selectedChannel || (privileged && ((selectedChannel.isFundCash && !fundAccountId) || (!selectedChannel.isFundCash && !selectedChannel.isOnAccount && !creditOwnerAdminUserId))), }} cancelText="取消" confirmLoading={confirmMutation.isPending} onOk={() => { void form.validateFields().then((values) => confirmMutation.mutate(values)) }} onCancel={onClose} destroyOnHidden width={560} > {pendingQuery.isLoading ? ( 正在读取待履约商品… ) : items.length === 0 ? ( ) : ( {items.length > 1 ? ( { setSelectedPlatformKey(value) form.setFieldValue('costYuan', undefined) }} options={configuredChannels.map((channel) => ({ value: channel.platformKey, label: channel.platformLabel, }))} style={{ width: '100%', marginTop: 6 }} /> ) : ( {selectedChannel?.platformLabel || '-'} )} {selectedChannel && !selectedChannel.isFundCash && !selectedChannel.isOnAccount ? ( 消耗 {selectedChannel.creditQuantity} 积分 ) : null} {selectedChannel?.isOnAccount ? ( 只生成虚拟账单,不扣积分或备用金 ) : null}
订单金额: ¥{((selected?.revenueFen || 0) / 100).toFixed(2)}
{privileged && selected && selectedChannel ? ( selectedChannel.isFundCash ? (
代录到客服备用金账户: setCreditOwnerAdminUserId(value)} options={(creditOwnersQuery.data?.data.items || []).map((item) => ({ value: item.id, label: item.displayName || item.username, }))} />
) ) : null} {showCostInput ? ( ) : ( )} form={form} layout="vertical"> {showCostInput ? ( ) : null}
)}
) }