diff --git a/frontend/src/api/modules/api-test/management.ts b/frontend/src/api/modules/api-test/management.ts index 64fafe285a..dd64105869 100644 --- a/frontend/src/api/modules/api-test/management.ts +++ b/frontend/src/api/modules/api-test/management.ts @@ -55,6 +55,7 @@ import { GetModuleTreeUrl, GetPoolId, GetPoolOptionUrl, + getSyncedCaseDetailUrl, GetTrashModuleCountUrl, GetTrashModuleTreeUrl, ignoreEveryTimeApiChangeUrl, @@ -125,6 +126,7 @@ import { DefinitionHistoryItem, DefinitionHistoryPageParams, DefinitionReferencePageParams, + diffSyncParams, EnvModule, ImportApiDefinitionParams, mockParams, @@ -330,10 +332,14 @@ export function ignoreEveryTimeChange(id: string, ignore: boolean) { export function caseTableBatchSync(data: TableQueryParams) { return MSR.post({ url: caseTableBatchSyncUrl, data }); } -// // 接口测试-接口用例-定义对比用例 +// 接口测试-接口用例-定义对比用例 export function diffDataRequest(id: string) { return MSR.get({ url: `${diffDataUrl}/${id}` }); } +// 接口测试-接口用例-定义对比用例-同步-获取同步后的用例详情 +export function getSyncedCaseDetail(data: diffSyncParams) { + return MSR.post({ url: getSyncedCaseDetailUrl, data }); +} /** * Mock diff --git a/frontend/src/api/requrls/api-test/management.ts b/frontend/src/api/requrls/api-test/management.ts index 5a21237d0e..ebe49dcb23 100644 --- a/frontend/src/api/requrls/api-test/management.ts +++ b/frontend/src/api/requrls/api-test/management.ts @@ -42,6 +42,7 @@ export const clearThisChangeUrl = '/api/case/api-change/clear'; // 接口定义- export const caseTableBatchSyncUrl = '/api/case/batch/api-change/sync'; // 接口测试-接口管理-接口用例-批量同步 export const ignoreEveryTimeApiChangeUrl = '/api/case/api-change/ignore'; // 接口测试-接口用例-忽略每次接口变更 export const diffDataUrl = '/api/case/api/compare'; // 接口测试-接口用例-定义对比用例 +export const getSyncedCaseDetailUrl = '/api/case/api-change/sync'; // 接口测试-接口用例-定义对比用例-同步-获取同步后的用例详情 /** * Mock diff --git a/frontend/src/components/pure/ms-code-editor/index.vue b/frontend/src/components/pure/ms-code-editor/index.vue index 5dc0d6a4ff..7b9059690e 100644 --- a/frontend/src/components/pure/ms-code-editor/index.vue +++ b/frontend/src/components/pure/ms-code-editor/index.vue @@ -89,7 +89,7 @@ // 编辑器实例,每次调用组件都会创建独立的实例 let editor: monaco.editor.IStandaloneCodeEditor; // 编辑器diffEditor实例 开启diffMode则会初始化 - let diffEditor: monaco.editor.IStandaloneDiffEditor; + let diffEditor: monaco.editor.IStandaloneDiffEditor | null; const codeContainerRef = ref(); // 用于全屏的容器 ref @@ -403,12 +403,18 @@ (newDiffMode) => { if (newDiffMode) { if (editor) { - editor.dispose(); + // 确保编辑器实例的 DOM 节点存在且是当前组件的一部分 + const editorDomNode = editor.getDomNode(); + if (editorDomNode && editorDomNode.parentNode) { + editor.dispose(); + } } initDiffEditor(props.originalValue, props.modelValue); } else { if (diffEditor) { + // 清空上一次的初始结果,避免初始编辑器已存在Error diffEditor.dispose(); + diffEditor = null; } init(); } diff --git a/frontend/src/models/apiTest/management.ts b/frontend/src/models/apiTest/management.ts index 1832f9ddf4..a9753da58c 100644 --- a/frontend/src/models/apiTest/management.ts +++ b/frontend/src/models/apiTest/management.ts @@ -8,6 +8,7 @@ import { import { BatchApiParams, ModuleTreeNode, TableQueryParams } from '../common'; import { ExecuteRequestParams, ResponseDefinition } from './common'; +import type { RequestParam } from '@/views/api-test/components/requestComposition/index.vue'; // 定义-自定义字段 export interface ApiDefinitionCustomField { @@ -419,3 +420,10 @@ export interface batchSyncForm { syncItems: syncItem; deleteRedundantParam: boolean; } +// 对比同步参数 +export interface diffSyncParams { + syncItems: syncItem; // 同步项 + id: string; + deleteRedundantParam: boolean; // 是否删除多余参数 + apiCaseRequest: RequestParam; // 用例详情请求request +} diff --git a/frontend/src/views/api-test/management/components/management/case/apiCaseDetail.vue b/frontend/src/views/api-test/management/components/management/case/apiCaseDetail.vue index 2e0e1b47c6..5e09711f01 100644 --- a/frontend/src/views/api-test/management/components/management/case/apiCaseDetail.vue +++ b/frontend/src/views/api-test/management/components/management/case/apiCaseDetail.vue @@ -57,6 +57,7 @@ ref="createAndEditCaseDrawerRef" v-bind="$attrs" @load-case="(id)=>getCaseDetailInfo(id as string)" + @show-diff="showDiffDrawer" /> @@ -404,9 +405,10 @@ getCaseDetailInfo(caseId.value); } - function syncHandler(id: string) { - // TODO 这里需要调用同步合并后的详情接口回显详情 - createAndEditCaseDrawerRef.value?.open(id, caseDetail.value, false); + // 同步参数 + async function syncParamsHandler(mergedRequestParam: RequestParam) { + caseDetail.value = { ...caseDetail.value, ...mergedRequestParam }; + createAndEditCaseDrawerRef.value?.open(caseDetail.value.apiDefinitionId, caseDetail.value, false); } onBeforeMount(() => { diff --git a/frontend/src/views/api-test/management/components/management/case/caseDetail.vue b/frontend/src/views/api-test/management/components/management/case/caseDetail.vue index 37a7e01404..9bf972390f 100644 --- a/frontend/src/views/api-test/management/components/management/case/caseDetail.vue +++ b/frontend/src/views/api-test/management/components/management/case/caseDetail.vue @@ -74,7 +74,7 @@ :active-defined-id="activeDefinedId" @close="closeDifferent" @clear-this-change="clearThisChangeHandler" - @sync="syncHandler" + @sync="syncParamsHandler" /> @@ -351,9 +351,10 @@ emit('loadCase', props.detail.id as string); } - function syncHandler(id: string) { - // TODO 这里需要调用同步合并后的详情接口回显详情 - createAndEditCaseDrawerRef.value?.open(id, caseDetail.value, false); + // 同步参数 + function syncParamsHandler(mergedRequestParam: RequestParam) { + caseDetail.value = { ...caseDetail.value, ...mergedRequestParam }; + createAndEditCaseDrawerRef.value?.open(caseDetail.value.apiDefinitionId, caseDetail.value, false); } watch( diff --git a/frontend/src/views/api-test/management/components/management/case/caseTable.vue b/frontend/src/views/api-test/management/components/management/case/caseTable.vue index 91ae5da74a..e158ba27c5 100644 --- a/frontend/src/views/api-test/management/components/management/case/caseTable.vue +++ b/frontend/src/views/api-test/management/components/management/case/caseTable.vue @@ -315,7 +315,7 @@ :active-defined-id="activeDefinedId" @close="closeDifferent" @clear-this-change="handleClearThisChange" - @sync="syncHandler" + @sync="syncParamsHandler" /> @@ -1034,10 +1034,12 @@ } // 对比抽屉同步成功打开编辑 - function syncHandler(definedId: string) { - // TODO 这里调用同步后的最新的合并后的详情,打开编辑抽屉用户手动保存更新即可生效 - createAndEditCaseDrawerRef.value?.open(definedId, caseDetail.value as RequestParam, false); + async function syncParamsHandler(mergedRequestParam: RequestParam) { + await getCaseDetailInfo(activeApiCaseId.value); + caseDetail.value = { ...caseDetail.value, ...mergedRequestParam }; + createAndEditCaseDrawerRef.value?.open(caseDetail.value.apiDefinitionId, caseDetail.value as RequestParam, false); } + defineExpose({ loadCaseList, }); diff --git a/frontend/src/views/api-test/management/components/management/case/diffRequestBody.vue b/frontend/src/views/api-test/management/components/management/case/diffRequestBody.vue index fb9d3fd9c9..bde45a21e0 100644 --- a/frontend/src/views/api-test/management/components/management/case/diffRequestBody.vue +++ b/frontend/src/views/api-test/management/components/management/case/diffRequestBody.vue @@ -1,6 +1,6 @@ - + {{ item.title }} @@ -47,7 +47,10 @@ {{ t('case.notSetData') }} - + {{ t('case.apiAndCaseDiff') }} - {{ t('case.syncItem') }} - + {{ t('case.syncItem') }} + - {{ item.label }} - + + {{ item.label }} - + {{ t('case.ignoreAllChange') }} - - {{ t('case.deleteNotCorrespondValue') }} + + {{ + t('case.deleteNotCorrespondValue') + }} {{ t('common.cancel') }} - + {{ t('case.ignoreThisChange') }} - {{ t('case.apiSyncChange') }} + {{ caseDetail.inconsistentWithApi ? t('case.apiSyncChange') : t('common.confirm') }} - - - {{ t('case.diffAdd') }} - - - - {{ t('common.delete') }} + + + + {{ t('case.diffAdd') }} + + + + {{ t('common.delete') }} + @@ -81,7 +93,6 @@ - (); const showDiffVisible = defineModel('visible', { @@ -165,8 +177,6 @@ query: false, rest: false, }, - noticeApiCaseCreator: true, - noticeApiScenarioCreator: true, ignoreApiChange: false, }; @@ -175,21 +185,13 @@ const form = ref({ ...initForm }); function cancel() { + form.value = { ...initForm }; + checkType.value = []; showDiffVisible.value = false; emit('close'); } - const syncLoading = ref(false); - // 同步 - function confirmSync() { - // 处理同步类型参数 - checkType.value.forEach((e: any) => { - const key = e.toLowerCase() as keyof syncItem; - form.value.syncItems[key] = true; - }); - emit('sync', props.activeDefinedId); - showDiffVisible.value = false; - } + const syncLoading = ref(false); const defaultCaseParams = inject('defaultCaseParams'); const caseDetail = ref>({}); @@ -318,10 +320,43 @@ getBodyData(RequestBodyFormat.FORM_DATA); getBodyData(RequestBodyFormat.WWW_FORM); } + const syncCaseDetail = ref>({}); + + // 同步 + async function confirmSync() { + if (!caseDetail.value.inconsistentWithApi) { + cancel(); + return; + } + syncLoading.value = true; + try { + // 处理同步类型参数 + checkType.value.forEach((e: any) => { + const key = e.toLowerCase() as keyof syncItem; + form.value.syncItems[key] = true; + }); + const { id, request } = syncCaseDetail.value; + + const params: diffSyncParams = { + ...form.value, + apiCaseRequest: request, + id, + }; + const mergeRequest = await getSyncedCaseDetail(params); + emit('sync', mergeRequest); + cancel(); + } catch (error) { + console.log(error); + } finally { + syncLoading.value = false; + } + } + // 获取用例详情 async function getCaseDetailInfo(id: string) { try { const res = await getCaseDetail(id); + syncCaseDetail.value = res; const result = await diffDataRequest(id); const { caseRequest, apiRequest } = result; caseDetail.value = { diff --git a/frontend/src/views/test-plan/report/detail/component/config.vue b/frontend/src/views/test-plan/report/detail/component/config.vue index bb3b32cedd..e74cd82a64 100644 --- a/frontend/src/views/test-plan/report/detail/component/config.vue +++ b/frontend/src/views/test-plan/report/detail/component/config.vue @@ -279,9 +279,8 @@ watch( [() => configList.value, () => cardItemList.value], () => { - const configValue = resetConfigEditList(configList.value); - const cardItemValue = resetConfigEditList(cardItemList.value); - + const configValue = resetConfigEditList(cloneDeep(configList.value)); + const cardItemValue = resetConfigEditList(cloneDeep(cardItemList.value)); const isisEqualList = props.isGroup ? cloneDeep(defaultGroupConfig) : cloneDeep(defaultSingleConfig); if (!isEqual(configValue, isisEqualList) || (!isEqual(cardItemValue, isisEqualList) && !isInit.value)) { if (isInit.value) { diff --git a/frontend/src/views/test-plan/report/detail/component/viewReport.vue b/frontend/src/views/test-plan/report/detail/component/viewReport.vue index b20870a9a9..94450c59fb 100644 --- a/frontend/src/views/test-plan/report/detail/component/viewReport.vue +++ b/frontend/src/views/test-plan/report/detail/component/viewReport.vue @@ -616,7 +616,6 @@ ...currentItem, ...formValue, }; - innerCardList.value = innerCardList.value.map((item: configItem) => { if (item.id === currentItem.id) { return { diff --git a/frontend/src/views/test-plan/report/detail/configReport.vue b/frontend/src/views/test-plan/report/detail/configReport.vue index b2747526bd..53f2659332 100644 --- a/frontend/src/views/test-plan/report/detail/configReport.vue +++ b/frontend/src/views/test-plan/report/detail/configReport.vue @@ -61,7 +61,7 @@ apiBugCount: 0, scenarioBugCount: 0, testPlanName: '', - defaultLayout: true, + defaultLayout: false, }); const isGroup = computed(() => route.query.type === 'GROUP');