feat(globalVar): 实现全局变量管理功能

- 新增全局变量接口定义- 实现全局变量页面UI及交互逻辑
- 添加全局变量新增弹窗组件
- 实现全局变量的增删查功能
- 添加数据类型映射和校验逻辑
- 支持全局变量按类型分类展示
- 实现全局变量搜索过滤功能
master
钟良源 3 months ago
parent 7047ef0ba5
commit e1b9d084c2

@ -0,0 +1,20 @@
import axios from 'axios';
import { GlobalParams } from '@/api/interface';
// 公共路径
const urlPrefix = '/api/v1/bpms-workbench';
// 新增全局变量
export function addGlobal(data: GlobalParams) {
return axios.post(`${urlPrefix}/global/add`, data);
}
// 获取全局变量列表
export function getGlobalList(sceneId: string) {
return axios.get(`${urlPrefix}/global/${sceneId}/map`);
}
// 删除全局变量
export function deleteGlobal(id: string) {
return axios.delete(`${urlPrefix}/global/${id}`);
}

@ -223,3 +223,11 @@ export interface ReconnectRunParams {
instanceId: string, instanceId: string,
newSocketId: string newSocketId: string
} }
export interface GlobalParams {
name: string,
dataType: any,
arrayType: any,
defaultValue: any,
sceneId: string,
}

@ -0,0 +1,261 @@
import React from 'react';
import { Form, Input, Modal, Select } from '@arco-design/web-react';
import { useSelector } from 'react-redux';
const FormItem = Form.Item;
// 定义数据类型枚举
const dataTypeEnum = [
'OBJECT',
'JSON',
'ARRAY',
'BOOLEAN',
'INTEGER',
'DOUBLE',
'STRING',
'DATE',
'DATETIME',
'TIMESTAMP',
'DATABASE'
];
// 定义数组元素类型枚举
const arrayElementTypeEnum = [
'STRING',
'INTEGER',
'DOUBLE',
'BOOLEAN',
'DATE',
'DATETIME',
'TIMESTAMP'
];
// 默认值类型校验方法
const validateDefaultValue = (value, dataType, arrayType) => {
// 如果没有值,则不进行校验
if (value === undefined || value === null || value === '') {
return true;
}
switch (dataType) {
case 'STRING':
case 'DATE':
case 'DATETIME':
case 'TIMESTAMP':
case 'DATABASE':
// 字符串类型 - 任何值都是有效的
return true;
case 'INTEGER':
// 整数类型 - 必须是整数
const intRegex = /^-?\d+$/;
return intRegex.test(value);
case 'DOUBLE':
// 双精度浮点类型 - 必须是数字
const doubleRegex = /^-?\d+(\.\d+)?$/;
return doubleRegex.test(value);
case 'BOOLEAN':
// 布尔类型 - 必须是 true 或 false
return value === 'true' || value === 'false' || value === true || value === false;
case 'ARRAY':
// 数组类型 - 尝试解析为JSON数组
try {
const parsed = JSON.parse(value);
if (!Array.isArray(parsed)) {
return false;
}
// 根据数组元素类型进行校验
if (arrayType) {
for (const item of parsed) {
switch (arrayType) {
case 'STRING':
case 'DATE':
case 'DATETIME':
case 'TIMESTAMP':
if (typeof item !== 'string') {
return false;
}
break;
case 'INTEGER':
if (!Number.isInteger(item)) {
return false;
}
break;
case 'DOUBLE':
if (typeof item !== 'number') {
return false;
}
break;
case 'BOOLEAN':
if (typeof item !== 'boolean') {
return false;
}
break;
}
}
}
return true;
} catch (e) {
return false;
}
case 'JSON':
// JSON类型 - 必须是有效的JSON
try {
JSON.parse(value);
return true;
} catch (e) {
return false;
}
case 'OBJECT':
// 对象类型 - 必须是有效的JSON对象
try {
const parsed = JSON.parse(value);
return typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed);
} catch (e) {
return false;
}
default:
// 其他类型暂时不做特殊校验
return true;
}
};
const AddGlobalVarModal = ({ visible, onOk, onChangeVisible, form }) => {
const { info } = useSelector((state: any) => state.ideContainer);
// 获取表单字段值
const formData = Form.useWatch('dataType', form);
const arrayTypeData = Form.useWatch('arrayType', form);
return (
<Modal
title="添加环境变量"
visible={visible}
onOk={() => onOk()}
onCancel={() => onChangeVisible(false)}
autoFocus={false}
focusLock={true}
maskClosable={false}
>
<Form form={form} autoComplete="off">
<FormItem
field="name"
label="变量名"
required
rules={[
{
validator(value, cb) {
if (!value) {
return cb('请填写变量名');
}
return cb();
}
}
]}
>
<Input placeholder="请输入变量名" />
</FormItem>
<FormItem
field="dataType"
label="数据类型"
required
rules={[
{
validator(value, cb) {
if (!value) {
return cb('请选择数据类型');
}
return cb();
}
}
]}
>
<Select placeholder="请选择数据类型">
{dataTypeEnum.map(key => (
<Select.Option key={key} value={key}>
{key}
</Select.Option>
))}
</Select>
</FormItem>
{/* 只有在数据类型选择为ARRAY时才展示数组类型选项 */}
{formData === 'ARRAY' && (
<FormItem
field="arrayType"
label="数组类型"
required
rules={[
{
validator(value, cb) {
if (!value) {
return cb('请选择数组类型');
}
return cb();
}
}
]}
>
<Select placeholder="请选择数组类型">
{arrayElementTypeEnum.map(key => (
<Select.Option key={key} value={key}>
{key}
</Select.Option>
))}
</Select>
</FormItem>
)}
<FormItem
field="defaultValue"
label="默认值"
required
rules={[
{
validator(value, cb) {
if (!value) {
return cb('请填写默认值');
}
// 校验默认值类型
if (!validateDefaultValue(value, formData, arrayTypeData)) {
// 根据数据类型返回不同的错误消息
switch (formData) {
case 'INTEGER':
return cb('默认值必须是整数');
case 'DOUBLE':
return cb('默认值必须是数字');
case 'BOOLEAN':
return cb('默认值必须是 true 或 false');
case 'ARRAY':
return cb('默认值必须是有效的JSON数组格式');
case 'JSON':
return cb('默认值必须是有效的JSON格式');
case 'OBJECT':
return cb('默认值必须是有效的格式');
default:
return cb('默认值格式不正确');
}
}
return cb();
}
}
]}
>
<Input placeholder="请输入默认值" />
</FormItem>
</Form>
</Modal>
);
};
export default AddGlobalVarModal;

