This commit is contained in:
2026-06-26 12:00:08 +08:00
parent faf31c8141
commit 24fac8fc1b
6 changed files with 157 additions and 192 deletions
@@ -1,8 +1,9 @@
import React, { useState, useEffect } from 'react';
import { Table, Button, Tag, Space, Typography, message, Modal } from 'antd';
import { CheckOutlined, DeleteOutlined, EyeOutlined, FilterOutlined } from '@ant-design/icons';
import { Table, Button, Tag, Space, Typography, message, Modal, Card, Popconfirm, Empty } from 'antd';
import { CheckOutlined, DeleteOutlined, EyeOutlined, FilterOutlined, MessageOutlined } from '@ant-design/icons';
import { useAdminStore } from '../store';
import { api } from '../api/client';
import { formatDate } from '../utils/formatDate';
interface ContactRequest {
id: string;
@@ -21,7 +22,7 @@ const AdminContactRequests: React.FC = () => {
const [total, setTotal] = useState(0);
const [loading, setLoading] = useState(false);
const [page, setPage] = useState(1);
const [pageSize, setPageSize] = useState(20);
const [pageSize, setPageSize] = useState(10);
const [isHandledFilter, setIsHandledFilter] = useState<boolean | null>(null);
const [selectedItem, setSelectedItem] = useState<ContactRequest | null>(null);
const [detailModalOpen, setDetailModalOpen] = useState(false);
@@ -63,19 +64,13 @@ const AdminContactRequests: React.FC = () => {
};
const handleDelete = async (id: string) => {
Modal.confirm({
title: '确认删除',
content: '确定要删除这条联系请求吗?',
onOk: async () => {
try {
await api.delete(`/contact/requests/${id}`);
message.success('删除成功');
fetchData();
} catch (err: any) {
message.error(err?.message || '删除失败');
}
},
});
try {
await api.delete(`/contact/requests/${id}`);
message.success('已删除');
fetchData();
} catch (err: any) {
message.error(err?.message || '删除失败');
}
};
const handleViewDetail = (item: ContactRequest) => {
@@ -83,12 +78,18 @@ const AdminContactRequests: React.FC = () => {
setDetailModalOpen(true);
};
const handlePageChange = (p: number, ps: number) => {
setPage(p);
setPageSize(ps);
};
const columns = [
{
title: '姓名',
dataIndex: 'name',
key: 'name',
width: 100,
render: (v: string) => <Typography.Text strong>{v}</Typography.Text>,
},
{
title: '手机号',
@@ -125,95 +126,90 @@ const AdminContactRequests: React.FC = () => {
dataIndex: 'created_at',
key: 'created_at',
width: 160,
render: (date: string) => {
return new Date(date).toLocaleString('zh-CN');
},
render: (date: string) => formatDate(date),
},
{
title: '操作',
key: 'actions',
width: 180,
render: (_: unknown, record: ContactRequest) => (
<Space size="middle">
<Button
type="text"
icon={<EyeOutlined />}
onClick={() => handleViewDetail(record)}
>
<Space size={4}>
<Button type="link" size="small" icon={<EyeOutlined />} onClick={() => handleViewDetail(record)}>
</Button>
{!record.is_handled && (
<Button
type="text"
icon={<CheckOutlined />}
onClick={() => handleMarkHandled(record.id)}
>
<Button type="link" size="small" icon={<CheckOutlined />} onClick={() => handleMarkHandled(record.id)}>
</Button>
)}
<Button
type="text"
danger
icon={<DeleteOutlined />}
onClick={() => handleDelete(record.id)}
>
</Button>
<Popconfirm title="确定删除该记录?" onConfirm={() => handleDelete(record.id)}>
<Button type="link" danger size="small" icon={<DeleteOutlined />}></Button>
</Popconfirm>
</Space>
),
},
];
return (
<div style={{ padding: 24 }}>
<Typography.Title level={2} style={{ marginBottom: 24 }}>
</Typography.Title>
<div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 16 }}>
<div style={{ display: 'flex', gap: 12 }}>
<Button
type={isHandledFilter === null ? 'primary' : 'default'}
onClick={() => setIsHandledFilter(null)}
icon={<FilterOutlined />}
>
</Button>
<Button
type={isHandledFilter === false ? 'primary' : 'default'}
onClick={() => setIsHandledFilter(false)}
>
</Button>
<Button
type={isHandledFilter === true ? 'primary' : 'default'}
onClick={() => setIsHandledFilter(true)}
>
</Button>
<div>
<Card variant="outlined" style={{ borderRadius: 12, border: '1px solid #f0f0f5' }}>
<div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 16 }}>
<Space>
<MessageOutlined style={{ fontSize: 18, color: '#6366f1' }} />
<Typography.Text strong style={{ fontSize: 16 }}></Typography.Text>
<Tag color="purple"> {total} </Tag>
</Space>
<div style={{ display: 'flex', gap: 8 }}>
<Button
type={isHandledFilter === null ? 'primary' : 'default'}
onClick={() => setIsHandledFilter(null)}
icon={<FilterOutlined />}
size="small"
>
</Button>
<Button
type={isHandledFilter === false ? 'primary' : 'default'}
onClick={() => setIsHandledFilter(false)}
size="small"
>
</Button>
<Button
type={isHandledFilter === true ? 'primary' : 'default'}
onClick={() => setIsHandledFilter(true)}
size="small"
>
</Button>
</div>
</div>
<Typography.Text style={{ color: '#64748b' }}>
{total}
</Typography.Text>
</div>
<Table
columns={columns}
dataSource={data}
loading={loading}
pagination={{
current: page,
pageSize,
total,
onChange: (p, s) => { setPage(p); setPageSize(s); },
}}
rowKey="id"
bordered={false}
style={{ background: '#ffffff', borderRadius: 12 }}
/>
{loading ? (
<div style={{ textAlign: 'center', padding: 40 }}>...</div>
) : data.length === 0 ? (
<Empty description="暂无联系请求" style={{ padding: '40px 0' }} />
) : (
<Table
columns={columns}
dataSource={data}
rowKey="id"
loading={loading}
pagination={{
current: page,
pageSize: pageSize,
total: total,
onChange: handlePageChange,
showSizeChanger: true,
showTotal: (t) => `${t} 条记录`,
}}
scroll={{ x: 900 }}
/>
)}
</Card>
<Modal
title="联系请求详情"
title={<Space><EyeOutlined /></Space>}
open={detailModalOpen}
onCancel={() => setDetailModalOpen(false)}
footer={null}
@@ -236,7 +232,7 @@ const AdminContactRequests: React.FC = () => {
<Typography.Text style={{ color: '#64748b' }}></Typography.Text>
<Typography.Text>{selectedItem.industry}</Typography.Text>
<Typography.Text style={{ color: '#64748b' }}></Typography.Text>
<Typography.Text>{new Date(selectedItem.created_at).toLocaleString('zh-CN')}</Typography.Text>
<Typography.Text>{formatDate(selectedItem.created_at)}</Typography.Text>
{selectedItem.message && (
<>
<Typography.Text style={{ color: '#64748b' }}></Typography.Text>