备份:PWA配置前的完整版本
包含所有最新开发的功能和修复,作为PWA正确配置前的备份点。
This commit is contained in:
@@ -1,196 +1,201 @@
|
||||
import React, { useCallback } from 'react';
|
||||
import { Card, Typography, Button, Table, Tag, Space, Modal, Form, Input, Select, DatePicker, InputNumber, message, Row, Col, Statistic } from 'antd';
|
||||
import { PlusOutlined, SearchOutlined, ShoppingOutlined } from '@ant-design/icons';
|
||||
import useFormDraft from '../hooks/useFormDraft';
|
||||
|
||||
const { Title, Paragraph } = Typography;
|
||||
const { RangePicker } = DatePicker;
|
||||
|
||||
const ProcurementPage: React.FC = () => {
|
||||
const [loading, setLoading] = React.useState(false);
|
||||
const [modalVisible, setModalVisible] = React.useState(false);
|
||||
const [form] = Form.useForm();
|
||||
|
||||
// 表单草稿保护
|
||||
const { save: saveDraft, restore: restoreDraft, clear: clearDraft, hasDraft } = useFormDraft({
|
||||
form,
|
||||
storageKey: 'procurement_create',
|
||||
})
|
||||
|
||||
const handleFormChange = useCallback(() => {
|
||||
saveDraft()
|
||||
}, [saveDraft])
|
||||
|
||||
const columns = [
|
||||
{ title: '采购单号', dataIndex: 'code', key: 'code', width: 140 },
|
||||
{ title: '采购日期', dataIndex: 'date', key: 'date', width: 120 },
|
||||
{ title: '供应商', dataIndex: 'supplier', key: 'supplier' },
|
||||
{ title: '物料名称', dataIndex: 'material', key: 'material' },
|
||||
{ title: '数量', dataIndex: 'quantity', key: 'quantity', width: 80 },
|
||||
{ title: '单价', dataIndex: 'unitPrice', key: 'unitPrice', width: 100, render: (v: number) => `¥${v}` },
|
||||
{ title: '总金额', dataIndex: 'amount', key: 'amount', width: 120, render: (v: number) => `¥${v?.toLocaleString()}` },
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
key: 'status',
|
||||
width: 100,
|
||||
render: (v: string) => {
|
||||
const colors: Record<string, string> = {
|
||||
pending: 'default',
|
||||
approved: 'processing',
|
||||
received: 'success',
|
||||
rejected: 'error'
|
||||
};
|
||||
const texts: Record<string, string> = {
|
||||
pending: '待审批',
|
||||
approved: '已批准',
|
||||
received: '已入库',
|
||||
rejected: '已拒绝'
|
||||
};
|
||||
return <Tag color={colors[v]}>{texts[v]}</Tag>;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: 150,
|
||||
render: () => (
|
||||
<Space>
|
||||
<Button size="small" type="link">查看</Button>
|
||||
<Button size="small" type="link">审批</Button>
|
||||
</Space>
|
||||
)
|
||||
}
|
||||
];
|
||||
|
||||
const data = [
|
||||
{ key: '1', code: 'PO20260318001', date: '2026-03-18', supplier: '老挝电力设备公司', material: '电缆 3x120', quantity: 1000, unitPrice: 45, amount: 45000, status: 'pending' },
|
||||
{ key: '2', code: 'PO20260317002', date: '2026-03-17', supplier: '万象建材供应商', material: '钢管 DN50', quantity: 200, unitPrice: 120, amount: 24000, status: 'approved' },
|
||||
{ key: '3', code: 'PO20260316003', date: '2026-03-16', supplier: '沙湾五金店', material: '螺栓 M12', quantity: 500, unitPrice: 5, amount: 2500, status: 'received' },
|
||||
];
|
||||
|
||||
const handleSubmit = () => {
|
||||
message.success('采购申请已提交');
|
||||
clearDraft()
|
||||
setModalVisible(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{ padding: 24 }}>
|
||||
<div style={{ marginBottom: 24, display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||||
<div>
|
||||
<Title level={3} style={{ marginBottom: 0 }}>采购管理</Title>
|
||||
<Paragraph type="secondary">管理采购订单和物料入库</Paragraph>
|
||||
</div>
|
||||
<Space>
|
||||
<RangePicker placeholder={['开始日期', '结束日期']} />
|
||||
<Input.Search placeholder="搜索采购单号" style={{ width: 200 }} />
|
||||
<Button type="primary" icon={<PlusOutlined />} onClick={() => {
|
||||
setModalVisible(true)
|
||||
// 检查是否有草稿,提示用户是否恢复
|
||||
setTimeout(() => {
|
||||
if (hasDraft()) {
|
||||
Modal.confirm({
|
||||
title: '发现未完成的草稿',
|
||||
content: '检测到上次未提交的采购信息,是否恢复?',
|
||||
okText: '恢复草稿',
|
||||
cancelText: '重新填写',
|
||||
onOk: () => {
|
||||
restoreDraft()
|
||||
},
|
||||
onCancel: () => {
|
||||
clearDraft()
|
||||
form.resetFields()
|
||||
},
|
||||
})
|
||||
}
|
||||
}, 0)
|
||||
}}>
|
||||
新建采购
|
||||
</Button>
|
||||
</Space>
|
||||
</div>
|
||||
|
||||
<Row gutter={16} style={{ marginBottom: 24 }}>
|
||||
<Col xs={24} sm={12} md={6}>
|
||||
<Card>
|
||||
<Statistic title="待审批" value={5} prefix={<ShoppingOutlined />} />
|
||||
</Card>
|
||||
</Col>
|
||||
<Col xs={24} sm={12} md={6}>
|
||||
<Card>
|
||||
<Statistic title="已批准" value={12} valueStyle={{ color: '#1890ff' }} />
|
||||
</Card>
|
||||
</Col>
|
||||
<Col xs={24} sm={12} md={6}>
|
||||
<Card>
|
||||
<Statistic title="已入库" value={28} valueStyle={{ color: '#52c41a' }} />
|
||||
</Card>
|
||||
</Col>
|
||||
<Col xs={24} sm={12} md={6}>
|
||||
<Card>
|
||||
<Statistic title="本月采购额" value={156000} prefix="¥" />
|
||||
</Card>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<Card>
|
||||
<Table columns={columns} dataSource={data} loading={loading} pagination={{ pageSize: 10 }} scroll={{ x: 1200 }} />
|
||||
</Card>
|
||||
|
||||
<Modal
|
||||
title="新建采购申请"
|
||||
open={modalVisible}
|
||||
onCancel={() => {
|
||||
if (form.isFieldsTouched()) {
|
||||
Modal.confirm({
|
||||
title: '确认关闭',
|
||||
content: '表单数据尚未保存,关闭后可通过草稿恢复。确定关闭吗?',
|
||||
okText: '关闭',
|
||||
cancelText: '继续编辑',
|
||||
onOk: () => {
|
||||
saveDraft()
|
||||
setModalVisible(false)
|
||||
},
|
||||
})
|
||||
} else {
|
||||
setModalVisible(false)
|
||||
}
|
||||
}}
|
||||
onOk={handleSubmit}
|
||||
width={600}
|
||||
maskClosable={false}
|
||||
>
|
||||
<Form form={form} layout="vertical" onValuesChange={handleFormChange}>
|
||||
<Form.Item label="供应商" name="supplier" rules={[{ required: true }]}>
|
||||
<Select placeholder="选择供应商" options={[
|
||||
{ value: 'supplier1', label: '老挝电力设备公司' },
|
||||
{ value: 'supplier2', label: '万象建材供应商' },
|
||||
{ value: 'supplier3', label: '沙湾五金店' }
|
||||
]} />
|
||||
</Form.Item>
|
||||
<Form.Item label="物料名称" name="material" rules={[{ required: true }]}>
|
||||
<Input placeholder="请输入物料名称" />
|
||||
</Form.Item>
|
||||
<Row gutter={16}>
|
||||
<Col span={12}>
|
||||
<Form.Item label="数量" name="quantity" rules={[{ required: true }]}>
|
||||
<InputNumber style={{ width: '100%' }} min={1} />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<Form.Item label="单价" name="unitPrice" rules={[{ required: true }]}>
|
||||
<InputNumber style={{ width: '100%' }} min={0} precision={2} prefix="¥" />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
</Row>
|
||||
<Form.Item label="备注" name="remark">
|
||||
<Input.TextArea rows={3} placeholder="请输入备注说明" />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Modal>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProcurementPage;
|
||||
import React, { useCallback } from 'react';
|
||||
import { Card, Typography, Button, Table, Tag, Space, Modal, Form, Input, Select, DatePicker, InputNumber, message, Row, Col, Statistic } from 'antd';
|
||||
import { PlusOutlined, SearchOutlined, ShoppingOutlined } from '@ant-design/icons';
|
||||
import useFormDraft from '../hooks/useFormDraft';
|
||||
import { useLanguageStore } from '../store/languageStore';
|
||||
|
||||
const { Title, Paragraph } = Typography;
|
||||
const { RangePicker } = DatePicker;
|
||||
|
||||
const ProcurementPage: React.FC = () => {
|
||||
const { t, currentLanguage } = useLanguageStore();
|
||||
const [loading, setLoading] = React.useState(false);
|
||||
const [modalVisible, setModalVisible] = React.useState(false);
|
||||
const [form] = Form.useForm();
|
||||
|
||||
// 表单草稿保护
|
||||
const { save: saveDraft, restore: restoreDraft, clear: clearDraft, hasDraft } = useFormDraft({
|
||||
form,
|
||||
storageKey: 'procurement_create',
|
||||
})
|
||||
|
||||
const handleFormChange = useCallback(() => {
|
||||
saveDraft()
|
||||
}, [saveDraft])
|
||||
|
||||
const columns = [
|
||||
{ title: t('procurement.orderCode'), dataIndex: 'code', key: 'code', width: 140 },
|
||||
{ title: t('procurement.purchaseDate'), dataIndex: 'date', key: 'date', width: 120 },
|
||||
{ title: t('procurement.supplier'), dataIndex: 'supplier', key: 'supplier' },
|
||||
{ title: t('procurement.materialName'), dataIndex: 'material', key: 'material' },
|
||||
{ title: t('procurement.quantity'), dataIndex: 'quantity', key: 'quantity', width: 80 },
|
||||
{ title: t('procurement.unitPrice'), dataIndex: 'unitPrice', key: 'unitPrice', width: 100, render: (v: number) => `¥${v}` },
|
||||
{ title: t('procurement.totalAmount'), dataIndex: 'amount', key: 'amount', width: 120, render: (v: number) => `¥${v?.toLocaleString()}` },
|
||||
{
|
||||
title: t('procurement.status'),
|
||||
dataIndex: 'status',
|
||||
key: 'status',
|
||||
width: 100,
|
||||
render: (v: string) => {
|
||||
const colors: Record<string, string> = {
|
||||
pending: 'default',
|
||||
approved: 'processing',
|
||||
received: 'success',
|
||||
rejected: 'error'
|
||||
};
|
||||
const texts: Record<string, string> = {
|
||||
pending: t('procurement.pendingApproval'),
|
||||
approved: t('procurement.approved'),
|
||||
received: t('procurement.stocked'),
|
||||
rejected: t('procurement.rejected')
|
||||
};
|
||||
return <Tag color={colors[v]}>{texts[v]}</Tag>;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: t('procurement.action'),
|
||||
key: 'action',
|
||||
width: 150,
|
||||
render: () => (
|
||||
<Space>
|
||||
<Button size="small" type="link">{t('procurement.view')}</Button>
|
||||
<Button size="small" type="link">{t('procurement.approve')}</Button>
|
||||
</Space>
|
||||
)
|
||||
}
|
||||
];
|
||||
|
||||
const data = [
|
||||
{ key: '1', code: 'PO20260318001', date: '2026-03-18', supplier: '老挝电力设备公司', material: '电缆 3x120', quantity: 1000, unitPrice: 45, amount: 45000, status: 'pending' },
|
||||
{ key: '2', code: 'PO20260317002', date: '2026-03-17', supplier: '万象建材供应商', material: '钢管 DN50', quantity: 200, unitPrice: 120, amount: 24000, status: 'approved' },
|
||||
{ key: '3', code: 'PO20260316003', date: '2026-03-16', supplier: '沙湾五金店', material: '螺栓 M12', quantity: 500, unitPrice: 5, amount: 2500, status: 'received' },
|
||||
];
|
||||
|
||||
const handleSubmit = () => {
|
||||
message.success(t('procurement.submitSuccess'));
|
||||
clearDraft()
|
||||
setModalVisible(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{ padding: 24 }}>
|
||||
<div style={{ marginBottom: 24, display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||||
<div>
|
||||
<Title level={3} style={{ marginBottom: 0 }}>{t('procurement.title')}</Title>
|
||||
<Paragraph type="secondary">{t('procurement.description')}</Paragraph>
|
||||
</div>
|
||||
<Space>
|
||||
<RangePicker placeholder={[t('procurement.startDate'), t('procurement.endDate')]} />
|
||||
<Input.Search placeholder={t('procurement.searchOrder')} style={{ width: 200 }} />
|
||||
<Button type="primary" icon={<PlusOutlined />} onClick={() => {
|
||||
setModalVisible(true)
|
||||
// 检查是否有草稿,提示用户是否恢复
|
||||
setTimeout(() => {
|
||||
if (hasDraft()) {
|
||||
Modal.confirm({
|
||||
title: t('common.draftFound'),
|
||||
content: t('common.draftRestore'),
|
||||
okText: t('common.restoreDraft'),
|
||||
cancelText: t('common.reFill'),
|
||||
onOk: () => {
|
||||
restoreDraft()
|
||||
},
|
||||
onCancel: () => {
|
||||
clearDraft()
|
||||
form.resetFields()
|
||||
},
|
||||
})
|
||||
}
|
||||
}, 0)
|
||||
}}>
|
||||
{t('procurement.newProcurement')}
|
||||
</Button>
|
||||
</Space>
|
||||
</div>
|
||||
|
||||
<Row gutter={16} style={{ marginBottom: 24 }}>
|
||||
<Col xs={24} sm={12} md={6}>
|
||||
<Card>
|
||||
<Statistic title={t('procurement.pendingApproval')} value={5} prefix={<ShoppingOutlined />} />
|
||||
</Card>
|
||||
</Col>
|
||||
<Col xs={24} sm={12} md={6}>
|
||||
<Card>
|
||||
<Statistic title={t('procurement.approved')} value={12} valueStyle={{ color: '#1890ff' }} />
|
||||
</Card>
|
||||
</Col>
|
||||
<Col xs={24} sm={12} md={6}>
|
||||
<Card>
|
||||
<Statistic title={t('procurement.stocked')} value={28} valueStyle={{ color: '#52c41a' }} />
|
||||
</Card>
|
||||
</Col>
|
||||
<Col xs={24} sm={12} md={6}>
|
||||
<Card>
|
||||
<Statistic title={t('procurement.monthPurchase')} value={156000} prefix="¥" />
|
||||
</Card>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<Card>
|
||||
<Table columns={columns} dataSource={data} loading={loading} pagination={{ pageSize: 10 }} scroll={{ x: 1200 }} />
|
||||
</Card>
|
||||
|
||||
<Modal
|
||||
title={t('procurement.newApplication')}
|
||||
open={modalVisible}
|
||||
onCancel={() => {
|
||||
if (form.isFieldsTouched()) {
|
||||
Modal.confirm({
|
||||
title: t('common.closeConfirm'),
|
||||
content: t('common.closeConfirmMsg'),
|
||||
okText: t('common.close'),
|
||||
cancelText: t('common.continueEdit'),
|
||||
onOk: () => {
|
||||
saveDraft()
|
||||
form.resetFields()
|
||||
setModalVisible(false)
|
||||
},
|
||||
})
|
||||
} else {
|
||||
form.resetFields()
|
||||
setModalVisible(false)
|
||||
}
|
||||
}}
|
||||
onOk={handleSubmit}
|
||||
destroyOnClose
|
||||
width={600}
|
||||
maskClosable={false}
|
||||
>
|
||||
<Form form={form} layout="vertical" onValuesChange={handleFormChange}>
|
||||
<Form.Item label={t('procurement.supplier')} name="supplier" rules={[{ required: true }]}>
|
||||
<Select placeholder={t('procurement.selectSupplier')} options={[
|
||||
{ value: 'supplier1', label: '老挝电力设备公司' },
|
||||
{ value: 'supplier2', label: '万象建材供应商' },
|
||||
{ value: 'supplier3', label: '沙湾五金店' }
|
||||
]} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t('procurement.materialName')} name="material" rules={[{ required: true }]}>
|
||||
<Input placeholder={t('procurement.inputMaterialName')} />
|
||||
</Form.Item>
|
||||
<Row gutter={16}>
|
||||
<Col span={12}>
|
||||
<Form.Item label={t('procurement.quantity')} name="quantity" rules={[{ required: true }]}>
|
||||
<InputNumber style={{ width: '100%' }} min={1} />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<Form.Item label={t('procurement.unitPrice')} name="unitPrice" rules={[{ required: true }]}>
|
||||
<InputNumber style={{ width: '100%' }} min={0} precision={2} prefix="¥" />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
</Row>
|
||||
<Form.Item label={t('procurement.remark')} name="remark">
|
||||
<Input.TextArea rows={3} placeholder={t('procurement.remarkPlaceholder')} />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Modal>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProcurementPage;
|
||||
Reference in New Issue
Block a user