@@ -8,6 +8,7 @@ export * from './template.data.ts' | |||||
export * from './platform-product.data.ts' | export * from './platform-product.data.ts' | ||||
export * from './notice.data.ts' | export * from './notice.data.ts' | ||||
export * from './logs.data.ts' | export * from './logs.data.ts' | ||||
export * from './system-dict.data.ts' | |||||
export interface ResponseDTO<T>{ | export interface ResponseDTO<T>{ | ||||
code: number; | code: number; | ||||
@@ -0,0 +1,47 @@ | |||||
export type DictTypeVO = { | |||||
id: number | |||||
name: string | |||||
type: string | |||||
status: number | |||||
remark: string | |||||
createTime: Date | |||||
} | |||||
export interface DictTypePageReqVO extends PageParam { | |||||
name?: string | |||||
type?: string | |||||
status?: number | |||||
createTime?: Date[] | |||||
} | |||||
export type DictTypeExportReqVO = { | |||||
name: string | |||||
type: string | |||||
status: number | |||||
createTime: Date[] | |||||
} | |||||
export type DictDataVO = { | |||||
id: number | |||||
sort: number | |||||
label: string | |||||
value: string | |||||
dictType: string | |||||
status: number | |||||
colorType: string | |||||
cssClass: string | |||||
remark: string | |||||
createTime: Date | |||||
} | |||||
export interface DictDataPageReqVO extends PageParam { | |||||
label?: string | |||||
dictType: string | |||||
status?: number | |||||
} | |||||
export type DictDataExportReqVO = { | |||||
label: string | |||||
dictType: string | |||||
status: number | |||||
} |
@@ -1,14 +1,13 @@ | |||||
import React, { useEffect, useState } from 'react' | import React, { useEffect, useState } from 'react' | ||||
import { Form, Input, InputNumber, Modal } from 'antd'; | import { Form, Input, InputNumber, Modal } from 'antd'; | ||||
import dictService from '@/request/service/dict'; | |||||
import dictService from '@/request/service/template-dict'; | |||||
import { useRequest } from '@/hooks/use-request'; | import { useRequest } from '@/hooks/use-request'; | ||||
import type { DataDictDetailVO } from '@/models' | import type { DataDictDetailVO } from '@/models' | ||||
import { antdUtils } from '@/utils/antd'; | import { antdUtils } from '@/utils/antd'; | ||||
const layout = { | const layout = { | ||||
labelCol: { span: 4, }, | labelCol: { span: 4, }, | ||||
wrapperCol: { span: 16 }, | |||||
bordered: false, | |||||
wrapperCol: { span: 16 } | |||||
}; | }; | ||||
export default (props: { | export default (props: { | ||||
@@ -1,6 +1,6 @@ | |||||
import React, { useEffect, useState } from 'react' | import React, { useEffect, useState } from 'react' | ||||
import { Form, Input, Modal } from 'antd'; | import { Form, Input, Modal } from 'antd'; | ||||
import dictService from '@/request/service/dict'; | |||||
import dictService from '@/request/service/template-dict'; | |||||
import { useRequest } from '@/hooks/use-request'; | import { useRequest } from '@/hooks/use-request'; | ||||
import type { DataDictVO } from '@/models' | import type { DataDictVO } from '@/models' | ||||
import { antdUtils } from '@/utils/antd'; | import { antdUtils } from '@/utils/antd'; | ||||
@@ -8,7 +8,6 @@ import { antdUtils } from '@/utils/antd'; | |||||
const layout = { | const layout = { | ||||
labelCol: { span: 4, }, | labelCol: { span: 4, }, | ||||
wrapperCol: { span: 16 }, | wrapperCol: { span: 16 }, | ||||
bordered: false, | |||||
}; | }; | ||||
export default (props: { | export default (props: { | ||||
@@ -8,7 +8,6 @@ import { antdUtils } from '@/utils/antd'; | |||||
const layout = { | const layout = { | ||||
labelCol: { span: 4, }, | labelCol: { span: 4, }, | ||||
wrapperCol: { span: 16 }, | wrapperCol: { span: 16 }, | ||||
bordered: false, | |||||
}; | }; | ||||
interface EditorProps { | 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> | |||||
</> | |||||
) | |||||
}; |
@@ -0,0 +1,206 @@ | |||||
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, 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'; | |||||
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} 的字典吗?`, | |||||
icon: <ExclamationCircleFilled />, | |||||
content: '请注意删除以后不可恢复!', | |||||
okText: '删除', | |||||
okType: 'danger', | |||||
cancelText: '取消', | |||||
onOk() { | |||||
return new Promise(async (resolve) => { | |||||
const [error, { code, msg }] = await deleteDictDataApi(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<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 () => { | |||||
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> = [ | |||||
{ | |||||
title: '数据标签', | |||||
dataIndex: 'label', | |||||
key: 'label', | |||||
align: 'center', | |||||
width: 150, | |||||
...getColumnSearchProps('label') | |||||
}, | |||||
{ | |||||
title: '数据键值', | |||||
dataIndex: 'value', | |||||
key: 'value', | |||||
align: 'center', | |||||
width: 120, | |||||
}, | |||||
{ | |||||
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]); | |||||
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> | |||||
{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> | |||||
<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}/> | |||||
</> | |||||
); | |||||
}; |
@@ -0,0 +1,31 @@ | |||||
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 [ currentDictType, setCurrentDictType ] = useState<DictTypeVO>() | |||||
return ( | |||||
<> | |||||
<div className='flex flex-row'> | |||||
<Card className='basis-1/2 mb-[10px] dark:bg-[rgb(33,41,70)] bg-white roundle-lg px[12px]' | |||||
bodyStyle={{ | |||||
paddingTop: 0, | |||||
paddingBottom: 0 | |||||
}}> | |||||
<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={currentDictType}/> | |||||
</Card> | |||||
</div> | |||||
</> | |||||
); | |||||
}; |
@@ -73,7 +73,6 @@ const MenuIcon: React.FC<MenuIconProps> = ({ value = '', onChange }) => { | |||||
const layout = { | const layout = { | ||||
labelCol: { span: 4, }, | labelCol: { span: 4, }, | ||||
wrapperCol: { span: 16 }, | wrapperCol: { span: 16 }, | ||||
bordered: false, | |||||
}; | }; | ||||
interface MenuEditorProps { | interface MenuEditorProps { | ||||
@@ -8,7 +8,6 @@ import { antdUtils } from '@/utils/antd'; | |||||
const layout = { | const layout = { | ||||
labelCol: { span: 4, }, | labelCol: { span: 4, }, | ||||
wrapperCol: { span: 16 }, | wrapperCol: { span: 16 }, | ||||
bordered: false, | |||||
}; | }; | ||||
interface EditorProps { | interface EditorProps { | ||||
@@ -9,7 +9,6 @@ import { antdUtils } from '@/utils/antd'; | |||||
const layout = { | const layout = { | ||||
labelCol: { span: 4, }, | labelCol: { span: 4, }, | ||||
wrapperCol: { span: 16 }, | wrapperCol: { span: 16 }, | ||||
bordered: false, | |||||
}; | }; | ||||
interface RoleEditorProps { | interface RoleEditorProps { | ||||
@@ -10,7 +10,6 @@ import { antdUtils } from '@/utils/antd'; | |||||
const layout = { | const layout = { | ||||
labelCol: { span: 4, }, | labelCol: { span: 4, }, | ||||
wrapperCol: { span: 16 }, | wrapperCol: { span: 16 }, | ||||
bordered: false, | |||||
}; | }; | ||||
interface EditorProps { | interface EditorProps { | ||||
@@ -0,0 +1,41 @@ | |||||
import request from '@/request'; | |||||
import { DictDataVO, DictDataPageReqVO, DictDataExportReqVO, PageData } from '@/models'; | |||||
const BASE_URL = '/admin-api/system/dict-data'; | |||||
export default { | |||||
// 查询字典数据(精简)列表 | |||||
listSimpleDictDataApi: () => { | |||||
return request.get(`${BASE_URL}/list-all-simple`) | |||||
}, | |||||
// 查询字典数据列表 | |||||
getDictDataPageApi: (params: DictDataPageReqVO) => { | |||||
return request.get<PageData<DictDataVO>>(`${BASE_URL}/page`, { params }) | |||||
}, | |||||
// 查询字典数据详情 | |||||
getDictDataApi: (id: number) => { | |||||
return request.get(`${BASE_URL}/get?id=${id}`) | |||||
}, | |||||
// 新增字典数据 | |||||
createDictDataApi: (data: DictDataVO) => { | |||||
return request.post(`${BASE_URL}/create`, data) | |||||
}, | |||||
// 修改字典数据 | |||||
updateDictDataApi: (data: DictDataVO) => { | |||||
return request.put(`${BASE_URL}/update`, data) | |||||
}, | |||||
// 删除字典数据 | |||||
deleteDictDataApi: (id: number) => { | |||||
return request.delete(`${BASE_URL}/delete?id=${id}`) | |||||
}, | |||||
// 导出字典类型数据 | |||||
exportDictDataApi: (params: DictDataExportReqVO) => { | |||||
return request.get(`${BASE_URL}/export`, { params }) | |||||
} | |||||
}; |
@@ -0,0 +1,43 @@ | |||||
import request from '@/request'; | |||||
import { DictTypeVO, DictTypePageReqVO, DictTypeExportReqVO, PageData } from '@/models'; | |||||
const BASE_URL = '/admin-api/system/dict-type'; | |||||
export default { | |||||
// 查询字典(精简)列表 | |||||
listSimpleDictTypeApi: () => { | |||||
return request.get(`${BASE_URL}/list-all-simple`) | |||||
}, | |||||
// 查询字典列表 | |||||
getDictTypePageApi: (params: DictTypePageReqVO) => { | |||||
return request.get<PageData<DictTypeVO>>(`${BASE_URL}/page`, { params }) | |||||
}, | |||||
// 查询字典详情 | |||||
getDictTypeApi: (id: number) => { | |||||
return request.get(`${BASE_URL}/get?id=${id}`) | |||||
}, | |||||
// 新增字典 | |||||
createDictTypeApi: (data: DictTypeVO) => { | |||||
return request.post(`${BASE_URL}/create`, data) | |||||
}, | |||||
// 修改字典 | |||||
updateDictTypeApi: (data: DictTypeVO) => { | |||||
return request.put(`${BASE_URL}/update`, data) | |||||
}, | |||||
// 删除字典 | |||||
deleteDictTypeApi: (id: number) => { | |||||
return request.delete(`${BASE_URL}/delete?id=${id}`) | |||||
}, | |||||
// 导出字典类型 | |||||
exportDictTypeApi: (params: DictTypeExportReqVO) => { | |||||
return request.get(`${BASE_URL}/export`, { params }) | |||||
} | |||||
}; | |||||