Merge branch 'refs/heads/master' into production

master
钟良源 3 months ago
commit d003a0f170

@ -1,6 +1,9 @@
# API基础URL # API基础URL
NEXT_PUBLIC_API_BASE_URL=/ NEXT_PUBLIC_API_BASE_URL=/
# code-server服务地址
NEXT_PUBLIC_DEV_CODE_SERVER_HOST='http://192.168.5.119:8443'
# 开发服务器主机地址 129穿透 # 开发服务器主机地址 129穿透
#NEXT_PUBLIC_DEV_SERVER_HOST=https://p29.ngsk.tech:7001 #NEXT_PUBLIC_DEV_SERVER_HOST=https://p29.ngsk.tech:7001

@ -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,
}

@ -84,7 +84,6 @@ const EventSelect: React.FC<EventSelectProps> = ({ nodeData, eventList, type, on
}; };
const handelSelect = (e) => { const handelSelect = (e) => {
console.log('e:', e);
const data = { const data = {
type: typeMap[type], type: typeMap[type],
customDef: { customDef: {

@ -7,12 +7,17 @@ import EventSelect from '@/components/FlowEditor/nodeEditors/components/EventSel
import { queryEventItemBySceneId } from '@/api/event'; import { queryEventItemBySceneId } from '@/api/event';
import ParamsTable from '@/components/FlowEditor/nodeEditors/components/ParamsTable'; import ParamsTable from '@/components/FlowEditor/nodeEditors/components/ParamsTable';
const EventSendEditor: React.FC<NodeEditorProps> = ({ nodeData, updateNodeData }) => { const EventSendEditor: React.FC<NodeEditorProps> = ({ node, nodeData, updateNodeData }) => {
const [eventList, setEventList] = useState<any[]>(); const [eventList, setEventList] = useState<any[]>();
const { currentAppData } = useSelector(state => state.ideContainer); const { currentAppData } = useSelector(state => state.ideContainer);
const getEventList = async () => { const getEventList = async () => {
const res = await queryEventItemBySceneId({sceneId:currentAppData.sceneId}); const params = {
nodeId: node.id,
appId: currentAppData.id,
sceneId: currentAppData.sceneId
};
const res = await queryEventItemBySceneId(params);
setEventList(res.data); setEventList(res.data);
}; };

@ -1,6 +1,7 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { Input, Select, Table, Button } from '@arco-design/web-react'; import { Input, Select, Table, Button } from '@arco-design/web-react';
import { IconDelete } from '@arco-design/web-react/icon'; import { IconDelete } from '@arco-design/web-react/icon';
import { useSelector } from 'react-redux';
interface TableDataItem { interface TableDataItem {
key: number | string; key: number | string;
@ -23,6 +24,7 @@ const ParamsTable: React.FC<ParamsTableProps> = ({
onUpdateData onUpdateData
}) => { }) => {
const [data, setData] = useState<TableDataItem[]>([]); const [data, setData] = useState<TableDataItem[]>([]);
const { gloBalVarList } = useSelector((state: any) => state.ideContainer);
useEffect(() => { useEffect(() => {
// 为现有数据添加key属性如果不存在 // 为现有数据添加key属性如果不存在
@ -34,19 +36,36 @@ const ParamsTable: React.FC<ParamsTableProps> = ({
}, [initialData]); }, [initialData]);
const dataTypeOptions = [ const dataTypeOptions = [
{ label: '字符串', value: 'STRING' }, { label: 'STRING', value: 'STRING' },
{ label: '数字', value: 'INTEGER' }, { label: 'INTEGER', value: 'INTEGER' },
{ label: '布尔值', value: 'BOOLEAN' }, { label: 'BOOLEAN', value: 'BOOLEAN' },
{ label: '数组', value: 'ARRAY' }, { label: 'ARRAY', value: 'ARRAY' },
{ label: '对象', value: 'OBJECT' } { label: 'OBJECT', value: 'OBJECT' },
{ label: 'JSON', value: 'JSON' },
{ label: 'DOUBLE', value: 'DOUBLE' }
]; ];
const arrayTypeOptions = [ const arrayTypeOptions = [
{ label: '字符串数组', value: 'STRING' }, { label: 'STRING', value: 'STRING' },
{ label: '数字数组', value: 'INTEGER' }, { label: 'INTEGER', value: 'INTEGER' },
{ label: '布尔数组', value: 'BOOLEAN' } { label: 'DOUBLE', value: 'DOUBLE' },
{ label: 'BOOLEAN', value: 'BOOLEAN' },
{ label: 'JSON', value: 'JSON' },
{ label: 'OBJECT', value: 'OBJECT' }
]; ];
// 根据数据类型获取对应的选项列表
const getOptionsByDataType = (dataType: string) => {
// 这里可以根据数据类型从gloBalVarList中筛选出对应的选项
if (gloBalVarList[dataType]) {
return gloBalVarList[dataType].map((item: any) => ({
label: item.name,
value: item.id
}));
}
return [];
};
const columns = [ const columns = [
{ {
title: '标识', title: '标识',
@ -83,7 +102,7 @@ const ParamsTable: React.FC<ParamsTableProps> = ({
title: '数组类型', title: '数组类型',
dataIndex: 'arrayType', dataIndex: 'arrayType',
render: (_: any, record: TableDataItem) => ( render: (_: any, record: TableDataItem) => (
record.dataType === 'array' ? ( record.dataType === 'ARRAY' ? (
<Select <Select
autoWidth={{ minWidth: 200, maxWidth: 500 }} autoWidth={{ minWidth: 200, maxWidth: 500 }}
options={arrayTypeOptions} options={arrayTypeOptions}
@ -113,22 +132,58 @@ const ParamsTable: React.FC<ParamsTableProps> = ({
{ {
title: '默认值', title: '默认值',
dataIndex: 'defaultValue', dataIndex: 'defaultValue',
render: (_: any, record: TableDataItem) => ( render: (_: any, record: TableDataItem) => {
record.id === 'maxTime' ? ( // 获取当前数据类型对应的选项
<Input const options = getOptionsByDataType(record.dataType);
type="number"
min="1" // 如果有选项则显示下拉选择框,否则显示输入框
step="1" if (options.length > 0) {
value={record.defaultValue} return (
onChange={(value) => handleSave({ ...record, defaultValue: value })} <>
/> <Select
) : ( value={record.refValue}
<Input onChange={(value) => {
value={record.defaultValue} const refValue = options.find((option) => option.value === value)?.label || null;
onChange={(value) => handleSave({ ...record, defaultValue: value })} handleSave({ ...record, refId: value, refValue });
/> }}
) placeholder="请选择默认值"
) // showSearch
allowClear
options={options}
style={{ width: '100%', minWidth: 100 }}
/>
<Input
style={{ width: '100%', minWidth: 100, marginTop: 10 }}
value={record.defaultValue}
onChange={(value) => handleSave({ ...record, defaultValue: value })}
placeholder="请输入默认值"
/>
</>
);
}
else {
// 特殊处理maxTime的情况
if (record.id === 'maxTime') {
return (
<Input
type="number"
min="1"
step="1"
value={record.defaultValue}
onChange={(value) => handleSave({ ...record, defaultValue: value })}
/>
);
}
return (
<Input
value={record.defaultValue}
onChange={(value) => handleSave({ ...record, defaultValue: value })}
placeholder="请输入默认值"
/>
);
}
}
}, },
{ {
title: '操作', title: '操作',

@ -10,12 +10,10 @@ const ComponentCoding = () => {
useEffect(() => { useEffect(() => {
const uri = process.env.NEXT_PUBLIC_DEV_SERVER_HOST; const uri = process.env.NEXT_PUBLIC_DEV_CODE_SERVER_HOST;
// const uri = 'http://api.myserver.com:4121';
const codeServerPrefix = '/code-server';
const codeServerFolderPre = '/app/data'; const codeServerFolderPre = '/app/data';
const tempData = '/000000/admin_testcode1/master'; const tempData = '/000000/admin_testcode1/master';
setServerUrl(`${uri}${codeServerPrefix}?folder=${codeServerFolderPre}${tempData}`); setServerUrl(`${uri}?folder=${codeServerFolderPre}${tempData}`);
}); });

@ -1,10 +1,44 @@
import React from 'react'; import React from 'react';
import { Button, Popconfirm, Table } from '@arco-design/web-react';
import { IconDelete } from '@arco-design/web-react/icon';
const InstanceList = () => { const InstanceList = () => {
const data = [];
// 定义表格列
const columns = [
{
title: '实例名',
dataIndex: 'name'
},
{
title: '实例标识',
dataIndex: 'dataType'
},
{
title: '运行类型',
dataIndex: 'defaultValue'
},
{
title: '实例状态',
dataIndex: 'description'
},
{
title: '实例测试时间',
dataIndex: 'description1'
},
{
title: '操作',
dataIndex: 'operations'
}
];
return ( return (
<div> <Table
columns={columns}
</div> data={data}
pagination={false}
rowKey="id"
/>
); );
}; };

@ -1,10 +1,39 @@
import React from 'react'; import React, { useState } from 'react';
import { Input, Tree } from '@arco-design/web-react';
import { IconSearch } from '@arco-design/web-react/icon';
import { menu } from './test/data';
const TreeNode = Tree.Node;
const SideBar = () => { const SideBar = () => {
const [searchValue, setSearchValue] = useState('');
const handleSearchChange = (value: string) => {
setSearchValue(value);
};
return ( return (
<div> <>
<Input
</div> prefix={<IconSearch />}
placeholder={'搜索'}
style={{ width: '90%' }}
value={searchValue}
onChange={handleSearchChange}
/>
<Tree
onSelect={(value, info) => {
console.log(value, info);
}}
onExpand={(keys, info) => {
console.log(keys, info);
}}
treeData={menu}
>
</Tree>
</>
); );
}; };

@ -0,0 +1,152 @@
export const menu = [
{
'id': '1770647707245903873',
'tenantId': '000000',
'parentId': '1658394185466220545',
'code': 'component_classify',
'dictKey': '设备数采与控制交互组件',
'dictValue': '设备数采与控制交互组件',
'title': '设备数采与控制交互组件',
'sort': 0,
'remark': '',
'isSealed': -1,
'isDeleted': -1,
'parentName': '',
'hasChildren': false
},
{
'id': '1770647743455330305',
'tenantId': '000000',
'parentId': '1658394185466220545',
'code': 'component_classify',
'dictKey': '视觉AI组件',
'dictValue': '视觉AI组件',
'title': '视觉AI组件',
'sort': 1,
'remark': '',
'isSealed': -1,
'isDeleted': -1,
'parentName': '',
'hasChildren': false
},
{
'id': '1770647774937776129',
'tenantId': '000000',
'parentId': '1658394185466220545',
'code': 'component_classify',
'dictKey': '运动规划组件',
'dictValue': '运动规划组件',
'title': '运动规划组件',
'sort': 2,
'remark': '',
'isSealed': -1,
'isDeleted': -1,
'parentName': '',
'hasChildren': false
},
{
'id': '1770647807334580225',
'tenantId': '000000',
'parentId': '1658394185466220545',
'code': 'component_classify',
'dictKey': '工艺知识服务组件',
'dictValue': '工艺知识服务组件',
'title': '工艺知识服务组件',
'sort': 2,
'remark': '',
'isSealed': -1,
'isDeleted': -1,
'parentName': '',
'hasChildren': false
},
{
'id': '1770647842776449026',
'tenantId': '000000',
'parentId': '1658394185466220545',
'code': 'component_classify',
'dictKey': '网络通信组件',
'dictValue': '网络通信组件',
'title': '网络通信组件',
'sort': 4,
'remark': '',
'isSealed': -1,
'isDeleted': -1,
'parentName': '',
'hasChildren': false
},
{
'id': '1770647878029574145',
'tenantId': '000000',
'parentId': '1658394185466220545',
'code': 'component_classify',
'dictKey': '数据存取组件',
'dictValue': '数据存取组件',
'title': '数据存取组件',
'sort': 5,
'remark': '',
'isSealed': -1,
'isDeleted': -1,
'parentName': '',
'hasChildren': false
},
{
'id': '1770647908987731969',
'tenantId': '000000',
'parentId': '1658394185466220545',
'code': 'component_classify',
'dictKey': '时序数据AI组件',
'dictValue': '时序数据AI组件',
'title': '时序数据AI组件',
'sort': 6,
'remark': '',
'isSealed': -1,
'isDeleted': -1,
'parentName': '',
'hasChildren': false
},
{
'id': '1770647940654727170',
'tenantId': '000000',
'parentId': '1658394185466220545',
'code': 'component_classify',
'dictKey': '文本数据AI组件',
'dictValue': '文本数据AI组件',
'title': '文本数据AI组件',
'sort': 7,
'remark': '',
'isSealed': -1,
'isDeleted': -1,
'parentName': '',
'hasChildren': false
},
{
'id': '1770648447733497858',
'tenantId': '000000',
'parentId': '1658394185466220545',
'code': 'component_classify',
'dictKey': '测试组件',
'dictValue': '测试组件',
'title': '测试组件',
'sort': 999,
'remark': '',
'isSealed': -1,
'isDeleted': -1,
'parentName': '',
'hasChildren': false
},
{
'id': '1938074918032830465',
'tenantId': '000000',
'parentId': '1658394185466220545',
'code': 'component_classify',
'dictKey': '监听组件',
'dictValue': '监听组件',
'title': '监听组件',
'sort': 10,
'remark': '',
'isSealed': -1,
'isDeleted': -1,
'parentName': '',
'hasChildren': false
}
];

@ -272,15 +272,13 @@ const NodeContent = ({ data }: { data: NodeContentData }) => {
{/*content栏-data部分*/} {/*content栏-data部分*/}
<div className={styles['node-data-box']}> <div className={styles['node-data-box']}>
<div className={styles['node-content']}> <div className={styles['node-content']}>
{!isStartNode && ( <div className={styles['node-inputs']}>
<div className={styles['node-inputs']}> {dataIns.map((input, index) => (
{dataIns.map((input, index) => ( <div key={input.id || `input-${index}`} className={styles['node-input-label']}>
<div key={input.id || `input-${index}`} className={styles['node-input-label']}> {input.id || `输入${index + 1}`} {input.dataType}
{input.id || `输入${index + 1}`} {input.dataType} </div>
</div> ))}
))} </div>
</div>
)}
{dataOuts.length > 0 && !isEndNode && ( {dataOuts.length > 0 && !isEndNode && (
<div className={styles['node-outputs']}> <div className={styles['node-outputs']}>

@ -14,7 +14,8 @@ import {
updateCurrentAppData, updateCurrentAppData,
updateInfo, updateInfo,
updateProjectComponentData, updateProjectComponentData,
updateEventList updateEventList,
updateGlobalVarList
} from '@/store/ideContainer'; } from '@/store/ideContainer';
import { getAppListBySceneId } from '@/api/apps'; import { getAppListBySceneId } from '@/api/apps';
import { getProjectComp } from '@/api/scene'; import { getProjectComp } from '@/api/scene';
@ -32,6 +33,7 @@ import ComponentTest from '@/pages/componentDevelopment/componentTest';
import { getUserToken } from '@/api/user'; import { getUserToken } from '@/api/user';
import { Message } from '@arco-design/web-react'; import { Message } from '@arco-design/web-react';
import { queryEventItemBySceneId, queryEventItemBySceneIdOld } from '@/api/event'; import { queryEventItemBySceneId, queryEventItemBySceneIdOld } from '@/api/event';
import { getGlobalList } from '@/api/global';
type UrlParamsOptions = { type UrlParamsOptions = {
identity?: string; identity?: string;
@ -225,6 +227,11 @@ function IDEContainer() {
if (res1.code === 200) dispatch(updateEventListOld(res1.data)); if (res1.code === 200) dispatch(updateEventListOld(res1.data));
}; };
const getGlobalVar = async () => {
const res: any = await getGlobalList(urlParams.id);
if (res.code === 200) dispatch(updateGlobalVarList(res.data));
};
useEffect(() => { useEffect(() => {
setUrlParams(getUrlParams(window.location.href) as UrlParamsOptions); setUrlParams(getUrlParams(window.location.href) as UrlParamsOptions);
dispatch(updateInfo(getUrlParams(window.location.href) as UrlParamsOptions)); dispatch(updateInfo(getUrlParams(window.location.href) as UrlParamsOptions));
@ -241,6 +248,7 @@ function IDEContainer() {
if (urlParams.identity && urlParams.identity === 'scene') { if (urlParams.identity && urlParams.identity === 'scene') {
connectWS(); connectWS();
getEvent(); getEvent();
getGlobalVar();
} }
}, [urlParams.identity]); }, [urlParams.identity]);

@ -0,0 +1,257 @@
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'
];
// 定义数组元素类型枚举
const arrayElementTypeEnum = [
'STRING',
'INTEGER',
'DOUBLE',
'BOOLEAN',
'ARRAY',
'JSON',
'OBJECT'
];
// 默认值类型校验方法
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,177 @@
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(dataType => {
const items = res.data[dataType];
if (Array.isArray(items) && initData[dataType]) {
initData[dataType] = items;
}
});
}
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);
};
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 +184,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 +198,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 +213,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>
); );
}; };

@ -24,6 +24,7 @@ interface IDEContainerState {
eventSendNodeList: any[], // [{nodeID:topic}] eventSendNodeList: any[], // [{nodeID:topic}]
eventlisteneList: any[] // [{nodeID:topic}] eventlisteneList: any[] // [{nodeID:topic}]
}>; }>;
gloBalVarList: any;
} }
// 初始状态 // 初始状态
@ -41,7 +42,8 @@ const initialState: IDEContainerState = {
socketId: '', // 工程的socketId socketId: '', // 工程的socketId
nodeStatusMap: {}, // 初始化节点状态映射 nodeStatusMap: {}, // 初始化节点状态映射
isRunning: false, // 默认未运行 isRunning: false, // 默认未运行
appRuntimeData: {} // 按应用ID隔离的应用运行状态和日志数据 appRuntimeData: {}, // 按应用ID隔离的应用运行状态和日志数据
gloBalVarList: [] // 工程级全局变量列表
}; };
// 创建切片 // 创建切片
@ -82,6 +84,9 @@ const ideContainerSlice = createSlice({
updateSocketId(state, action) { updateSocketId(state, action) {
state.socketId = action.payload; state.socketId = action.payload;
}, },
updateGlobalVarList(state, action) {
state.gloBalVarList = action.payload;
},
// 更新节点状态 // 更新节点状态
updateNodeStatus: (state, { payload }) => { updateNodeStatus: (state, { payload }) => {
const { nodeId, status, actionType } = payload; const { nodeId, status, actionType } = payload;
@ -208,6 +213,7 @@ export const {
updateEventTopicList, updateEventTopicList,
updateLogBarStatus, updateLogBarStatus,
updateSocketId, updateSocketId,
updateGlobalVarList,
updateNodeStatus, updateNodeStatus,
resetNodeStatus, resetNodeStatus,
updateIsRunning, updateIsRunning,

Loading…
Cancel
Save