feat(worker-platform): 增加寄卖白名单总开关,关闭后全员可发布
资金配置与打手列表可一键切换白名单模式;发布校验、打手端入口按总开关放行。同时收紧未开通判定、关权限确认和开通弹窗文案。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -44,6 +44,7 @@ type FinanceConfigFormValues = {
|
||||
depositUnfreezeDays?: number
|
||||
rewardUnfreezeEnabled?: boolean
|
||||
consignmentPublishDepositYuan?: number
|
||||
consignmentWhitelistEnabled?: boolean
|
||||
recharge?: {
|
||||
enabled?: boolean
|
||||
channelName?: string
|
||||
@@ -173,6 +174,7 @@ export default function FinancePanel() {
|
||||
consignmentPublishDepositFen: Math.round(
|
||||
Number(values.consignmentPublishDepositYuan ?? 20) * 100,
|
||||
),
|
||||
consignmentWhitelistEnabled: values.consignmentWhitelistEnabled !== false,
|
||||
recharge: {
|
||||
enabled: values.recharge?.enabled !== false,
|
||||
channelName: String(values.recharge?.channelName || '').trim(),
|
||||
@@ -426,6 +428,14 @@ export default function FinancePanel() {
|
||||
>
|
||||
<InputNumber min={0} max={10000} step={1} addonBefore="¥" />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="寄卖白名单"
|
||||
name="consignmentWhitelistEnabled"
|
||||
valuePropName="checked"
|
||||
tooltip="开启后只有后台开通权限的打手能发布寄卖;关闭后所有打手均可发布。打手身上的白名单标记会保留,方便再次开启。"
|
||||
>
|
||||
<Switch checkedChildren="仅白名单" unCheckedChildren="全员可寄卖" />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="报酬待解冻"
|
||||
name="rewardUnfreezeEnabled"
|
||||
@@ -687,6 +697,7 @@ function mapFinanceConfigToFormValues(config?: WorkerFinanceConfig): FinanceConf
|
||||
depositUnfreezeDays: Number(config?.depositUnfreezeDays ?? 3),
|
||||
rewardUnfreezeEnabled: config?.rewardUnfreezeEnabled !== false,
|
||||
consignmentPublishDepositYuan: Number(config?.consignmentPublishDepositFen ?? 2000) / 100,
|
||||
consignmentWhitelistEnabled: config?.consignmentWhitelistEnabled !== false,
|
||||
recharge: {
|
||||
enabled: config?.recharge.enabled !== false,
|
||||
channelName: config?.recharge.channelName || '',
|
||||
|
||||
@@ -177,7 +177,7 @@ function OverviewSection({ workerId }: { workerId: number }) {
|
||||
<Descriptions.Item label="寄卖权限" span={2}>
|
||||
<Space>
|
||||
<Tag color={worker.canConsign ? 'green' : 'default'}>
|
||||
{worker.canConsign ? '已开通寄卖' : '未开通(白名单限制)'}
|
||||
{worker.canConsign ? '已加入白名单' : '未加入白名单'}
|
||||
</Tag>
|
||||
{worker.consignmentActivatedAt ? (
|
||||
<Typography.Text type="secondary" style={{ fontSize: 12 }}>
|
||||
|
||||
@@ -23,11 +23,13 @@ import { useSearchParams } from 'react-router'
|
||||
|
||||
import {
|
||||
creditAdminWorkerWallet,
|
||||
fetchAdminWorkerFinanceConfig,
|
||||
fetchAdminWorkerLevels,
|
||||
fetchAdminWorkerUsers,
|
||||
fetchAdminWorkerWithdrawalAccounts,
|
||||
resetAdminWorkerPassword,
|
||||
reviewAdminWorkerUser,
|
||||
saveAdminWorkerFinanceConfig,
|
||||
saveAdminWorkerPersonalDepositFreeAmount,
|
||||
saveAdminWorkerWithdrawalAccount,
|
||||
updateAdminWorkerWithdrawalBlacklist,
|
||||
@@ -205,6 +207,13 @@ export default function WorkersPanel() {
|
||||
queryFn: () => fetchAdminWorkerLevels(),
|
||||
})
|
||||
const workersPagination = workersQuery.data?.data.pagination
|
||||
const financeConfigQuery = useQuery({
|
||||
queryKey: ['admin-worker-platform-finance-config'],
|
||||
queryFn: () => fetchAdminWorkerFinanceConfig(),
|
||||
})
|
||||
const consignmentWhitelistEnabled =
|
||||
financeConfigQuery.data?.data.consignmentWhitelistEnabled !== false
|
||||
const [updatingWhitelist, setUpdatingWhitelist] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
// 从工单流转记录等入口带 ?workerId= 定位到打手后,自动打开一次详情,关闭后不再重复弹。
|
||||
@@ -225,6 +234,9 @@ export default function WorkersPanel() {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ['admin-worker-platform-summary'],
|
||||
}),
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ['admin-worker-platform-finance-config'],
|
||||
}),
|
||||
])
|
||||
}
|
||||
|
||||
@@ -466,47 +478,117 @@ export default function WorkersPanel() {
|
||||
}
|
||||
}
|
||||
|
||||
const [updatingConsignmentWorkerId, setUpdatingConsignmentWorkerId] = useState<number | null>(
|
||||
null,
|
||||
const [updatingConsignmentWorkerIds, setUpdatingConsignmentWorkerIds] = useState<Set<number>>(
|
||||
() => new Set(),
|
||||
)
|
||||
|
||||
function markConsignmentWorkerUpdating(workerId: number, updating: boolean) {
|
||||
setUpdatingConsignmentWorkerIds((prev) => {
|
||||
const next = new Set(prev)
|
||||
if (updating) next.add(workerId)
|
||||
else next.delete(workerId)
|
||||
return next
|
||||
})
|
||||
}
|
||||
|
||||
function applyUpdatedWorker(row: WorkerUser, updatedWorker: WorkerUser) {
|
||||
queryClient.setQueriesData<{ data: { items: WorkerUser[]; pagination: any } }>(
|
||||
{ queryKey: ['admin-worker-platform-workers'] },
|
||||
(old) => {
|
||||
if (!old?.data?.items) return old
|
||||
return {
|
||||
...old,
|
||||
data: {
|
||||
...old.data,
|
||||
items: old.data.items.map((item) =>
|
||||
item.workerId === row.workerId ? { ...item, ...updatedWorker } : item,
|
||||
),
|
||||
},
|
||||
}
|
||||
},
|
||||
)
|
||||
setDetailWorker((current) =>
|
||||
current?.workerId === row.workerId ? { ...current, ...updatedWorker } : current,
|
||||
)
|
||||
}
|
||||
|
||||
async function handleToggleConsignmentPermission(row: WorkerUser, checked: boolean) {
|
||||
setUpdatingConsignmentWorkerId(row.workerId)
|
||||
markConsignmentWorkerUpdating(row.workerId, true)
|
||||
try {
|
||||
const res = await updateAdminWorkerConsignmentPermission(row.workerId, {
|
||||
canConsign: checked,
|
||||
})
|
||||
const updatedWorker = res.data?.worker
|
||||
if (updatedWorker) {
|
||||
queryClient.setQueriesData<{ data: { items: WorkerUser[]; pagination: any } }>(
|
||||
{ queryKey: ['admin-worker-platform-workers'] },
|
||||
(old) => {
|
||||
if (!old?.data?.items) return old
|
||||
return {
|
||||
...old,
|
||||
data: {
|
||||
...old.data,
|
||||
items: old.data.items.map((item) =>
|
||||
item.workerId === row.workerId ? { ...item, ...updatedWorker } : item,
|
||||
),
|
||||
},
|
||||
}
|
||||
},
|
||||
)
|
||||
applyUpdatedWorker(row, updatedWorker)
|
||||
}
|
||||
message.success(
|
||||
checked
|
||||
? `已为打手 ${row.displayName || row.username} 开通寄卖权限`
|
||||
: `已关闭打手 ${row.displayName || row.username} 的寄卖权限`,
|
||||
? `已为打手 ${row.displayName || row.username} 加入寄卖白名单`
|
||||
: `已将打手 ${row.displayName || row.username} 移出寄卖白名单`,
|
||||
)
|
||||
await refreshWorkers()
|
||||
} catch (err: any) {
|
||||
} catch (err: unknown) {
|
||||
message.error(err instanceof Error ? err.message : '更新寄卖权限失败')
|
||||
} finally {
|
||||
setUpdatingConsignmentWorkerId(null)
|
||||
markConsignmentWorkerUpdating(row.workerId, false)
|
||||
}
|
||||
}
|
||||
|
||||
function requestToggleConsignmentPermission(row: WorkerUser, checked: boolean) {
|
||||
if (checked) {
|
||||
void handleToggleConsignmentPermission(row, true)
|
||||
return
|
||||
}
|
||||
modal.confirm({
|
||||
title: '移出寄卖白名单?',
|
||||
content: `确认关闭打手“${row.displayName || row.username}”的寄卖权限?白名单开启时,该打手将无法发布新寄卖;已在途的寄卖不受影响。`,
|
||||
okText: '确认关闭',
|
||||
okButtonProps: { danger: true },
|
||||
cancelText: '取消',
|
||||
onOk: () => handleToggleConsignmentPermission(row, false),
|
||||
})
|
||||
}
|
||||
|
||||
async function handleToggleConsignmentWhitelist(checked: boolean) {
|
||||
const current = financeConfigQuery.data?.data
|
||||
if (!current) {
|
||||
message.error('资金配置尚未加载完成,请稍后重试')
|
||||
return
|
||||
}
|
||||
modal.confirm({
|
||||
title: checked ? '开启寄卖白名单?' : '关闭寄卖白名单?',
|
||||
content: checked
|
||||
? '开启后只有白名单中的打手可以发布寄卖,未开通的打手会被拦截。'
|
||||
: '关闭后所有打手都可以发布寄卖。打手身上的白名单标记会保留,方便再次开启。',
|
||||
okText: checked ? '确认开启' : '确认关闭',
|
||||
okButtonProps: checked ? undefined : { danger: true },
|
||||
cancelText: '取消',
|
||||
onOk: async () => {
|
||||
setUpdatingWhitelist(true)
|
||||
try {
|
||||
await saveAdminWorkerFinanceConfig({
|
||||
depositUnfreezeDays: current.depositUnfreezeDays,
|
||||
rewardUnfreezeEnabled: current.rewardUnfreezeEnabled,
|
||||
consignmentPublishDepositFen: current.consignmentPublishDepositFen,
|
||||
consignmentWhitelistEnabled: checked,
|
||||
recharge: current.recharge,
|
||||
adminContact: current.adminContact,
|
||||
withdraw: current.withdraw,
|
||||
})
|
||||
message.success(checked ? '已开启寄卖白名单' : '已关闭寄卖白名单,全部打手可发布')
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: ['admin-worker-platform-finance-config'],
|
||||
})
|
||||
} catch (error) {
|
||||
message.error(error instanceof Error ? error.message : '更新寄卖白名单失败')
|
||||
} finally {
|
||||
setUpdatingWhitelist(false)
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
const columns: TableColumnsType<WorkerUser> = [
|
||||
{
|
||||
title: '打手',
|
||||
@@ -598,16 +680,24 @@ export default function WorkersPanel() {
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '寄卖权限',
|
||||
width: 120,
|
||||
title: '寄卖白名单',
|
||||
width: 130,
|
||||
render: (_, row) => (
|
||||
<Switch
|
||||
checkedChildren="已开通"
|
||||
unCheckedChildren="未开通"
|
||||
checked={row.canConsign}
|
||||
loading={updatingConsignmentWorkerId === row.workerId}
|
||||
onChange={(checked) => handleToggleConsignmentPermission(row, checked)}
|
||||
/>
|
||||
<Tooltip
|
||||
title={
|
||||
consignmentWhitelistEnabled
|
||||
? '白名单开启中:仅已开通的打手可发布寄卖'
|
||||
: '白名单已关闭:开关暂不限制发布,再次开启后才会生效'
|
||||
}
|
||||
>
|
||||
<Switch
|
||||
checkedChildren="已开通"
|
||||
unCheckedChildren="未开通"
|
||||
checked={row.canConsign}
|
||||
loading={updatingConsignmentWorkerIds.has(row.workerId)}
|
||||
onChange={(checked) => requestToggleConsignmentPermission(row, checked)}
|
||||
/>
|
||||
</Tooltip>
|
||||
),
|
||||
},
|
||||
{
|
||||
@@ -778,7 +868,33 @@ export default function WorkersPanel() {
|
||||
) : null}
|
||||
</Card>
|
||||
<WorkerStatisticsBar statistics={workersQuery.data?.data.statistics} />
|
||||
<Card title="打手列表" bordered={false}>
|
||||
<Card
|
||||
title="打手列表"
|
||||
bordered={false}
|
||||
extra={
|
||||
<Space>
|
||||
<Typography.Text type="secondary">寄卖白名单</Typography.Text>
|
||||
<Switch
|
||||
checkedChildren="仅白名单"
|
||||
unCheckedChildren="全员可寄卖"
|
||||
checked={consignmentWhitelistEnabled}
|
||||
loading={updatingWhitelist || financeConfigQuery.isLoading}
|
||||
disabled={!financeConfigQuery.data?.data}
|
||||
onChange={(checked) => void handleToggleConsignmentWhitelist(checked)}
|
||||
/>
|
||||
</Space>
|
||||
}
|
||||
>
|
||||
<Alert
|
||||
showIcon
|
||||
type={consignmentWhitelistEnabled ? 'warning' : 'info'}
|
||||
style={{ marginBottom: 12 }}
|
||||
message={
|
||||
consignmentWhitelistEnabled
|
||||
? '寄卖白名单已开启:仅下方开关为「已开通」的打手可发布寄卖。客服无法开通,需运营或管理员操作。'
|
||||
: '寄卖白名单已关闭:全部打手均可发布寄卖。下方开关仅在重新开启白名单后生效。'
|
||||
}
|
||||
/>
|
||||
<Table<WorkerUser>
|
||||
rowKey="workerId"
|
||||
loading={workersQuery.isLoading}
|
||||
|
||||
Reference in New Issue
Block a user