diff --git a/src/api/componentTestCase.ts b/src/api/componentTestCase.ts index 2e29226..1ac28e4 100644 --- a/src/api/componentTestCase.ts +++ b/src/api/componentTestCase.ts @@ -37,4 +37,15 @@ export function exportTemplate(componentBaseId) { // 导出当前测试用例 export function exportTestCases(componentBaseId) { return axios.get(`${urlPrefix}/componentTestCase/export/${componentBaseId}`, { responseType: 'blob' }); +} + +// 导入测试用例 +export function importTestCases(params: { componentBaseId: string, file: File }) { + const formData = new FormData(); + formData.append('file', params.file); + return axios.post(`${urlPrefix}/componentTestCase/import/${params.componentBaseId}`, formData, { + headers: { + 'Content-Type': 'multipart/form-data' + } + }); } \ No newline at end of file diff --git a/src/pages/componentDevelopment/componentTest/testInstance.tsx b/src/pages/componentDevelopment/componentTest/testInstance.tsx index 4b46315..b5e7c04 100644 --- a/src/pages/componentDevelopment/componentTest/testInstance.tsx +++ b/src/pages/componentDevelopment/componentTest/testInstance.tsx @@ -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([]); const [isSocketConnected, setIsSocketConnected] = useState(false); + const fileInputRef = useRef(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) => { + 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 (
+ {/* 隐藏的文件input */} + + {/* 顶部标签栏 */}
@@ -263,11 +320,11 @@ const TestInstance = ({ instance, parentId, onBack }: { instance: any; parentId: type="outline" onClick={handleExportTemplate} > - 下载当前测试用例 + 下载当前测试用例模板