@@ -0,0 +1,202 @@ | |||
import React, { useState, useEffect, useRef } from 'react'; | |||
import { useSetState } from 'ahooks'; | |||
import { Space, Table, Button, Divider, Card, Input } from 'antd'; | |||
import type { InputRef } from 'antd'; | |||
import type { ColumnsType, ColumnType, TableProps } from 'antd/es/table'; | |||
import { t } from '@/utils/i18n'; | |||
import { PlusOutlined, ExclamationCircleFilled, SearchOutlined } from '@ant-design/icons'; | |||
import { antdUtils } from '@/utils/antd'; | |||
import { useRequest } from '@/hooks/use-request'; | |||
import { DataDictVO, DataDictPageReqVO } from '@/models'; | |||
import DictEditor from './dict-editor'; | |||
import templateDictService from '@/request/service/template-dict'; | |||
export default (props: { | |||
onSelectItem: (item: DataDictVO) => void; | |||
}) => { | |||
const { onSelectItem } = props; | |||
const [dataDicts, setDataDicts] = useState<DataDictVO[]>(); | |||
const [searchState, setSearchState] = useSetState<DataDictPageReqVO>({ | |||
pageNo: 1, | |||
pageSize: 10 | |||
}); | |||
const [total, setTotal] = useState(0) | |||
const searchInput = useRef<InputRef>(null); | |||
const [onSearching, setOnSearching] = useState(false); | |||
const [editorVisable, seEditorVisable] = useState<boolean>(false); | |||
const [editData, seEditData] = useState<DataDictVO>(); | |||
//获取字典分页数据 | |||
const { runAsync: getDictPageApi } = useRequest(templateDictService.getDictPageApi, { manual: true }); | |||
//删除字典数据 | |||
const { runAsync: deleteDictApi } = useRequest(templateDictService.deleteDictApi, { manual: true }); | |||
const load = async () => { | |||
setOnSearching(true); | |||
const [error, { data }] = await getDictPageApi(searchState); | |||
setOnSearching(false); | |||
if (!error) { | |||
setDataDicts(data.list); | |||
setTotal(data.total); | |||
} | |||
} | |||
const showDeleteConfirm = (item: DataDictVO) => { | |||
antdUtils.modal?.confirm({ | |||
title: `确认删除名称为: ${item.name} 的字典吗?`, | |||
icon: <ExclamationCircleFilled />, | |||
content: '请注意删除以后不可恢复!', | |||
okText: '删除', | |||
okType: 'danger', | |||
cancelText: '取消', | |||
onOk: async () => { | |||
const [error, { code, msg }] = await deleteDictApi(item.id); | |||
if (error || code !== 0) { | |||
antdUtils.message?.open({ type: 'error', content: msg ?? '操作失败' }) | |||
} else { | |||
antdUtils.message?.open({ type: 'success', content: '删除成功' }) | |||
} | |||
await load(); | |||
}, | |||
onCancel() { | |||
}, | |||
}); | |||
}; | |||
const getColumnSearchProps = (placeholder: string): ColumnType<DataDictVO> => ({ | |||
filterDropdown: ({ setSelectedKeys, selectedKeys, confirm, clearFilters, close }) => ( | |||
<div style={{ padding: 8 }} onKeyDown={(e) => e.stopPropagation()}> | |||
<Input.Search | |||
ref={searchInput} | |||
placeholder={placeholder} | |||
value={selectedKeys[0]} | |||
onChange={(e) => { | |||
setSelectedKeys(e.target.value && e.target.value !== '' ? [e.target.value] : []) | |||
}} | |||
onSearch={(value) => { | |||
if (value === '' && clearFilters) { | |||
clearFilters!!() | |||
} | |||
confirm(); | |||
}} | |||
onPressEnter={() => confirm()} | |||
allowClear | |||
style={{ marginBottom: 8, display: 'block' }} | |||
enterButton="搜索" | |||
size="middle" | |||
loading={onSearching} | |||
/> | |||
</div> | |||
), | |||
filterIcon: (filtered: boolean) => ( | |||
<SearchOutlined style={{ color: filtered ? 'primaryColor' : undefined }} /> | |||
), | |||
onFilterDropdownOpenChange: (visible) => { | |||
if (visible) { | |||
setTimeout(() => searchInput.current?.select(), 100); | |||
} | |||
}, | |||
}); | |||
const columns: ColumnsType<DataDictVO> = [ | |||
{ | |||
title: '名称', | |||
dataIndex: 'name', | |||
key: 'name', | |||
align: 'center', | |||
...getColumnSearchProps('请输入名称'), | |||
}, | |||
{ | |||
title: '描述', | |||
key: 'description', | |||
dataIndex: 'description', | |||
align: 'center', | |||
// ...getColumnSearchProps('请输入描述'), | |||
}, | |||
{ | |||
title: t("QkOmYwne" /* 操作 */), | |||
key: 'action', | |||
align: 'center', | |||
render: (_, record) => ( | |||
<Space size="middle" split={( | |||
<Divider type='vertical' /> | |||
)}> | |||
<a | |||
onClick={() => { | |||
seEditData(record) | |||
seEditorVisable(true); | |||
}}> | |||
编辑 | |||
</a> | |||
<a | |||
onClick={() => { | |||
showDeleteConfirm(record) | |||
}}> | |||
删除 | |||
</a> | |||
</Space> | |||
), | |||
width: 150, | |||
}, | |||
]; | |||
useEffect(() => { | |||
load(); | |||
}, [searchState]); | |||
const onChange: TableProps<DataDictVO>['onChange'] = (pagination, filters, sorter, extra) => { | |||
const state: DataDictPageReqVO = { | |||
name: filters.name ? filters.name[0] as string : undefined, | |||
description: filters.description ? filters.description[0] as string : undefined, | |||
pageNo: pagination.current, | |||
pageSize: pagination.pageSize | |||
} | |||
setOnSearching(true); | |||
setSearchState(state); | |||
}; | |||
return ( | |||
<> | |||
<div> | |||
<Card className='mb-[10px] dark:bg-[rgb(33,41,70)] bg-white roundle-lg px[12px]' bodyStyle={{ | |||
paddingTop: 0, | |||
paddingBottom: 0 | |||
}}> | |||
<div className="py-[8px] flex flex-row-reverse"> | |||
<Button className="ml-5" type='primary' size='middle' icon={<PlusOutlined />} | |||
onClick={() => { | |||
seEditData(undefined); | |||
seEditorVisable(true); | |||
}}> 新增 </Button> | |||
</div> | |||
<Table rowKey="id" scroll={{ x: true }} columns={columns} dataSource={dataDicts} className='bg-transparent' | |||
onRow={(record) => { | |||
return { | |||
onClick: () => { | |||
onSelectItem(record); | |||
} | |||
}; | |||
}} | |||
onChange={onChange} | |||
pagination={{ | |||
current: searchState.pageNo, | |||
pageSize: searchState.pageSize, | |||
total, | |||
position: ['bottomRight'] | |||
}} | |||
/> | |||
</Card> | |||
</div> | |||
<DictEditor | |||
onSave={() => { | |||
load(); | |||
seEditorVisable(false); | |||
}} | |||
onCancel={() => { seEditorVisable(false) }} | |||
visible={editorVisable} | |||
data={editData} | |||
/> | |||
</> | |||
); | |||
}; |
@@ -120,7 +120,7 @@ export default forwardRef((props, ref) => { | |||
return ( | |||
<> | |||
<div> | |||
<Card className='basis-3/5 mb-[10px] ml-[10px] dark:bg-[rgb(33,41,70)] bg-white roundle-lg px[12px]' bodyStyle={{ | |||
<Card className='mb-[10px] ml-[10px] dark:bg-[rgb(33,41,70)] bg-white roundle-lg px[12px]' bodyStyle={{ | |||
paddingTop: 0, | |||
paddingBottom: 0 | |||
}}> | |||
@@ -1,213 +1,26 @@ | |||
import React, { useState, useRef, useEffect } from 'react'; | |||
import { Space, Table, Button, Image, Divider, Card, Input } from 'antd'; | |||
import type { InputRef } from 'antd'; | |||
import type { ColumnType, ColumnsType } from 'antd/es/table'; | |||
import type { FilterConfirmProps, TableRowSelection } from 'antd/es/table/interface'; | |||
import { t } from '@/utils/i18n'; | |||
import { PlusOutlined, ExclamationCircleFilled, DeleteOutlined, SearchOutlined } from '@ant-design/icons'; | |||
import { antdUtils } from '@/utils/antd'; | |||
import { useRequest } from '@/hooks/use-request'; | |||
import { DataDictVO, DataDictDetailVO } from '@/models'; | |||
import DictEditor from './dict-editor'; | |||
import DictDetailEditor from './dict-detail-editor'; | |||
import templateDictService from '@/request/service/template-dict'; | |||
import React, { useRef } from 'react'; | |||
import { DataDictVO } from '@/models'; | |||
import DictDetail from './dict-detail'; | |||
import DictData from './dict-data'; | |||
import type { DictDetailRef } from './dict-detail' | |||
export default () => { | |||
const [dataDicts, setDataDicts] = useState<DataDictVO[]>(); | |||
const [dictDetail, setDictDetail] = useState<DataDictDetailVO[]>(); | |||
const [total, setTotal] = useState(0); | |||
const [editorVisable, seEditorVisable] = useState<boolean>(false); | |||
const [editData, seEditData] = useState<DataDictVO>(); | |||
const [detailEditorVisable, seEdtailEditorVisable] = useState<boolean>(false); | |||
const [editDetailData, seEditDetailData] = useState<DataDictDetailVO>(); | |||
const detailRef = useRef<DictDetailRef>() | |||
//获取字典分页数据 | |||
const { runAsync: getDictPageApi } = useRequest(templateDictService.getDictPageApi, { manual: true }); | |||
//删除字典数据 | |||
const { runAsync: deleteDictApi } = useRequest(templateDictService.deleteDictApi, { manual: true }); | |||
const load = async () => { | |||
const [error, { data }] = await getDictPageApi(); | |||
if (!error) { | |||
setDataDicts(data.list); | |||
setTotal(data.total); | |||
} | |||
} | |||
useEffect(() => { | |||
load(); | |||
}, []); | |||
const showDeleteConfirm = (item: DataDictVO) => { | |||
antdUtils.modal?.confirm({ | |||
title: `确认删除名称为: ${item.name} 的字典吗?`, | |||
icon: <ExclamationCircleFilled />, | |||
content: '请注意删除以后不可恢复!', | |||
okText: '删除', | |||
okType: 'danger', | |||
cancelText: '取消', | |||
onOk: async () => { | |||
const [error, { code, msg }] = await deleteDictApi(item.id); | |||
if (error || code !== 0) { | |||
antdUtils.message?.open({ type: 'error', content: msg ?? '操作失败' }) | |||
} else { | |||
antdUtils.message?.open({ type: 'success', content: '删除成功' }) | |||
} | |||
await load(); | |||
}, | |||
onCancel() { | |||
}, | |||
}); | |||
}; | |||
const columns: ColumnsType<DataDictDetailVO> = [ | |||
{ | |||
title: '字典标签', | |||
dataIndex: 'label', | |||
key: 'label', | |||
align: 'center', | |||
width: 150, | |||
}, | |||
{ | |||
title: '字典值', | |||
key: 'value', | |||
dataIndex: 'value', | |||
align: 'center', | |||
}, | |||
{ | |||
title: '排序', | |||
key: 'dictSort', | |||
dataIndex: 'dictSort', | |||
width: 100, | |||
}, | |||
{ | |||
title: t("QkOmYwne" /* 操作 */), | |||
key: 'action', | |||
render: (_, record) => ( | |||
<Space size="middle" split={( | |||
<Divider type='vertical' /> | |||
)}> | |||
<a | |||
onClick={() => { | |||
seEditDetailData(record) | |||
seEdtailEditorVisable(true); | |||
}}> | |||
编辑 | |||
</a> | |||
<a | |||
onClick={() => { | |||
}}> | |||
删除 | |||
</a> | |||
</Space> | |||
), | |||
width: 150, | |||
}, | |||
]; | |||
const updateDactDetail = (data: DataDictVO) => { | |||
detailRef.current?.updateDictData(data) | |||
} | |||
const dictColumns: ColumnsType<DataDictVO> = [ | |||
{ | |||
title: '名称', | |||
dataIndex: 'name', | |||
key: 'name', | |||
align: 'center', | |||
}, | |||
{ | |||
title: '描述', | |||
key: 'description', | |||
dataIndex: 'description', | |||
align: 'center', | |||
}, | |||
{ | |||
title: t("QkOmYwne" /* 操作 */), | |||
key: 'action', | |||
align: 'center', | |||
render: (_, record) => ( | |||
<Space size="middle" split={( | |||
<Divider type='vertical' /> | |||
)}> | |||
<a | |||
onClick={() => { | |||
seEditData(record) | |||
seEditorVisable(true); | |||
}}> | |||
编辑 | |||
</a> | |||
<a | |||
onClick={() => { | |||
showDeleteConfirm(record) | |||
}}> | |||
删除 | |||
</a> | |||
</Space> | |||
), | |||
width: 150, | |||
}, | |||
]; | |||
return ( | |||
<> | |||
<div className='flex flex-row'> | |||
<Card className='basis-2/5 w-[100px] mb-[10px] dark:bg-[rgb(33,41,70)] bg-white roundle-lg px[12px]' bodyStyle={{ | |||
paddingTop: 0, | |||
paddingBottom: 0 | |||
}}> | |||
<div className="py-[8px] flex flex-row-reverse"> | |||
<Button className="ml-5" type='primary' size='middle' icon={<PlusOutlined />} | |||
onClick={() => { | |||
seEditData(undefined); | |||
seEditorVisable(true); | |||
}}> 新增 </Button> | |||
</div> | |||
<Table rowKey="id" scroll={{ x: true }} columns={dictColumns} dataSource={dataDicts} className='bg-transparent' | |||
onRow={(record) => { | |||
return { | |||
onClick: () => { | |||
updateDactDetail(record) | |||
} | |||
}; | |||
}} | |||
pagination={{ position: ['bottomRight'] }} | |||
/> | |||
</Card> | |||
<div className='basis-2/5 '> | |||
<DictData | |||
onSelectItem={(item: DataDictVO) => { | |||
detailRef.current?.updateDictData(item); | |||
}} /> | |||
</div> | |||
<div className='basis-3/5 '> | |||
<DictDetail ref={detailRef}/> | |||
<DictDetail ref={detailRef} /> | |||
</div> | |||
</div> | |||
<DictEditor | |||
onSave={() => { | |||
load(); | |||
seEditorVisable(false); | |||
}} | |||
onCancel={() => { seEditorVisable(false) }} | |||
visible={editorVisable} | |||
data={editData} | |||
/> | |||
<DictDetailEditor | |||
onSave={() => { | |||
}} | |||
onCancel={() => { seEdtailEditorVisable(false) }} | |||
visible={detailEditorVisable} | |||
data={editDetailData} | |||
/> | |||
</> | |||
); | |||
}; |