import { useCallback, useEffect, useMemo, useState } from 'react'; import { App, Button, Form, Input, InputNumber, Modal, Popconfirm, Radio, Select, Space, Table, Tag, } from 'antd'; import type { TableColumnsType } from 'antd'; import { DeleteOutlined, DownloadOutlined, EditOutlined, PlusOutlined, ReloadOutlined, SearchOutlined, } from '@ant-design/icons'; import { useParams } from 'react-router-dom'; import { saveAs } from 'file-saver'; import dayjs from 'dayjs'; import { addDictData, delDictData, getDictData, getDictType, listDictData, updateDictData, } from '@/api/system/dict'; import PageBackButton from '@/components/PageBackButton'; import Permission from '@/components/Permission'; import ReadonlyAction from '@/components/Permission/ReadonlyAction'; import { parseTime } from '@/utils/ruoyi'; import './system-admin.css'; interface DictDataRecord { dictCode?: number | string; dictLabel?: string; dictValue?: string; dictType?: string; dictSort?: number | string; cssClass?: string; listClass?: string; isDefault?: string; status?: string; remark?: string; createTime?: string | number | Date; [key: string]: unknown; } const statusOptions = [ { value: '0', label: '正常' }, { value: '1', label: '停用' }, ]; const defaultQueryParams = { pageNum: 1, pageSize: 10, dictLabel: undefined as string | undefined, status: undefined as string | undefined, }; const DictDataPage = () => { const { message } = App.useApp(); const { dictId = '' } = useParams(); const [queryForm] = Form.useForm(); const [dictDataForm] = Form.useForm(); const [loading, setLoading] = useState(false); const [modalVisible, setModalVisible] = useState(false); const [modalTitle, setModalTitle] = useState(''); const [dictTypeName, setDictTypeName] = useState(''); const [dictType, setDictType] = useState(''); const [dictDataList, setDictDataList] = useState([]); const [total, setTotal] = useState(0); const [selectedRowKeys, setSelectedRowKeys] = useState([]); const [currentRecord, setCurrentRecord] = useState({}); const [queryParams, setQueryParams] = useState(defaultQueryParams); const currentDictId = useMemo(() => Number(dictId) || dictId, [dictId]); const loadDictType = useCallback(async () => { if (!currentDictId) { return; } try { const response = await getDictType(currentDictId); const detail = (response && typeof response === 'object' && 'data' in response ? response.data : response) as { dictType?: string; dictName?: string } | undefined; setDictType(detail?.dictType ?? ''); setDictTypeName(detail?.dictName ?? ''); } catch (error) { console.error('Failed to load dict type detail:', error); message.error('获取字典类型信息失败'); } }, [currentDictId, message]); const loadList = useCallback(async () => { if (!dictType) { return; } setLoading(true); try { const response = await listDictData({ ...queryParams, dictType, }) as { rows?: DictDataRecord[]; total?: number }; setDictDataList(response.rows ?? []); setTotal(Number(response.total ?? 0)); } catch (error) { console.error('Failed to load dict data list:', error); message.error('获取字典数据失败'); } finally { setLoading(false); } }, [dictType, message, queryParams]); useEffect(() => { void loadDictType(); }, [loadDictType]); useEffect(() => { if (dictType) { void loadList(); } }, [dictType, loadList]); const handleAdd = () => { setCurrentRecord({}); dictDataForm.resetFields(); dictDataForm.setFieldsValue({ dictType, status: '0', isDefault: 'N', dictSort: 0, }); setModalTitle('添加字典数据'); setModalVisible(true); }; const handleEdit = async (record?: DictDataRecord) => { const targetId = record?.dictCode ?? selectedRowKeys[0]; if (targetId === undefined) { message.warning('请选择要修改的数据'); return; } try { const response = await getDictData(targetId as string | number); const detail = (response && typeof response === 'object' && 'data' in response ? response.data : response) as DictDataRecord | undefined; setCurrentRecord(detail ?? {}); dictDataForm.setFieldsValue({ ...detail, status: String(detail?.status ?? '0'), isDefault: String(detail?.isDefault ?? 'N'), }); setModalTitle('修改字典数据'); setModalVisible(true); } catch (error) { console.error('Failed to load dict data detail:', error); message.error('获取字典数据详情失败'); } }; const handleDelete = async (record?: DictDataRecord) => { const ids = record?.dictCode !== undefined ? [record.dictCode] : selectedRowKeys; if (ids.length === 0) { message.warning('请选择要删除的数据'); return; } try { await delDictData(ids.join(',')); message.success('删除成功'); setSelectedRowKeys([]); await loadList(); } catch (error) { console.error('Failed to delete dict data:', error); message.error('删除失败'); } }; const handleExport = async () => { const hide = message.loading('正在导出数据...', 0); try { const response = await listDictData({ ...queryParams, dictType, pageNum: undefined, pageSize: undefined, }) as { rows?: DictDataRecord[] }; const rows = response.rows ?? []; const csvContent = [ ['字典编码', '字典标签', '字典键值', '字典排序', '状态', '默认', '创建时间'], ...rows.map((item) => [ item.dictCode, item.dictLabel, item.dictValue, item.dictSort, String(item.status ?? '') === '0' ? '正常' : '停用', item.isDefault, parseTime(item.createTime), ]), ] .map((row) => row.map((cell) => `"${String(cell ?? '').replace(/"/g, '""')}"`).join(',')) .join('\n'); saveAs(new Blob([csvContent], { type: 'text/csv;charset=utf-8;' }), `dict_data_${dayjs().format('YYYYMMDDHHmmss')}.csv`); hide(); message.success('导出成功'); } catch (error) { hide(); console.error('Failed to export dict data:', error); message.error('导出失败'); } }; const submitForm = async () => { try { const values = await dictDataForm.validateFields(); const payload = { ...currentRecord, ...values, dictType, }; if (payload.dictCode !== undefined) { await updateDictData(payload); message.success('修改成功'); } else { await addDictData(payload); message.success('新增成功'); } setModalVisible(false); await loadList(); } catch (error) { if (error && typeof error === 'object' && 'errorFields' in error) { return; } console.error('Failed to submit dict data form:', error); message.error('保存失败'); } }; const columns: TableColumnsType = [ { title: '字典编码', dataIndex: 'dictCode', align: 'center', width: 120 }, { title: '字典标签', dataIndex: 'dictLabel', align: 'center' }, { title: '字典键值', dataIndex: 'dictValue', align: 'center' }, { title: '排序', dataIndex: 'dictSort', align: 'center', width: 100 }, { title: '状态', dataIndex: 'status', align: 'center', width: 100, render: (value) => ( {String(value ?? '') === '0' ? '正常' : '停用'} ), }, { title: '默认', dataIndex: 'isDefault', align: 'center', width: 100 }, { title: '创建时间', dataIndex: 'createTime', align: 'center', width: 180, render: (value) => parseTime(value), }, { title: '操作', key: 'operation', align: 'center', width: 180, render: (_value, record) => ( }>修改}> } danger>删除}> void handleDelete(record)}> ), }, ]; return (
{dictTypeName || '字典数据'} {dictType || '-'}
setQueryParams((prev) => ({ ...prev, pageNum: 1, ...queryForm.getFieldsValue(), })) } >
setSelectedRowKeys(keys), }} pagination={{ current: queryParams.pageNum, pageSize: queryParams.pageSize, total, showSizeChanger: true, showQuickJumper: true, showTotal: (count) => `共 ${count} 条`, onChange: (page, pageSize) => setQueryParams((prev) => ({ ...prev, pageNum: page, pageSize })), }} /> void submitForm()} onCancel={() => setModalVisible(false)} width={560} forceRender >
{statusOptions.map((item) => ( {item.label} ))}
); }; export default DictDataPage;