- 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)
285 lines
7.3 KiB
TypeScript
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>
|
|
);
|
|
}
|