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',
|
||||
name: 'roleManagement',
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "lms",
|
||||
"version": "1.0.8",
|
||||
"version": "1.1.0",
|
||||
"private": true,
|
||||
"description": "An out-of-box UI solution for enterprise applications",
|
||||
"scripts": {
|
||||
|
||||
@ -7,6 +7,7 @@ export default function access(initialState: { currentUser?: API.CurrentUser } |
|
||||
let access = {
|
||||
canPrompt: false,
|
||||
canRoleManagement: false,
|
||||
canOptionManagement: false,
|
||||
|
||||
canUserManagement: false,
|
||||
canEditUser: false,
|
||||
@ -87,6 +88,7 @@ export default function access(initialState: { currentUser?: API.CurrentUser } |
|
||||
access = {
|
||||
...access,
|
||||
canPrompt: true,
|
||||
canOptionManagement : true,
|
||||
|
||||
canUserManagement: true,
|
||||
canEditUser: true,
|
||||
@ -121,7 +123,8 @@ export default function access(initialState: { currentUser?: API.CurrentUser } |
|
||||
...access,
|
||||
canPrompt: true,
|
||||
canRoleManagement: true,
|
||||
|
||||
canOptionManagement : true,
|
||||
|
||||
canUserManagement: true,
|
||||
canEditUser: true,
|
||||
canDeleteUser: true,
|
||||
|
||||
@ -13,6 +13,8 @@ export default {
|
||||
|
||||
'menu.roleManagement': '角色管理',
|
||||
|
||||
'menu.optionManagement': '数据管理',
|
||||
|
||||
'menu.userManagement': '用户管理',
|
||||
|
||||
'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 TemplateContainer from '@/pages/TemplateContainer';
|
||||
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 { SearchOutlined } from '@ant-design/icons';
|
||||
import { ColumnsType } from 'antd/lib/table';
|
||||
@ -68,18 +68,11 @@ const DataInfo: React.FC = () => {
|
||||
const [currentJsonData, setCurrentJsonData] = useState<any>(null);
|
||||
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
|
||||
const handleDataClick = (dataString: string) => {
|
||||
let isJsonString = CheckJson(dataString);
|
||||
let isJsonString = CheckJsonString(dataString);
|
||||
|
||||
if (isJsonString) {
|
||||
const jsonData = JSON.parse(dataString);
|
||||
|
||||
@ -5,6 +5,43 @@ export enum OptionType {
|
||||
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 {
|
||||
/** 获取所有的 Option */
|
||||
|
||||
@ -25,4 +25,56 @@ function objectToQueryString(params: Record<string, any>): string {
|
||||
|
||||
export {
|
||||
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 {
|
||||
canPrompt: boolean;
|
||||
canRoleManagement: boolean;
|
||||
/** 是不是显示数据管理 */
|
||||
canOptionManagement : boolean;
|
||||
|
||||
//#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 {
|
||||
|
||||
type Option = {
|
||||
key: string;
|
||||
interface Option {
|
||||
key?: string;
|
||||
value: string;
|
||||
type: OptionType;
|
||||
}
|
||||
|
||||
|
||||
interface OptionsItem extends Option {
|
||||
roleNames: string[];
|
||||
category: OptionCategory;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user