Ver código fonte

add:data dict page

dev
powersir 1 ano atrás
pai
commit
748ccac9a2
6 arquivos alterados com 554 adições e 5 exclusões
  1. +1
    -0
      src/models/index.ts
  2. +16
    -0
      src/models/template.data.ts
  3. +112
    -0
      src/pages/custom/template/dict/dict-detail-editor.tsx
  4. +101
    -0
      src/pages/custom/template/dict/dict-editor.tsx
  5. +296
    -5
      src/pages/custom/template/dict/index.tsx
  6. +28
    -0
      src/request/service/dict.ts

+ 1
- 0
src/models/index.ts Ver arquivo

@@ -4,6 +4,7 @@ export * from './role.data.ts'
export * from './position.data.ts'
export * from './department.data.ts'
export * from './tenant.data.ts'
export * from './template.data.ts'

export interface ResponseDTO<T>{
code: number;


+ 16
- 0
src/models/template.data.ts Ver arquivo

@@ -0,0 +1,16 @@

//数据字典
export interface DataDictVO{
description: string;
id: number;
name: string;
}

//数据字典详情
export interface DataDictDetailVO {
dictId: number;
dictSort: number;
id: number;
label: string;
value: string;
}

+ 112
- 0
src/pages/custom/template/dict/dict-detail-editor.tsx Ver arquivo

@@ -0,0 +1,112 @@
import React, { useEffect, useState } from 'react'
import { Form, Input, InputNumber, Modal } from 'antd';
import dictService from '@/request/service/dict';
import { useRequest } from '@/hooks/use-request';
import type { DataDictDetailVO } from '@/models'
import { antdUtils } from '@/utils/antd';

const layout = {
labelCol: { span: 4, },
wrapperCol: { span: 16 },
bordered: false,
};

export default (props: {
visible: boolean;
onCancel: (flag?: boolean) => void;
onSave: (role: DataDictDetailVO) => void;
data?: DataDictDetailVO | null;
}) => {

const { visible, onCancel, onSave, data } = props;

const { runAsync: updateApi } = useRequest(dictService.updateDictDetailApi, { manual: true });
const { runAsync: createApi } = useRequest(dictService.deleteDictDetailApi, { 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 updateApi(newValue) : await createApi(newValue);
if (!error && code === 0) {
onSave(newValue);
} else {
antdUtils.message?.open({
type: 'error',
content: msg ?? '操作失败',
});
}
setSaveLoading(false);
}

return (
<>
<Modal
open={visible}
title="新建"
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="label" label="字典标签"
rules={[
{
required: true,
message: '请输字典标签',
},
]}
>
<Input />
</Form.Item>

<Form.Item name="value" label="字典值"
rules={[
{
required: true,
message: '请输入字典值',
},
]}
>
<Input.TextArea />
</Form.Item>

<Form.Item name="dictSort" label="字典排序"
rules={[
{
required: true,
message: '请输入字典排序',
},
]}
>
<InputNumber min={1} />
</Form.Item>
</Form>
</Modal>
</>
)
};

+ 101
- 0
src/pages/custom/template/dict/dict-editor.tsx Ver arquivo

@@ -0,0 +1,101 @@
import React, { useEffect, useState } from 'react'
import { Form, Input, Modal } from 'antd';
import dictService from '@/request/service/dict';
import { useRequest } from '@/hooks/use-request';
import type { DataDictVO } from '@/models'
import { antdUtils } from '@/utils/antd';

const layout = {
labelCol: { span: 4, },
wrapperCol: { span: 16 },
bordered: false,
};

export default (props: {
visible: boolean;
onCancel: (flag?: boolean) => void;
onSave: (role: DataDictVO) => void;
data?: DataDictVO | null;
}) => {

const { visible, onCancel, onSave, data } = props;

const { runAsync: updateApi } = useRequest(dictService.updateDictApi, { manual: true });
const { runAsync: createApi } = useRequest(dictService.createDictApi, { 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 updateApi(newValue) : await createApi(newValue);
if (!error && code === 0) {
onSave(newValue);
} else {
antdUtils.message?.open({
type: 'error',
content: msg ?? '操作失败',
});
}
setSaveLoading(false);
}

return (
<>
<Modal
open={visible}
title="新建"
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="description" label="字典描述"
rules={[
{
required: true,
message: '请输入字典描述',
},
]}
>
<Input />
</Form.Item>
</Form>
</Modal>
</>
)
};

+ 296
- 5
src/pages/custom/template/dict/index.tsx Ver arquivo

@@ -1,9 +1,300 @@
import { Empty } from 'antd';
import React, { useState, useRef } 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 { DataDictVO, DataDictDetailVO } from '@/models';
import DictEditor from './dict-editor';
import DictDetailEditor from './dict-detail-editor';

const dataDicts: DataDictVO[] = [
{
"id": 43,
"name": "爆款词",
"description": "爆款词"
},
{
"id": 42,
"name": "T-T",
"description": "t-shirt"
},
{
"id": 41,
"name": "T-shirt Background",
"description": "T桖背景"
}
]

const dictDetailsA: DataDictDetailVO[] = [
{
"id": 114,
"dictId": 43,
"label": "tshirt for women",
"value": "tshirt for women",
"dictSort": 1
},
{
"id": 113,
"dictId": 43,
"label": "oversize t shirt black",
"value": "oversize t shirt black",
"dictSort": 1
},
{
"id": 112,
"dictId": 43,
"label": "oversize t shirt",
"value": "oversize t shirt",
"dictSort": 1
}
]

const dictDetailsB: DataDictDetailVO[] = [
{
"id": 107,
"dictId": 42,
"label": "three",
"value": "three",
"dictSort": 3
},
{
"id": 106,
"dictId": 42,
"label": "two",
"value": "two",
"dictSort": 2
},
{
"id": 105,
"dictId": 42,
"label": "one",
"value": "one",
"dictSort": 1
}
]

const dictDetailsC: DataDictDetailVO[] = [
{
"id": 111,
"dictId": 41,
"label": "Soothing hot springs",
"value": "Hot spring photos, hot spring water, beautiful scenery, no one, film quality, 8K, meticulous",
"dictSort": 5
},
{
"id": 110,
"dictId": 41,
"label": "Great Eiffel Tower",
"value": "Keywords Paris Tower, photo, high quality, 8K,",
"dictSort": 4
},
{
"id": 109,
"dictId": 41,
"label": "Iconic Eiffel Tower",
"value": "Keywords Paris Tower, photo, high quality, 8K,",
"dictSort": 3
},
{
"id": 108,
"dictId": 41,
"label": "Pleasant Tunisia",
"value": "Venice, photos, high quality, 8K, water, details, film quality, rendering, beautiful scenery.",
"dictSort": 2
},
{
"id": 104,
"dictId": 41,
"label": "Trendy Tunisia",
"value": "Venice, photos, high quality, 8K, water, details, film quality, rendering, beautiful scenery.",
"dictSort": 1
}
]


export default () => {

const [dictDetail, setDictDetail] = useState<DataDictDetailVO[]>();

const [editorVisable, seEditorVisable] = useState<boolean>(false);
const [editData, seEditData] = useState<DataDictVO>();

const [detailEditorVisable, seEdtailEditorVisable] = useState<boolean>(false);
const [editDetailData, seEditDetailData] = useState<DataDictDetailVO>();

const showDeleteConfirm = (item: DataDictVO) => {
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 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) => {
if (data.id == 43) {
setDictDetail(dictDetailsA)
} else if (data.id == 42) {
setDictDetail(dictDetailsB)
} else {
setDictDetail(dictDetailsC)
}
}


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,
},
];

const CustomMade = () => {
return (
<Empty />
<>
<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]'>
<Table rowKey="id" scroll={{ x: true }} columns={dictColumns} dataSource={dataDicts} className='bg-transparent'
onRow={(record) => {
return {
onClick: () => {
updateDactDetail(record)
}
};
}}
pagination={{ position: ['bottomRight'] }}
/>
</Card>
<Card className='basis-3/5 mb-[10px] ml-[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={dictDetail} className='bg-transparent'
pagination={{ position: ['bottomRight'] }}
/>
</Card>
</div>
<DictEditor
onSave={() => {
}}
onCancel={() => { seEditorVisable(false) }}
visible={editorVisable}
data={editData}
/>

<DictDetailEditor
onSave={() => {
}}
onCancel={() => { seEdtailEditorVisable(false) }}
visible={detailEditorVisable}
data={editDetailData}
/>
</>
);
};

export default CustomMade;

+ 28
- 0
src/request/service/dict.ts Ver arquivo

@@ -0,0 +1,28 @@
import request from '@/request';
import { DataDictVO, DataDictDetailVO } from '@/models';

const BASE_URL = '/admin-api/system/dict';

export default {

createDictApi: (data: DataDictVO) => {
return request.post(`${BASE_URL}/create`, data);
},

updateDictApi: (data: DataDictVO) => {
return request.put(`${BASE_URL}/update`, data);
},

deleteDictApi: (id: number) => {
return request.delete(`${BASE_URL}/delete?id=${id}`);
},

updateDictDetailApi: (data: DataDictDetailVO) => {
return request.put(`${BASE_URL}/update`, data);
},

deleteDictDetailApi: (id: number) => {
return request.delete(`${BASE_URL}/delete?id=${id}`);
},

};

Carregando…
Cancelar
Salvar