From e1b9d084c28fb6cff2ced66699347f10bbbc9bf8 Mon Sep 17 00:00:00 2001 From: ZLY Date: Tue, 4 Nov 2025 11:25:49 +0800 Subject: [PATCH] =?UTF-8?q?feat(globalVar):=20=E5=AE=9E=E7=8E=B0=E5=85=A8?= =?UTF-8?q?=E5=B1=80=E5=8F=98=E9=87=8F=E7=AE=A1=E7=90=86=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增全局变量接口定义- 实现全局变量页面UI及交互逻辑 - 添加全局变量新增弹窗组件 - 实现全局变量的增删查功能 - 添加数据类型映射和校验逻辑 - 支持全局变量按类型分类展示 - 实现全局变量搜索过滤功能 --- src/api/global.ts | 20 ++ src/api/interface/index.ts | 8 + .../orchestration/globalVar/addModal.tsx | 261 ++++++++++++++++++ src/pages/orchestration/globalVar/index.tsx | 210 ++++++++++++-- 4 files changed, 482 insertions(+), 17 deletions(-) create mode 100644 src/api/global.ts create mode 100644 src/pages/orchestration/globalVar/addModal.tsx diff --git a/src/api/global.ts b/src/api/global.ts new file mode 100644 index 0000000..182114a --- /dev/null +++ b/src/api/global.ts @@ -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}`); +} \ No newline at end of file diff --git a/src/api/interface/index.ts b/src/api/interface/index.ts index 5c5ba29..0af6396 100644 --- a/src/api/interface/index.ts +++ b/src/api/interface/index.ts @@ -222,4 +222,12 @@ export interface ExecuteCurrentEventParams { export interface ReconnectRunParams { instanceId: string, newSocketId: string +} + +export interface GlobalParams { + name: string, + dataType: any, + arrayType: any, + defaultValue: any, + sceneId: string, } \ No newline at end of file diff --git a/src/pages/orchestration/globalVar/addModal.tsx b/src/pages/orchestration/globalVar/addModal.tsx new file mode 100644 index 0000000..7665862 --- /dev/null +++ b/src/pages/orchestration/globalVar/addModal.tsx @@ -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 ( + onOk()} + onCancel={() => onChangeVisible(false)} + autoFocus={false} + focusLock={true} + maskClosable={false} + > +
+ + + + + + + {/* 只有在数据类型选择为ARRAY时才展示数组类型选项 */} + {formData === 'ARRAY' && ( + + + + )} + + + +
+
+ ); +}; + +export default AddGlobalVarModal; \ No newline at end of file diff --git a/src/pages/orchestration/globalVar/index.tsx b/src/pages/orchestration/globalVar/index.tsx index 3557fa4..209ca1a 100644 --- a/src/pages/orchestration/globalVar/index.tsx +++ b/src/pages/orchestration/globalVar/index.tsx @@ -1,20 +1,180 @@ -import React, { useState } from 'react'; +import React, { useEffect, useState, useMemo } from 'react'; import styles from './style/index.module.less'; -import { Button, Divider, Input, Space, Table } from '@arco-design/web-react'; -import { IconSearch } from '@arco-design/web-react/icon'; +import { Button, Divider, Input, Space, Table, Form, Message, Popconfirm } from '@arco-design/web-react'; +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 [selectedItem, setSelectedItem] = useState('数字类型'); - - const menuItems = [ - '数字类型', - '字符串类型', - '布尔类型', - '复合类型', - '集合类型', - '元祖类型', - '实例类型', - '列表类型' + const [selectedItem, setSelectedItem] = useState('OBJECT'); + const { info } = useSelector((state: any) => state.ideContainer); + 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) => ( + handleDeleteGlobalVar(record.id)} + > + @@ -53,9 +216,22 @@ const GlobalVarContainer = () => { {/*数据列表*/}
- {/**/} +
+ + {/* 添加全局变量弹窗 */} + ); };