@@ -7,11 +7,11 @@ export type DictTypeVO = { | |||
createTime: Date | |||
} | |||
export type DictTypePageReqVO = { | |||
name: string | |||
type: string | |||
status: number | |||
createTime: Date[] | |||
export interface DictTypePageReqVO extends PageParam { | |||
name?: string | |||
type?: string | |||
status?: number | |||
createTime?: Date[] | |||
} | |||
export type DictTypeExportReqVO = { | |||
@@ -33,10 +33,11 @@ export type DictDataVO = { | |||
remark: string | |||
createTime: Date | |||
} | |||
export type DictDataPageReqVO = { | |||
label: string | |||
export interface DictDataPageReqVO extends PageParam { | |||
label?: string | |||
dictType: string | |||
status: number | |||
status?: number | |||
} | |||
export type DictDataExportReqVO = { | |||
@@ -7,8 +7,7 @@ import { antdUtils } from '@/utils/antd'; | |||
const layout = { | |||
labelCol: { span: 4, }, | |||
wrapperCol: { span: 16 }, | |||
bordered: false, | |||
wrapperCol: { span: 16 } | |||
}; | |||
export default (props: { | |||
@@ -8,7 +8,6 @@ import { antdUtils } from '@/utils/antd'; | |||
const layout = { | |||
labelCol: { span: 4, }, | |||
wrapperCol: { span: 16 }, | |||
bordered: false, | |||
}; | |||
export default (props: { | |||
@@ -8,7 +8,6 @@ import { antdUtils } from '@/utils/antd'; | |||
const layout = { | |||
labelCol: { span: 4, }, | |||
wrapperCol: { span: 16 }, | |||
bordered: false, | |||
}; | |||
interface EditorProps { | |||
@@ -0,0 +1,137 @@ | |||
import React, { useEffect, useState } from 'react' | |||
import { Form, Input, Radio, Modal, InputNumber, ColorPicker } from 'antd'; | |||
import dictDataService from '@/request/service/system-dictdata'; | |||
import { useRequest } from '@/hooks/use-request'; | |||
import type { DictDataVO } from '@/models' | |||
import { antdUtils } from '@/utils/antd'; | |||
const layout = { | |||
labelCol: { span: 4, }, | |||
wrapperCol: { span: 16 } | |||
}; | |||
interface DataTypeEditorProps { | |||
visible: boolean; | |||
onCancel: (flag?: boolean) => void; | |||
onSave: (role: DictDataVO) => void; | |||
data?: DictDataVO | null; | |||
dictType: string; | |||
} | |||
export default (props: DataTypeEditorProps) => { | |||
const { visible, onCancel, onSave, data, dictType } = props; | |||
const { runAsync: update } = useRequest(dictDataService.updateDictDataApi, { manual: true }); | |||
const { runAsync: create } = useRequest(dictDataService.createDictDataApi, { manual: true }); | |||
const isEdit = !!data; | |||
const [saveLoading, setSaveLoading] = useState(false); | |||
const [form] = Form.useForm(); | |||
useEffect(() => { | |||
if (visible) { | |||
if (data) { | |||
form.setFieldsValue(data); | |||
} | |||
form.setFieldValue('dictType', dictType); | |||
} else { | |||
form.resetFields(); | |||
} | |||
}, [visible]); | |||
const save = async () => { | |||
setSaveLoading(true); | |||
const fieldValues = form.getFieldsValue(); | |||
const cssClass = fieldValues.cssClass ? fieldValues.cssClass.toHex() : ''; | |||
const newValue = isEdit ? { ...data, ...fieldValues, cssClass } : fieldValues; | |||
const [error, { msg, code }] = isEdit ? await update(newValue) : await create(newValue); | |||
if (!error && code === 0) { | |||
onSave(newValue); | |||
} else { | |||
antdUtils.message?.open({ | |||
type: 'error', | |||
content: msg ?? '操作失败', | |||
}); | |||
} | |||
setSaveLoading(false); | |||
} | |||
return ( | |||
<> | |||
<Modal | |||
open={visible} | |||
title={isEdit ? "编辑" : "新建"} | |||
width={640} | |||
onOk={save} | |||
onCancel={() => onCancel()} | |||
confirmLoading={saveLoading} | |||
destroyOnClose | |||
> | |||
<Form | |||
form={form} | |||
{...layout} | |||
onFinish={save} | |||
labelCol={{ flex: '0 0 100px' }} | |||
wrapperCol={{ span: 16 }} | |||
> | |||
<Form.Item name="dictType" label="字典类型"> | |||
<Input value={dictType} disabled={true} /> | |||
</Form.Item> | |||
<Form.Item name="label" label="数据标签" | |||
rules={[ | |||
{ | |||
required: true, | |||
message: '请输入数据标签', | |||
}, | |||
]} | |||
> | |||
<Input /> | |||
</Form.Item> | |||
<Form.Item name="value" label="数据键值" | |||
rules={[ | |||
{ | |||
required: true, | |||
message: '请输入数据键值', | |||
}, | |||
]} | |||
> | |||
<Input /> | |||
</Form.Item> | |||
<Form.Item name="sort" label="显示排序" | |||
rules={[ | |||
{ | |||
required: true, | |||
message: '请输入显示排序', | |||
}, | |||
]}> | |||
<InputNumber min={0} /> | |||
</Form.Item> | |||
<Form.Item | |||
name="cssClass" | |||
label="颜色" | |||
> | |||
<ColorPicker format="hex"/> | |||
</Form.Item> | |||
<Form.Item name="status" label="状态"> | |||
<Radio.Group options={[ | |||
{ value: 0, label: "开启" }, | |||
{ value: 1, label: "关闭" } | |||
]} optionType="default"> | |||
</Radio.Group> | |||
</Form.Item> | |||
<Form.Item name="remark" label="备注" > | |||
<Input.TextArea showCount maxLength={100} /> | |||
</Form.Item> | |||
</Form> | |||
</Modal> | |||
</> | |||
) | |||
}; |
@@ -1,26 +1,26 @@ | |||
import React, { useState, useRef, useEffect } from 'react'; | |||
import { Space, Table, Button, Image, Divider, Card, Input, Form } 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 React, { useState, useEffect } from 'react'; | |||
import { Space, Table, Button, Badge, Divider, Input } from 'antd'; | |||
import { useSetState } from 'ahooks'; | |||
import type { TableProps, ColumnsType, ColumnType } from 'antd/es/table'; | |||
import { t } from '@/utils/i18n'; | |||
import { PlusOutlined, ExclamationCircleFilled, DeleteOutlined, SearchOutlined } from '@ant-design/icons'; | |||
import { PlusOutlined, ExclamationCircleFilled, SearchOutlined } from '@ant-design/icons'; | |||
import { antdUtils } from '@/utils/antd'; | |||
import { useRequest } from '@/hooks/use-request'; | |||
import type { DictTypeVO, DictDataVO, DictDataPageReqVO } from '@/models' | |||
import dictDataService from '@/request/service/system-dictdata'; | |||
import DictDataEditor from './dict-data-editor'; | |||
const { Search } = Input; | |||
type DataIndex = keyof DictDataVO; | |||
interface DictDataProps { | |||
data?: DictTypeVO | null; | |||
} | |||
export default (props: DictDataProps) => { | |||
const { data } = props; | |||
const showDeleteConfirm = (item: DictDataVO) => { | |||
antdUtils.modal?.confirm({ | |||
title: `确认删除值为: ${item.value} 的字典吗?`, | |||
title: `确认删除值为 ${item.value} 的字典吗?`, | |||
icon: <ExclamationCircleFilled />, | |||
content: '请注意删除以后不可恢复!', | |||
okText: '删除', | |||
@@ -50,22 +50,55 @@ export default (props: DictDataProps) => { | |||
const [editData, seEditData] = useState<DictDataVO>(); | |||
const [dataSource, setDataSource] = useState<DictDataVO[]>([]); | |||
const [total, setTotal] = useState(0); | |||
const [searchState, setSearchState] = useSetState<DictDataPageReqVO>({ dictType: data?.type ?? "" }); | |||
const [onSearching, setOnSearching] = useState(false); | |||
const { runAsync: getDictDataPageApi } = useRequest(dictDataService.getDictDataPageApi, { manual: true }); | |||
const { runAsync: deleteDictDataApi } = useRequest(dictDataService.deleteDictDataApi, { manual: true }); | |||
const showEditor = (record: DictDataVO | undefined) => { | |||
seEditData(record); | |||
seEditorVisable(true); | |||
} | |||
const load = async () => { | |||
const [error, { data }] = await getDictDataPageApi({ | |||
dictType: props.data?.type, | |||
pageSize:10, | |||
pageNo:1 | |||
}); | |||
setOnSearching(true); | |||
const [error, { data }] = await getDictDataPageApi(searchState); | |||
setOnSearching(false); | |||
if (!error) { | |||
setDataSource(data.list); | |||
setTotal(data.total); | |||
} | |||
}; | |||
const getColumnSearchProps = (dataIndex: DataIndex): ColumnType<DictDataVO> => ({ | |||
filterDropdown: ({ setSelectedKeys, selectedKeys, confirm, clearFilters, close }) => ( | |||
<div style={{ padding: 8 }} onKeyDown={(e) => e.stopPropagation()}> | |||
<Input.Search | |||
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 }} /> | |||
), | |||
}); | |||
const columns: ColumnsType<DictDataVO> = [ | |||
{ | |||
@@ -74,6 +107,7 @@ export default (props: DictDataProps) => { | |||
key: 'label', | |||
align: 'center', | |||
width: 150, | |||
...getColumnSearchProps('label') | |||
}, | |||
{ | |||
title: '数据键值', | |||
@@ -89,6 +123,9 @@ export default (props: DictDataProps) => { | |||
dataIndex: 'status', | |||
align: 'center', | |||
width: 120, | |||
render: (value: number) => { | |||
return (value === 0 ? <Badge status="success" text="已开启" /> : <Badge status="error" text="已关闭" />) | |||
} | |||
}, | |||
{ | |||
title: t("QkOmYwne" /* 操作 */), | |||
@@ -99,10 +136,7 @@ export default (props: DictDataProps) => { | |||
<Divider type='vertical' /> | |||
)}> | |||
<a | |||
onClick={() => { | |||
// setCreateVisible(true); | |||
// setCurRowData(record); | |||
}}> | |||
onClick={() => showEditor(record)}> | |||
编辑 | |||
</a> | |||
<a | |||
@@ -119,25 +153,54 @@ export default (props: DictDataProps) => { | |||
useEffect(() => { | |||
load(); | |||
}, [props]); | |||
}, [searchState]); | |||
useEffect(() => { | |||
if (props.data) | |||
setSearchState({ dictType: props.data!!.type }) | |||
}, [props]) | |||
const onChange: TableProps<DictDataVO>['onChange'] = (pagination, filters, sorter, extra) => { | |||
const state: DictDataPageReqVO = { | |||
label: filters.label ? filters.label[0] as string : undefined, | |||
dictType: props.data?.type ?? "", | |||
pageNo: pagination.current ?? 1, | |||
pageSize: pagination.pageSize | |||
} | |||
setSearchState(state); | |||
}; | |||
return ( | |||
<div> | |||
<div className="py-[8px] flex flex-row-reverse"> | |||
<Button className="ml-5" type='primary' size='middle' icon={<PlusOutlined />}> 添加字典数据 </Button> | |||
<> | |||
<div> | |||
{data ? (<div className="py-[8px] flex flex-row-reverse"> | |||
<Button className="ml-5" type='primary' size='middle' icon={<PlusOutlined />} | |||
onClick={() => showEditor(undefined)}> 添加字典数据 </Button> | |||
</div>) : null} | |||
<Table rowKey="id" | |||
scroll={{ x: true }} | |||
columns={columns} | |||
dataSource={dataSource} | |||
className='bg-transparent' | |||
onChange={onChange} | |||
pagination={{ | |||
pageSize: searchState.pageSize, | |||
current: searchState.pageNo, | |||
total, | |||
position: ['bottomRight'] | |||
}} | |||
/> | |||
</div> | |||
<Table rowKey="id" | |||
scroll={{ x: true }} | |||
columns={columns} | |||
dataSource={dataSource} | |||
className='bg-transparent' | |||
pagination={{ | |||
pageSize: 10, | |||
current: 1, | |||
total, | |||
position: ['bottomRight'] | |||
}} | |||
/> | |||
</div> | |||
<DictDataEditor onSave={() => { | |||
load(); | |||
seEditorVisable(false); | |||
}} | |||
onCancel={() => { seEditorVisable(false) }} | |||
visible={editorVisable} | |||
data={editData} | |||
dictType={data?.type ?? ""} /> | |||
</> | |||
); | |||
}; |
@@ -0,0 +1,115 @@ | |||
import React, { useEffect, useState } from 'react' | |||
import { Form, Input, Radio, Modal } from 'antd'; | |||
import dictTypeService from '@/request/service/system-dicttype'; | |||
import { useRequest } from '@/hooks/use-request'; | |||
import type { DictTypeVO } from '@/models' | |||
import { antdUtils } from '@/utils/antd'; | |||
const layout = { | |||
labelCol: { span: 4, }, | |||
wrapperCol: { span: 16 } | |||
}; | |||
interface DataTypeEditorProps { | |||
visible: boolean; | |||
onCancel: (flag?: boolean) => void; | |||
onSave: (role: DictTypeVO) => void; | |||
data?: DictTypeVO | null; | |||
} | |||
export default (props: DataTypeEditorProps) => { | |||
const { visible, onCancel, onSave, data } = props; | |||
const { runAsync: update } = useRequest(dictTypeService.updateDictTypeApi, { manual: true }); | |||
const { runAsync: create } = useRequest(dictTypeService.createDictTypeApi, { manual: true }); | |||
const isEdit = !!data; | |||
const [saveLoading, setSaveLoading] = useState(false); | |||
const [form] = Form.useForm(); | |||
useEffect(() => { | |||
if (visible) { | |||
if (data) { | |||
form.setFieldsValue(data); | |||
} | |||
} else { | |||
form.resetFields(); | |||
} | |||
}, [visible]); | |||
const save = async () => { | |||
setSaveLoading(true); | |||
const fieldValues = form.getFieldsValue(); | |||
const newValue = isEdit ? { ...data, ...fieldValues } : fieldValues; | |||
const [error, { msg, code }] = isEdit ? await update(newValue) : await create(newValue); | |||
if (!error && code === 0) { | |||
onSave(newValue); | |||
} else { | |||
antdUtils.message?.open({ | |||
type: 'error', | |||
content: msg ?? '操作失败', | |||
}); | |||
} | |||
setSaveLoading(false); | |||
} | |||
return ( | |||
<> | |||
<Modal | |||
open={visible} | |||
title={isEdit ? "编辑" : "新建"} | |||
width={640} | |||
onOk={save} | |||
onCancel={() => onCancel()} | |||
confirmLoading= {saveLoading} | |||
destroyOnClose | |||
> | |||
<Form | |||
form={form} | |||
{...layout} | |||
onFinish={save} | |||
labelCol={{ flex: '0 0 100px' }} | |||
wrapperCol={{ span: 16 }} | |||
> | |||
<Form.Item name="name" label="字典名称" | |||
rules={[ | |||
{ | |||
required: true, | |||
message: '请输入字典名称', | |||
}, | |||
]} | |||
> | |||
<Input /> | |||
</Form.Item> | |||
<Form.Item name="type" label="字典类型" | |||
rules={[ | |||
{ | |||
required: true, | |||
message: '请输入字典类型', | |||
}, | |||
]} | |||
> | |||
<Input disabled={isEdit}/> | |||
</Form.Item> | |||
<Form.Item name="status" label="状态"> | |||
<Radio.Group options={[ | |||
{ value: 0, label: "开启" }, | |||
{ value: 1, label: "关闭" } | |||
]} optionType="default"> | |||
</Radio.Group> | |||
</Form.Item> | |||
<Form.Item name="remark" label="备注" > | |||
<Input.TextArea showCount maxLength={100} /> | |||
</Form.Item> | |||
</Form> | |||
</Modal> | |||
</> | |||
) | |||
}; |
@@ -0,0 +1,213 @@ | |||
import React, { useState, useEffect, useMemo } from 'react'; | |||
import { Space, Table, Button, Badge, Divider, Input } from 'antd'; | |||
import { useSetState } from 'ahooks'; | |||
import type { TableProps, ColumnsType, ColumnType } 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 type { DictTypeVO, DictTypePageReqVO } from '@/models' | |||
import dictTypeService from '@/request/service/system-dicttype'; | |||
import DictTypeEditor from './dict-type-editor'; | |||
type DataIndex = keyof DictTypeVO; | |||
interface DictTypeProps { | |||
onSelectDictType?: (data: DictTypeVO) => void; | |||
} | |||
export default (props: DictTypeProps) => { | |||
const showDeleteConfirm = (item: DictTypeVO) => { | |||
antdUtils.modal?.confirm({ | |||
title: `确认删除名称为: "${item.name}" 的字典吗?`, | |||
icon: <ExclamationCircleFilled />, | |||
content: '请注意删除以后不可恢复!', | |||
okText: '删除', | |||
okType: 'danger', | |||
cancelText: '取消', | |||
onOk() { | |||
return new Promise(async (resolve, reject) => { | |||
const [error, { code, msg }] = await deleteDictTypeApi(item.id); | |||
if (error || code !== 0) { | |||
antdUtils.message?.open({ type: 'error', content: msg ?? '操作失败' }) | |||
} else { | |||
antdUtils.message?.open({ type: 'success', content: '删除成功' }) | |||
} | |||
await load(); | |||
resolve(''); | |||
}).catch(() => antdUtils.message?.open({ | |||
type: 'error', | |||
content: '操作失败', | |||
})); | |||
}, | |||
onCancel() { | |||
}, | |||
}); | |||
}; | |||
const [editorVisable, seEditorVisable] = useState<boolean>(false); | |||
const [editData, seEditData] = useState<DictTypeVO>(); | |||
const [dataSource, setDataSource] = useState<DictTypeVO[]>([]); | |||
const [total, setTotal] = useState(0); | |||
const [searchState, setSearchState] = useSetState<DictTypePageReqVO>({}); | |||
const [onSearching, setOnSearching] = useState(false); | |||
const { runAsync: getDictTypePageApi } = useRequest(dictTypeService.getDictTypePageApi, { manual: true }); | |||
const { runAsync: deleteDictTypeApi } = useRequest(dictTypeService.deleteDictTypeApi, { manual: true }); | |||
const showEditor = (record: DictTypeVO | undefined)=> { | |||
seEditData(record); | |||
seEditorVisable(true); | |||
} | |||
const load = async () => { | |||
const [error, { data, code, msg }] = await getDictTypePageApi(searchState); | |||
setOnSearching(false); | |||
if (!error) { | |||
setDataSource(data.list); | |||
setTotal(data.total); | |||
} else { | |||
if (error || code !== 0) { | |||
antdUtils.message?.open({ type: 'error', content: msg ?? '操作失败' }); | |||
return | |||
} | |||
} | |||
}; | |||
const getColumnSearchProps = (dataIndex: DataIndex): ColumnType<DictTypeVO> => ({ | |||
filterDropdown: ({ setSelectedKeys, selectedKeys, confirm, clearFilters, close }) => ( | |||
<div style={{ padding: 8 }} onKeyDown={(e) => e.stopPropagation()}> | |||
<Input.Search | |||
placeholder={dataIndex === 'name' ? '输入要搜索的字典名称' : '输入要搜索的字典类型'} | |||
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 }} /> | |||
), | |||
}); | |||
const columns: ColumnsType<DictTypeVO> = [ | |||
{ | |||
title: '字典名称', | |||
dataIndex: 'name', | |||
key: 'name', | |||
align: 'center', | |||
width: 150, | |||
...getColumnSearchProps('name') | |||
}, | |||
{ | |||
title: '字典类型', | |||
dataIndex: 'type', | |||
key: 'type', | |||
align: 'center', | |||
width: 120, | |||
...getColumnSearchProps('type') | |||
}, | |||
{ | |||
title: '状态', | |||
key: 'status', | |||
dataIndex: 'status', | |||
align: 'center', | |||
width: 120, | |||
render: (value: number) => { | |||
return (value === 0 ? <Badge status="success" text="已开启" /> : <Badge status="error" text="已关闭" />) | |||
} | |||
}, | |||
{ | |||
title: t("QkOmYwne" /* 操作 */), | |||
key: 'action', | |||
align: 'center', | |||
render: (_, record) => ( | |||
<Space size="middle" split={( | |||
<Divider type='vertical' /> | |||
)}> | |||
<a onClick={() => showEditor(record) }> | |||
编辑 | |||
</a> | |||
<a | |||
onClick={() => { | |||
showDeleteConfirm(record) | |||
}}> | |||
删除 | |||
</a> | |||
</Space> | |||
), | |||
width: 150, | |||
}, | |||
]; | |||
useEffect(() => { | |||
load(); | |||
}, [searchState]); | |||
useMemo(() => { | |||
console.log('onMemChanged: ' + editData) | |||
}, [editData]) | |||
const onChange: TableProps<DictTypeVO>['onChange'] = (pagination, filters, sorter, extra) => { | |||
const state: DictTypePageReqVO = { | |||
name: filters.name ? filters.name[0] as string : undefined, | |||
type: filters.type ? filters.type[0] as string : undefined, | |||
pageNo: pagination.current, | |||
pageSize: pagination.pageSize | |||
} | |||
setSearchState(state); | |||
}; | |||
return ( | |||
<> | |||
<div> | |||
<div className="py-[8px] flex flex-row-reverse"> | |||
<Button className="ml-5" | |||
type='primary' size='middle' icon={<PlusOutlined />} | |||
onClick={() => showEditor(undefined)}> 新增字典 </Button> | |||
</div> | |||
<Table rowKey="id" | |||
scroll={{ x: true }} | |||
onChange={onChange} | |||
columns={columns} | |||
dataSource={dataSource} | |||
rowSelection={{ | |||
type: 'radio', | |||
onSelect: (record, select) => { | |||
if (select && props.onSelectDictType) | |||
props.onSelectDictType!!(record) | |||
} | |||
}} | |||
className='bg-transparent' | |||
pagination={{ | |||
pageSize: searchState.pageSize, | |||
current: searchState.pageNo, | |||
total, | |||
position: ['bottomRight'] | |||
}} | |||
/> | |||
</div> | |||
<DictTypeEditor onSave={() => { | |||
load(); | |||
seEditorVisable(false); | |||
}} | |||
onCancel={() => { seEditorVisable(false) }} | |||
visible={editorVisable} | |||
data={editData}/> | |||
</> | |||
); | |||
}; |
@@ -1,164 +1,29 @@ | |||
import React, { useState, useRef, useEffect } from 'react'; | |||
import { Space, Table, Button, Image, Divider, Card, Input, Form } 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 type { DictTypeVO, DictTypePageReqVO, DictDataVO, DictDataPageReqVO } from '@/models' | |||
import dictDataService from '@/request/service/system-dictdata'; | |||
import dictTypeService from '@/request/service/system-dicttype'; | |||
import DictData from './dict-data' | |||
const { Search } = Input; | |||
import React, { useState } from 'react'; | |||
import { Card } from 'antd'; | |||
import type { DictTypeVO } from '@/models' | |||
import DictData from './dict-data'; | |||
import DictType from './dict-type'; | |||
export default () => { | |||
const showDeleteConfirm = (item: DictTypeVO) => { | |||
antdUtils.modal?.confirm({ | |||
title: `确认删除名称为: ${item.name} 的字典吗?`, | |||
icon: <ExclamationCircleFilled />, | |||
content: '请注意删除以后不可恢复!', | |||
okText: '删除', | |||
okType: 'danger', | |||
cancelText: '取消', | |||
onOk() { | |||
return new Promise((resolve, reject) => { | |||
setTimeout(() => { | |||
antdUtils.message?.open({ | |||
type: 'success', | |||
content: '删除成功', | |||
}); | |||
resolve(null) | |||
}, 1000); | |||
}).catch(() => antdUtils.message?.open({ | |||
type: 'error', | |||
content: '操作失败', | |||
})); | |||
}, | |||
onCancel() { | |||
}, | |||
}); | |||
}; | |||
const [editorVisable, seEditorVisable] = useState<boolean>(false); | |||
const [editData, seEditData] = useState<DictTypeVO>(); | |||
const [dataSource, setDataSource] = useState<DictTypeVO[]>([]); | |||
const [total, setTotal] = useState(0); | |||
const [searchFrom] = Form.useForm(); | |||
const { runAsync: getDictTypePageApi } = useRequest(dictTypeService.getDictTypePageApi, { manual: true }); | |||
const { runAsync: deleteDictTypeApi } = useRequest(dictTypeService.deleteDictTypeApi, { manual: true }); | |||
const { runAsync: getDictDataPageApi } = useRequest(dictDataService.getDictDataPageApi, { manual: true }); | |||
const { runAsync: deleteDictDataApi } = useRequest(dictDataService.deleteDictDataApi, { manual: true }); | |||
const load = async () => { | |||
const [error, { data }] = await getDictTypePageApi(searchFrom.getFieldsValue()); | |||
if (!error) { | |||
setDataSource(data.list); | |||
setTotal(data.total); | |||
} | |||
}; | |||
const columns: ColumnsType<DictTypeVO> = [ | |||
{ | |||
title: '字典名称', | |||
dataIndex: 'name', | |||
key: 'name', | |||
align: 'center', | |||
width: 150, | |||
}, | |||
{ | |||
title: '字典类型', | |||
dataIndex: 'type', | |||
key: 'type', | |||
align: 'center', | |||
width: 120, | |||
}, | |||
{ | |||
title: '状态', | |||
key: 'status', | |||
dataIndex: 'status', | |||
align: 'center', | |||
width: 120, | |||
}, | |||
{ | |||
title: t("QkOmYwne" /* 操作 */), | |||
key: 'action', | |||
align: 'center', | |||
render: (_, record) => ( | |||
<Space size="middle" split={( | |||
<Divider type='vertical' /> | |||
)}> | |||
<a | |||
onClick={() => { | |||
// setCreateVisible(true); | |||
// setCurRowData(record); | |||
}}> | |||
编辑 | |||
</a> | |||
<a | |||
onClick={() => { | |||
showDeleteConfirm(record) | |||
}}> | |||
删除 | |||
</a> | |||
</Space> | |||
), | |||
width: 150, | |||
}, | |||
]; | |||
const [isDisableDelete, setDisableDelete] = useState<boolean>(true) | |||
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]); | |||
const onSelectChange = (newSelectedRowKeys: React.Key[]) => { | |||
console.log('selectedRowKeys changed: ', newSelectedRowKeys); | |||
setSelectedRowKeys(newSelectedRowKeys); | |||
setDisableDelete(newSelectedRowKeys.length === 0) | |||
}; | |||
useEffect(() => { | |||
load(); | |||
}, []); | |||
const [ currentDictType, setCurrentDictType ] = useState<DictTypeVO>() | |||
return ( | |||
<> | |||
<div className='flex flex-row'> | |||
<Card className='basis-1/2 w-[100px] mb-[10px] dark:bg-[rgb(33,41,70)] bg-white roundle-lg px[12px]' | |||
<Card className='basis-1/2 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 />}> 新增字典 </Button> | |||
</div> | |||
<Table rowKey="id" | |||
scroll={{ x: true }} | |||
columns={columns} | |||
dataSource={dataSource} | |||
className='bg-transparent' | |||
pagination={{ | |||
pageSize: 10, | |||
current: 1, | |||
total, | |||
position: ['bottomRight'] | |||
}} | |||
/> | |||
<DictType | |||
onSelectDictType={(data) => setCurrentDictType(data)}/> | |||
</Card> | |||
<Card className='basis-1/2 mb-[10px] ml-[10px] dark:bg-[rgb(33,41,70)] bg-white roundle-lg px[12px]' bodyStyle={{ | |||
paddingTop: 0, | |||
paddingBottom: 0 | |||
}}> | |||
<DictData | |||
data={dataSource[0]}/> | |||
data={currentDictType}/> | |||
</Card> | |||
</div> | |||
</> | |||
@@ -73,7 +73,6 @@ const MenuIcon: React.FC<MenuIconProps> = ({ value = '', onChange }) => { | |||
const layout = { | |||
labelCol: { span: 4, }, | |||
wrapperCol: { span: 16 }, | |||
bordered: false, | |||
}; | |||
interface MenuEditorProps { | |||
@@ -8,7 +8,6 @@ import { antdUtils } from '@/utils/antd'; | |||
const layout = { | |||
labelCol: { span: 4, }, | |||
wrapperCol: { span: 16 }, | |||
bordered: false, | |||
}; | |||
interface EditorProps { | |||
@@ -9,7 +9,6 @@ import { antdUtils } from '@/utils/antd'; | |||
const layout = { | |||
labelCol: { span: 4, }, | |||
wrapperCol: { span: 16 }, | |||
bordered: false, | |||
}; | |||
interface RoleEditorProps { | |||
@@ -10,7 +10,6 @@ import { antdUtils } from '@/utils/antd'; | |||
const layout = { | |||
labelCol: { span: 4, }, | |||
wrapperCol: { span: 16 }, | |||
bordered: false, | |||
}; | |||
interface EditorProps { | |||