diff --git a/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiScenarioMapper.xml b/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiScenarioMapper.xml index c93cea8846..b8cd6cd386 100644 --- a/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiScenarioMapper.xml +++ b/backend/services/api-test/src/main/java/io/metersphere/api/mapper/ExtApiScenarioMapper.xml @@ -125,11 +125,11 @@ - + and ( - api_scenario.num like concat('%', #{request.keyword},'%') - or api_scenario.name like concat('%', #{request.keyword},'%') - or api_scenario.tags like JSON_CONTAINS(tags, concat('["',#{request.keyword},'"]')) + api_scenario.num like concat('%', #{request.condition.keyword},'%') + or api_scenario.name like concat('%', #{request.condition.keyword},'%') + or api_scenario.tags like JSON_CONTAINS(tags, concat('["',#{request.condition.keyword},'"]')) ) diff --git a/frontend/src/api/modules/api-test/scenario.ts b/frontend/src/api/modules/api-test/scenario.ts index 4eb499b124..bd45a21c00 100644 --- a/frontend/src/api/modules/api-test/scenario.ts +++ b/frontend/src/api/modules/api-test/scenario.ts @@ -1,19 +1,30 @@ import MSR from '@/api/http/index'; import { AddModuleUrl, + BatchCopyScenarioUrl, + BatchEditScenarioUrl, + BatchMoveScenarioUrl, + BatchRecycleScenarioUrl, DeleteModuleUrl, GetModuleCountUrl, GetModuleTreeUrl, MoveModuleUrl, + RecycleScenarioUrl, + ScenarioPageUrl, UpdateModuleUrl, + UpdateScenarioUrl, } from '@/api/requrls/api-test/scenario'; -import { ApiScenarioGetModuleParams, ApiScenarioModuleUpdateParams } from '@/models/apiTest/scenario'; import { - AddModuleParams, - ModuleTreeNode, - MoveModules, -} from '@/models/common'; + ApiScenarioBatchDeleteParams, + ApiScenarioBatchEditParams, + ApiScenarioDetail, + ApiScenarioGetModuleParams, + ApiScenarioModuleUpdateParams, + ApiScenarioPageParams, + ApiScenarioUpdateDTO, +} from '@/models/apiTest/scenario'; +import { AddModuleParams, CommonList, ModuleTreeNode, MoveModules } from '@/models/common'; // 更新模块 export function updateModule(data: ApiScenarioModuleUpdateParams) { @@ -30,7 +41,6 @@ export function moveModule(data: MoveModules) { return MSR.post({ url: MoveModuleUrl, data }); } - // 获取模块统计数量 export function getModuleCount(data: ApiScenarioGetModuleParams) { return MSR.post({ url: GetModuleCountUrl, data }); @@ -45,3 +55,49 @@ export function addModule(data: AddModuleParams) { export function deleteModule(id: string) { return MSR.get({ url: DeleteModuleUrl, params: id }); } + +// 获取接口场景列表 +export function getScenarioPage(data: ApiScenarioPageParams) { + return MSR.post>({ url: ScenarioPageUrl, data }); +} + +// 更新接口场景 +export function updateScenario(data: ApiScenarioUpdateDTO) { + return MSR.post({ url: UpdateScenarioUrl, data }); +} + +// 删除场景 +export function recycleScenario(id: string) { + return MSR.get({ url: RecycleScenarioUrl, params: id }); +} + +// 批量删除场景 +export function batchRecycleScenario(data: ApiScenarioBatchDeleteParams) { + return MSR.post({ url: BatchRecycleScenarioUrl, data }); +} + +// 批量操作场景 +export function batchOptionScenario( + optionType: string, + data: { + moduleIds: string[]; + selectAll: boolean; + condition: { keyword: string }; + excludeIds: any[]; + selectIds: any[]; + projectId: string; + targetModuleId: string; + } +) { + if (optionType === 'batchMove') { + return MSR.post({ url: BatchMoveScenarioUrl, data }); + } + if (optionType === 'batchCopy') { + return MSR.post({ url: BatchCopyScenarioUrl, data }); + } +} + +// 批量编辑场景 +export function batchEditScenario(params: ApiScenarioBatchEditParams) { + return MSR.post({ url: BatchEditScenarioUrl, params }); +} diff --git a/frontend/src/api/requrls/api-test/scenario.ts b/frontend/src/api/requrls/api-test/scenario.ts index 1907e1cfb5..ed8a8bed4b 100644 --- a/frontend/src/api/requrls/api-test/scenario.ts +++ b/frontend/src/api/requrls/api-test/scenario.ts @@ -4,27 +4,32 @@ export const MoveModuleUrl = '/api/scenario/module/move'; // 移动模块 export const GetModuleCountUrl = '/api/scenario/module/count'; // 获取模块统计数量 export const AddModuleUrl = '/api/scenario/module/add'; // 添加模块 export const DeleteModuleUrl = '/api/scenario/module/delete'; // 删除模块 +export const ScenarioPageUrl = '/api/scenario/page'; // 接口场景列表 +export const UpdateScenarioUrl = '/api/scenario/update'; // 更新接口场景 +export const RecycleScenarioUrl = '/api/scenario/delete-to-gc'; // 删除接口场景 +export const BatchRecycleScenarioUrl = '/api/scenario/batch-operation/delete-gc'; // 批量删除接口场景 +export const BatchMoveScenarioUrl = '/api/scenario/batch-operation/move'; // 批量移动接口场景 +export const BatchCopyScenarioUrl = '/api/scenario/batch-operation/copy'; // 批量复制接口场景 +export const BatchEditScenarioUrl = '/api/scenario/batch-operation/edit'; // 批量编辑接口场景 + // export const GetEnvModuleUrl = '/api/scenario/module/env/tree'; // 获取环境的模块树 -// export const DefinitionPageUrl = '/api/scenario/page'; // 接口定义列表 -// export const AddDefinitionUrl = '/api/scenario/add'; // 添加接口定义 -// export const UpdateDefinitionUrl = '/api/scenario/update'; // 更新接口定义 -// export const GetDefinitionDetailUrl = '/api/scenario/get-detail'; // 获取接口定义详情 +// export const AddDefinitionUrl = '/api/scenario/add'; // 添加接口场景 +// export const GetDefinitionDetailUrl = '/api/scenario/get-detail'; // 获取接口场景详情 // export const TransferFileUrl = '/api/scenario/transfer'; // 文件转存 // export const TransferFileModuleOptionUrl = '/api/scenario/transfer/options'; // 文件转存目录 // export const UploadTempFileUrl = '/api/scenario/upload/temp/file'; // 临时文件上传 // export const DefinitionMockPageUrl = '/api/scenario/mock/page'; // mock列表 // export const UpdateMockStatusUrl = '/api/scenario/mock/enable/'; // 更新mock状态 -// export const DeleteMockUrl = '/api/scenario/mock/delete'; // 刪除mock -// export const DeleteDefinitionUrl = '/api/scenario/delete-to-gc'; // 删除接口定义 -// export const ImportDefinitionUrl = '/api/scenario/import'; // 导入接口定义 -// export const SortDefinitionUrl = '/api/scenario/edit/pos'; // 接口定义拖拽 -// export const BatchUpdateDefinitionUrl = '/api/scenario/batch-update'; // 批量更新接口定义 -// export const BatchMoveDefinitionUrl = '/api/scenario/batch-move'; // 批量移动接口定义 -// export const BatchDeleteDefinitionUrl = '/api/scenario/batch/delete-to-gc'; // 批量删除接口定义 -// export const UpdateDefinitionScheduleUrl = '/api/scenario/schedule/update'; // 接口定义-定时同步-更新 -// export const CheckDefinitionScheduleUrl = '/api/scenario/schedule/check'; // 接口定义-定时同步-检查 url 是否存在 -// export const AddDefinitionScheduleUrl = '/api/scenario/schedule/add'; // 接口定义-定时同步-添加 -// export const SwitchDefinitionScheduleUrl = '/api/scenario/schedule/switch'; // 接口定义-定时同步-开启关闭 -// export const GetDefinitionScheduleUrl = '/api/scenario/schedule/get'; // 接口定义-定时同步-查询 -// export const DeleteDefinitionScheduleUrl = '/api/scenario/schedule/delete'; // 接口定义-定时同步-删除 -// export const DebugDefinitionUrl = '/api/scenario/debug'; // 接口定义-调试 +// export const DeleteDefinitionUrl = '/api/scenario/delete-to-gc'; // 删除接口场景 +// export const ImportDefinitionUrl = '/api/scenario/import'; // 导入接口场景 +// export const SortDefinitionUrl = '/api/scenario/edit/pos'; // 接口场景拖拽 +// export const BatchUpdateDefinitionUrl = '/api/scenario/batch-update'; // 批量更新接口场景 +// export const BatchMoveDefinitionUrl = '/api/scenario/batch-move'; // 批量移动接口场景 + +// export const UpdateDefinitionScheduleUrl = '/api/scenario/schedule/update'; // 接口场景-定时同步-更新 +// export const CheckDefinitionScheduleUrl = '/api/scenario/schedule/check'; // 接口场景-定时同步-检查 url 是否存在 +// export const AddDefinitionScheduleUrl = '/api/scenario/schedule/add'; // 接口场景-定时同步-添加 +// export const SwitchDefinitionScheduleUrl = '/api/scenario/schedule/switch'; // 接口场景-定时同步-开启关闭 +// export const GetDefinitionScheduleUrl = '/api/scenario/schedule/get'; // 接口场景-定时同步-查询 +// export const DeleteDefinitionScheduleUrl = '/api/scenario/schedule/delete'; // 接口场景-定时同步-删除 +// export const DebugDefinitionUrl = '/api/scenario/debug'; // 接口场景-调试 diff --git a/frontend/src/config/pathMap.ts b/frontend/src/config/pathMap.ts index 5c5080260a..9de51b90d8 100644 --- a/frontend/src/config/pathMap.ts +++ b/frontend/src/config/pathMap.ts @@ -95,6 +95,13 @@ export const pathMap: PathMapItem[] = [ }, ], }, + { + key: 'API_TEST_SCENARIO', // 接口测试-场景 + locale: 'menu.apiTest.scenario', + route: RouteEnum.API_TEST_SCENARIO, + permission: [], + level: MENU_LEVEL[2], + }, { key: 'API_TEST_REPORT', // 接口测试-接口测试报告 locale: 'menu.apiTest.report', diff --git a/frontend/src/enums/apiEnum.ts b/frontend/src/enums/apiEnum.ts index 7107722b6b..92f5c64154 100644 --- a/frontend/src/enums/apiEnum.ts +++ b/frontend/src/enums/apiEnum.ts @@ -69,6 +69,13 @@ export enum RequestDefinitionStatus { DEBUGGING = 'DEBUGGING', DONE = 'DONE', } + +// 接口场景状态 +export enum ApiScenarioStatus { + DEPRECATED = 'DEPRECATED', + UNDERWAY = 'UNDERWAY', + COMPLETED = 'COMPLETED', +} // 接口导入支持格式 export enum RequestImportFormat { SWAGGER = 'Swagger3', diff --git a/frontend/src/locale/en-US/common.ts b/frontend/src/locale/en-US/common.ts index 66a8d3ef2b..e25ac5e049 100644 --- a/frontend/src/locale/en-US/common.ts +++ b/frontend/src/locale/en-US/common.ts @@ -114,6 +114,7 @@ export default { 'common.tagsInputPlaceholder': 'Enter the content and press Enter to directly add tags', 'common.move': 'Move', 'common.batchMove': 'Batch move', + 'common.batchCopy': 'Batch copy', 'common.batchMoveSuccess': 'Batch move successful', 'common.importSuccess': 'Import successful', 'common.nameIsTooLang': 'The name exceeds 255 characters', diff --git a/frontend/src/locale/en-US/index.ts b/frontend/src/locale/en-US/index.ts index 744a7884c9..6f454582d3 100644 --- a/frontend/src/locale/en-US/index.ts +++ b/frontend/src/locale/en-US/index.ts @@ -28,7 +28,7 @@ export default { 'menu.apiTest.debug.debug': 'Debug', 'menu.apiTest.management': 'API Management', 'menu.apiTest.management.definition': 'API Definition', - 'menu.apiTest.scenario': 'API Scenario', + 'menu.apiTest.scenario': 'Scenario', 'menu.apiTest.report': 'API Report', 'menu.uiTest': 'UI Test', 'menu.performanceTest': 'Performance Test', diff --git a/frontend/src/locale/zh-CN/common.ts b/frontend/src/locale/zh-CN/common.ts index 7ac3d7d7fc..eac06ebbcc 100644 --- a/frontend/src/locale/zh-CN/common.ts +++ b/frontend/src/locale/zh-CN/common.ts @@ -117,6 +117,7 @@ export default { 'common.tagsInputPlaceholder': '输入内容后回车可直接添加标签', 'common.move': '移动', 'common.batchMove': '批量移动', + 'common.batchCopy': '批量复制', 'common.batchMoveSuccess': '批量移动成功', 'common.importSuccess': '导入成功', 'common.nameIsTooLang': '名称超过255个字符', diff --git a/frontend/src/locale/zh-CN/index.ts b/frontend/src/locale/zh-CN/index.ts index f9142942c9..58dd84aee1 100644 --- a/frontend/src/locale/zh-CN/index.ts +++ b/frontend/src/locale/zh-CN/index.ts @@ -29,7 +29,7 @@ export default { 'menu.apiTest.management': '接口管理', 'menu.apiTest.management.definition': '接口定义', 'menu.apiTest.api': 'API列表', - 'menu.apiTest.scenario': '接口场景', + 'menu.apiTest.scenario': '场景', 'menu.apiTest.report': '接口报告', 'menu.uiTest': 'UI测试', 'menu.workstation': '工作台', diff --git a/frontend/src/models/apiTest/scenario.ts b/frontend/src/models/apiTest/scenario.ts index 17dff957c0..7835595461 100644 --- a/frontend/src/models/apiTest/scenario.ts +++ b/frontend/src/models/apiTest/scenario.ts @@ -1,8 +1,8 @@ -import { RequestDefinitionStatus, RequestImportFormat, RequestImportType } from '@/enums/apiEnum'; - -import { BatchApiParams, ModuleTreeNode, TableQueryParams } from '../common'; -import { ExecuteRequestParams, ResponseDefinition } from './common'; +import { ApiDefinitionCustomField } from '@/models/apiTest/management'; +import { ApiScenarioStatus, RequestDefinitionStatus, RequestImportFormat, RequestImportType } from '@/enums/apiEnum'; +import { BatchApiParams, TableQueryParams } from '../common'; +import { ResponseDefinition } from './common'; // 场景-更新模块参数 export interface ApiScenarioModuleUpdateParams { @@ -12,35 +12,72 @@ export interface ApiScenarioModuleUpdateParams { // 场景-获取模块树参数 export interface ApiScenarioGetModuleParams { - keyword: string; + keyword?: string; searchMode?: 'AND' | 'OR'; filter?: Record; combine?: Record; - moduleIds: string[]; + moduleIds?: string[]; projectId: string; versionId?: string; refId?: string; } -// 环境-选中的模块 -export interface SelectedModule { - // 选中的模块 +// 场景修改参数 +export interface ApiScenarioUpdateDTO { + id: string; + name?: string; + priority?: string; + status?: ApiScenarioStatus; + moduleId?: string; + description?: string; + tags?: string[]; + grouped?: boolean; + environmentId?: string; + uploadFileIds?: string[]; + linkFileIds?: string[]; + deleteFileIds?: string[]; + unLinkFileIds?: string[]; +} + +// 场景详情 +export interface ApiScenarioDetail { + id: string; + name: string; + method: string; + path: string; + num: number; + pos: number; + projectId: string; moduleId: string; - containChildModule: boolean; // 是否包含新增子模块 - disabled: boolean; + latest: boolean; + versionId: string; + refId: string; + createTime: number; + createUser: string; + updateTime: number; + updateUser: string; + deleteUser: string; + deleteTime: number; + deleted: boolean; + createUserName: string; + updateUserName: string; + deleteUserName: string; + versionName: string; + caseTotal: number; + casePassRate: string; + caseStatus: string; + follow: boolean; + tags: string[]; + response: ResponseDefinition; + description: string; + status: RequestDefinitionStatus; + customFields: ApiDefinitionCustomField[]; } -// 环境-模块树 -export interface EnvModule { - moduleTree: ModuleTreeNode[]; - selectedModules: SelectedModule[]; -} - -// 定义列表查询参数 +// 场景列表查询参数 export interface ApiScenarioPageParams extends TableQueryParams { id: string; name: string; - protocol: string; projectId: string; versionId: string; refId: string; @@ -48,13 +85,7 @@ export interface ApiScenarioPageParams extends TableQueryParams { deleted: boolean; } - -export interface mockParams { - id: string; - projectId: string; -} - -// 批量更新定义参数 +// 批量更新场景参数 export interface ApiScenarioBatchUpdateParams extends BatchApiParams { type?: string; append?: boolean; @@ -64,18 +95,39 @@ export interface ApiScenarioBatchUpdateParams extends BatchApiParams { customField?: Record; } -// 批量移动定义参数 -export interface ApiScenarioBatchMoveParams extends BatchApiParams { - moduleId: string | number; +export interface BatchOptionParams extends BatchApiParams { + apiScenarioId?: string; + versionId?: string; + refId?: string; } -// 批量删除定义参数 +// 批量移动场景参数 +export interface ApiScenarioBatchMoveParams extends BatchOptionParams { + targetModuleId: string | number; +} + +// 批量编辑场景参数 +export interface ApiScenarioBatchEditParams extends BatchOptionParams { + // 修改操作的类型 + type?: string; + + // 修改标签相关 + appendTag?: boolean; + tags?: string[]; + + // 修改环境相关 + grouped?: boolean; + envId?: string; + groupId?: string; + + // 修改状态 + status?: string; + + // 修改优先级 + priority?: string; +} + +// 批量删除场景参数 export interface ApiScenarioBatchDeleteParams extends BatchApiParams { deleteAll: boolean; } - -// 场景-定时同步-更新参数 -export interface UpdateScheduleParams { - id: string; - taskId: string; -} diff --git a/frontend/src/router/routes/modules/apiTest.ts b/frontend/src/router/routes/modules/apiTest.ts index 52add954e3..0b52ede6b3 100644 --- a/frontend/src/router/routes/modules/apiTest.ts +++ b/frontend/src/router/routes/modules/apiTest.ts @@ -69,11 +69,12 @@ const ApiTest: AppRouteRecordRaw = { component: () => import('@/views/api-test/scenario/index.vue'), meta: { locale: 'menu.apiTest.scenario', - roles: ['*'], isTopMenu: true, + roles: ['PROJECT_API_SCENARIO:READ'], }, }, + // 接口场景回收站 { path: 'scenarioRecycle', name: ApiTestRouteEnum.API_TEST_SCENARIO_RECYCLE, diff --git a/frontend/src/views/api-test/components/apiStatus.vue b/frontend/src/views/api-test/components/apiStatus.vue index 4a68424ae5..b6b60df53c 100644 --- a/frontend/src/views/api-test/components/apiStatus.vue +++ b/frontend/src/views/api-test/components/apiStatus.vue @@ -7,10 +7,10 @@ import { useI18n } from '@/hooks/useI18n'; - import { RequestDefinitionStatus } from '@/enums/apiEnum'; + import { ApiScenarioStatus, RequestDefinitionStatus } from '@/enums/apiEnum'; const props = defineProps<{ - status: RequestDefinitionStatus; + status: RequestDefinitionStatus | ApiScenarioStatus; size?: Size; }>(); @@ -27,6 +27,11 @@ color: 'rgb(var(--link-5))', text: 'apiTestManagement.processing', }, + [ApiScenarioStatus.UNDERWAY]: { + bgColor: 'rgb(var(--link-2))', + color: 'rgb(var(--link-5))', + text: 'apiTestManagement.processing', + }, [RequestDefinitionStatus.DEBUGGING]: { bgColor: 'rgb(var(--link-2))', color: 'rgb(var(--link-6))', @@ -37,6 +42,11 @@ color: 'rgb(var(--success-6))', text: 'apiTestManagement.done', }, + [ApiScenarioStatus.COMPLETED]: { + bgColor: 'rgb(var(--success-2))', + color: 'rgb(var(--success-6))', + text: 'apiTestManagement.done', + }, }; const status = computed(() => { const config = statusMap[props.status]; diff --git a/frontend/src/views/api-test/scenario/components/operationScenarioModuleTree.vue b/frontend/src/views/api-test/scenario/components/operationScenarioModuleTree.vue new file mode 100644 index 0000000000..87436af776 --- /dev/null +++ b/frontend/src/views/api-test/scenario/components/operationScenarioModuleTree.vue @@ -0,0 +1,235 @@ + + + + + + + + + + {{ nodeData.name }} + ({{ nodeData.count || 0 }}) + + + + + + + + + + diff --git a/frontend/src/views/api-test/scenario/components/scenarioModuleTree.vue b/frontend/src/views/api-test/scenario/components/scenarioModuleTree.vue index b8817e2264..2777f9a2e0 100644 --- a/frontend/src/views/api-test/scenario/components/scenarioModuleTree.vue +++ b/frontend/src/views/api-test/scenario/components/scenarioModuleTree.vue @@ -6,15 +6,9 @@ :placeholder="t('apiScenario.tree.selectorPlaceholder')" allow-clear /> - - {{ t('apiScenario.createScenario') }} - - {{ t('apiScenario.createScenario') }} - - {{ t('apiScenario.importScenario') }} - - - + {{ + t('apiScenario.createScenario') + }} @@ -30,7 +24,7 @@ - + initModules()" > - + @@ -145,7 +145,9 @@ import useModal from '@/hooks/useModal'; import useAppStore from '@/store/modules/app'; import { mapTree } from '@/utils'; + import { hasAnyPermission } from '@/utils/permission'; + import { ApiScenarioGetModuleParams } from '@/models/apiTest/scenario'; import { ModuleTreeNode } from '@/models/common'; const props = withDefaults( @@ -231,6 +233,7 @@ { label: 'common.rename', eventTag: 'rename', + permission: ['PROJECT_API_SCENARIO:READ+UPDATE'], }, { isDivider: true, @@ -238,6 +241,7 @@ { label: 'common.delete', eventTag: 'delete', + permission: ['PROJECT_API_SCENARIO:READ+DELETE'], danger: true, }, ]; @@ -299,28 +303,6 @@ } } - async function initModuleCount() { - try { - const res = await getModuleCount({ - keyword: moduleKeyword.value, - projectId: appStore.currentProjectId, - moduleIds: [], - }); - modulesCount.value = res; - folderTree.value = mapTree(folderTree.value, (node) => { - return { - ...node, - count: res[node.id] || 0, - draggable: !props.readOnly, - disabled: props.readOnly ? node.id === selectedKeys.value[0] : false, - }; - }); - } catch (error) { - // eslint-disable-next-line no-console - console.log(error); - } - } - watch( () => props.isExpandAll, (val) => { @@ -337,13 +319,10 @@ */ function folderNodeSelect(_selectedKeys: (string | number)[], node: MsTreeNodeData) { const offspringIds: string[] = []; - if (props.isShowScenario) { - mapTree(node.children || [], (e) => { - offspringIds.push(e.id); - return e; - }); - } - + mapTree(node.children || [], (e) => { + offspringIds.push(e.id); + return e; + }); emit('folderNodeSelect', _selectedKeys, offspringIds); } @@ -366,7 +345,6 @@ await deleteModule(node.id); Message.success(t('apiScenario.deleteSuccess')); await initModules(); - initModuleCount(); } catch (error) { // eslint-disable-next-line no-console console.log(error); @@ -437,7 +415,6 @@ } finally { loading.value = false; await initModules(); - initModuleCount(); } } @@ -448,18 +425,35 @@ } } - onBeforeMount(async () => { - await initModules(); - initModuleCount(); - }); - async function refresh() { await initModules(); - initModuleCount(); } + async function initModuleCount(params: ApiScenarioGetModuleParams) { + try { + const res = await getModuleCount(params); + modulesCount.value = res; + folderTree.value = mapTree(folderTree.value, (node) => { + return { + ...node, + count: res[node.id] || 0, + draggable: !props.readOnly, + disabled: props.readOnly ? node.id === selectedKeys.value[0] : false, + }; + }); + } catch (error) { + console.log(error); + } + } + onBeforeMount(async () => { + await initModules(); + await initModuleCount({ + projectId: appStore.currentProjectId, + }); + }); defineExpose({ refresh, + initModuleCount, }); diff --git a/frontend/src/views/api-test/scenario/components/scenarioTable.vue b/frontend/src/views/api-test/scenario/components/scenarioTable.vue new file mode 100644 index 0000000000..9cefb674d6 --- /dev/null +++ b/frontend/src/views/api-test/scenario/components/scenarioTable.vue @@ -0,0 +1,885 @@ + + + + + + + {{ + t('apiScenario.table.showChildrenModuleScenario') + }} + + + + + + + + + + + + + + + + {{ t(columnConfig.title as string) }} + + + + + + + + + + + + + + + + + {{ record.num }} + + + handleStatusChange(record)" + > + + + + + + + + + + handlePriorityStatusChange(record)" + > + + + + + + + + + + + + + {{ t('apiScenario.execute') }} + + + + {{ t('common.copy') }} + + + + + + + + + + {{ t('common.batchEdit') }} + + {{ + t('api_scenario.table.batchModalSubTitle', { + count: batchParams.currentSelectCount || tableSelected.length, + }) + }} + + + + + + + {{ t(item.name) }} + + + + + + + + + + + + + + + + + + {{ t(item.name) }} + + + + + + + {{ t('common.cancel') }} + + + {{ t('common.update') }} + + + + + + + + + {{ t('common.batchCopy') }} + + {{ t('api_scenario.table.batchModalSubTitle', { count: tableSelected.length }) }} + + + + {{ t('common.batchMove') }} + + {{ t('api_scenario.table.batchModalSubTitle', { count: batchOptionScenarioCount }) }} + + + + + + + + + + + diff --git a/frontend/src/views/api-test/scenario/index.vue b/frontend/src/views/api-test/scenario/index.vue index f339f8edbd..b8f886ab3d 100644 --- a/frontend/src/views/api-test/scenario/index.vue +++ b/frontend/src/views/api-test/scenario/index.vue @@ -43,9 +43,12 @@ - - - + @@ -66,10 +69,11 @@ import MsSplitBox from '@/components/pure/ms-split-box/index.vue'; import scenarioModuleTree from './components/scenarioModuleTree.vue'; import detail from './detail/index.vue'; - import ApiTable from '@/views/api-test/management/components/management/api/apiTable.vue'; + import ScenarioTable from '@/views/api-test/scenario/components/scenarioTable.vue'; import { useI18n } from '@/hooks/useI18n'; + import { ApiScenarioGetModuleParams } from '@/models/apiTest/scenario'; import { ModuleTreeNode } from '@/models/common'; const { t } = useI18n(); @@ -94,10 +98,10 @@ const folderTree = ref([]); const folderTreePathMap = ref>({}); - const activeFolder = ref('all'); const activeModule = ref('all'); + const activeFolder = ref('all'); const offspringIds = ref([]); - + const recycleModulesCount = ref(0); const isShowScenario = ref(false); // 获取激活用例类型样式 @@ -105,9 +109,9 @@ return activeFolder.value === type ? 'folder-text case-active' : 'folder-text'; }; - const scenarioModuleTreeRef = ref(); + const scenarioModuleTreeRef = ref>(); - function handleModuleInit(tree, _protocol: string, pathMap: Record) { + function handleModuleInit(tree: any, _protocol: string, pathMap: Record) { folderTree.value = tree; folderTreePathMap.value = pathMap; } @@ -117,6 +121,10 @@ offspringIds.value = _offspringIds; } + function refreshTree(params: ApiScenarioGetModuleParams) { + scenarioModuleTreeRef.value?.initModuleCount(params); + } + function redirectRecycle() {} diff --git a/frontend/src/views/api-test/scenario/locale/en-US.ts b/frontend/src/views/api-test/scenario/locale/en-US.ts index 56fa0b2586..933886bfbe 100644 --- a/frontend/src/views/api-test/scenario/locale/en-US.ts +++ b/frontend/src/views/api-test/scenario/locale/en-US.ts @@ -32,4 +32,25 @@ export default { 'apiScenario.params.paramValue': 'Parameter value', 'apiScenario.params.tag': 'Tag', 'apiScenario.params.desc': 'Description', + 'apiScenario.table.showChildrenModuleScenario': 'Show subdirectory scenarios', + + 'apiScenario.table.columns.name': 'Name', + 'apiScenario.table.columns.level': 'Level', + 'apiScenario.table.columns.status': 'status', + 'apiScenario.table.columns.runResult': 'Run result', + 'apiScenario.table.columns.tags': 'Tags', + 'apiScenario.table.columns.scenarioEnv': 'Scenario environment', + 'apiScenario.table.columns.steps': 'Steps', + 'apiScenario.table.columns.passRate': 'Pass rate', + 'apiScenario.table.columns.module': 'Module', + 'apiScenario.table.columns.createUser': 'Create user', + 'apiScenario.table.columns.createTime': 'Create time', + 'apiScenario.table.columns.updateUser': 'Update user', + 'apiScenario.table.columns.updateTime': 'Update time', + + 'apiScenario.execute': 'Execute', + + // 批量操作文案 + 'api_scenario.batch_operation.success': 'Success {opt} to {name}', + 'api_scenario.table.batchMoveConfirm': 'Ready to {opt} {count} scenarios', }; diff --git a/frontend/src/views/api-test/scenario/locale/zh-CN.ts b/frontend/src/views/api-test/scenario/locale/zh-CN.ts index 5642dfec92..82cbe40574 100644 --- a/frontend/src/views/api-test/scenario/locale/zh-CN.ts +++ b/frontend/src/views/api-test/scenario/locale/zh-CN.ts @@ -31,4 +31,39 @@ export default { 'apiScenario.params.paramValue': '参数值', 'apiScenario.params.tag': '标签', 'apiScenario.params.desc': '描述', + 'apiScenario.table.showChildrenModuleScenario': '显示子目录场景', + + 'apiScenario.table.columns.name': '场景名称', + 'apiScenario.table.columns.level': '场景等级', + 'apiScenario.table.columns.status': '状态', + 'apiScenario.table.columns.runResult': '运行结果', + 'apiScenario.table.columns.tags': '标签', + 'apiScenario.table.columns.scenarioEnv': '场景环境', + 'apiScenario.table.columns.steps': '步骤数', + 'apiScenario.table.columns.passRate': '通过率', + 'apiScenario.table.columns.module': '所属模块', + 'apiScenario.table.columns.createUser': '创建人', + 'apiScenario.table.columns.createTime': '创建时间', + 'apiScenario.table.columns.updateUser': '更新人', + 'apiScenario.table.columns.updateTime': '更新时间', + + 'api_scenario.table.searchPlaceholder': '通过 ID/名称/标签搜索', + 'api_scenario.table.batchModalSubTitle': '(已选 {count} 个场景)', + 'api_scenario.table.chooseAttr': '选择属性', + 'api_scenario.table.attrRequired': '属性不能为空', + 'api_scenario.table.batchUpdate': '批量更新为', + 'api_scenario.table.valueRequired': '属性值不能为空', + 'api_scenario.table.deleteScenarioTipTitle': '确认删除 {name} 吗?', + 'api_scenario.table.batchDeleteScenarioTip': '确认删除已选中的 {count} 个场景吗?', + 'api_scenario.table.deleteScenarioTip': '删除后,可能导致引用该场景的资源执行失败,请谨慎操作!', + 'api_scenario.table.apiStatus': '状态', + 'api_scenario.table.status.underway': '进行中', + 'api_scenario.table.status.completed': '已完成', + 'api_scenario.table.status.deprecate': '已废弃', + + 'apiScenario.execute': '执行', + + // 批量操作文案 + 'api_scenario.batch_operation.success': '成功{opt}至 {name}', + 'api_scenario.table.batchMoveConfirm': '{opt}{count}个场景至已选模块', };