2025-06-20 02:33:53 +08:00

308 lines
8.5 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 { useEffect, useState } from 'react';
import { Modal, Table, Form, Input, Button, Space, Select, DatePicker, message, Popconfirm } from 'antd';
import { SearchOutlined, PlusOutlined, EditOutlined, DeleteOutlined } from '@ant-design/icons';
import { useTicketStore } from '@/store';
import type { Ticket as TicketType } from '@/pages/define/type';
import type { ColumnsType } from 'antd/es/table';
import dayjs from 'dayjs';
export const Ticket = () => {
const [searchForm] = Form.useForm();
const store = useTicketStore();
useEffect(() => {
fetchTickets();
}, [store.searchForm]);
const fetchTickets = async () => {
try {
store.setLoading(true);
await store.getTickets(store.searchForm);
} catch (error) {
message.error('获取票据列表失败');
} finally {
store.setLoading(false);
}
};
const handleSearch = async (values: any) => {
store.setSearchForm({
...store.searchForm,
...values,
current: 1,
startDate: values.dateRange?.[0]?.format('YYYY-MM-DD'),
endDate: values.dateRange?.[1]?.format('YYYY-MM-DD'),
});
};
const handleReset = () => {
searchForm.resetFields();
store.setSearchForm({
current: 1,
pageSize: 10,
});
};
const handleAdd = () => {
store.setFormData(null);
store.setShowEdit(true);
};
const handleEdit = (record: TicketType) => {
store.setFormData(record);
store.setShowEdit(true);
};
const handleDelete = async (id: string) => {
try {
store.setLoading(true);
await store.deleteTicket(id);
} catch (error) {
} finally {
store.setLoading(false);
}
};
const columns: ColumnsType<TicketType> = [
{
title: 'ID',
dataIndex: 'id',
key: 'id',
width: 320,
},
{
title: '类型',
dataIndex: 'type',
key: 'type',
width: 120,
},
{
title: '标题',
dataIndex: 'title',
key: 'title',
width: 200,
},
{
title: '描述',
dataIndex: 'description',
key: 'description',
ellipsis: true,
},
{
title: '状态',
dataIndex: 'status',
key: 'status',
width: 100,
},
{
title: '价格',
dataIndex: 'price',
key: 'price',
width: 100,
},
{
title: '创建时间',
dataIndex: 'createdAt',
key: 'createdAt',
width: 180,
render: (text) => (text ? dayjs(text).format('YYYY-MM-DD HH:mm') : '-'),
},
{
title: '更新时间',
dataIndex: 'updatedAt',
key: 'updatedAt',
width: 180,
render: (text) => (text ? dayjs(text).format('YYYY-MM-DD HH:mm') : '-'),
},
{
title: '操作',
key: 'action',
width: 150,
render: (_, record) => (
<Space size='middle'>
<Button type='text' icon={<EditOutlined />} onClick={() => handleEdit(record)} />
<Popconfirm title='确定要删除这条记录吗?' onConfirm={() => handleDelete(record.id)} okText='确定' cancelText='取消'>
<Button type='text' danger icon={<DeleteOutlined />} />
</Popconfirm>
</Space>
),
},
];
return (
<div className='ticket-container p-4 h-full overflow-auto scrollbar'>
<h1></h1>
{/* 搜索表单 */}
<div className='search-form-container' style={{ marginBottom: 16, padding: 16, background: '#f9f9f9', borderRadius: 4 }}>
<Form form={searchForm} layout='inline' onFinish={handleSearch}>
<Form.Item name='search' label='关键词'>
<Input placeholder='标题/描述' allowClear />
</Form.Item>
<Form.Item name='type' label='类型'>
<Select
placeholder='选择类型'
allowClear
style={{ width: 120 }}
options={[
{ value: 'type1', label: '类型1' },
{ value: 'type2', label: '类型2' },
]}
/>
</Form.Item>
<Form.Item name='status' label='状态'>
<Select
placeholder='选择状态'
allowClear
style={{ width: 120 }}
options={[
{ value: 'rule', label: '规则' },
{ value: 'people', label: '人工' },
]}
/>
</Form.Item>
<Form.Item name='dateRange' label='日期范围'>
<DatePicker.RangePicker />
</Form.Item>
<Form.Item>
<Space>
<Button type='primary' htmlType='submit' icon={<SearchOutlined />}>
</Button>
<Button onClick={handleReset}></Button>
</Space>
</Form.Item>
</Form>
</div>
{/* 操作按钮 */}
<div style={{ marginBottom: 16 }}>
<Button type='primary' icon={<PlusOutlined />} onClick={handleAdd}>
</Button>
</div>
{/* 表格 */}
<Table
columns={columns}
dataSource={store.tickets}
rowKey='id'
loading={store.loading}
pagination={{
...store.pagination,
current: store.searchForm.current,
pageSize: store.searchForm.pageSize,
onChange: (page, pageSize) => {
store.setSearchForm({
...store.searchForm,
current: page,
pageSize,
});
},
showSizeChanger: true,
showQuickJumper: true,
showTotal: (total) => `${total}`,
}}
/>
{/* 引入弹窗表单组件 */}
<TicketModelForm />
</div>
);
};
export const TicketModelForm = () => {
const [form] = Form.useForm();
const store = useTicketStore();
const isEdit = !!store.formData?.id;
useEffect(() => {
if (!store.showEdit) {
return;
}
if (store.formData) {
form.setFieldsValue(store.formData);
} else {
// form.resetFields();
form.setFieldsValue({ title: '', type: '', status: '', price: '', description: '' });
}
}, [store.showEdit, store.formData, form]);
const handleSubmit = async () => {
try {
const values = await form.validateFields();
store.setLoading(true);
if (isEdit) {
// 编辑模式
await store.updateTicket({
...store.formData,
...values,
});
} else {
// 新增模式 - 假设后端会生成ID这里模拟API调用
const newTicket = {
...values,
};
// 这里应该是一个创建票据的API调用
// 暂时使用更新方法模拟
await store.updateTicket(newTicket as TicketType);
}
// 关闭弹窗并刷新列表
store.setShowEdit(false);
store.getTickets(store.searchForm);
} catch (error) {
console.error('表单提交错误:', error);
message.error('操作失败,请检查表单');
} finally {
store.setLoading(false);
}
};
return (
<Modal
title={isEdit ? '编辑票据' : '新增票据'}
open={store.showEdit}
onCancel={() => store.setShowEdit(false)}
onOk={handleSubmit}
confirmLoading={store.loading}
maskClosable={false}>
<Form form={form} layout='vertical' initialValues={store.formData || {}}>
<Form.Item name='title' label='标题' rules={[{ required: true, message: '请输入标题' }]}>
<Input placeholder='请输入标题' />
</Form.Item>
<Form.Item name='type' label='类型' rules={[{ required: true, message: '请选择类型' }]}>
<Select
placeholder='请选择类型'
options={[
{ value: 'type1', label: '类型1' },
{ value: 'type2', label: '类型2' },
]}
/>
</Form.Item>
<Form.Item name='status' label='状态' rules={[{ required: true, message: '请选择状态' }]}>
<Select
placeholder='请选择状态'
options={[
{ value: 'rule', label: '规则' },
{ value: 'people', label: '人工' },
]}
/>
</Form.Item>
<Form.Item name='price' label='价格' rules={[{ required: true, message: '请输入价格' }]}>
<Input placeholder='请输入价格' />
</Form.Item>
<Form.Item name='description' label='描述' rules={[{ required: true, message: '请输入描述' }]}>
<Input.TextArea rows={4} placeholder='请输入描述' />
</Form.Item>
</Form>
</Modal>
);
};