import { UploadOutlined } from '@ant-design/icons'; import { ActionType, PageContainer, ProTable, } 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, useRef, useState } from 'react'; const { Sider, Content } = Layout; const DictPage: React.FC = () => { // 左侧字典列表的状态 const [dicts, setDicts] = useState([]); const [loadingDicts, setLoadingDicts] = useState(false); const [searchText, setSearchText] = useState(''); const [selectedDict, setSelectedDict] = useState(null); const [isAddDictModalVisible, setIsAddDictModalVisible] = useState(false); const [editingDict, setEditingDict] = useState(null); const [newDictName, setNewDictName] = useState(''); const [newDictTitle, setNewDictTitle] = useState(''); // 右侧字典项列表的状态 const [isDictItemModalVisible, setIsDictItemModalVisible] = useState(false); const [editingDictItem, setEditingDictItem] = useState(null); const [dictItemForm] = Form.useForm(); const actionRef = useRef(); // 获取字典列表 const fetchDicts = async (name = '') => { setLoadingDicts(true); try { const res = await request('/dict/list', { params: { name } }); setDicts(res); } catch (error) { message.error('获取字典列表失败'); } finally { setLoadingDicts(false); } }; // 搜索字典 const handleSearch = (value: string) => { fetchDicts(value); }; // 添加或编辑字典 const handleAddDict = async () => { const values = { name: newDictName, title: newDictTitle }; try { if (editingDict) { await request(`/dict/${editingDict.id}`, { method: 'PUT', data: values, }); message.success('更新成功'); } else { await request('/dict', { method: 'POST', data: values }); message.success('添加成功'); } setIsAddDictModalVisible(false); setEditingDict(null); setNewDictName(''); setNewDictTitle(''); fetchDicts(); // 重新获取列表 } catch (error) { message.error(editingDict ? '更新失败' : '添加失败'); } }; // 删除字典 const handleDeleteDict = async (id: number) => { try { await request(`/dict/${id}`, { method: 'DELETE' }); message.success('删除成功'); fetchDicts(); if (selectedDict?.id === id) { setSelectedDict(null); } } catch (error) { message.error('删除失败'); } }; // 编辑字典 const handleEditDict = (record: any) => { setEditingDict(record); setNewDictName(record.name); setNewDictTitle(record.title); setIsAddDictModalVisible(true); }; // 下载字典导入模板 const handleDownloadDictTemplate = async () => { try { // 使用 request 函数获取带认证的文件数据 const response = await request('/dict/template', { method: 'GET', responseType: 'blob', // 指定响应类型为 blob skipErrorHandler: true, // 跳过默认错误处理,自己处理错误 }); // 创建 blob 对象和下载链接 const blob = new Blob([response], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', }); const url = window.URL.createObjectURL(blob); const link = document.createElement('a'); link.href = url; link.setAttribute('download', 'dict_template.xlsx'); document.body.appendChild(link); link.click(); link.remove(); window.URL.revokeObjectURL(url); } catch (error: any) { message.error('下载字典模板失败:' + (error.message || '未知错误')); } }; // 添加字典项 const handleAddDictItem = () => { setEditingDictItem(null); dictItemForm.resetFields(); setIsDictItemModalVisible(true); }; // 编辑字典项 const handleEditDictItem = (record: any) => { setEditingDictItem(record); dictItemForm.setFieldsValue(record); setIsDictItemModalVisible(true); }; // 删除字典项 const handleDeleteDictItem = async (id: number) => { try { await request(`/dict/item/${id}`, { method: 'DELETE' }); message.success('删除成功'); actionRef.current?.reload(); } catch (error) { message.error('删除失败'); } }; // 字典项表单提交 const handleDictItemFormSubmit = async (values: any) => { const url = editingDictItem ? `/dict/item/${editingDictItem.id}` : '/dict/item'; const method = editingDictItem ? 'PUT' : 'POST'; const data = editingDictItem ? { ...values } : { ...values, dict: { id: selectedDict.id } }; try { await request(url, { method, data }); message.success(editingDictItem ? '更新成功' : '添加成功'); setIsDictItemModalVisible(false); actionRef.current?.reload(); } catch (error) { message.error(editingDictItem ? '更新失败' : '添加失败'); } }; // 导出字典项数据 const handleExportDictItems = async () => { if (!selectedDict) { message.warning('请先选择字典'); return; } try { // 获取当前字典的所有数据 const response = await request('/dict/items', { method: 'GET', params: { dictId: selectedDict.id }, }); if (!response || response.length === 0) { message.warning('当前字典没有数据可导出'); return; } // 将数据转换为CSV格式 const headers = [ 'name', 'title', 'titleCN', 'value', 'sort', 'image', 'shortName', ]; const csvContent = [ headers.join(','), ...response.map((item: any) => headers .map((header) => { const value = item[header] || ''; // 如果值包含逗号或引号,需要转义 if ( typeof value === 'string' && (value.includes(',') || value.includes('"')) ) { return `"${value.replace(/"/g, '""')}"`; } return value; }) .join(','), ), ].join('\n'); // 创建blob并下载 const blob = new Blob(['\ufeff' + csvContent], { // 添加BOM以支持中文 type: 'text/csv;charset=utf-8', }); const url = window.URL.createObjectURL(blob); const link = document.createElement('a'); link.href = url; link.setAttribute('download', `${selectedDict.name}_dict_items.csv`); document.body.appendChild(link); link.click(); link.remove(); window.URL.revokeObjectURL(url); message.success(`成功导出 ${response.length} 条数据`); } catch (error: any) { message.error('导出字典项失败:' + (error.message || '未知错误')); } }; // Effects useEffect(() => { fetchDicts(); }, []); // 左侧字典表格的列定义 const dictColumns = [ { title: '字典名称', dataIndex: 'name', key: 'name' }, { title: '操作', key: 'action', render: (_: any, record: any) => ( ), }, ]; // 右侧字典项列表的列定义 const dictItemColumns = [ { title: '名称', dataIndex: 'name', key: 'name', copyable: true, }, { title: '简称', dataIndex: 'shortName', key: 'shortName', copyable: true, }, { title: '图片', dataIndex: 'image', key: 'image', valueType: 'image', width: 80, }, { title: '标题', dataIndex: 'title', key: 'title', copyable: true, }, { title: '中文标题', dataIndex: 'titleCN', key: 'titleCN', copyable: true, }, { title: '操作', key: 'action', render: (_: any, record: any) => ( ), }, ]; return ( setSearchText(e.target.value)} enterButton allowClear /> { if (info.file.status === 'done') { message.success(`${info.file.name} 文件上传成功`); fetchDicts(); } else if (info.file.status === 'error') { message.error(`${info.file.name} 文件上传失败`); } }} > ({ onClick: () => { // 如果点击的是当前已选中的行,则取消选择 if (selectedDict?.id === record.id) { setSelectedDict(null); } else { setSelectedDict(record); } }, })} rowClassName={(record) => selectedDict?.id === record.id ? 'ant-table-row-selected' : '' } pagination={false} />
{ if (info.file.status === 'done') { message.success(`${info.file.name} 文件上传成功`); actionRef.current?.reload(); } else if (info.file.status === 'error') { message.error(`${info.file.name} 文件上传失败`); } }} >
{ // 当没有选择字典时,不发起请求 if (!selectedDict?.id) { return { data: [], success: true, }; } const { name, title } = params; const res = await request('/dict/items', { params: { dictId: selectedDict?.id, name, title, }, }); return { data: res, success: true, }; }} rowKey="id" search={{ layout: 'vertical', }} pagination={false} options={false} size="small" key={selectedDict?.id} />
dictItemForm.submit()} onCancel={() => setIsDictItemModalVisible(false)} destroyOnClose >
setIsAddDictModalVisible(false)} >
setNewDictName(e.target.value)} /> setNewDictTitle(e.target.value)} />
); }; export default DictPage;