|
|
|
|
@ -1,4 +1,4 @@
|
|
|
|
|
import React, { useEffect, useState } from 'react';
|
|
|
|
|
import React, { useEffect, useState, useRef } from 'react';
|
|
|
|
|
import { Button, Space, Tree, Collapse, Divider, Message, Modal } from '@arco-design/web-react';
|
|
|
|
|
import { IconLeft, IconPlus, IconEdit, IconDelete, IconLink, IconSend } from '@arco-design/web-react/icon';
|
|
|
|
|
import styles from './style/testInstance.module.less';
|
|
|
|
|
@ -8,7 +8,8 @@ import {
|
|
|
|
|
submitTestCase,
|
|
|
|
|
deleteTestCase,
|
|
|
|
|
exportTemplate,
|
|
|
|
|
exportTestCases
|
|
|
|
|
exportTestCases,
|
|
|
|
|
importTestCases
|
|
|
|
|
} from '@/api/componentTestCase';
|
|
|
|
|
import TestCaseModal from './TestCaseModal';
|
|
|
|
|
import useWebSocket from '@/hooks/useWebSocket';
|
|
|
|
|
@ -25,6 +26,7 @@ const TestInstance = ({ instance, parentId, onBack }: { instance: any; parentId:
|
|
|
|
|
const [editingTestCase, setEditingTestCase] = useState(null);
|
|
|
|
|
const [logs, setLogs] = useState<string[]>([]);
|
|
|
|
|
const [isSocketConnected, setIsSocketConnected] = useState(false);
|
|
|
|
|
const fileInputRef = useRef<HTMLInputElement>(null);
|
|
|
|
|
|
|
|
|
|
// WebSocket hook
|
|
|
|
|
const { connect, disconnect, isConnected, sendMessage } = useWebSocket({
|
|
|
|
|
@ -224,6 +226,52 @@ const TestInstance = ({ instance, parentId, onBack }: { instance: any; parentId:
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 触发文件选择
|
|
|
|
|
const handleImportClick = () => {
|
|
|
|
|
fileInputRef.current?.click();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 处理文件上传
|
|
|
|
|
const handleFileChange = async (event: React.ChangeEvent<HTMLInputElement>) => {
|
|
|
|
|
const file = event.target.files?.[0];
|
|
|
|
|
if (!file) return;
|
|
|
|
|
|
|
|
|
|
// 验证文件类型
|
|
|
|
|
const allowedTypes = [
|
|
|
|
|
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', // .xlsx
|
|
|
|
|
'application/vnd.ms-excel' // .xls
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
if (!allowedTypes.includes(file.type) && !file.name.match(/\.(xlsx|xls)$/i)) {
|
|
|
|
|
Message.error('请选择Excel文件(.xlsx 或 .xls)');
|
|
|
|
|
event.target.value = ''; // 清空input
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
Message.loading('正在导入测试用例...');
|
|
|
|
|
|
|
|
|
|
const res: any = await importTestCases({
|
|
|
|
|
componentBaseId: parentId,
|
|
|
|
|
file: file
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (res.code === 200) {
|
|
|
|
|
Message.success(`导入成功!`);
|
|
|
|
|
getTestCaseList(); // 刷新列表
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
Message.error(res.msg || '导入失败');
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('导入测试用例失败:', error);
|
|
|
|
|
Message.error('导入测试用例失败');
|
|
|
|
|
} finally {
|
|
|
|
|
// 清空input,允许重复选择同一文件
|
|
|
|
|
event.target.value = '';
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleModalOk = async (values: any) => {
|
|
|
|
|
const params = {
|
|
|
|
|
...values,
|
|
|
|
|
@ -246,6 +294,15 @@ const TestInstance = ({ instance, parentId, onBack }: { instance: any; parentId:
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className={styles['test-instance']}>
|
|
|
|
|
{/* 隐藏的文件input */}
|
|
|
|
|
<input
|
|
|
|
|
ref={fileInputRef}
|
|
|
|
|
type="file"
|
|
|
|
|
accept=".xlsx,.xls"
|
|
|
|
|
style={{ display: 'none' }}
|
|
|
|
|
onChange={handleFileChange}
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
{/* 顶部标签栏 */}
|
|
|
|
|
<div className={styles['tabs']}>
|
|
|
|
|
<div className={styles['tab-left']}>
|
|
|
|
|
@ -263,11 +320,11 @@ const TestInstance = ({ instance, parentId, onBack }: { instance: any; parentId:
|
|
|
|
|
type="outline"
|
|
|
|
|
onClick={handleExportTemplate}
|
|
|
|
|
>
|
|
|
|
|
下载当前测试用例
|
|
|
|
|
下载当前测试用例模板
|
|
|
|
|
</Button>
|
|
|
|
|
<Button
|
|
|
|
|
type="outline"
|
|
|
|
|
onClick={() => setActiveTab('add')}
|
|
|
|
|
onClick={handleImportClick}
|
|
|
|
|
>
|
|
|
|
|
从模板导入用例
|
|
|
|
|
</Button>
|
|
|
|
|
|