import React, { useState, useEffect, useRef } from 'react'; import styles from './style/index.module.less'; import { Button, Input, Modal, Radio, Space, Select, Message } from '@arco-design/web-react'; import { IconSearch } from '@arco-design/web-react/icon'; import CollapseList from './collapseList'; import { startStatusConstant } from '@/const/isdp/componentDeploy'; import ConfigTutorial from '@/pages/componentDevelopment/componentEnv/configTutorial'; import { getComponentClassify } from '@/api/componentClassify'; import useWebSocket from '@/hooks/useWebSocket'; import { getToken } from '@/utils/auth'; import { isJSON } from '@/utils/common'; const ComponentDeployment = () => { const [searchKeyword, setSearchKeyword] = useState(''); const [debouncedKeyword, setDebouncedKeyword] = useState(''); const [selectedClassify, setSelectedClassify] = useState(undefined); const [classifyOptions, setClassifyOptions] = useState<{ label: string; value: string }[]>([]); const [selectedStatus, setSelectedStatus] = useState(undefined); const [tutorialVisible, setTutorialVisible] = useState(false); // 编译日志相关状态 - 按实例 ID 分组存储 const [compileLogsMap, setCompileLogsMap] = useState>({}); // 编译状态管理 - 按实例 ID 存储状态 const [compileStatusMap, setCompileStatusMap] = useState>({}); const compileLogSequenceRef = useRef>({}); const currentCompileIdRef = useRef(null); // WebSocket 连接 - 用于接收编译日志 const { connect: wsConnect, disconnect: wsDisconnect, sendMessage, isConnected } = useWebSocket({ onMessage: (event) => { const id = currentCompileIdRef.current; if (!id) return; try { const currentSequence = (compileLogSequenceRef.current[id] || 0) + 1; compileLogSequenceRef.current[id] = currentSequence; if (isJSON(event.data)) { const parseData = JSON.parse(event.data); const message = parseData.message || parseData.line || event.data; const sequenceMessage = `${currentSequence}. ${message}`; setCompileLogsMap(prev => ({ ...prev, [id]: prev[id] ? prev[id] + '\n' + sequenceMessage : sequenceMessage })); } else { const data = `${currentSequence}. ${event.data}`; setCompileLogsMap(prev => ({ ...prev, [id]: prev[id] ? prev[id] + '\n' + data : data })); } } catch (error) { console.error('解析 WebSocket 消息失败:', error); } }, onOpen: () => { console.log('编译日志 WebSocket 连接成功'); }, onError: (error) => { console.error('编译日志 WebSocket 错误:', error); }, onClose: () => { console.log('编译日志 WebSocket 连接已关闭'); } }); // 页面挂载时连接 WebSocket useEffect(() => { const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'; const host = window.location.host; let wsUrl; if (window.location.host.includes('localhost')) { wsUrl = `${process.env.NEXT_PUBLIC_DEV_SOCKET_HOST}/ws/v1/bpms-workbench/instance-log?Authorization=Bearer ${getToken()}`; } else { wsUrl = `${protocol}//${host}/ws/v1/bpms-workbench/instance-log?Authorization=Bearer ${getToken()}`; } wsConnect(wsUrl); return () => { wsDisconnect(); }; }, []); useEffect(() => { const timer = setTimeout(() => setDebouncedKeyword(searchKeyword), 500); return () => clearTimeout(timer); }, [searchKeyword]); useEffect(() => { getComponentClassify('component').then((res: any) => { if (res.code === 200) { setClassifyOptions(res.data.map((item) => ({ label: item.classifyName, value: item.classifyName }))); } }); }, []); // 订阅实例编译日志 const subscribeInstanceLog = (instanceId: string) => { currentCompileIdRef.current = instanceId; compileLogSequenceRef.current[instanceId] = 0; // 清空该实例之前的日志 setCompileLogsMap(prev => ({ ...prev, [instanceId]: '' })); // 设置编译状态为 running setCompileStatusMap(prev => ({ ...prev, [instanceId]: 'running' })); if (isConnected) { sendMessage({ instanceId, type: 'subscribe' }); } else { Message.warning('WebSocket 未连接,无法实时接收日志'); } }; // 取消订阅实例编译日志 const unsubscribeInstanceLog = (instanceId: string) => { if (isConnected && instanceId) { sendMessage({ instanceId, type: 'unsubscribe' }); } if (currentCompileIdRef.current === instanceId) { currentCompileIdRef.current = null; } }; // 更新编译状态 const updateCompileStatus = (instanceId: string, status: 'idle' | 'running' | 'success' | 'failed' | 'canceled') => { setCompileStatusMap(prev => ({ ...prev, [instanceId]: status })); }; // 状态选项配置 const statusOptions = [ { label: '全部', value: undefined }, { label: '启用中', value: 'RUN' }, { label: '已下架', value: 'STOP' } ]; return ( <>
setSelectedStatus(value)} name="button-radio-group" > {statusOptions.map((item) => { return ( {({ checked }) => { return ( ); }} ); })} } placeholder={'搜索'} style={{ width: 236 }} value={searchKeyword} onChange={(value) => setSearchKeyword(value)} onPressEnter={() => { // 触发搜索 }} />
setTutorialVisible(false)} footer={null} style={{ top: 20, width: '100%' }} > ); }; export default ComponentDeployment;