WEB/src/pages/Dict/List/index.tsx

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;