448 lines
13 KiB
TypeScript
448 lines
13 KiB
TypeScript
import { UploadOutlined } from '@ant-design/icons';
|
|
import { PageContainer } from '@ant-design/pro-components';
|
|
import { request } from '@umijs/max';
|
|
import {
|
|
Button,
|
|
Form,
|
|
Input,
|
|
Layout,
|
|
Modal,
|
|
Space,
|
|
Table,
|
|
Upload,
|
|
message,
|
|
} from 'antd';
|
|
import React, { useEffect, useState } from 'react';
|
|
|
|
const { Sider, Content } = Layout;
|
|
|
|
const DictPage: React.FC = () => {
|
|
// 左侧字典列表的状态
|
|
const [dicts, setDicts] = useState<any[]>([]);
|
|
const [loadingDicts, setLoadingDicts] = useState(false);
|
|
const [searchText, setSearchText] = useState('');
|
|
const [selectedDict, setSelectedDict] = useState<any>(null);
|
|
|
|
// 右侧字典项列表的状态
|
|
const [dictItems, setDictItems] = useState<any[]>([]);
|
|
const [loadingDictItems, setLoadingDictItems] = useState(false);
|
|
|
|
// 控制添加字典模态框的显示
|
|
const [isAddDictModalVisible, setIsAddDictModalVisible] = useState(false);
|
|
const [newDictName, setNewDictName] = useState('');
|
|
const [newDictTitle, setNewDictTitle] = useState('');
|
|
const [editingDict, setEditingDict] = useState<any>(null);
|
|
|
|
// 控制字典项模态框的显示
|
|
const [isDictItemModalVisible, setIsDictItemModalVisible] = useState(false);
|
|
const [editingDictItem, setEditingDictItem] = useState<any>(null);
|
|
const [dictItemForm, setDictItemForm] = useState({
|
|
name: '',
|
|
title: '',
|
|
value: '',
|
|
});
|
|
|
|
// 获取字典列表
|
|
const fetchDicts = async (title?: string) => {
|
|
setLoadingDicts(true);
|
|
try {
|
|
const res = await request('/dict/list', { params: { title } });
|
|
if (res) {
|
|
setDicts(res);
|
|
}
|
|
} catch (error) {
|
|
message.error('获取字典列表失败');
|
|
}
|
|
setLoadingDicts(false);
|
|
};
|
|
|
|
// 获取字典项列表
|
|
const fetchDictItems = async (dictId?: number) => {
|
|
setLoadingDictItems(true);
|
|
try {
|
|
const res = await request('/dict/items', { params: { dictId } });
|
|
if (res) {
|
|
setDictItems(res);
|
|
}
|
|
} catch (error) {
|
|
message.error('获取字典项列表失败');
|
|
}
|
|
setLoadingDictItems(false);
|
|
};
|
|
|
|
// 组件加载时获取数据
|
|
useEffect(() => {
|
|
fetchDicts();
|
|
fetchDictItems();
|
|
}, []);
|
|
|
|
// 当选择的字典变化时,重新获取字典项
|
|
useEffect(() => {
|
|
fetchDictItems(selectedDict?.id);
|
|
}, [selectedDict]);
|
|
|
|
// 处理字典搜索
|
|
const handleSearch = (value: string) => {
|
|
fetchDicts(value);
|
|
};
|
|
|
|
// 处理添加字典
|
|
const handleAddDict = async () => {
|
|
if (!newDictName || !newDictTitle) {
|
|
message.warning('请输入字典名称和标题');
|
|
return;
|
|
}
|
|
try {
|
|
if (editingDict) {
|
|
await request(`/dict/${editingDict.id}`, {
|
|
method: 'PUT',
|
|
data: { name: newDictName, title: newDictTitle },
|
|
});
|
|
message.success('更新成功');
|
|
} else {
|
|
await request('/dict', {
|
|
method: 'POST',
|
|
data: { name: newDictName, title: newDictTitle },
|
|
});
|
|
message.success('添加成功');
|
|
}
|
|
setIsAddDictModalVisible(false);
|
|
setNewDictName('');
|
|
setNewDictTitle('');
|
|
setEditingDict(null);
|
|
fetchDicts(); // 重新获取字典列表
|
|
} catch (error) {
|
|
message.error(editingDict ? '更新失败' : '添加失败');
|
|
}
|
|
};
|
|
|
|
const handleEditDict = (dict: any) => {
|
|
setEditingDict(dict);
|
|
setNewDictName(dict.name);
|
|
setNewDictTitle(dict.title);
|
|
setIsAddDictModalVisible(true);
|
|
};
|
|
|
|
// 打开添加字典项模态框
|
|
const handleAddDictItem = () => {
|
|
setEditingDictItem(null);
|
|
setDictItemForm({ name: '', title: '', value: '' });
|
|
setIsDictItemModalVisible(true);
|
|
};
|
|
|
|
// 打开编辑字典项模态框
|
|
const handleEditDictItem = (item: any) => {
|
|
setEditingDictItem(item);
|
|
setDictItemForm(item);
|
|
setIsDictItemModalVisible(true);
|
|
};
|
|
|
|
// 处理字典项表单提交(添加/编辑)
|
|
const handleDictItemFormSubmit = async () => {
|
|
if (!dictItemForm.name || !dictItemForm.title) {
|
|
message.warning('请输入名称和标题');
|
|
return;
|
|
}
|
|
try {
|
|
if (editingDictItem) {
|
|
// 编辑
|
|
await request(`/dict/item/${editingDictItem.id}`, {
|
|
method: 'PUT',
|
|
data: dictItemForm,
|
|
});
|
|
message.success('更新成功');
|
|
} else {
|
|
// 添加
|
|
await request('/dict/item', {
|
|
method: 'POST',
|
|
data: { ...dictItemForm, dictId: selectedDict.id },
|
|
});
|
|
message.success('添加成功');
|
|
}
|
|
setIsDictItemModalVisible(false);
|
|
fetchDictItems(selectedDict.id);
|
|
} catch (error) {
|
|
message.error(editingDictItem ? '更新失败' : '添加失败');
|
|
}
|
|
};
|
|
|
|
// 处理删除字典项
|
|
const handleDeleteDictItem = async (itemId: number) => {
|
|
try {
|
|
await request(`/dict/item/${itemId}`, { method: 'DELETE' });
|
|
message.success('删除成功');
|
|
fetchDictItems(selectedDict.id);
|
|
} catch (error) {
|
|
message.error('删除失败');
|
|
}
|
|
};
|
|
|
|
// 处理删除字典
|
|
const handleDeleteDict = async (dictId: number) => {
|
|
try {
|
|
await request(`/dict/${dictId}`, { method: 'DELETE' });
|
|
message.success('删除成功');
|
|
fetchDicts(); // 重新获取字典列表
|
|
// 如果删除的是当前选中的字典,则清空右侧列表
|
|
if (selectedDict?.id === dictId) {
|
|
setSelectedDict(null);
|
|
setDictItems([]);
|
|
}
|
|
} catch (error) {
|
|
message.error('删除失败');
|
|
}
|
|
};
|
|
|
|
// 左侧字典列表的列定义
|
|
const dictColumns = [
|
|
{
|
|
title: '名称',
|
|
dataIndex: 'name',
|
|
key: 'name',
|
|
},
|
|
{
|
|
title: '标题',
|
|
dataIndex: 'title',
|
|
key: 'title',
|
|
},
|
|
{
|
|
title: '操作',
|
|
key: 'action',
|
|
render: (_: any, record: any) => (
|
|
<Space>
|
|
<Button
|
|
type="link"
|
|
onClick={(e) => {
|
|
e.stopPropagation();
|
|
handleEditDict(record);
|
|
}}
|
|
>
|
|
编辑
|
|
</Button>
|
|
<Button
|
|
type="link"
|
|
danger
|
|
onClick={(e) => {
|
|
e.stopPropagation();
|
|
handleDeleteDict(record.id);
|
|
}}
|
|
>
|
|
删除
|
|
</Button>
|
|
</Space>
|
|
),
|
|
},
|
|
];
|
|
|
|
// 右侧字典项列表的列定义
|
|
const dictItemColumns = [
|
|
{
|
|
title: '名称',
|
|
dataIndex: 'name',
|
|
key: 'name',
|
|
},
|
|
{
|
|
title: '标题',
|
|
dataIndex: 'title',
|
|
key: 'title',
|
|
},
|
|
{
|
|
title: '操作',
|
|
key: 'action',
|
|
render: (_: any, record: any) => (
|
|
<Space size="middle">
|
|
<Button type="link" onClick={() => handleEditDictItem(record)}>
|
|
编辑
|
|
</Button>
|
|
<Button
|
|
type="link"
|
|
danger
|
|
onClick={() => handleDeleteDictItem(record.id)}
|
|
>
|
|
删除
|
|
</Button>
|
|
</Space>
|
|
),
|
|
},
|
|
];
|
|
|
|
return (
|
|
<PageContainer>
|
|
<Layout style={{ background: '#fff' }}>
|
|
<Sider
|
|
width={300}
|
|
style={{
|
|
background: '#fff',
|
|
padding: '16px',
|
|
borderRight: '1px solid #f0f0f0',
|
|
}}
|
|
>
|
|
<Space direction="vertical" style={{ width: '100%' }}>
|
|
<Input.Search
|
|
placeholder="搜索字典"
|
|
onSearch={handleSearch}
|
|
onChange={(e) => setSearchText(e.target.value)}
|
|
enterButton
|
|
allowClear
|
|
/>
|
|
<Button
|
|
type="primary"
|
|
onClick={() => setIsAddDictModalVisible(true)}
|
|
block
|
|
>
|
|
添加字典
|
|
</Button>
|
|
<Space>
|
|
<Upload
|
|
name="file"
|
|
action="/dict/import"
|
|
showUploadList={false}
|
|
onChange={(info) => {
|
|
if (info.file.status === 'done') {
|
|
message.success(`${info.file.name} 文件上传成功`);
|
|
fetchDicts();
|
|
} else if (info.file.status === 'error') {
|
|
message.error(`${info.file.name} 文件上传失败`);
|
|
}
|
|
}}
|
|
>
|
|
<Button icon={<UploadOutlined />}>导入字典</Button>
|
|
</Upload>
|
|
<Button onClick={() => window.open('/dict/template')}>
|
|
下载模板
|
|
</Button>
|
|
</Space>
|
|
<Table
|
|
dataSource={dicts}
|
|
columns={dictColumns}
|
|
rowKey="id"
|
|
loading={loadingDicts}
|
|
onRow={(record) => ({
|
|
onClick: () => {
|
|
// 如果点击的是当前已选中的行,则取消选择
|
|
if (selectedDict?.id === record.id) {
|
|
setSelectedDict(null);
|
|
} else {
|
|
setSelectedDict(record);
|
|
}
|
|
},
|
|
})}
|
|
rowClassName={(record) =>
|
|
selectedDict?.id === record.id ? 'ant-table-row-selected' : ''
|
|
}
|
|
pagination={false}
|
|
/>
|
|
</Space>
|
|
</Sider>
|
|
<Content style={{ padding: '16px' }}>
|
|
<Space direction="vertical" style={{ width: '100%' }}>
|
|
<Button
|
|
type="primary"
|
|
onClick={handleAddDictItem}
|
|
disabled={!selectedDict}
|
|
>
|
|
添加字典项
|
|
</Button>
|
|
<Space>
|
|
<Upload
|
|
name="file"
|
|
action={`/dict/item/import`}
|
|
data={{ dictId: selectedDict?.id }}
|
|
showUploadList={false}
|
|
disabled={!selectedDict}
|
|
onChange={(info) => {
|
|
if (info.file.status === 'done') {
|
|
message.success(`${info.file.name} 文件上传成功`);
|
|
fetchDictItems(selectedDict.id);
|
|
} else if (info.file.status === 'error') {
|
|
message.error(`${info.file.name} 文件上传失败`);
|
|
}
|
|
}}
|
|
>
|
|
<Button icon={<UploadOutlined />} disabled={!selectedDict}>
|
|
导入字典项
|
|
</Button>
|
|
</Upload>
|
|
<Button
|
|
onClick={() => window.open('/dict/item/template')}
|
|
disabled={!selectedDict}
|
|
>
|
|
下载模板
|
|
</Button>
|
|
</Space>
|
|
<Table
|
|
dataSource={dictItems}
|
|
columns={dictItemColumns}
|
|
rowKey="id"
|
|
loading={loadingDictItems}
|
|
/>
|
|
</Space>
|
|
</Content>
|
|
</Layout>
|
|
|
|
<Modal
|
|
title={editingDictItem ? '编辑字典项' : '添加字典项'}
|
|
visible={isDictItemModalVisible}
|
|
onOk={handleDictItemFormSubmit}
|
|
onCancel={() => setIsDictItemModalVisible(false)}
|
|
>
|
|
<Form layout="vertical">
|
|
<Form.Item label="名称">
|
|
<Input
|
|
placeholder="名称 (e.g., zyn)"
|
|
value={dictItemForm.name}
|
|
onChange={(e) =>
|
|
setDictItemForm({ ...dictItemForm, name: e.target.value })
|
|
}
|
|
/>
|
|
</Form.Item>
|
|
<Form.Item label="标题">
|
|
<Input
|
|
placeholder="标题 (e.g., ZYN)"
|
|
value={dictItemForm.title}
|
|
onChange={(e) =>
|
|
setDictItemForm({ ...dictItemForm, title: e.target.value })
|
|
}
|
|
/>
|
|
</Form.Item>
|
|
<Form.Item label="值 (可选)">
|
|
<Input
|
|
placeholder="值 (可选)"
|
|
value={dictItemForm.value}
|
|
onChange={(e) =>
|
|
setDictItemForm({ ...dictItemForm, value: e.target.value })
|
|
}
|
|
/>
|
|
</Form.Item>
|
|
</Form>
|
|
</Modal>
|
|
|
|
<Modal
|
|
title={editingDict ? '编辑字典' : '添加新字典'}
|
|
visible={isAddDictModalVisible}
|
|
onOk={handleAddDict}
|
|
onCancel={() => setIsAddDictModalVisible(false)}
|
|
>
|
|
<Form layout="vertical">
|
|
<Form.Item label="字典名称">
|
|
<Input
|
|
placeholder="字典名称 (e.g., brand)"
|
|
value={newDictName}
|
|
onChange={(e) => setNewDictName(e.target.value)}
|
|
/>
|
|
</Form.Item>
|
|
<Form.Item label="字典标题">
|
|
<Input
|
|
placeholder="字典标题 (e.g., 品牌)"
|
|
value={newDictTitle}
|
|
onChange={(e) => setNewDictTitle(e.target.value)}
|
|
/>
|
|
</Form.Item>
|
|
</Form>
|
|
</Modal>
|
|
</PageContainer>
|
|
);
|
|
};
|
|
|
|
export default DictPage;
|