WEB/src/pages/Site/Shop/Customers/index.tsx

222 lines
7.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { ActionType, DrawerForm, PageContainer, ProColumns, ProFormText, ProTable } from '@ant-design/pro-components';
import { request, useParams } from '@umijs/max';
import { App, Avatar, Button, Popconfirm, Space, Tag } from 'antd';
import React, { useRef, useState } from 'react';
import { DeleteFilled, EditOutlined, PlusOutlined, UserOutlined } from '@ant-design/icons';
const CustomerPage: React.FC = () => {
const { message } = App.useApp();
const { siteId } = useParams<{ siteId: string }>();
const [editing, setEditing] = useState<any>(null);
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
const actionRef = useRef<ActionType>();
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<any>[] = [
{
title: '头像',
dataIndex: 'avatar_url',
hideInSearch: true,
width: 80,
render: (_, record) => {
// 从raw数据中获取头像URL因为DTO中没有这个字段
const avatarUrl = record.raw?.avatar_url || record.avatar_url;
return <Avatar src={avatarUrl} icon={<UserOutlined />} size="large" />;
},
},
{
title: '姓名',
dataIndex: 'username',
render: (_, record) => {
// DTO中有first_name和last_name字段username可能从raw数据中获取
const username = record.username || record.raw?.username || 'N/A';
return (
<div>
<div>{username}</div>
<div style={{ fontSize: 12, color: '#888' }}>
{record.first_name} {record.last_name}
</div>
</div>
);
},
},
{
title: '邮箱',
dataIndex: 'email',
copyable: true,
},
{
title: '角色',
dataIndex: 'role',
render: (_, record) => {
// 角色信息可能从raw数据中获取因为DTO中没有这个字段
const role = record.role || record.raw?.role || 'N/A';
return <Tag color="blue">{role}</Tag>;
},
},
{
title: '账单地址',
dataIndex: 'billing',
hideInSearch: true,
render: (_, record) => {
const { billing } = record;
if (!billing) return '-';
return (
<div style={{ fontSize: 12 }}>
<div>{billing.address_1} {billing.address_2}</div>
<div>{billing.city}, {billing.state}, {billing.postcode}</div>
<div>{billing.country}</div>
<div>{billing.phone}</div>
</div>
);
},
},
{
title: '注册时间',
dataIndex: 'date_created',
valueType: 'dateTime',
hideInSearch: true,
},
{
title: '操作',
valueType: 'option',
width: 120,
render: (_, record) => (
<Space>
<Button type="link" title="编辑" icon={<EditOutlined />} onClick={() => setEditing(record)} />
<Popconfirm title="确定删除?" onConfirm={() => handleDelete(record.id)}>
<Button type="link" danger title="删除" icon={<DeleteFilled />} />
</Popconfirm>
</Space>
),
},
];
return (
<PageContainer
ghost
header={{
title: null,
breadcrumb: undefined
}}
>
<ProTable
rowKey="id"
columns={columns}
search={false}
options={false}
actionRef={actionRef}
rowSelection={{
selectedRowKeys,
onChange: setSelectedRowKeys,
}}
request={async (params) => {
if (!siteId) return { data: [], total: 0, success: true };
const response = await request(`/site-api/${siteId}/customers`, {
params: { page: params.current, per_page: params.pageSize },
});
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={() => [
<DrawerForm
title="新增客户"
trigger={<Button type="primary" title="新增" icon={<PlusOutlined />} />}
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;
}}
>
<ProFormText name="email" label="邮箱" rules={[{ required: true }]} />
<ProFormText name="first_name" label="名" />
<ProFormText name="last_name" label="姓" />
<ProFormText name="username" label="用户名" />
</DrawerForm>,
<Button
title="批量编辑"
icon={<EditOutlined />}
onClick={() => message.info('批量编辑暂未实现')}
/>,
<Button
title="批量删除"
danger
icon={<DeleteFilled />}
onClick={async () => {
if (!siteId) return;
let ok = 0, fail = 0;
for (const id of selectedRowKeys) {
const res = await request(`/site-api/${siteId}/customers/${id}`, { method: 'DELETE' });
if (res.success) ok++; else fail++;
}
message.success(`删除成功 ${ok} 条, 失败 ${fail}`);
actionRef.current?.reload();
setSelectedRowKeys([]);
}}
/>
]}
/>
<DrawerForm
title="编辑客户"
open={!!editing}
onOpenChange={(visible) => !visible && setEditing(null)}
initialValues={editing || {}}
onFinish={async (values) => {
if (!siteId || !editing) return false;
const res = await request(`/site-api/${siteId}/customers/${editing.id}`, { method: 'PUT', data: values });
if (res.success) {
message.success('更新成功');
actionRef.current?.reload();
setEditing(null);
return true;
}
message.error(res.message || '更新失败');
return false;
}}
>
<ProFormText name="email" label="邮箱" rules={[{ required: true }]} />
<ProFormText name="first_name" label="名" />
<ProFormText name="last_name" label="姓" />
<ProFormText name="username" label="用户名" />
</DrawerForm>
</PageContainer>
);
};
export default CustomerPage;