import Address from '@/components/Address'; import { DeleteFilled, EditOutlined, PlusOutlined, UserOutlined, } from '@ant-design/icons'; import { ActionType, DrawerForm, ModalForm, PageContainer, ProColumns, ProFormText, ProFormTextArea, ProTable, } from '@ant-design/pro-components'; import { request, useParams } from '@umijs/max'; import { App, Avatar, Button, Modal, Popconfirm, Space, Tag } from 'antd'; import React, { useEffect, useRef, useState } from 'react'; const BatchEditCustomers: React.FC<{ tableRef: React.MutableRefObject; selectedRowKeys: React.Key[]; setSelectedRowKeys: (keys: React.Key[]) => void; siteId?: string; }> = ({ tableRef, selectedRowKeys, setSelectedRowKeys, siteId }) => { const { message } = App.useApp(); return ( } > 批量编辑 } width={400} modalProps={{ destroyOnHidden: true }} onFinish={async (values) => { if (!siteId) return false; let ok = 0, fail = 0; for (const id of selectedRowKeys) { try { // Remove undefined values const data = Object.fromEntries( Object.entries(values).filter( ([_, v]) => v !== undefined && v !== '', ), ); if (Object.keys(data).length === 0) continue; const res = await request(`/site-api/${siteId}/customers/${id}`, { method: 'PUT', data: data, }); if (res.success) ok++; else fail++; } catch (e) { fail++; } } message.success(`成功 ${ok}, 失败 ${fail}`); tableRef.current?.reload(); setSelectedRowKeys([]); return true; }} > ); }; const CustomerPage: React.FC = () => { const { message } = App.useApp(); const { siteId } = useParams<{ siteId: string }>(); const [editing, setEditing] = useState(null); const [selectedRowKeys, setSelectedRowKeys] = useState([]); const actionRef = useRef(); const [ordersVisible, setOrdersVisible] = useState(false); const [ordersCustomer, setOrdersCustomer] = useState(null); useEffect(() => { // 当siteId变化时, 重新加载表格数据 if (siteId) { actionRef.current?.reload(); } }, [siteId]); const handleDelete = async (id: number) => { if (!siteId) return; try { const res = await request(`/site-api/${siteId}/customers/${id}`, { method: 'DELETE', }); if (res.success) { message.success('删除成功'); actionRef.current?.reload(); } else { message.error(res.message || '删除失败'); } } catch (e) { message.error('删除失败'); } }; const columns: ProColumns[] = [ { title: '头像', dataIndex: 'avatar_url', hideInSearch: true, width: 80, render: (_, record) => { // 从raw数据中获取头像URL,因为DTO中没有这个字段 const avatarUrl = record.raw?.avatar_url || record.avatar_url; return } size="large" />; }, }, { title: '姓名', dataIndex: 'name', hideInTable: true, }, { title: 'ID', dataIndex: 'id', hideInSearch: true, width: 120, copyable: true, render: (_, record) => { return record?.id ?? '-'; }, }, { title: '姓名', dataIndex: 'username', hideInSearch: true, render: (_, record) => { // DTO中有first_name和last_name字段,username可能从raw数据中获取 const username = record.username || record.raw?.username || 'N/A'; return (
{username}
{record.first_name} {record.last_name}
); }, }, { title: '邮箱', dataIndex: 'email', copyable: true, }, { title: '电话', dataIndex: 'phone', render: (_, record) => record.phone || record.billing?.phone || record.shipping?.phone || '-', copyable: true, }, { title: '角色', dataIndex: 'role', render: (_, record) => { // 角色信息可能从raw数据中获取,因为DTO中没有这个字段 const role = record.role || record.raw?.role || 'N/A'; return {role}; }, }, { title: '账单地址', dataIndex: 'billing', hideInSearch: true, render: (_, record) => { const { billing } = record; return
; }, }, { title: '物流地址', dataIndex: 'shipping', hideInSearch: true, render: (shipping) => { return
; }, }, { title: '创建时间', dataIndex: 'date_created', valueType: 'dateTime', hideInSearch: true, }, { title: '更新时间', dataIndex: 'date_modified', valueType: 'dateTime', hideInSearch: true, }, { title: '操作', valueType: 'option', width: 120, fixed: 'right', render: (_, record) => ( ), }, ]; return ( { if (!siteId) return { data: [], total: 0, success: true }; const { current, pageSize, name, email, ...rest } = params || {}; const where = { ...rest, ...(filter || {}) }; if (email) { (where as any).email = email; } let orderObj: Record | undefined = undefined; if (sort && typeof sort === 'object') { const [field, dir] = Object.entries(sort)[0] || []; if (field && dir) { orderObj = { [field]: dir === 'descend' ? 'desc' : 'asc' }; } } const response = await request(`/site-api/${siteId}/customers`, { params: { page: current, per_page: pageSize, where, ...(orderObj ? { order: orderObj } : {}), ...(name || email ? { search: name || email } : {}), }, }); if (!response.success) { message.error(response.message || '获取客户列表失败'); return { data: [], total: 0, success: false, }; } const data = response.data; return { total: data?.total || 0, data: data?.items || [], success: true, }; }} toolBarRender={() => [ } /> } onFinish={async (values) => { if (!siteId) return false; const res = await request(`/site-api/${siteId}/customers`, { method: 'POST', data: values, }); if (res.success) { message.success('新增成功'); actionRef.current?.reload(); return true; } message.error(res.message || '新增失败'); return false; }} > , , , 批量导入 } width={600} modalProps={{ destroyOnHidden: true }} onFinish={async (values) => { if (!siteId) return false; const csv = values.csv || ''; const items = values.items || []; const res = await request( `/site-api/${siteId}/customers/import`, { method: 'POST', data: { csv, items } }, ); if (res.success) { message.success('导入完成'); actionRef.current?.reload(); return true; } message.error(res.message || '导入失败'); return false; }} > ,