Files
erp/apps/web/src/pages/settings/NumberingRules.tsx
iven 9568dd7875 chore: apply cargo fmt across workspace and update docs
- Run cargo fmt on all Rust crates for consistent formatting
- Update CLAUDE.md with WASM plugin commands and dev.ps1 instructions
- Update wiki: add WASM plugin architecture, rewrite dev environment docs
- Minor frontend cleanup (unused imports)
2026-04-15 00:49:20 +08:00

285 lines
7.3 KiB
TypeScript

import { useEffect, useState, useCallback } from 'react';
import {
Table,
Button,
Space,
Modal,
Form,
Input,
InputNumber,
Select,
Popconfirm,
message,
Typography,
} from 'antd';
import { PlusOutlined, NumberOutlined } from '@ant-design/icons';
import {
listNumberingRules,
createNumberingRule,
updateNumberingRule,
deleteNumberingRule,
generateNumber,
type NumberingRuleInfo,
type CreateNumberingRuleRequest,
type UpdateNumberingRuleRequest,
} from '../../api/numberingRules';
// --- Types ---
type NumberingRule = NumberingRuleInfo;
// --- Constants ---
const resetCycleOptions = [
{ label: '不重置', value: 'never' },
{ label: '每天', value: 'daily' },
{ label: '每月', value: 'monthly' },
{ label: '每年', value: 'yearly' },
];
const resetCycleLabels: Record<string, string> = {
never: '不重置',
daily: '每天',
monthly: '每月',
yearly: '每年',
};
// --- Component ---
export default function NumberingRules() {
const [rules, setRules] = useState<NumberingRule[]>([]);
const [loading, setLoading] = useState(false);
const [modalOpen, setModalOpen] = useState(false);
const [editRule, setEditRule] = useState<NumberingRule | null>(null);
const [form] = Form.useForm();
const fetchRules = useCallback(async () => {
setLoading(true);
try {
const result = await listNumberingRules();
setRules(Array.isArray(result) ? result : result.data ?? []);
} catch {
message.error('加载编号规则失败');
}
setLoading(false);
}, []);
useEffect(() => {
fetchRules();
}, [fetchRules]);
const handleSubmit = async (values: CreateNumberingRuleRequest) => {
try {
if (editRule) {
await updateNumberingRule(editRule.id, values as UpdateNumberingRuleRequest);
message.success('编号规则更新成功');
} else {
await createNumberingRule(values);
message.success('编号规则创建成功');
}
closeModal();
fetchRules();
} catch (err: unknown) {
const errorMsg =
(err as { response?: { data?: { message?: string } } })?.response?.data
?.message || '操作失败';
message.error(errorMsg);
}
};
const handleDelete = async (id: string) => {
try {
await deleteNumberingRule(id);
message.success('编号规则已删除');
fetchRules();
} catch {
message.error('删除失败');
}
};
const handleGenerate = async (rule: NumberingRule) => {
try {
const result = await generateNumber(rule.id);
message.success(`生成编号: ${result.number}`);
} catch (err: unknown) {
const errorMsg =
(err as { response?: { data?: { message?: string } } })?.response?.data
?.message || '生成编号失败';
message.error(errorMsg);
}
};
const openCreate = () => {
setEditRule(null);
form.resetFields();
form.setFieldsValue({
seq_length: 4,
seq_start: 1,
separator: '-',
reset_cycle: 'never',
});
setModalOpen(true);
};
const openEdit = (rule: NumberingRule) => {
setEditRule(rule);
form.setFieldsValue({
name: rule.name,
code: rule.code,
prefix: rule.prefix,
date_format: rule.date_format,
seq_length: rule.seq_length,
seq_start: rule.seq_start,
separator: rule.separator,
reset_cycle: rule.reset_cycle,
});
setModalOpen(true);
};
const closeModal = () => {
setModalOpen(false);
setEditRule(null);
form.resetFields();
};
const columns = [
{ title: '名称', dataIndex: 'name', key: 'name' },
{ title: '编码', dataIndex: 'code', key: 'code' },
{
title: '前缀',
dataIndex: 'prefix',
key: 'prefix',
render: (v?: string) => v || '-',
},
{
title: '日期格式',
dataIndex: 'date_format',
key: 'date_format',
render: (v?: string) => v || '-',
},
{
title: '序列长度',
dataIndex: 'seq_length',
key: 'seq_length',
width: 90,
},
{
title: '当前值',
dataIndex: 'current_value',
key: 'current_value',
width: 90,
},
{
title: '重置周期',
dataIndex: 'reset_cycle',
key: 'reset_cycle',
width: 100,
render: (v: string) => resetCycleLabels[v] ?? v,
},
{
title: '操作',
key: 'actions',
render: (_: unknown, record: NumberingRule) => (
<Space>
<Button
size="small"
icon={<NumberOutlined />}
onClick={() => handleGenerate(record)}
>
</Button>
<Button size="small" onClick={() => openEdit(record)}>
</Button>
<Popconfirm
title="确定删除此编号规则?"
onConfirm={() => handleDelete(record.id)}
>
<Button size="small" danger>
</Button>
</Popconfirm>
</Space>
),
},
];
return (
<div>
<div
style={{
display: 'flex',
justifyContent: 'space-between',
marginBottom: 16,
}}
>
<Typography.Title level={5} style={{ margin: 0 }}>
</Typography.Title>
<Button type="primary" icon={<PlusOutlined />} onClick={openCreate}>
</Button>
</div>
<Table
columns={columns}
dataSource={rules}
rowKey="id"
loading={loading}
pagination={{ pageSize: 20 }}
/>
<Modal
title={editRule ? '编辑编号规则' : '新建编号规则'}
open={modalOpen}
onCancel={closeModal}
onOk={() => form.submit()}
width={560}
>
<Form form={form} onFinish={handleSubmit} layout="vertical">
<Form.Item
name="name"
label="名称"
rules={[{ required: true, message: '请输入规则名称' }]}
>
<Input />
</Form.Item>
<Form.Item
name="code"
label="编码"
rules={[{ required: true, message: '请输入规则编码' }]}
>
<Input disabled={!!editRule} />
</Form.Item>
<Form.Item name="prefix" label="前缀">
<Input placeholder="如 PO、SO" />
</Form.Item>
<Form.Item name="date_format" label="日期格式">
<Input placeholder="如 YYYYMMDD" />
</Form.Item>
<Form.Item name="separator" label="分隔符">
<Input placeholder="默认 -" />
</Form.Item>
<Form.Item
name="seq_length"
label="序列长度"
rules={[{ required: true, message: '请输入序列长度' }]}
>
<InputNumber min={1} max={20} style={{ width: '100%' }} />
</Form.Item>
<Form.Item name="seq_start" label="起始值" initialValue={1}>
<InputNumber min={1} style={{ width: '100%' }} />
</Form.Item>
<Form.Item
name="reset_cycle"
label="重置周期"
rules={[{ required: true, message: '请选择重置周期' }]}
>
<Select options={resetCycleOptions} />
</Form.Item>
</Form>
</Modal>
</div>
);
}