@ -1,20 +1,180 @@
import React, { useState } from 'react'; import React, { useEffect, useState, useMemo } from 'react';
import styles from './style/index.module.less'; import styles from './style/index.module.less';
import { Button, Divider, Input, Space, Table } from '@arco-design/web-react'; import { Button, Divider, Input, Space, Table, Form, Message, Popconfirm } from '@arco-design/web-react';
import { IconSearch } from '@arco-design/web-react/icon'; import { IconSearch, IconDelete } from '@arco-design/web-react/icon';
import { addGlobal, deleteGlobal, getGlobalList } from '@/api/global';
import { useSelector } from 'react-redux';
import AddGlobalVarModal from './addModal';
// 定义数据类型映射对象
const dataTypeMap = {
OBJECT: '复合类型',
JSON: 'JSON类型',
ARRAY: '数组类型',
BOOLEAN: '布尔类型',
INTEGER: '整数类型',
DOUBLE: '双精度浮点类型',
STRING: '字符串类型',
DATE: '日期类型',
DATETIME: '日期时间类型',
TIMESTAMP: '时间戳类型',
DATABASE: '数据库类型'
};
const GlobalVarContainer = () => { const GlobalVarContainer = () => {
const [selectedItem, setSelectedItem] = useState('数字类型'); const [selectedItem, setSelectedItem] = useState('OBJECT');
const { info } = useSelector((state: any) => state.ideContainer);
const menuItems = [ const [addModalVisible, setAddModalVisible] = useState(false); // 控制弹窗显示状态
'数字类型', const [form] = Form.useForm(); // 创建表单实例
'字符串类型', const [globalVarData, setGlobalVarData] = useState({}); // 存储全局变量数据
'布尔类型', const [searchText, setSearchText] = useState(''); // 搜索文本
'复合类型',
'集合类型', // 获取所有数据类型键值
'元祖类型', const menuItems = Object.keys(dataTypeMap);
'实例类型',
'列表类型' const getGlobalVar = async () => {
try {
const res: any = await getGlobalList(info.id);
if (res.code === 200) {
// 初始化所有数据类型为空数组
const initData = {};
menuItems.forEach(item => {
initData[item] = [];
});
// 处理接口返回的数据,按类型分类
if (res.data) {
Object.keys(res.data).forEach(key => {
const item = res.data[key];
if (item.dataType && initData[item.dataType]) {
initData[item.dataType].push(item);
}
});
}
setGlobalVarData(initData);
}
else {
Message.error('获取全局变量失败');
}
} catch (error) {
console.error('获取全局变量失败:', error);
Message.error('获取全局变量失败');
}
};
const handleAddGlobalVar = () => {
setAddModalVisible(true); // 显示弹窗
};
// 处理弹窗确认
const handleAddModalOk = async () => {
try {
const values = await form.validate();
const params = {
...values,
sceneId: info.id
};
if (!params?.arrayType) params.arrayType = null;
const res: any = await addGlobal(params);
if (res.code === 200) {
Message.success('添加成功');
await getGlobalVar(); // 重新获取数据
}
else {
Message.error('添加失败: ' + res.msg);
}
form.resetFields(); // 重置表单
setAddModalVisible(false); // 关闭弹窗
} catch (error) {
console.log('表单验证失败:', error);
Message.error('添加失败');
}
};
// 处理弹窗关闭
const handleAddModalCancel = () => {
form.resetFields(); // 重置表单
setAddModalVisible(false); // 关闭弹窗
};
// 处理删除全局变量
const handleDeleteGlobalVar = async (id) => {
console.log('删除全局变量:', id);
try {
const res: any = await deleteGlobal(id);
if (res.code === 200) {
Message.success('删除成功');
await getGlobalVar(); // 重新获取数据
}
else {
Message.error('删除失败: ' + res.msg);
}
} catch (error) {
console.log('删除失败:', error);
Message.error('删除失败');
}
};
// 处理搜索输入变化
const handleSearchChange = (value) => {
setSearchText(value);
};
// 使用 useMemo 优化搜索过滤
const filteredData = useMemo(() => {
const currentData = globalVarData[selectedItem] || [];
if (!searchText) {
return currentData;
}
return currentData.filter(item => {
// 在变量名、数据类型、默认值和描述中搜索
return (
item.name?.toLowerCase().includes(searchText.toLowerCase()) ||
item.dataType?.toLowerCase().includes(searchText.toLowerCase()) ||
item.defaultValue?.toLowerCase().includes(searchText.toLowerCase()) ||
item.description?.toLowerCase().includes(searchText.toLowerCase())
);
});
}, [globalVarData, selectedItem, searchText]);
useEffect(() => {
getGlobalVar();
}, []);
// 定义表格列
const columns = [
{
title: '变量名',
dataIndex: 'name'
},
{
title: '数据类型',
dataIndex: 'dataType'
},
{
title: '默认值',
dataIndex: 'defaultValue'
},
{
title: '描述',
dataIndex: 'description'
},
{
title: '操作',
dataIndex: 'operations',
render: (_, record) => (
<Popconfirm
title="确定删除该全局变量吗?"
onOk={() => handleDeleteGlobalVar(record.id)}
>
<Button type="text" icon={<IconDelete />} />
</Popconfirm>
)
}
]; ];
return ( return (
@ -27,7 +187,7 @@ const GlobalVarContainer = () => {
className={selectedItem === item ? styles['selected'] : ''} className={selectedItem === item ? styles['selected'] : ''}
onClick={() => setSelectedItem(item)} onClick={() => setSelectedItem(item)}
> >
{item} {dataTypeMap[item]}
</div> </div>
))} ))}
</div> </div>
@ -41,10 +201,13 @@ const GlobalVarContainer = () => {
prefix={<IconSearch />} prefix={<IconSearch />}
placeholder={'搜索'} placeholder={'搜索'}
style={{ width: 236 }} style={{ width: 236 }}
value={searchText}
onChange={handleSearchChange}
/> />
<Button <Button
type="primary" type="primary"
style={{ marginLeft: 5, borderRadius: 4 }} style={{ marginLeft: 5, borderRadius: 4 }}
onClick={handleAddGlobalVar}
> >
+ +
</Button> </Button>
@ -53,9 +216,22 @@ const GlobalVarContainer = () => {
</div> </div>
{/*数据列表*/} {/*数据列表*/}
<div className={styles['global-var-list']}> <div className={styles['global-var-list']}>
{/*<Table columns={columns} data={eventData} pagination={false} />*/} <Table
columns={columns}
data={filteredData}
pagination={false}
rowKey="id"
/>
</div> </div>
</div> </div>
{/* 添加全局变量弹窗 */}
<AddGlobalVarModal
visible={addModalVisible}
onOk={handleAddModalOk}
onChangeVisible={setAddModalVisible}
form={form}
/>
</div> </div>
); );
}; };

Loading…
Cancel
Save