import { PlusOutlined, ReloadOutlined, SearchOutlined } from '@ant-design/icons' import { useQuery, useQueryClient } from '@tanstack/react-query' import { App, Button, Card, Form, Input, InputNumber, Modal, Select, Space, Switch, Tag, Typography, } from 'antd' import { useEffect, useState } from 'react' import PercentTable from '@/components/common/PercentTable' import { fetchAdminSession } from '@/services/admin/auth' import { createAdminConsignmentContact, deleteAdminConsignmentContact, fetchAdminConsignmentContacts, setAdminConsignmentContactEnabled, updateAdminConsignmentContact, } from '@/services/admin/consignment' import type { ConsignmentContactSupporter } from '@/types/consignment' import { resolveAdminPermission } from '@/utils/admin-auth' import { formatDateTime } from '@/utils/date-time' import type { TableColumnsType } from 'antd' const { Text } = Typography type ContactForm = { name: string note?: string sortOrder?: number enabled?: boolean } const ENABLED_FILTER_OPTIONS = [ { label: '全部状态', value: '' }, { label: '启用中', value: 'true' }, { label: '已禁用', value: 'false' }, ] /** * 接单平台 → 对接客服。 * * 独立名单(不复用后台账号):打手发布寄卖时必选,后台按人统计提成与快速联系。 * 已被寄卖记录引用的客服只能禁用,不能删除,保证历史单归属不丢。 */ export default function ConsignmentContactsPanel() { const { message, modal } = App.useApp() const queryClient = useQueryClient() const [form] = Form.useForm() const [keywordInput, setKeywordInput] = useState('') const [keyword, setKeyword] = useState('') const [enabledFilter, setEnabledFilter] = useState('') const [editingContact, setEditingContact] = useState(null) const [formOpen, setFormOpen] = useState(false) const [submitting, setSubmitting] = useState(false) const [actionId, setActionId] = useState(null) useEffect(() => { const timer = window.setTimeout(() => setKeyword(keywordInput.trim()), 300) return () => window.clearTimeout(timer) }, [keywordInput]) const adminSessionQuery = useQuery({ queryKey: ['admin-session'], queryFn: fetchAdminSession, retry: false, }) // 写操作统一按 consignment.manage 门控:后端接口都挂了 requireAdminPermission, // 没有权限时按钮点了只会 403,所以直接从界面隐藏。 const canManage = resolveAdminPermission( adminSessionQuery.data?.data.user.permissions, 'consignment.manage', ) const query = useQuery({ queryKey: ['admin-consignment-contacts', keyword, enabledFilter], queryFn: () => fetchAdminConsignmentContacts({ keyword: keyword || undefined, enabled: enabledFilter || undefined, }), }) const items = query.data?.data.items || [] const total = Number(query.data?.data.total || 0) const enabledCount = items.filter((item) => item.enabled).length async function reload() { await queryClient.invalidateQueries({ queryKey: ['admin-consignment-contacts'] }) } function openCreate() { setEditingContact(null) form.resetFields() form.setFieldsValue({ enabled: true, sortOrder: 0 }) setFormOpen(true) } function openEdit(record: ConsignmentContactSupporter) { setEditingContact(record) form.setFieldsValue({ name: record.name, note: record.note, sortOrder: record.sortOrder, enabled: record.enabled, }) setFormOpen(true) } async function handleSubmit() { try { const values = await form.validateFields() setSubmitting(true) const payload = { name: values.name, note: values.note || '', sortOrder: Number(values.sortOrder || 0), enabled: values.enabled !== false, } if (editingContact) { await updateAdminConsignmentContact(editingContact.id, payload) message.success('对接客服已更新') } else { await createAdminConsignmentContact(payload) message.success('对接客服已新增') } setFormOpen(false) setEditingContact(null) await reload() } catch (error: any) { if (error?.errorFields) return message.error(error?.message || '保存对接客服失败') } finally { setSubmitting(false) } } async function handleToggleEnabled(record: ConsignmentContactSupporter, enabled: boolean) { setActionId(record.id) try { await setAdminConsignmentContactEnabled(record.id, enabled) message.success(enabled ? '已启用该对接客服' : '已禁用该对接客服') await reload() } catch (error: any) { message.error(error?.message || '更新对接客服状态失败') } finally { setActionId(null) } } function handleDelete(record: ConsignmentContactSupporter) { modal.confirm({ title: `删除对接客服「${record.name}」?`, content: '只有未被任何寄卖记录使用的客服可以删除。已被使用的请改为「禁用」,历史寄卖单仍会保留对接客服信息。', okText: '删除', okType: 'danger', cancelText: '取消', onOk: async () => { try { await deleteAdminConsignmentContact(record.id) message.success('对接客服已删除') await reload() } catch (error: any) { message.error(error?.message || '删除对接客服失败') throw error } }, }) } const columns: TableColumnsType = [ { title: '姓名', dataIndex: 'name', width: 160, render: (value: string) => {value}, }, { title: '备注', dataIndex: 'note', width: 240, ellipsis: true, render: (value: string) => value ? {value} : -, }, { title: '排序', dataIndex: 'sortOrder', width: 80, render: (value: number) => value || 0, }, { title: '状态', key: 'enabled', width: 110, render: (_, record) => ( void handleToggleEnabled(record, checked)} /> {record.enabled ? '启用中' : '已禁用'} ), }, { title: '更新时间', dataIndex: 'updatedAt', width: 170, render: (value: string) => formatDateTime(value), }, { title: '操作', key: 'actions', width: 140, render: (_, record) => canManage ? ( ) : ( - ), }, ] return (
} placeholder="搜索姓名 / 备注" value={keywordInput} onChange={(event) => setKeywordInput(event.target.value)} style={{ width: 280 }} />
) }