From bba9318e9d4e4bb756ccf8304e6c9ff57b6d8b19 Mon Sep 17 00:00:00 2001 From: ZLY Date: Wed, 26 Nov 2025 10:05:58 +0800 Subject: [PATCH] =?UTF-8?q?feat(component-test):=20=E5=AE=8C=E5=96=84?= =?UTF-8?q?=E7=BB=84=E4=BB=B6=E6=B5=8B=E8=AF=95=E5=8A=9F=E8=83=BD=E4=B8=8E?= =?UTF-8?q?=E7=95=8C=E9=9D=A2=E4=BA=A4=E4=BA=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../componentTest/index.tsx | 5 +- .../componentTest/sideBar.tsx | 7 +- .../style/testInstance.module.less | 47 +++++ .../componentTest/testInstance.tsx | 196 ++++++++++++------ 4 files changed, 192 insertions(+), 63 deletions(-) diff --git a/src/pages/componentDevelopment/componentTest/index.tsx b/src/pages/componentDevelopment/componentTest/index.tsx index 32b8ab1..1f3877d 100644 --- a/src/pages/componentDevelopment/componentTest/index.tsx +++ b/src/pages/componentDevelopment/componentTest/index.tsx @@ -11,6 +11,7 @@ const BreadcrumbItem = Breadcrumb.Item; const ComponentTest = () => { const [selectedIdentifier, setSelectedIdentifier] = useState(''); + const [selectedParentId, setSelectedParentId] = useState(''); const [refreshKey, setRefreshKey] = useState(0); const [count, setCount] = useState({ total: 0, passed: 0, failed: 0 }); const [currentView, setCurrentView] = useState<'list' | 'test'>('list'); @@ -24,8 +25,9 @@ const ComponentTest = () => { ]; // 处理子节点选择 - const handleNodeSelect = (identifier: string) => { + const handleNodeSelect = (identifier: string, parentId: string) => { setSelectedIdentifier(identifier); + setSelectedParentId(parentId); // 每次选择都更新 refreshKey,确保即使选择同一个节点也会触发刷新 setRefreshKey(prev => prev + 1); }; @@ -106,6 +108,7 @@ const ComponentTest = () => { ) : ( diff --git a/src/pages/componentDevelopment/componentTest/sideBar.tsx b/src/pages/componentDevelopment/componentTest/sideBar.tsx index 521cb86..626dd62 100644 --- a/src/pages/componentDevelopment/componentTest/sideBar.tsx +++ b/src/pages/componentDevelopment/componentTest/sideBar.tsx @@ -64,6 +64,7 @@ const SideBar = ({ onNodeSelect, getCount }) => { classifyMap.set(classify, { title: classify, key: `classify-${classify}`, + id: item.id, children: [] }); } @@ -72,6 +73,7 @@ const SideBar = ({ onNodeSelect, getCount }) => { classifyMap.get(classify).children.push({ title: item.name, key: item.identifier, + id: item.id, data: item }); }); @@ -116,8 +118,9 @@ const SideBar = ({ onNodeSelect, getCount }) => { } } else if (selectedKey) { - // 子节点的key就是identifier - onNodeSelect(selectedKey); + const parentId = info.node.props.id; + + onNodeSelect(selectedKey, parentId); } }; diff --git a/src/pages/componentDevelopment/componentTest/style/testInstance.module.less b/src/pages/componentDevelopment/componentTest/style/testInstance.module.less index 26f3805..5448f0a 100644 --- a/src/pages/componentDevelopment/componentTest/style/testInstance.module.less +++ b/src/pages/componentDevelopment/componentTest/style/testInstance.module.less @@ -207,10 +207,32 @@ padding: 16px; .node-function { + display: flex; + align-items: center; + gap: 8px; font-size: 15px; font-weight: 500; color: #1d2129; margin-bottom: 10px; + opacity: 0.4; + transition: opacity 0.3s; + + .function-dot { + width: 10px; + height: 10px; + border-radius: 50%; + background: #86909c; + flex-shrink: 0; + transition: background 0.3s; + } + + &.active { + opacity: 1; + + .function-dot { + background: #165dff; + } + } } .node-params { @@ -223,18 +245,30 @@ display: flex; align-items: center; gap: 8px; + opacity: 0.4; + transition: opacity 0.3s; .param-dot { width: 8px; height: 8px; border-radius: 50%; background: #86909c; + flex-shrink: 0; + transition: background 0.3s; } .param-label { font-size: 14px; color: #4e5969; } + + &.active { + opacity: 1; + + .param-dot { + background: #165dff; + } + } } } @@ -243,18 +277,31 @@ align-items: center; justify-content: flex-end; gap: 8px; + margin-bottom: 7px; + opacity: 0.4; + transition: opacity 0.3s; .param-dot { width: 8px; height: 8px; border-radius: 50%; background: #86909c; + flex-shrink: 0; + transition: background 0.3s; } .param-label { font-size: 14px; color: #4e5969; } + + &.active { + opacity: 1; + + .param-dot { + background: #165dff; + } + } } } } diff --git a/src/pages/componentDevelopment/componentTest/testInstance.tsx b/src/pages/componentDevelopment/componentTest/testInstance.tsx index ff22222..7deee67 100644 --- a/src/pages/componentDevelopment/componentTest/testInstance.tsx +++ b/src/pages/componentDevelopment/componentTest/testInstance.tsx @@ -1,22 +1,65 @@ import React, { useEffect, useState } from 'react'; -import { Button, Space, Tree, Collapse } from '@arco-design/web-react'; +import { Button, Space, Tree, Collapse, Divider, Message } 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'; import { getComponentDesign } from '@/api/componentDevelopProcess'; +import { getComponentTestCaseList, submitTestCase } from '@/api/componentTestCase'; +import TestCaseModal from './TestCaseModal'; const CollapseItem = Collapse.Item; -const TestInstance = ({ instance, onBack }: { instance: any; onBack: () => void }) => { +const TestInstance = ({ instance, parentId, onBack }: { instance: any; parentId: string; onBack: () => void }) => { const [activeTab, setActiveTab] = useState('link'); + const [testCaseList, setTestCaseList] = useState([]); + const [design, setDesign] = useState(null); + const [modalVisible, setModalVisible] = useState(false); + const [selectedOperationIdent, setSelectedOperationIdent] = useState(''); + const [activeOperationIdent, setActiveOperationIdent] = useState(''); const getDesign = async () => { - const res: any = await getComponentDesign(instance.id); - console.log('res:', res); + const res: any = await getComponentDesign(parentId); + if (res.code === 200) { + setDesign(res.data); + // 默认激活第一个 operation + if (res.data?.operates?.length > 0) { + setActiveOperationIdent(res.data.operates[0].ident); + } + } + }; + + const getTestCaseList = async () => { + const res: any = await getComponentTestCaseList({ componentBaseId: parentId, identifier: instance.identifier }); + if (res.code === 200) setTestCaseList(res.data); }; useEffect(() => { + getTestCaseList(); getDesign(); - }, [instance]); + }, [parentId, instance]); + + const handleAddTestCase = (operationIdent: string) => { + setSelectedOperationIdent(operationIdent); + setModalVisible(true); + }; + + const handleModalOk = async (values: any) => { + const params = { + ...values, + componentBaseId: parentId, + identifier: instance.identifier + }; + const res: any = await submitTestCase(params); + if (res.code === 200) { + Message.success('添加测试用例成功'); + getTestCaseList(); + } + else Message.error(res.msg); + setModalVisible(false); + }; + + const handleModalCancel = () => { + setModalVisible(false); + }; return (
@@ -68,35 +111,44 @@ const TestInstance = ({ instance, onBack }: { instance: any; onBack: () => void 测试用例
- - }> -
-
- 测试类型 -
- - - + + {testCaseList.map((item: any, index: number) => ( + setActiveOperationIdent(item.operationIdent)}> + {item.operationIdent}
+ } + name={index.toString()} + key={index} + extra={ + { + e.stopPropagation(); + handleAddTestCase(item.operationIdent); + }} + style={{ cursor: 'pointer' }} + /> + } + > +
+ {item.children.map((child: any, index1: number) => ( +
setActiveOperationIdent(item.operationIdent)} + > + {child.testCaseName} +
+ + + +
+
+ ))}
-
- 视频回调jck|ssss -
- - - -
-
-
- 短剧题图识别 -
- - - -
-
-
- + + ))}
@@ -108,7 +160,6 @@ const TestInstance = ({ instance, onBack }: { instance: any; onBack: () => void
- 🔧 开始
流程协作接口
@@ -119,38 +170,56 @@ const TestInstance = ({ instance, onBack }: { instance: any; onBack: () => void
- {/* 组件节点 */} + {/* 组件节点 - 单个节点展示所有接口 */}
- - 计算组件#1 + {instance.identifier}
-
lineMove
-
circleMove
-
-
- - input -
-
- - strpos ARR -
-
- - ufNum INT -
-
- - ufNum INT + {/* 显示所有接口函数 - 固定在上方 */} + {design?.operates?.map((operation: any, index: number) => ( +
+ + {operation.ident}
-
-
- output - -
+ ))} + + {/* 分割线 */} + + + {/* 显示激活接口的参数 */} + {design?.operates?.map((operation: any, index: number) => ( + activeOperationIdent === operation.ident && ( +
+
+ {/* Input 参数 - 显示 parameters */} + {operation.parameters?.map((param: any, paramIndex: number) => ( +
+ + + {param.ident} {param.type} + +
+ ))} +
+ {/* Output 参数 - 显示 responses */} + {operation.responses?.map((response: any, respIndex: number) => ( +
+ + {response.ident} {response.type} + + +
+ ))} +
+ ) + ))}
@@ -163,7 +232,6 @@ const TestInstance = ({ instance, onBack }: { instance: any; onBack: () => void
- 📍 结束
流程协作接口
@@ -192,6 +260,14 @@ const TestInstance = ({ instance, onBack }: { instance: any; onBack: () => void
+ + {modalVisible && }
); };