V 1.1.0
新增数据信息 完善数据信息得权限问题
This commit is contained in:
parent
896461f6d4
commit
6e52f5ce9a
@ -83,6 +83,13 @@ export default [
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/optionManagement',
|
||||||
|
name: 'optionManagement',
|
||||||
|
icon: 'Product',
|
||||||
|
access: 'canOptionManagement',
|
||||||
|
component: './Options/OptionsManagement',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/roleManagement',
|
path: '/roleManagement',
|
||||||
name: 'roleManagement',
|
name: 'roleManagement',
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "lms",
|
"name": "lms",
|
||||||
"version": "1.0.8",
|
"version": "1.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"description": "An out-of-box UI solution for enterprise applications",
|
"description": "An out-of-box UI solution for enterprise applications",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@ -7,6 +7,7 @@ export default function access(initialState: { currentUser?: API.CurrentUser } |
|
|||||||
let access = {
|
let access = {
|
||||||
canPrompt: false,
|
canPrompt: false,
|
||||||
canRoleManagement: false,
|
canRoleManagement: false,
|
||||||
|
canOptionManagement: false,
|
||||||
|
|
||||||
canUserManagement: false,
|
canUserManagement: false,
|
||||||
canEditUser: false,
|
canEditUser: false,
|
||||||
@ -87,6 +88,7 @@ export default function access(initialState: { currentUser?: API.CurrentUser } |
|
|||||||
access = {
|
access = {
|
||||||
...access,
|
...access,
|
||||||
canPrompt: true,
|
canPrompt: true,
|
||||||
|
canOptionManagement : true,
|
||||||
|
|
||||||
canUserManagement: true,
|
canUserManagement: true,
|
||||||
canEditUser: true,
|
canEditUser: true,
|
||||||
@ -121,7 +123,8 @@ export default function access(initialState: { currentUser?: API.CurrentUser } |
|
|||||||
...access,
|
...access,
|
||||||
canPrompt: true,
|
canPrompt: true,
|
||||||
canRoleManagement: true,
|
canRoleManagement: true,
|
||||||
|
canOptionManagement : true,
|
||||||
|
|
||||||
canUserManagement: true,
|
canUserManagement: true,
|
||||||
canEditUser: true,
|
canEditUser: true,
|
||||||
canDeleteUser: true,
|
canDeleteUser: true,
|
||||||
|
|||||||
@ -13,6 +13,8 @@ export default {
|
|||||||
|
|
||||||
'menu.roleManagement': '角色管理',
|
'menu.roleManagement': '角色管理',
|
||||||
|
|
||||||
|
'menu.optionManagement': '数据管理',
|
||||||
|
|
||||||
'menu.userManagement': '用户管理',
|
'menu.userManagement': '用户管理',
|
||||||
|
|
||||||
'menu.machineManagement': '机器码管理',
|
'menu.machineManagement': '机器码管理',
|
||||||
|
|||||||
236
src/pages/Options/AddModifyOption.tsx
Normal file
236
src/pages/Options/AddModifyOption.tsx
Normal file
@ -0,0 +1,236 @@
|
|||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import { Form, Input, Button, Card, Select, message, Spin, FormInstance, SelectProps, Tag } from 'antd';
|
||||||
|
import { ArrowLeftOutlined, SaveOutlined } from '@ant-design/icons';
|
||||||
|
import { useParams, history } from 'umi';
|
||||||
|
import { PageContainer } from '@ant-design/pro-layout';
|
||||||
|
import { useModel } from '@umijs/max';
|
||||||
|
import { cusRequest } from '@/request';
|
||||||
|
import { getOptionCategoryOptions, getOptionTypeOptions, OptionCategory, OptionType } from '@/services/enum/optionEnum';
|
||||||
|
import { useSoftStore } from '@/store/software';
|
||||||
|
import { OptionModel } from '@/services/typing/options/option';
|
||||||
|
import { CheckJsonString } from '@/services/services/common';
|
||||||
|
import { QueryRoleOption } from '@/services/services/role';
|
||||||
|
import { isEmpty } from 'lodash';
|
||||||
|
|
||||||
|
const { TextArea } = Input;
|
||||||
|
|
||||||
|
interface OptionParams {
|
||||||
|
optionKey?: string;
|
||||||
|
category?: OptionCategory;
|
||||||
|
setFormRef: (form: FormInstance) => void;
|
||||||
|
open: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const AddModifyOption: React.FC<OptionParams> = ({ optionKey, setFormRef, open, category }) => {
|
||||||
|
const { initialState } = useModel('@@initialState');
|
||||||
|
const [form] = Form.useForm();
|
||||||
|
const [loading, setLoading] = useState<boolean>(false);
|
||||||
|
const [tip, setTip] = useState<string>('加载数据中。。。');
|
||||||
|
const [roleOptions, setRoleOptions] = useState<SelectProps['options']>([]);
|
||||||
|
const [messageApi, messageHolder] = message.useMessage();
|
||||||
|
type TagRender = SelectProps['tagRender'];
|
||||||
|
const isEdit = !!optionKey;
|
||||||
|
|
||||||
|
const tagRender: TagRender = (props) => {
|
||||||
|
const { label, value, closable, onClose } = props;
|
||||||
|
const onPreventMouseDown = (event: React.MouseEvent<HTMLSpanElement>) => {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<Tag
|
||||||
|
color="cyan"
|
||||||
|
onMouseDown={onPreventMouseDown}
|
||||||
|
closable={closable}
|
||||||
|
onClose={onClose}
|
||||||
|
style={{ marginInlineEnd: 4 }}
|
||||||
|
>
|
||||||
|
{label}
|
||||||
|
</Tag>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// 获取选项详情
|
||||||
|
const fetchOptionDetail = async () => {
|
||||||
|
debugger;
|
||||||
|
if (isEmpty(optionKey)) return;
|
||||||
|
setLoading(true);
|
||||||
|
setTip('正在获取选项详情,请稍等。。。');
|
||||||
|
try {
|
||||||
|
const res = await cusRequest<any>(`/lms/Options/GetAllMessageOptionsByKey/${category}/${optionKey}`, {
|
||||||
|
method: 'GET',
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res.code === 1) {
|
||||||
|
form.setFieldsValue(res.data);
|
||||||
|
} else {
|
||||||
|
messageApi.error(res.message || '获取选项详情失败');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取选项详情失败:', error);
|
||||||
|
messageApi.error('获取选项详情失败');
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 保存选项
|
||||||
|
const handleSubmit = async (values: OptionModel.OptionsItem) => {
|
||||||
|
setLoading(true);
|
||||||
|
setTip('正在保存数据,请稍等。。。');
|
||||||
|
try {
|
||||||
|
|
||||||
|
// 判断类型和值
|
||||||
|
if (values.type == OptionType.JSON) {
|
||||||
|
if (CheckJsonString(values.value) == false) {
|
||||||
|
messageApi.error("JSON格式不正确,请检查");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (values.type == OptionType.Number) {
|
||||||
|
if (isNaN(Number(values.value))) {
|
||||||
|
messageApi.error("数字格式不正确,请检查");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (values.type == OptionType.Boolean) {
|
||||||
|
if (values.value !== 'true' && values.value !== 'false') {
|
||||||
|
messageApi.error("布尔值格式不正确,请检查");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let url = '/lms/Options/AddOptions';
|
||||||
|
let method = 'POST';
|
||||||
|
|
||||||
|
if (isEdit) {
|
||||||
|
url = `/lms/Options/ModifyOptionsByKey/${optionKey}`;
|
||||||
|
method = 'POST';
|
||||||
|
delete values.key;
|
||||||
|
}
|
||||||
|
debugger;
|
||||||
|
if (values.roleNames == null || values.roleNames == undefined) {
|
||||||
|
values.roleNames = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await cusRequest<string>(url, {
|
||||||
|
method,
|
||||||
|
data: values,
|
||||||
|
});
|
||||||
|
console.log(res);
|
||||||
|
|
||||||
|
if (res.code == 1) {
|
||||||
|
messageApi.success(`${isEdit ? '修改' : '添加'}成功`);
|
||||||
|
} else {
|
||||||
|
messageApi.error(res.message || `${isEdit ? '修改' : '添加'}失败`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`${isEdit ? '修改' : '添加'}选项失败:`, error);
|
||||||
|
messageApi.error(`${isEdit ? '修改' : '添加'}失败`);
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// 获取选项列表
|
||||||
|
const fetchOptions = async () => {
|
||||||
|
QueryRoleOption().then((res: string[]) => {
|
||||||
|
let temRoleNames = res.map((item) => {
|
||||||
|
return {
|
||||||
|
value: item,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (!initialState?.currentUser?.roleNames.includes("Super Admin")) {
|
||||||
|
temRoleNames = res.filter(item => item !== "Super Admin").map((item) => {
|
||||||
|
return {
|
||||||
|
value: item,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
console.log("temRoleNames", temRoleNames);
|
||||||
|
setRoleOptions(temRoleNames);
|
||||||
|
}).catch((error: any) => {
|
||||||
|
messageApi.error(error.message);
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
// 组件加载时获取数据
|
||||||
|
useEffect(() => {
|
||||||
|
fetchOptions();
|
||||||
|
setFormRef(form);
|
||||||
|
debugger
|
||||||
|
if (isEdit) {
|
||||||
|
fetchOptionDetail();
|
||||||
|
}
|
||||||
|
}, [optionKey, open, setFormRef]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Spin spinning={loading} tip={tip}>
|
||||||
|
<Card title={isEdit ? '修改选项' : '添加选项'}>
|
||||||
|
<Form
|
||||||
|
form={form}
|
||||||
|
layout="vertical"
|
||||||
|
onFinish={handleSubmit}
|
||||||
|
>
|
||||||
|
|
||||||
|
<Form.Item name="key" label="键" rules={[{ required: true, message: '请输入键' }]}>
|
||||||
|
<Input placeholder="请输入键" allowClear />
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
name="value"
|
||||||
|
label="键值"
|
||||||
|
rules={[{ required: true, message: '请输入键值' }]}
|
||||||
|
>
|
||||||
|
<TextArea
|
||||||
|
placeholder="请输入键值"
|
||||||
|
autoSize={{ minRows: 4, maxRows: 8 }}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item name="type" label="值类型" rules={[{ required: true, message: '请选择值类型' }]}>
|
||||||
|
<Select
|
||||||
|
placeholder="请选择值类型"
|
||||||
|
options={getOptionTypeOptions()}
|
||||||
|
allowClear
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item name="category" label="数据分类" rules={[{ required: true, message: '请选择数据分类' }]}>
|
||||||
|
<Select
|
||||||
|
allowClear
|
||||||
|
placeholder="请选择数据分类"
|
||||||
|
|
||||||
|
options={getOptionCategoryOptions()}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item name="roleNames" label="权限角色" help="选择角色分组后,只有该角色组的用户才能使用该选项">
|
||||||
|
<Select
|
||||||
|
allowClear
|
||||||
|
mode="multiple"
|
||||||
|
tagRender={tagRender}
|
||||||
|
options={roleOptions}
|
||||||
|
placeholder="请选择角色分组"
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item>
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
htmlType="submit"
|
||||||
|
icon={<SaveOutlined />}
|
||||||
|
style={{ marginRight: 16 }}
|
||||||
|
>
|
||||||
|
保存
|
||||||
|
</Button>
|
||||||
|
</Form.Item>
|
||||||
|
</Form>
|
||||||
|
</Card>
|
||||||
|
{messageHolder}
|
||||||
|
</Spin>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AddModifyOption;
|
||||||
443
src/pages/Options/OptionsManagement.tsx
Normal file
443
src/pages/Options/OptionsManagement.tsx
Normal file
@ -0,0 +1,443 @@
|
|||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import { Table, Form, Input, Button, Space, Select, message, Popconfirm, Tag, SelectProps, Modal } from 'antd';
|
||||||
|
import { PlusOutlined, SearchOutlined, EditOutlined, DeleteOutlined } from '@ant-design/icons';
|
||||||
|
import { cusRequest } from '@/request';
|
||||||
|
|
||||||
|
import { useModel } from '@umijs/max';
|
||||||
|
import type { ColumnsType, TablePaginationConfig } from 'antd/es/table';
|
||||||
|
import { history } from 'umi';
|
||||||
|
import TemplateContainer from '../TemplateContainer';
|
||||||
|
import { QueryRoleOption } from '@/services/services/role';
|
||||||
|
import { getOptionCategoryOptions, getOptionTypeOptions, OptionCategory } from '@/services/enum/optionEnum';
|
||||||
|
import { OptionModel } from '@/services/typing/options/option';
|
||||||
|
import { CheckJsonString, objectToQueryString } from '@/services/services/common';
|
||||||
|
import JsonView from '@uiw/react-json-view';
|
||||||
|
import { useFormReset } from '@/hooks/useFormReset';
|
||||||
|
import AddModifyOption from './AddModifyOption';
|
||||||
|
import { useSoftStore } from '@/store/software';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const OptionsManagement: React.FC = () => {
|
||||||
|
const { initialState } = useModel('@@initialState');
|
||||||
|
const [form] = Form.useForm();
|
||||||
|
const [loading, setLoading] = useState<boolean>(false);
|
||||||
|
const { setTopSpinning, setTopSpinTip } = useSoftStore();
|
||||||
|
const [key, setKey] = useState<string | undefined>(undefined);
|
||||||
|
const [category, setCategory] = useState<OptionCategory | undefined>(undefined);
|
||||||
|
const [dataSource, setDataSource] = useState<OptionModel.OptionsItem[]>([]);
|
||||||
|
const [openModal, setOpenModal] = useState<boolean>(false);
|
||||||
|
const [roleOptions, setRoleOptions] = useState<SelectProps['options']>([]);
|
||||||
|
const [tableParams, setTableParams] = useState<TableModel.TableParams>({
|
||||||
|
pagination: {
|
||||||
|
current: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
showQuickJumper: true,
|
||||||
|
totalBoundaryShowSizeChanger: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const [messageApi, messageHolder] = message.useMessage();
|
||||||
|
const [modalApi, modalHolder] = Modal.useModal();
|
||||||
|
const { setFormRef, resetForm } = useFormReset();
|
||||||
|
|
||||||
|
const [isModalVisible, setIsModalVisible] = useState<boolean>(false);
|
||||||
|
const [currentJsonData, setCurrentJsonData] = useState<any>(null);
|
||||||
|
const [isJsonFormat, setIsJsonFormat] = useState<boolean>(false);
|
||||||
|
|
||||||
|
type TagRender = SelectProps['tagRender'];
|
||||||
|
|
||||||
|
|
||||||
|
// 获取选项列表
|
||||||
|
const fetchOptions = async () => {
|
||||||
|
QueryRoleOption().then((res: string[]) => {
|
||||||
|
let temRoleNames = res.map((item) => {
|
||||||
|
return {
|
||||||
|
value: item,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (!initialState?.currentUser?.roleNames.includes("Super Admin")) {
|
||||||
|
temRoleNames = res.filter(item => item !== "Super Admin").map((item) => {
|
||||||
|
return {
|
||||||
|
value: item,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
console.log("temRoleNames", temRoleNames);
|
||||||
|
setRoleOptions(temRoleNames);
|
||||||
|
}).catch((error: any) => {
|
||||||
|
messageApi.error(error.message);
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
// 删除选项
|
||||||
|
const handleDelete = async (record: OptionModel.OptionsItem) => {
|
||||||
|
try {
|
||||||
|
let confirm = await modalApi.confirm({
|
||||||
|
title: "确认删除",
|
||||||
|
content: "该操作会删除当前数据信息,请谨慎操作!",
|
||||||
|
okText: "继续",
|
||||||
|
});
|
||||||
|
if (!confirm) {
|
||||||
|
messageApi.info("已取消删除操作");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
setTopSpinning(true);
|
||||||
|
setTopSpinTip("正在删除选项");
|
||||||
|
const res = await cusRequest<any>(`/lms/Options/DeleteOptionsByKey/${record.category}/${record.key}`, {
|
||||||
|
method: 'DELETE',
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res.code === 1) {
|
||||||
|
messageApi.success('删除成功');
|
||||||
|
await QueryOption();
|
||||||
|
} else {
|
||||||
|
messageApi.error(res.message || '删除失败');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('删除选项失败:', error);
|
||||||
|
messageApi.error('删除失败');
|
||||||
|
} finally {
|
||||||
|
setTopSpinning(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 编辑选项
|
||||||
|
const handleEdit = (record: OptionModel.OptionsItem) => {
|
||||||
|
debugger
|
||||||
|
setKey(record.key);
|
||||||
|
setCategory(record.category);
|
||||||
|
setOpenModal(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 添加选项
|
||||||
|
const handleAdd = () => {
|
||||||
|
setKey("");
|
||||||
|
setCategory(undefined);
|
||||||
|
setOpenModal(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Function to handle clicking on data
|
||||||
|
const handleDataClick = (dataString: string) => {
|
||||||
|
let isJsonString = CheckJsonString(dataString);
|
||||||
|
|
||||||
|
if (isJsonString) {
|
||||||
|
const jsonData = JSON.parse(dataString);
|
||||||
|
setCurrentJsonData(jsonData);
|
||||||
|
setIsJsonFormat(true);
|
||||||
|
} else {
|
||||||
|
// 不是JSON格式,直接展示原始字符串
|
||||||
|
setCurrentJsonData(dataString);
|
||||||
|
setIsJsonFormat(false);
|
||||||
|
}
|
||||||
|
setIsModalVisible(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 关闭Modal的函数
|
||||||
|
const handleModalClose = () => {
|
||||||
|
setIsModalVisible(false);
|
||||||
|
setCurrentJsonData(null);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 表格列定义
|
||||||
|
const columns: ColumnsType<OptionModel.OptionsItem> = [
|
||||||
|
|
||||||
|
{
|
||||||
|
title: '键',
|
||||||
|
dataIndex: 'key',
|
||||||
|
key: 'key',
|
||||||
|
width: 150,
|
||||||
|
fixed: 'left',
|
||||||
|
ellipsis: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '值',
|
||||||
|
dataIndex: 'value',
|
||||||
|
key: 'value',
|
||||||
|
ellipsis: true,
|
||||||
|
render: (text) => (
|
||||||
|
<a style={{ cursor: 'pointer', color: 'black' }}>
|
||||||
|
{text}
|
||||||
|
</a>
|
||||||
|
),
|
||||||
|
onCell: (record) => ({
|
||||||
|
onClick: () => handleDataClick(record.value),
|
||||||
|
style: { cursor: 'pointer' }
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '类型',
|
||||||
|
dataIndex: 'type',
|
||||||
|
key: 'type',
|
||||||
|
width: 120,
|
||||||
|
render: (text) => {
|
||||||
|
return getOptionTypeOptions().find((item) => item.value == text)?.label;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '分类',
|
||||||
|
dataIndex: 'category',
|
||||||
|
key: 'category',
|
||||||
|
width: 120,
|
||||||
|
render: (text) => {
|
||||||
|
return getOptionCategoryOptions().find((item) => item.value == text)?.label;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '角色',
|
||||||
|
dataIndex: 'roleNames',
|
||||||
|
render: (text, record) => {
|
||||||
|
let res = record.roleNames.map((item) => {
|
||||||
|
return <Tag key={item} color="cyan">{item}</Tag>
|
||||||
|
});
|
||||||
|
return res;
|
||||||
|
},
|
||||||
|
width: '340px',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '操作',
|
||||||
|
key: 'action',
|
||||||
|
fixed: 'right',
|
||||||
|
width: 160,
|
||||||
|
render: (_, record) => (
|
||||||
|
<Space>
|
||||||
|
<Button
|
||||||
|
type='primary'
|
||||||
|
size='small'
|
||||||
|
icon={<EditOutlined />}
|
||||||
|
onClick={() => handleEdit(record)}
|
||||||
|
>
|
||||||
|
编辑
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Button danger size='small' onClick={() => handleDelete(record)} icon={<DeleteOutlined />}>
|
||||||
|
删除
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
</Space>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
async function QueryOption() {
|
||||||
|
await queryOptionBasic(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询查询数据
|
||||||
|
async function queryOptionBasic(pagination: TablePaginationConfig | null) {
|
||||||
|
setLoading(true);
|
||||||
|
try {
|
||||||
|
let tableParamsParams = pagination ? { pagination } : tableParams;
|
||||||
|
|
||||||
|
let query = objectToQueryString({
|
||||||
|
...form.getFieldsValue(),
|
||||||
|
page: tableParamsParams.pagination?.current ?? 1,
|
||||||
|
pageSize: tableParamsParams.pagination?.pageSize ?? 10,
|
||||||
|
});
|
||||||
|
let res = await cusRequest<BasicModel.QueryCollection<OptionModel.OptionsItem[]>>(`/lms/Options/QueryOptionCollection?${query}`, {
|
||||||
|
method: 'GET',
|
||||||
|
});
|
||||||
|
if (res.code != 1) {
|
||||||
|
messageApi.error(res.message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (res.data == undefined) {
|
||||||
|
messageApi.error("没有查询到数据");
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
setDataSource(res.data.collection);
|
||||||
|
setTableParams({
|
||||||
|
pagination: {
|
||||||
|
...tableParamsParams.pagination,
|
||||||
|
total: res.data.total,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} catch (error: any) {
|
||||||
|
messageApi.error(error.message);
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 表格变化处理
|
||||||
|
const handleTableChange = async (
|
||||||
|
pagination: any,
|
||||||
|
filters: any,
|
||||||
|
sorter: any
|
||||||
|
) => {
|
||||||
|
setLoading(true);
|
||||||
|
try {
|
||||||
|
await queryOptionBasic(pagination);
|
||||||
|
setTableParams({
|
||||||
|
pagination: {
|
||||||
|
...pagination,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
} catch (error: any) {
|
||||||
|
message.error(error.message);
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const tagRender: TagRender = (props) => {
|
||||||
|
const { label, value, closable, onClose } = props;
|
||||||
|
const onPreventMouseDown = (event: React.MouseEvent<HTMLSpanElement>) => {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<Tag
|
||||||
|
color="cyan"
|
||||||
|
onMouseDown={onPreventMouseDown}
|
||||||
|
closable={closable}
|
||||||
|
onClose={onClose}
|
||||||
|
style={{ marginInlineEnd: 4 }}
|
||||||
|
>
|
||||||
|
{label}
|
||||||
|
</Tag>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
async function modalCancel(): Promise<void> {
|
||||||
|
setOpenModal(false);
|
||||||
|
setKey('');
|
||||||
|
setCategory(undefined);
|
||||||
|
resetForm();
|
||||||
|
// 这边调用加载数据的方法
|
||||||
|
await QueryOption();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 初始化加载
|
||||||
|
useEffect(() => {
|
||||||
|
fetchOptions();
|
||||||
|
QueryOption();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TemplateContainer navTheme={initialState?.settings?.navTheme ?? "light"}>
|
||||||
|
<Form
|
||||||
|
form={form}
|
||||||
|
layout="inline"
|
||||||
|
onFinish={QueryOption}
|
||||||
|
style={{ marginBottom: 16 }}
|
||||||
|
>
|
||||||
|
<div style={{ display: 'flex', flexWrap: 'wrap', gap: '16px', marginBottom: '16px' }}>
|
||||||
|
<Form.Item name="key" label="键">
|
||||||
|
<Input placeholder="请输入键" style={{ width: 200 }} allowClear />
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item name="type" label="值类型">
|
||||||
|
<Select
|
||||||
|
placeholder="请选择值类型"
|
||||||
|
style={{ width: 200 }}
|
||||||
|
options={getOptionTypeOptions()}
|
||||||
|
allowClear
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item name="category" label="数据分类">
|
||||||
|
<Select
|
||||||
|
allowClear
|
||||||
|
placeholder="请选择数据分类"
|
||||||
|
style={{ width: 200 }}
|
||||||
|
options={getOptionCategoryOptions()}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item name="roleNames" label="权限角色">
|
||||||
|
<Select
|
||||||
|
allowClear
|
||||||
|
mode="multiple"
|
||||||
|
tagRender={tagRender}
|
||||||
|
style={{ maxWidth: '400px', minWidth: "260px" }}
|
||||||
|
options={roleOptions}
|
||||||
|
placeholder="请选择角色分组"
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item>
|
||||||
|
<Space>
|
||||||
|
<Button type="primary" htmlType="submit" icon={<SearchOutlined />}>
|
||||||
|
查询
|
||||||
|
</Button>
|
||||||
|
<Button onClick={() => {
|
||||||
|
form.resetFields()
|
||||||
|
QueryOption()
|
||||||
|
}}>
|
||||||
|
重置
|
||||||
|
</Button>
|
||||||
|
<Button type="primary" onClick={handleAdd} icon={<PlusOutlined />}>
|
||||||
|
新增数据
|
||||||
|
</Button>
|
||||||
|
</Space>
|
||||||
|
</Form.Item>
|
||||||
|
</div>
|
||||||
|
</Form>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<Table
|
||||||
|
columns={columns}
|
||||||
|
rowKey="id"
|
||||||
|
dataSource={dataSource}
|
||||||
|
pagination={tableParams.pagination}
|
||||||
|
loading={loading}
|
||||||
|
onChange={handleTableChange}
|
||||||
|
scroll={{ x: 1500 }}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* JSON 数据查看器 Modal */}
|
||||||
|
<Modal
|
||||||
|
title="数据详情"
|
||||||
|
open={isModalVisible}
|
||||||
|
onCancel={handleModalClose}
|
||||||
|
footer={null}
|
||||||
|
width={800}
|
||||||
|
>
|
||||||
|
{isJsonFormat ? (
|
||||||
|
<JsonView
|
||||||
|
value={currentJsonData}
|
||||||
|
displayDataTypes={false}
|
||||||
|
displayObjectSize={false}
|
||||||
|
enableClipboard={true}
|
||||||
|
style={{
|
||||||
|
padding: '10px',
|
||||||
|
borderRadius: '4px',
|
||||||
|
maxHeight: '70vh',
|
||||||
|
overflow: 'auto',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<pre
|
||||||
|
style={{
|
||||||
|
whiteSpace: 'pre-wrap',
|
||||||
|
wordWrap: 'break-word',
|
||||||
|
maxHeight: '70vh',
|
||||||
|
overflow: 'auto',
|
||||||
|
padding: '10px',
|
||||||
|
background: '#f5f5f5',
|
||||||
|
borderRadius: '4px',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{currentJsonData}
|
||||||
|
</pre>
|
||||||
|
)}
|
||||||
|
</Modal>
|
||||||
|
|
||||||
|
<Modal width={840} maskClosable={false} open={openModal} footer={null} onCancel={modalCancel}>
|
||||||
|
<AddModifyOption setFormRef={setFormRef} open={openModal} optionKey={key} category={category} />
|
||||||
|
</Modal>
|
||||||
|
|
||||||
|
{messageHolder}
|
||||||
|
{modalHolder}
|
||||||
|
</TemplateContainer>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default OptionsManagement;
|
||||||
@ -2,7 +2,7 @@ import React, { useState, useEffect } from 'react';
|
|||||||
import { Table, Button, message, Space, Spin, Form, Input, Select, Modal } from 'antd';
|
import { Table, Button, message, Space, Spin, Form, Input, Select, Modal } from 'antd';
|
||||||
import TemplateContainer from '@/pages/TemplateContainer';
|
import TemplateContainer from '@/pages/TemplateContainer';
|
||||||
import { useModel } from '@umijs/max';
|
import { useModel } from '@umijs/max';
|
||||||
import { objectToQueryString } from '@/services/services/common';
|
import { CheckJsonString, objectToQueryString } from '@/services/services/common';
|
||||||
import { GetDataInfoTypeOption, GetDataInfoTypeOptions } from '@/services/enum/dataInfo';
|
import { GetDataInfoTypeOption, GetDataInfoTypeOptions } from '@/services/enum/dataInfo';
|
||||||
import { SearchOutlined } from '@ant-design/icons';
|
import { SearchOutlined } from '@ant-design/icons';
|
||||||
import { ColumnsType } from 'antd/lib/table';
|
import { ColumnsType } from 'antd/lib/table';
|
||||||
@ -68,18 +68,11 @@ const DataInfo: React.FC = () => {
|
|||||||
const [currentJsonData, setCurrentJsonData] = useState<any>(null);
|
const [currentJsonData, setCurrentJsonData] = useState<any>(null);
|
||||||
const [isJsonFormat, setIsJsonFormat] = useState<boolean>(false);
|
const [isJsonFormat, setIsJsonFormat] = useState<boolean>(false);
|
||||||
|
|
||||||
function CheckJson(str: string) {
|
|
||||||
try {
|
|
||||||
JSON.parse(str);
|
|
||||||
} catch (e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function to handle clicking on data
|
// Function to handle clicking on data
|
||||||
const handleDataClick = (dataString: string) => {
|
const handleDataClick = (dataString: string) => {
|
||||||
let isJsonString = CheckJson(dataString);
|
let isJsonString = CheckJsonString(dataString);
|
||||||
|
|
||||||
if (isJsonString) {
|
if (isJsonString) {
|
||||||
const jsonData = JSON.parse(dataString);
|
const jsonData = JSON.parse(dataString);
|
||||||
|
|||||||
@ -5,6 +5,43 @@ export enum OptionType {
|
|||||||
Boolean = 4,
|
Boolean = 4,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取选项类型的下拉框选项
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function getOptionTypeOptions(): {
|
||||||
|
label: string;
|
||||||
|
value: OptionType;
|
||||||
|
}[] {
|
||||||
|
return [
|
||||||
|
{ label: "String", value: OptionType.String },
|
||||||
|
{ label: "JSON", value: OptionType.JSON },
|
||||||
|
{ label: "Number", value: OptionType.Number },
|
||||||
|
{ label: "Boolean", value: OptionType.Boolean },
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum OptionCategory {
|
||||||
|
System = 1,
|
||||||
|
LaiTool = 2,
|
||||||
|
NanFeng = 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取选项分类的下拉框选项
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function getOptionCategoryOptions(): {
|
||||||
|
label: string;
|
||||||
|
value: OptionCategory;
|
||||||
|
}[] {
|
||||||
|
return [
|
||||||
|
{ label: "System", value: OptionCategory.System },
|
||||||
|
{ label: "LaiTool", value: OptionCategory.LaiTool },
|
||||||
|
{ label: "NanFengAI", value: OptionCategory.NanFeng },
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export enum AllOptionKeyName {
|
export enum AllOptionKeyName {
|
||||||
/** 获取所有的 Option */
|
/** 获取所有的 Option */
|
||||||
|
|||||||
@ -25,4 +25,56 @@ function objectToQueryString(params: Record<string, any>): string {
|
|||||||
|
|
||||||
export {
|
export {
|
||||||
objectToQueryString
|
objectToQueryString
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查字符串是否为有效且有意义的JSON
|
||||||
|
* @param str 要检查的字符串
|
||||||
|
* @returns 如果是有意义的JSON则返回true,否则返回false
|
||||||
|
*/
|
||||||
|
export function CheckJsonString(str: string): boolean {
|
||||||
|
// 处理无效输入
|
||||||
|
if (!str || typeof str !== 'string') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 去除空白字符
|
||||||
|
const trimmed = str.trim();
|
||||||
|
|
||||||
|
// 排除简单值
|
||||||
|
const simpleValues = ['true', 'false', 'null', 'undefined', '1', '0'];
|
||||||
|
if (simpleValues.includes(trimmed.toLowerCase())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 排除纯数字
|
||||||
|
if (!isNaN(Number(trimmed)) && isFinite(Number(trimmed))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 尝试解析JSON
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(trimmed);
|
||||||
|
|
||||||
|
// 进一步检查是否为有意义的对象或数组
|
||||||
|
if (parsed === null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof parsed === 'object') {
|
||||||
|
// 检查是否为空对象或空数组
|
||||||
|
if (Array.isArray(parsed)) {
|
||||||
|
return parsed.length > 0; // 非空数组
|
||||||
|
} else {
|
||||||
|
return Object.keys(parsed).length > 0; // 非空对象
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 其他非对象类型(数字、字符串等)
|
||||||
|
return false;
|
||||||
|
} catch (e) {
|
||||||
|
// 解析失败,不是有效的JSON
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
2
src/services/typing/access.d.ts
vendored
2
src/services/typing/access.d.ts
vendored
@ -2,6 +2,8 @@ declare namespace AccessType {
|
|||||||
interface AccessType {
|
interface AccessType {
|
||||||
canPrompt: boolean;
|
canPrompt: boolean;
|
||||||
canRoleManagement: boolean;
|
canRoleManagement: boolean;
|
||||||
|
/** 是不是显示数据管理 */
|
||||||
|
canOptionManagement : boolean;
|
||||||
|
|
||||||
//#region 用户权限
|
//#region 用户权限
|
||||||
/** 是不是显示用户管理的菜单 */
|
/** 是不是显示用户管理的菜单 */
|
||||||
|
|||||||
12
src/services/typing/basic.d.ts
vendored
Normal file
12
src/services/typing/basic.d.ts
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
|
||||||
|
declare namespace BasicModel {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询数据集合得基础数据
|
||||||
|
*/
|
||||||
|
interface QueryCollection<T> {
|
||||||
|
current: number;
|
||||||
|
total: number;
|
||||||
|
collection: T;
|
||||||
|
}
|
||||||
|
}
|
||||||
13
src/services/typing/options/option.d.ts
vendored
13
src/services/typing/options/option.d.ts
vendored
@ -1,9 +1,18 @@
|
|||||||
|
import { OptionCategory } from "@/services/enum/optionEnum";
|
||||||
|
|
||||||
declare namespace OptionModel {
|
declare namespace OptionModel {
|
||||||
|
|
||||||
type Option = {
|
interface Option {
|
||||||
key: string;
|
key?: string;
|
||||||
value: string;
|
value: string;
|
||||||
type: OptionType;
|
type: OptionType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
interface OptionsItem extends Option {
|
||||||
|
roleNames: string[];
|
||||||
|
category: OptionCategory;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user