feat(fulfillment): 增加统一结算与多渠道人工履约
This commit is contained in:
@@ -32,7 +32,7 @@ import {
|
||||
fetchAdminManualFulfillmentPending,
|
||||
fetchAdminPlatformCreditOwners,
|
||||
} from '@/services/admin'
|
||||
import type { ManualFulfillmentPendingItem } from '@/types/admin'
|
||||
import type { ManualConfiguredChannel, ManualFulfillmentPendingItem } from '@/types/admin'
|
||||
import { getAdminRole, getAdminUserId } from '@/utils/admin-auth'
|
||||
|
||||
type ConfirmFormValues = {
|
||||
@@ -67,6 +67,7 @@ export function ManualFulfillmentConfirmModal({
|
||||
const queryClient = useQueryClient()
|
||||
const [form] = Form.useForm<ConfirmFormValues>()
|
||||
const [selectedId, setSelectedId] = useState<number | null>(null)
|
||||
const [selectedPlatformKey, setSelectedPlatformKey] = useState<string | null>(null)
|
||||
const [fundAccountId, setFundAccountId] = useState<number | null>(null)
|
||||
const [creditOwnerAdminUserId, setCreditOwnerAdminUserId] = useState<number | null>(null)
|
||||
const role = getAdminRole()
|
||||
@@ -91,30 +92,51 @@ export function ManualFulfillmentConfirmModal({
|
||||
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 && Boolean(selected?.isFundCash),
|
||||
enabled: open && privileged && selectedChannel?.isFundCash === true,
|
||||
retry: false,
|
||||
})
|
||||
const creditOwnersQuery = useQuery({
|
||||
queryKey: ['admin-manual-confirm-credit-owners'],
|
||||
queryFn: () => fetchAdminPlatformCreditOwners(),
|
||||
enabled: open && privileged && Boolean(selected) && !selected?.isFundCash,
|
||||
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 (selected?.isFundCash) {
|
||||
if (selectedChannel?.isFundCash) {
|
||||
const accounts = (fundAccountsQuery.data?.data.items || []).filter(
|
||||
(item) => item.accountType === 'agent' && item.status === 'active',
|
||||
)
|
||||
@@ -122,6 +144,11 @@ export function ManualFulfillmentConfirmModal({
|
||||
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)
|
||||
@@ -129,7 +156,8 @@ export function ManualFulfillmentConfirmModal({
|
||||
open,
|
||||
privileged,
|
||||
selected?.orderItemId,
|
||||
selected?.isFundCash,
|
||||
selectedChannel?.isFundCash,
|
||||
selectedChannel?.isOnAccount,
|
||||
currentUserId,
|
||||
fundAccountsQuery.data,
|
||||
creditOwnersQuery.data,
|
||||
@@ -139,18 +167,25 @@ export function ManualFulfillmentConfirmModal({
|
||||
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 && selected?.isFundCash && fundAccountId ? { fundAccountId } : {}),
|
||||
...(privileged && selected && !selected.isFundCash && creditOwnerAdminUserId
|
||||
...(privileged && selectedChannel?.isFundCash && fundAccountId ? { fundAccountId } : {}),
|
||||
...(privileged &&
|
||||
selectedChannel &&
|
||||
!selectedChannel.isFundCash &&
|
||||
!selectedChannel.isOnAccount &&
|
||||
creditOwnerAdminUserId
|
||||
? { creditOwnerAdminUserId }
|
||||
: {}),
|
||||
}),
|
||||
onSuccess: (response) => {
|
||||
const result = response.data
|
||||
message.success(
|
||||
`履约已确认,扣 ${result.creditQuantity} 积分,成本 ¥${(result.costFen / 100).toFixed(2)}`,
|
||||
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'] })
|
||||
@@ -167,7 +202,8 @@ export function ManualFulfillmentConfirmModal({
|
||||
},
|
||||
})
|
||||
|
||||
const showCostInput = selected?.costFen === null
|
||||
const showCostInput = selectedChannel?.costFen === null
|
||||
const costRequired = showCostInput && selectedChannel?.isOnAccount !== true
|
||||
|
||||
return (
|
||||
<Modal
|
||||
@@ -178,9 +214,12 @@ export function ManualFulfillmentConfirmModal({
|
||||
icon: <CheckOutlined />,
|
||||
disabled:
|
||||
!selected ||
|
||||
!selectedChannel ||
|
||||
(privileged &&
|
||||
((selected.isFundCash && !fundAccountId) ||
|
||||
(!selected.isFundCash && !creditOwnerAdminUserId))),
|
||||
((selectedChannel.isFundCash && !fundAccountId) ||
|
||||
(!selectedChannel.isFundCash &&
|
||||
!selectedChannel.isOnAccount &&
|
||||
!creditOwnerAdminUserId))),
|
||||
}}
|
||||
cancelText="取消"
|
||||
confirmLoading={confirmMutation.isPending}
|
||||
@@ -227,12 +266,30 @@ export function ManualFulfillmentConfirmModal({
|
||||
</Typography.Text>
|
||||
</div>
|
||||
<div>
|
||||
<Typography.Text type="secondary">履约渠道:</Typography.Text>
|
||||
<Tag color={PLATFORM_TAG_COLORS[selected?.platformKey || ''] || 'default'}>
|
||||
{selected?.platformLabel || '-'}
|
||||
</Tag>
|
||||
{selected && !selected.isFundCash ? (
|
||||
<Typography.Text>消耗 {selected.creditQuantity} 积分</Typography.Text>
|
||||
<Typography.Text type="secondary">本次实际履约渠道:</Typography.Text>
|
||||
{selected && configuredChannels.length > 1 ? (
|
||||
<Select
|
||||
value={selectedChannel?.platformKey}
|
||||
onChange={(value) => {
|
||||
setSelectedPlatformKey(value)
|
||||
form.setFieldValue('costYuan', undefined)
|
||||
}}
|
||||
options={configuredChannels.map((channel) => ({
|
||||
value: channel.platformKey,
|
||||
label: channel.platformLabel,
|
||||
}))}
|
||||
style={{ width: '100%', marginTop: 6 }}
|
||||
/>
|
||||
) : (
|
||||
<Tag color={PLATFORM_TAG_COLORS[selectedChannel?.platformKey || ''] || 'default'}>
|
||||
{selectedChannel?.platformLabel || '-'}
|
||||
</Tag>
|
||||
)}
|
||||
{selectedChannel && !selectedChannel.isFundCash && !selectedChannel.isOnAccount ? (
|
||||
<Typography.Text>消耗 {selectedChannel.creditQuantity} 积分</Typography.Text>
|
||||
) : null}
|
||||
{selectedChannel?.isOnAccount ? (
|
||||
<Typography.Text>只生成虚拟账单,不扣积分或备用金</Typography.Text>
|
||||
) : null}
|
||||
</div>
|
||||
<div>
|
||||
@@ -240,8 +297,8 @@ export function ManualFulfillmentConfirmModal({
|
||||
<Typography.Text>¥{((selected?.revenueFen || 0) / 100).toFixed(2)}</Typography.Text>
|
||||
</div>
|
||||
|
||||
{privileged && selected ? (
|
||||
selected.isFundCash ? (
|
||||
{privileged && selected && selectedChannel ? (
|
||||
selectedChannel.isFundCash ? (
|
||||
<div>
|
||||
<Typography.Text type="secondary">代录到客服备用金账户:</Typography.Text>
|
||||
<Select
|
||||
@@ -260,7 +317,7 @@ export function ManualFulfillmentConfirmModal({
|
||||
}))}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
) : selectedChannel.isOnAccount ? null : (
|
||||
<div>
|
||||
<Typography.Text type="secondary">代录到客服积分账户:</Typography.Text>
|
||||
<Select
|
||||
@@ -281,11 +338,19 @@ export function ManualFulfillmentConfirmModal({
|
||||
) : null}
|
||||
|
||||
{showCostInput ? (
|
||||
<Alert type="warning" showIcon message="该商品成本不固定,请填写本次实际成本" />
|
||||
<Alert
|
||||
type="warning"
|
||||
showIcon
|
||||
message={
|
||||
selectedChannel?.isOnAccount
|
||||
? '统一结算金额可以先留空,后续统一对账时补录'
|
||||
: '该商品成本不固定,请填写本次实际成本'
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<Statistic
|
||||
title="本次成本"
|
||||
value={(selected?.costFen || 0) / 100}
|
||||
value={(selectedChannel?.costFen || 0) / 100}
|
||||
precision={2}
|
||||
prefix="¥"
|
||||
/>
|
||||
@@ -295,11 +360,11 @@ export function ManualFulfillmentConfirmModal({
|
||||
{showCostInput ? (
|
||||
<Form.Item
|
||||
name="costYuan"
|
||||
label="实际成本(元)"
|
||||
rules={[{ required: true, message: '请填写实际成本' }]}
|
||||
label={selectedChannel?.isOnAccount ? '预计结算金额(元)' : '实际成本(元)'}
|
||||
rules={costRequired ? [{ required: true, message: '请填写实际成本' }] : []}
|
||||
>
|
||||
<InputNumber
|
||||
min={0.01}
|
||||
min={selectedChannel?.isOnAccount ? 0 : 0.01}
|
||||
precision={2}
|
||||
style={{ width: '100%' }}
|
||||
placeholder="例如 12.50"
|
||||
|
||||
Reference in New Issue
Block a user