diff --git a/src/api/componentTestCase.ts b/src/api/componentTestCase.ts index 3653b44..2e29226 100644 --- a/src/api/componentTestCase.ts +++ b/src/api/componentTestCase.ts @@ -22,4 +22,19 @@ export function submitTestCase(params) { // 删除测试用例 export function deleteTestCase(ids) { return axios.post(`${urlPrefix}/componentTestCase/remove?ids=${ids}`); +} + +// 发送测试用例 +export function sendTestCase(params) { + return axios.post(`${urlPrefix}/componentTestCase/handler`, params); +} + +// 导出测试用例模板 +export function exportTemplate(componentBaseId) { + return axios.get(`${urlPrefix}/componentTestCase/export-template/${componentBaseId}`, { responseType: 'blob' }); +} + +// 导出当前测试用例 +export function exportTestCases(componentBaseId) { + return axios.get(`${urlPrefix}/componentTestCase/export/${componentBaseId}`, { responseType: 'blob' }); } \ No newline at end of file diff --git a/src/pages/componentDevelopment/componentTest/style/testInstance.module.less b/src/pages/componentDevelopment/componentTest/style/testInstance.module.less index bed2e26..c1ea47b 100644 --- a/src/pages/componentDevelopment/componentTest/style/testInstance.module.less +++ b/src/pages/componentDevelopment/componentTest/style/testInstance.module.less @@ -381,11 +381,30 @@ color: #86909c; font-size: 13px; line-height: 1.8; + padding-top: 40px; p { margin: 8px 0; } } + + .log-list { + display: flex; + flex-direction: column; + gap: 4px; + + .log-item { + padding: 8px 12px; + background: #f7f8fa; + border-radius: 4px; + font-size: 12px; + font-family: 'Consolas', 'Monaco', 'Courier New', monospace; + color: #4e5969; + line-height: 1.6; + word-break: break-all; + white-space: pre-wrap; + } + } } } } diff --git a/src/pages/componentDevelopment/componentTest/testInstance.tsx b/src/pages/componentDevelopment/componentTest/testInstance.tsx index 132e631..4b46315 100644 --- a/src/pages/componentDevelopment/componentTest/testInstance.tsx +++ b/src/pages/componentDevelopment/componentTest/testInstance.tsx @@ -3,8 +3,15 @@ import { Button, Space, Tree, Collapse, Divider, Message, Modal } from '@arco-de import { IconLeft, IconPlus, IconEdit, IconDelete, IconLink, IconSend } from '@arco-design/web-react/icon'; import styles from './style/testInstance.module.less'; import { getComponentDesign } from '@/api/componentDevelopProcess'; -import { getComponentTestCaseList, submitTestCase, deleteTestCase } from '@/api/componentTestCase'; +import { + getComponentTestCaseList, + submitTestCase, + deleteTestCase, + exportTemplate, + exportTestCases +} from '@/api/componentTestCase'; import TestCaseModal from './TestCaseModal'; +import useWebSocket from '@/hooks/useWebSocket'; const CollapseItem = Collapse.Item; @@ -16,6 +23,42 @@ const TestInstance = ({ instance, parentId, onBack }: { instance: any; parentId: const [selectedOperationIdent, setSelectedOperationIdent] = useState(''); const [activeOperationIdent, setActiveOperationIdent] = useState(''); const [editingTestCase, setEditingTestCase] = useState(null); + const [logs, setLogs] = useState([]); + const [isSocketConnected, setIsSocketConnected] = useState(false); + + // WebSocket hook + const { connect, disconnect, isConnected, sendMessage } = useWebSocket({ + onOpen: () => { + setIsSocketConnected(true); + addLog('连接信息:连接成功!'); + }, + onClose: () => { + setIsSocketConnected(false); + addLog('连接信息:连接已断开'); + }, + onError: () => { + addLog('连接错误:连接失败'); + }, + onMessage: (event) => { + try { + const data = JSON.parse(event.data); + addLog(`收到消息: ${JSON.stringify(data)}`); + } catch (e) { + addLog(`收到消息: ${event.data}`); + } + } + }); + + // 添加日志 + const addLog = (message: string) => { + const timestamp = new Date().toLocaleTimeString(); + setLogs(prev => [...prev, `[${timestamp}] ${message}`]); + }; + + // 清空日志 + const clearLogs = () => { + setLogs([]); + }; const getDesign = async () => { const res: any = await getComponentDesign(parentId); @@ -38,6 +81,42 @@ const TestInstance = ({ instance, parentId, onBack }: { instance: any; parentId: getDesign(); }, [parentId, instance]); + // 组件卸载时断开连接 + useEffect(() => { + return () => { + disconnect(); + }; + }, [disconnect]); + + + const cryptoRandom = () => { + return new Date().getTime().toString(16) + Math.random().toString(16).substring(2); + }; + + // 链接实例 + const handleLinkInstance = () => { + if (isSocketConnected) { + disconnect(); + Message.info('已断开连接'); + } + else { + // 构建WebSocket URL,根据你的实际后端配置调整 + const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'; + const host = window.location.host; + let wsUrl = ''; + if (window.location.host.includes('localhost')) { + wsUrl = `ws://192.168.5.119/wst/test-case/${instance.id}/${cryptoRandom()}`; + } + else { + wsUrl = `${protocol}//${host}/wst/test-case/${instance.id}/${cryptoRandom()}`; + } + + + connect(wsUrl); + addLog('正在连接测试实例...'); + } + }; + const handleAddTestCase = (operationIdent: string) => { setSelectedOperationIdent(operationIdent); setEditingTestCase(null); @@ -62,7 +141,8 @@ const TestInstance = ({ instance, parentId, onBack }: { instance: any; parentId: if (res.code === 200) { Message.success('删除成功'); getTestCaseList(); - } else { + } + else { Message.error(res.msg || '删除失败'); } } catch (error) { @@ -72,6 +152,78 @@ const TestInstance = ({ instance, parentId, onBack }: { instance: any; parentId: }); }; + // 导出测试用例模板 + const handleExportTemplate = async () => { + try { + Message.loading('正在生成模板文件...'); + const res: any = await exportTemplate(parentId); + + // 创建下载链接 + const blob = new Blob([res], { + type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' + }); + const url = window.URL.createObjectURL(blob); + const link = document.createElement('a'); + link.href = url; + + // 设置文件名 + const fileName = `测试用例模板_${instance.identifier}_${new Date().getTime()}.xlsx`; + link.setAttribute('download', fileName); + + // 触发下载 + document.body.appendChild(link); + link.click(); + + // 清理 + document.body.removeChild(link); + window.URL.revokeObjectURL(url); + + Message.success('模板下载成功'); + } catch (error) { + console.error('导出模板失败:', error); + Message.error('导出模板失败'); + } + }; + + // 导出当前测试用例 + const handleExportTestCases = async () => { + try { + // 检查是否有测试用例 + if (!testCaseList || testCaseList.length === 0) { + Message.warning('当前没有测试用例可导出'); + return; + } + + Message.loading('正在生成测试用例文件...'); + const res: any = await exportTestCases(parentId); + + // 创建下载链接 + const blob = new Blob([res], { + type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' + }); + const url = window.URL.createObjectURL(blob); + const link = document.createElement('a'); + link.href = url; + + // 设置文件名 + const fileName = `测试用例_${instance.identifier}_${new Date().getTime()}.xlsx`; + link.setAttribute('download', fileName); + + // 触发下载 + document.body.appendChild(link); + link.click(); + + // 清理 + document.body.removeChild(link); + window.URL.revokeObjectURL(url); + + Message.success('测试用例导出成功'); + } catch (error) { + console.error('导出测试用例失败:', error); + Message.error('导出测试用例失败'); + } + }; + const handleModalOk = async (values: any) => { const params = { ...values, @@ -100,16 +252,16 @@ const TestInstance = ({ instance, parentId, onBack }: { instance: any; parentId:
@@ -119,15 +271,15 @@ const TestInstance = ({ instance, parentId, onBack }: { instance: any; parentId: > 从模板导入用例 + {/* setActiveTab('batch')}*/} + {/*>*/} + {/* 一键生成测试用例*/} + {/**/} - @@ -294,18 +446,24 @@ const TestInstance = ({ instance, parentId, onBack }: { instance: any; parentId:
运行日志
- 📋 - 📁 - 💾 - 📊 - 🗑️ + 🗑️
-
-

连接信息:连接成功!

-

未启动任务或任务已完成

-
+ {logs.length === 0 ? ( +
+

暂无日志信息

+

请点击"链接实例"按钮连接测试实例

+
+ ) : ( +
+ {logs.map((log, index) => ( +
+ {log} +
+ ))} +
+ )}