fix(接口管理): 执行结果抽屉&用例列表跳转执行&部分细节

This commit is contained in:
teukkk 2024-03-27 16:42:30 +08:00 committed by Craftsman
parent 3a5a33ad0d
commit ad6bc5be35
16 changed files with 449 additions and 249 deletions

View File

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.66602 0.666504L8.72002 0.668504L8.76532 0.67385C8.77665 0.675589 8.78827 0.677639 8.79983 0.679997C8.81451 0.68293 8.82897 0.686393 8.84324 0.690318C8.85366 0.693236 8.86392 0.696323 8.87411 0.699663C8.88721 0.703919 8.9004 0.708714 8.91339 0.713907L8.94816 0.728953C8.96194 0.735422 8.97554 0.742367 8.98887 0.749754C8.99694 0.75417 9.00509 0.758909 9.01315 0.763834C9.0302 0.774316 9.04677 0.785497 9.06279 0.79738L9.07736 0.808456C9.07912 0.809885 9.08106 0.811419 9.08298 0.812963L9.13742 0.861766L12.4708 4.1951L12.516 4.2465L12.5351 4.26963C12.547 4.28575 12.5582 4.30232 12.5686 4.3194L12.5829 4.3438C12.5902 4.35697 12.5971 4.37058 12.6036 4.38444L12.6185 4.41895C12.6238 4.43212 12.6286 4.44531 12.633 4.45868C12.6362 4.4686 12.6393 4.47886 12.6421 4.48917C12.6461 4.50355 12.6496 4.51801 12.6526 4.53264C12.6549 4.54425 12.6569 4.55587 12.6587 4.56753C12.6597 4.57435 12.6607 4.58153 12.6615 4.58876L12.6635 4.60902C12.6646 4.62099 12.6653 4.63299 12.6657 4.645L12.666 4.6665V7.99984H11.3327V5.33317H8.66602C8.32412 5.33317 8.04234 5.07581 8.00383 4.74425L7.99935 4.6665V1.99984H1.99935V13.9998H7.99935V15.3332H1.99935C1.26297 15.3332 0.666016 14.7362 0.666016 13.9998V1.99984C0.666016 1.26346 1.26297 0.666504 1.99935 0.666504H8.66602ZM12.5381 8.8665C13.7153 8.8665 14.5574 9.64206 14.666 10.637H13.2444C13.1629 10.2923 12.9727 10.0259 12.5291 10.0259H11.5783C11.0531 10.0259 10.7181 10.4098 10.7181 10.872L10.7271 13.3277C10.7271 13.7899 11.0622 14.1737 11.5874 14.1737H12.5381C12.9727 14.1737 13.1538 13.9231 13.2444 13.5862H14.6751C14.5664 14.5654 13.7153 15.3332 12.5472 15.3332H11.5783C10.3468 15.3332 9.34174 14.4636 9.34174 13.3982L9.33268 10.8093C9.33268 9.73607 10.3378 8.8665 11.5692 8.8665H12.5381ZM9.33268 2.94317V3.99984H10.3893L9.33268 2.94317Z" fill="#3370FF"/>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -1,7 +1,6 @@
<template> <template>
<a-dropdown-button <a-dropdown-button
v-if="!caseDetail?.executeLoading && !props.executeLoading" v-if="hasLocalExec && !props.executeLoading"
v-permission="['PROJECT_API_DEFINITION_CASE:READ+EXECUTE']"
class="exec-btn" class="exec-btn"
@click="() => execute(isPriorityLocalExec ? 'localExec' : 'serverExec')" @click="() => execute(isPriorityLocalExec ? 'localExec' : 'serverExec')"
@select="execute" @select="execute"
@ -16,32 +15,21 @@
</a-doption> </a-doption>
</template> </template>
</a-dropdown-button> </a-dropdown-button>
<a-button v-else type="primary" @click="stopDebug">{{ t('common.stop') }}</a-button> <a-button v-else-if="!hasLocalExec && !props.executeLoading" type="primary" @click="() => execute('serverExec')">
{{ t('apiTestDebug.serverExec') }}
</a-button>
<a-button v-else type="primary" @click="emit('stopDebug')">
{{ t('common.stop') }}
</a-button>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { cloneDeep } from 'lodash-es';
import { RequestParam } from '@/views/api-test/components/requestComposition/index.vue'; import { getLocalConfig } from '@/api/modules/user/index';
import { localExecuteApiDebug } from '@/api/modules/api-test/common';
import { debugCase, runCase } from '@/api/modules/api-test/management';
import { getSocket } from '@/api/modules/project-management/commonScript';
import useAppStore from '@/store/modules/app';
import { getGenerateId } from '@/utils';
import { LocalConfig } from '@/models/user';
import { defaultResponse } from '@/views/api-test/components/config';
const props = defineProps<{ const props = defineProps<{
environmentId?: string;
request?: (...args) => Record<string, any>;
isCaseDetail?: boolean;
executeCase?: boolean;
executeLoading?: boolean; executeLoading?: boolean;
isEmit?: boolean;
}>(); }>();
const emit = defineEmits<{ const emit = defineEmits<{
@ -50,117 +38,35 @@
}>(); }>();
const { t } = useI18n(); const { t } = useI18n();
const appStore = useAppStore();
const caseDetail = defineModel<RequestParam>('detail', { const hasLocalExec = ref(false); // api
required: false, const isPriorityLocalExec = ref(false); //
}); const localExecuteUrl = ref('');
const apiLocalExec = inject<Ref<LocalConfig>>('apiLocalExec'); async function initLocalConfig() {
const isPriorityLocalExec = ref(apiLocalExec?.value?.enable || false); // if (hasLocalExec.value) {
const localExecuteUrl = ref(apiLocalExec?.value?.userUrl || '');
const reportId = ref('');
const websocket = ref<WebSocket>();
const temporaryResponseMap = {}; // websockettab
/**
* 开启websocket监听接收执行结果
*/
function debugSocket(executeType?: 'localExec' | 'serverExec') {
websocket.value = getSocket(
reportId.value,
executeType === 'localExec' ? '/ws/debug' : '',
executeType === 'localExec' ? localExecuteUrl.value : ''
);
websocket.value.addEventListener('message', (event) => {
if (!caseDetail.value || props.isEmit) return;
const data = JSON.parse(event.data);
if (data.msgType === 'EXEC_RESULT') {
if (caseDetail.value.reportId === data.reportId) {
// tabtab
caseDetail.value.response = data.taskResult; //
caseDetail.value.executeLoading = false;
} else {
// tab
temporaryResponseMap[data.reportId] = data.taskResult;
}
} else if (data.msgType === 'EXEC_END') {
// websocket
websocket.value?.close();
caseDetail.value.executeLoading = false;
}
});
}
async function execute(executeType?: 'localExec' | 'serverExec') {
if (!caseDetail.value || props.isEmit) {
emit('execute', executeType, localExecuteUrl.value);
return; return;
} }
try { try {
caseDetail.value.executeLoading = true; const res = await getLocalConfig();
caseDetail.value.response = cloneDeep(defaultResponse); const apiLocalExec = res.find((e) => e.type === 'API');
const makeRequestParams = props.request && props.request(executeType); // reportIdreportId if (apiLocalExec) {
reportId.value = getGenerateId(); hasLocalExec.value = true;
caseDetail.value.reportId = reportId.value; // ID isPriorityLocalExec.value = apiLocalExec.enable || false;
let res; localExecuteUrl.value = apiLocalExec.userUrl || '';
const params = {
environmentId: props.environmentId as string,
frontendDebug: executeType === 'localExec',
reportId: reportId.value,
apiDefinitionId: caseDetail.value.apiDefinitionId,
};
debugSocket(executeType); // websocket
if (!(caseDetail.value.id as string).startsWith('c') && executeType === 'serverExec') {
//
res = await runCase({
request: props.isCaseDetail ? caseDetail.value.request : makeRequestParams?.request,
id: caseDetail.value.id as string,
projectId: caseDetail.value.projectId,
linkFileIds: caseDetail.value.linkFileIds,
uploadFileIds: caseDetail.value.uploadFileIds,
...params,
});
} else {
res = await debugCase({
request: props.isCaseDetail ? caseDetail.value.request : makeRequestParams?.request,
linkFileIds: makeRequestParams?.linkFileIds,
uploadFileIds: makeRequestParams?.uploadFileIds,
id: `case-${Date.now()}`,
projectId: appStore.currentProjectId,
...params,
});
}
if (executeType === 'localExec') {
await localExecuteApiDebug(localExecuteUrl.value, res);
} }
} catch (error) { } catch (error) {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.log(error); console.log(error);
caseDetail.value.executeLoading = false;
} }
} }
onBeforeMount(() => {
initLocalConfig();
});
function stopDebug() { async function execute(executeType?: 'localExec' | 'serverExec') {
if (!caseDetail.value || props.isEmit) { emit('execute', executeType, localExecuteUrl.value);
emit('stopDebug');
return;
} }
websocket.value?.close();
caseDetail.value.executeLoading = false;
}
watch(
() => props.executeCase,
(val) => {
if (val === true) {
setTimeout(() => {
execute(isPriorityLocalExec.value ? 'localExec' : 'serverExec');
}, 300);
}
},
{ immediate: true }
);
defineExpose({ defineExpose({
isPriorityLocalExec, isPriorityLocalExec,

View File

@ -705,7 +705,7 @@
.length .length
); );
const bodyTabBadgeApi = computed(() => const bodyTabBadgeApi = computed(() =>
props.apiDetail?.request.body?.bodyType !== RequestBodyFormat.NONE ? '1' : '' props.apiDetail?.request?.body?.bodyType !== RequestBodyFormat.NONE ? '1' : ''
); );
// tab // tab
const contentTabList = computed(() => { const contentTabList = computed(() => {
@ -1575,6 +1575,7 @@
} }
onBeforeMount(() => { onBeforeMount(() => {
if (props.isCase) return;
initLocalConfig(); initLocalConfig();
}); });

View File

@ -11,7 +11,13 @@
/> />
</div> </div>
<div v-if="activeApiTab.id !== 'all'" class="flex-1 overflow-hidden"> <div v-if="activeApiTab.id !== 'all'" class="flex-1 overflow-hidden">
<a-tabs v-model:active-key="activeApiTab.definitionActiveKey" animation lazy-load class="ms-api-tab-nav"> <a-tabs
v-model:active-key="activeApiTab.definitionActiveKey"
animation
lazy-load
class="ms-api-tab-nav"
@change="changeDefinitionActiveKey"
>
<a-tab-pane <a-tab-pane
v-if="!activeApiTab.isNew" v-if="!activeApiTab.isNew"
key="preview" key="preview"
@ -52,6 +58,7 @@
</a-tab-pane> </a-tab-pane>
<a-tab-pane v-if="!activeApiTab.isNew" key="case" :title="t('apiTestManagement.case')" class="ms-api-tab-pane"> <a-tab-pane v-if="!activeApiTab.isNew" key="case" :title="t('apiTestManagement.case')" class="ms-api-tab-pane">
<caseTable <caseTable
ref="caseTableRef"
:is-api="true" :is-api="true"
:active-module="props.activeModule" :active-module="props.activeModule"
:protocol="activeApiTab.protocol" :protocol="activeApiTab.protocol"
@ -229,6 +236,7 @@
} }
const apiTableRef = ref<InstanceType<typeof apiTable>>(); const apiTableRef = ref<InstanceType<typeof apiTable>>();
const caseTableRef = ref<InstanceType<typeof caseTable>>();
watch( watch(
() => activeApiTab.value.id, () => activeApiTab.value.id,
@ -299,6 +307,13 @@
apiTableRef.value?.loadApiList(); apiTableRef.value?.loadApiList();
} }
function changeDefinitionActiveKey(val: string | number) {
// case
if (val === 'case') {
caseTableRef.value?.loadCaseList();
}
}
defineExpose({ defineExpose({
openApiTab, openApiTab,
addApiTab, addApiTab,

View File

@ -1,15 +1,15 @@
<template> <template>
<div class="h-full w-full overflow-hidden"> <div class="h-full w-full overflow-hidden">
<a-tabs v-model:active-key="activeKey" class="h-full px-[16px]" animation lazy-load> <a-tabs v-model:active-key="activeKey" class="h-full px-[16px]" animation lazy-load @change="changeActiveKey">
<template #extra> <template #extra>
<div class="flex gap-[12px]"> <div class="flex gap-[12px]">
<environmentSelect v-if="props.isDrawer" v-model:current-env="environmentIdByDrawer" /> <environmentSelect v-if="props.isDrawer" v-model:current-env="environmentIdByDrawer" />
<execute <executeButton
ref="executeRef" ref="executeRef"
v-model:detail="caseDetail" v-permission="['PROJECT_API_DEFINITION_CASE:READ+EXECUTE']"
:execute-case="props.executeCase" :execute-loading="caseDetail.executeLoading"
:environment-id="environmentId as string" @stop-debug="stopDebug"
is-case-detail @execute="handleExecute"
/> />
<a-dropdown position="br" :hide-on-select="false" @select="handleSelect"> <a-dropdown position="br" :hide-on-select="false" @select="handleSelect">
<a-button v-if="!props.isDrawer" type="outline">{{ t('common.operation') }}</a-button> <a-button v-if="!props.isDrawer" type="outline">{{ t('common.operation') }}</a-button>
@ -42,7 +42,7 @@
</a-dropdown> </a-dropdown>
</div> </div>
</template> </template>
<a-tab-pane key="detail" :title="t('apiTestManagement.detail')" class="px-[18px] py-[16px]"> <a-tab-pane key="detail" :title="t('case.detail')" class="px-[18px] py-[16px]">
<MsDetailCard :title="`【${caseDetail.num}】${caseDetail.name}`" :description="description" class="mb-[8px]"> <MsDetailCard :title="`【${caseDetail.num}】${caseDetail.name}`" :description="description" class="mb-[8px]">
<template #type="{ value }"> <template #type="{ value }">
<apiMethodName :method="value as RequestMethods" tag-size="small" is-tag /> <apiMethodName :method="value as RequestMethods" tag-size="small" is-tag />
@ -56,14 +56,19 @@
:protocols="protocols as ProtocolItem[]" :protocols="protocols as ProtocolItem[]"
:is-priority-local-exec="isPriorityLocalExec" :is-priority-local-exec="isPriorityLocalExec"
is-case is-case
@execute="(val: 'localExec' | 'serverExec')=>executeRef?.execute(val)" @execute="handleExecute"
/> />
</a-tab-pane> </a-tab-pane>
<a-tab-pane key="reference" :title="t('apiTestManagement.reference')" class="px-[18px] py-[16px]"> <a-tab-pane key="reference" :title="t('apiTestManagement.reference')" class="px-[18px] py-[16px]">
<tab-case-dependency :source-id="caseDetail.id" /> <tab-case-dependency :source-id="caseDetail.id" />
</a-tab-pane> </a-tab-pane>
<a-tab-pane key="executeHistory" :title="t('apiTestManagement.executeHistory')" class="px-[18px] py-[16px]"> <a-tab-pane key="executeHistory" :title="t('apiTestManagement.executeHistory')" class="px-[18px] py-[16px]">
<tab-case-execute-history :source-id="caseDetail.id" module-type="API_REPORT" :protocol="caseDetail.protocol" /> <tab-case-execute-history
ref="executeHistoryRef"
:source-id="caseDetail.id"
module-type="API_REPORT"
:protocol="caseDetail.protocol"
/>
</a-tab-pane> </a-tab-pane>
<!-- <a-tab-pane key="dependencies" :title="t('apiTestManagement.dependencies')" class="px-[18px] py-[16px]"> <!-- <a-tab-pane key="dependencies" :title="t('apiTestManagement.dependencies')" class="px-[18px] py-[16px]">
</a-tab-pane> --> </a-tab-pane> -->
@ -88,22 +93,26 @@
import createAndEditCaseDrawer from './createAndEditCaseDrawer.vue'; import createAndEditCaseDrawer from './createAndEditCaseDrawer.vue';
import apiMethodName from '@/views/api-test/components/apiMethodName.vue'; import apiMethodName from '@/views/api-test/components/apiMethodName.vue';
import environmentSelect from '@/views/api-test/components/environmentSelect.vue'; import environmentSelect from '@/views/api-test/components/environmentSelect.vue';
import execute from '@/views/api-test/components/executeButton.vue'; import executeButton from '@/views/api-test/components/executeButton.vue';
import { RequestParam } from '@/views/api-test/components/requestComposition/index.vue'; import { RequestParam } from '@/views/api-test/components/requestComposition/index.vue';
import TabCaseChangeHistory from '@/views/api-test/management/components/management/case/tabContent/tabCaseChangeHistory.vue'; import TabCaseChangeHistory from '@/views/api-test/management/components/management/case/tabContent/tabCaseChangeHistory.vue';
import TabCaseDependency from '@/views/api-test/management/components/management/case/tabContent/tabCaseDependency.vue'; import TabCaseDependency from '@/views/api-test/management/components/management/case/tabContent/tabCaseDependency.vue';
import TabCaseExecuteHistory from '@/views/api-test/management/components/management/case/tabContent/tabCaseExecuteHistory.vue'; import TabCaseExecuteHistory from '@/views/api-test/management/components/management/case/tabContent/tabCaseExecuteHistory.vue';
import { deleteCase, toggleFollowCase } from '@/api/modules/api-test/management'; import { localExecuteApiDebug } from '@/api/modules/api-test/common';
import { debugCase, deleteCase, runCase, toggleFollowCase } from '@/api/modules/api-test/management';
import { getSocket } from '@/api/modules/project-management/commonScript';
import useModal from '@/hooks/useModal'; import useModal from '@/hooks/useModal';
import { getGenerateId } from '@/utils';
import { ProtocolItem } from '@/models/apiTest/common'; import { ProtocolItem } from '@/models/apiTest/common';
import { EnvConfig } from '@/models/projectManagement/environmental'; import { EnvConfig } from '@/models/projectManagement/environmental';
import { RequestMethods } from '@/enums/apiEnum'; import { RequestMethods } from '@/enums/apiEnum';
import { defaultResponse } from '@/views/api-test/components/config';
const props = defineProps<{ const props = defineProps<{
isDrawer?: boolean; // isDrawer?: boolean; //
executeCase?: boolean;
detail: RequestParam; detail: RequestParam;
}>(); }>();
const emit = defineEmits<{ const emit = defineEmits<{
@ -115,12 +124,9 @@
const { t } = useI18n(); const { t } = useI18n();
const { openModal } = useModal(); const { openModal } = useModal();
const executeCase = defineModel<boolean>('executeCase', { default: false });
const caseDetail = ref<RequestParam>(cloneDeep(props.detail)); // props.detailprops.detail const caseDetail = ref<RequestParam>(cloneDeep(props.detail)); // props.detailprops.detail
const environmentIdByDrawer = ref(props.detail.environmentId); const environmentIdByDrawer = ref(props.detail.environmentId);
watchEffect(() => {
caseDetail.value = cloneDeep(props.detail); // props.detailprops.detail
environmentIdByDrawer.value = props.detail.environmentId;
});
const activeKey = ref('detail'); const activeKey = ref('detail');
@ -226,9 +232,105 @@
props.isDrawer ? environmentIdByDrawer.value : currentEnvConfigByInject?.value?.id props.isDrawer ? environmentIdByDrawer.value : currentEnvConfigByInject?.value?.id
); );
const executeRef = ref<InstanceType<typeof execute>>(); const executeHistoryRef = ref<InstanceType<typeof TabCaseExecuteHistory>>();
function changeActiveKey(val: string | number) {
if (val === 'executeHistory') {
executeHistoryRef.value?.loadExecuteList();
}
}
const executeRef = ref<InstanceType<typeof executeButton>>();
const isPriorityLocalExec = computed(() => executeRef.value?.isPriorityLocalExec ?? false); const isPriorityLocalExec = computed(() => executeRef.value?.isPriorityLocalExec ?? false);
const reportId = ref('');
const websocket = ref<WebSocket>();
const temporaryResponseMap = {}; // websockettab
// websocket
function debugSocket(executeType?: 'localExec' | 'serverExec') {
websocket.value = getSocket(
reportId.value,
executeType === 'localExec' ? '/ws/debug' : '',
executeType === 'localExec' ? executeRef.value?.localExecuteUrl : ''
);
websocket.value.addEventListener('message', (event) => {
const data = JSON.parse(event.data);
if (data.msgType === 'EXEC_RESULT') {
if (caseDetail.value.reportId === data.reportId) {
// tabtab
caseDetail.value.response = data.taskResult; //
caseDetail.value.executeLoading = false;
executeCase.value = false;
} else {
// tab
temporaryResponseMap[data.reportId] = data.taskResult;
}
} else if (data.msgType === 'EXEC_END') {
// websocket
websocket.value?.close();
caseDetail.value.executeLoading = false;
executeCase.value = false;
}
});
}
async function handleExecute(executeType?: 'localExec' | 'serverExec') {
try {
caseDetail.value.executeLoading = true;
caseDetail.value.response = cloneDeep(defaultResponse);
reportId.value = getGenerateId();
caseDetail.value.reportId = reportId.value; // ID
let res;
const params = {
id: caseDetail.value.id as string,
environmentId: environmentId.value,
frontendDebug: executeType === 'localExec',
reportId: reportId.value,
apiDefinitionId: caseDetail.value.apiDefinitionId,
request: caseDetail.value.request,
projectId: caseDetail.value.projectId,
linkFileIds: caseDetail.value.linkFileIds,
uploadFileIds: caseDetail.value.uploadFileIds,
};
debugSocket(executeType); // websocket
if (executeType === 'serverExec') {
//
res = await runCase(params);
} else {
res = await debugCase(params);
}
if (executeType === 'localExec') {
await localExecuteApiDebug(executeRef.value?.localExecuteUrl as string, res);
}
//
executeHistoryRef.value?.loadExecuteList();
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
caseDetail.value.executeLoading = false;
executeCase.value = false;
}
}
function stopDebug() {
websocket.value?.close();
caseDetail.value.executeLoading = false;
executeCase.value = false;
}
watch(
() => props.detail,
() => {
caseDetail.value = cloneDeep(props.detail); // props.detailprops.detail
environmentIdByDrawer.value = props.detail.environmentId;
},
{ immediate: true }
);
onMounted(async () => {
if (executeCase.value && !caseDetail.value.executeLoading) {
//
handleExecute(isPriorityLocalExec.value ? 'localExec' : 'serverExec');
}
});
defineExpose({ defineExpose({
editCase, editCase,
share, share,

View File

@ -56,8 +56,8 @@
</template> </template>
<caseDetail <caseDetail
ref="caseDerailRef" ref="caseDerailRef"
v-model:execute-case="executeCase"
is-drawer is-drawer
:execute-case="props.executeCase"
:detail="props.detail" :detail="props.detail"
:api-detail="props.apiDetail" :api-detail="props.apiDetail"
v-bind="$attrs" v-bind="$attrs"
@ -78,7 +78,6 @@
const props = defineProps<{ const props = defineProps<{
detail: RequestParam; detail: RequestParam;
apiDetail?: RequestParam; apiDetail?: RequestParam;
executeCase?: boolean;
}>(); }>();
const { t } = useI18n(); const { t } = useI18n();
@ -86,6 +85,7 @@
const innerVisible = defineModel<boolean>('visible', { const innerVisible = defineModel<boolean>('visible', {
required: true, required: true,
}); });
const executeCase = defineModel<boolean>('executeCase', { default: false });
const caseDerailRef = ref<InstanceType<typeof caseDetail>>(); const caseDerailRef = ref<InstanceType<typeof caseDetail>>();
function handleSelect(val: string | number | Record<string, any> | undefined) { function handleSelect(val: string | number | Record<string, any> | undefined) {

View File

@ -0,0 +1,139 @@
<template>
<MsDrawer
v-model:visible="innerVisible"
:title="reportStepDetail.name"
:width="1200"
:footer="false"
unmount-on-close
no-content-padding
show-full-screen
>
<template #tbutton>
<MsButton type="icon" status="secondary" class="mr-4 !rounded-[var(--border-radius-small)]" @click="shareHandler">
<MsIcon type="icon-icon_share1" class="mr-2 font-[16px]" />
{{ t('common.share') }}
</MsButton>
</template>
<CaseReportCom :detail-info="reportStepDetail" />
</MsDrawer>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { Message } from '@arco-design/web-vue';
import MsButton from '@/components/pure/ms-button/index.vue';
import MsDrawer from '@/components/pure/ms-drawer/index.vue';
import CaseReportCom from '@/views/api-test/report/component/caseReportCom.vue';
import { getShareInfo, reportCaseDetail } from '@/api/modules/api-test/report';
import { useI18n } from '@/hooks/useI18n';
import { useAppStore } from '@/store';
import type { ReportDetail } from '@/models/apiTest/report';
import { RouteEnum } from '@/enums/routeEnum';
const props = defineProps<{
reportId: string;
}>();
const appStore = useAppStore();
const { t } = useI18n();
const innerVisible = defineModel<boolean>('visible', {
required: true,
});
const reportStepDetail = ref<ReportDetail>({
id: '',
name: '', //
testPlanId: '',
createUser: '',
deleteTime: 0,
deleteUser: '',
deleted: false,
updateUser: '',
updateTime: 0,
startTime: 0, // /
endTime: 0, // /
requestDuration: 0, //
status: '', // /SUCCESS/ERROR
triggerMode: '', //
runMode: '', //
poolId: '', //
poolName: '', //
versionId: '',
integrated: false, //
projectId: '',
environmentId: '', // id
environmentName: '', //
errorCount: 0, //
fakeErrorCount: 0, //
pendingCount: 0, //
successCount: 0, //
assertionCount: 0, //
assertionSuccessCount: 0, //
requestErrorRate: '', //
requestPendingRate: '', //
requestFakeErrorRate: '', //
requestPassRate: '', //
assertionPassRate: '', //
scriptIdentifier: '', //
children: [], //
stepTotal: 0, //
console: '',
});
async function getReportCaseDetail() {
try {
reportStepDetail.value = await reportCaseDetail(props.reportId);
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
}
}
watch(
() => innerVisible.value,
async (val) => {
if (val) {
await getReportCaseDetail();
}
}
);
// share
const shareLink = ref<string>('');
async function shareHandler() {
try {
const res = await getShareInfo({
reportId: reportStepDetail.value.id,
projectId: appStore.currentProjectId,
});
const shareId = res.shareUrl;
const { origin } = window.location;
shareLink.value = `${origin}/#/${RouteEnum.SHARE}/${RouteEnum.SHARE_REPORT_CASE}${shareId}`;
if (navigator.clipboard) {
navigator.clipboard.writeText(shareLink.value).then(
() => {
Message.info(t('bugManagement.detail.shareTip'));
},
(e) => {
Message.error(e);
}
);
} else {
const input = document.createElement('input');
input.value = shareLink.value;
document.body.appendChild(input);
input.select();
document.execCommand('copy');
document.body.removeChild(input);
Message.info(t('bugManagement.detail.shareTip'));
}
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
}
}
</script>

View File

@ -148,7 +148,12 @@
</a-trigger> </a-trigger>
</template> </template>
<template #lastReportStatus="{ record }"> <template #lastReportStatus="{ record }">
<ExecutionStatus :module-type="ReportEnum.API_REPORT" :status="record.lastReportStatus" /> <ExecutionStatus
:module-type="ReportEnum.API_REPORT"
:status="record.lastReportStatus"
:class="[!record.lastReportId ? '' : 'cursor-pointer']"
@click="showResult(record)"
/>
</template> </template>
<template #passRateColumn> <template #passRateColumn>
<div class="flex items-center text-[var(--color-text-3)]"> <div class="flex items-center text-[var(--color-text-3)]">
@ -285,9 +290,9 @@
/> />
<caseDetailDrawer <caseDetailDrawer
v-model:visible="caseDetailDrawerVisible" v-model:visible="caseDetailDrawerVisible"
v-model:execute-case="caseExecute"
:detail="caseDetail as RequestParam" :detail="caseDetail as RequestParam"
:api-detail="apiDetail as RequestParam" :api-detail="apiDetail as RequestParam"
:execute-case="caseExecute"
@update-follow="caseDetail.follow = !caseDetail.follow" @update-follow="caseDetail.follow = !caseDetail.follow"
@load-case="(id: string) => loadCase(id)" @load-case="(id: string) => loadCase(id)"
@delete-case="deleteCaseByDetail" @delete-case="deleteCaseByDetail"
@ -300,6 +305,8 @@
:batch-run-func="batchExecuteCase" :batch-run-func="batchExecuteCase"
@finished="loadCaseListAndResetSelector" @finished="loadCaseListAndResetSelector"
/> />
<!-- 执行结果抽屉 -->
<caseReportDrawer v-model:visible="showExecuteResult" :report-id="activeReportId" />
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@ -316,6 +323,7 @@
import MsTagsInput from '@/components/pure/ms-tags-input/index.vue'; import MsTagsInput from '@/components/pure/ms-tags-input/index.vue';
import caseLevel from '@/components/business/ms-case-associate/caseLevel.vue'; import caseLevel from '@/components/business/ms-case-associate/caseLevel.vue';
import caseDetailDrawer from './caseDetailDrawer.vue'; import caseDetailDrawer from './caseDetailDrawer.vue';
import caseReportDrawer from './caseReportDrawer.vue';
import createAndEditCaseDrawer from './createAndEditCaseDrawer.vue'; import createAndEditCaseDrawer from './createAndEditCaseDrawer.vue';
import apiStatus from '@/views/api-test/components/apiStatus.vue'; import apiStatus from '@/views/api-test/components/apiStatus.vue';
import BatchRunModal from '@/views/api-test/components/batchRunModal.vue'; import BatchRunModal from '@/views/api-test/components/batchRunModal.vue';
@ -367,7 +375,6 @@
const { openModal } = useModal(); const { openModal } = useModal();
const keyword = ref(''); const keyword = ref('');
const refreshModuleTree: (() => Promise<any>) | undefined = inject('refreshModuleTree');
const hasOperationPermission = computed(() => const hasOperationPermission = computed(() =>
hasAnyPermission([ hasAnyPermission([
@ -712,9 +719,6 @@
Message.success(t('common.deleteSuccess')); Message.success(t('common.deleteSuccess'));
resetSelector(); resetSelector();
loadCaseListAndResetSelector(); loadCaseListAndResetSelector();
if (typeof refreshModuleTree === 'function') {
refreshModuleTree();
}
} catch (error) { } catch (error) {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.log(error); console.log(error);
@ -932,6 +936,14 @@
loadCaseList(); loadCaseList();
} }
const activeReportId = ref('');
const showExecuteResult = ref(false);
async function showResult(record: ApiCaseDetail) {
if (!record.lastReportId) return;
activeReportId.value = record.lastReportId;
showExecuteResult.value = true;
}
defineExpose({ defineExpose({
loadCaseList, loadCaseList,
}); });

View File

@ -34,12 +34,13 @@
:max-length="255" :max-length="255"
show-word-limit show-word-limit
/> />
<environmentSelect v-model:current-env="environmentId" /> <environmentSelect ref="environmentSelectRef" v-model:current-env="environmentId" />
<execute <executeButton
ref="executeRef" ref="executeRef"
v-model:detail="detailForm" v-permission="['PROJECT_API_DEFINITION_CASE:READ+EXECUTE']"
:environment-id="currentEnvConfig?.id as string" :execute-loading="detailForm.executeLoading"
:request="requestCompositionRef?.makeRequestParams" @stop-debug="stopDebug"
@execute="handleExecute"
/> />
</div> </div>
</a-form-item> </a-form-item>
@ -84,7 +85,7 @@
:file-save-as-api="transferFileCase" :file-save-as-api="transferFileCase"
:current-env-config="currentEnvConfig" :current-env-config="currentEnvConfig"
is-definition is-definition
@execute="(val: 'localExec' | 'serverExec')=>executeRef?.execute(val)" @execute="handleExecute"
/> />
</div> </div>
</div> </div>
@ -103,25 +104,30 @@
import apiMethodName from '@/views/api-test/components/apiMethodName.vue'; import apiMethodName from '@/views/api-test/components/apiMethodName.vue';
import apiStatus from '@/views/api-test/components/apiStatus.vue'; import apiStatus from '@/views/api-test/components/apiStatus.vue';
import environmentSelect from '@/views/api-test/components/environmentSelect.vue'; import environmentSelect from '@/views/api-test/components/environmentSelect.vue';
import execute from '@/views/api-test/components/executeButton.vue'; import executeButton from '@/views/api-test/components/executeButton.vue';
import requestComposition, { RequestParam } from '@/views/api-test/components/requestComposition/index.vue'; import requestComposition, { RequestParam } from '@/views/api-test/components/requestComposition/index.vue';
import { localExecuteApiDebug } from '@/api/modules/api-test/common';
import { import {
addCase, addCase,
debugCase,
getDefinitionDetail, getDefinitionDetail,
getTransferOptionsCase, getTransferOptionsCase,
runCase,
transferFileCase, transferFileCase,
updateCase, updateCase,
uploadTempFileCase, uploadTempFileCase,
} from '@/api/modules/api-test/management'; } from '@/api/modules/api-test/management';
import { getSocket } from '@/api/modules/project-management/commonScript';
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
import useAppStore from '@/store/modules/app'; import useAppStore from '@/store/modules/app';
import { getGenerateId } from '@/utils';
import { AddApiCaseParams, ApiCaseDetail, ApiDefinitionDetail } from '@/models/apiTest/management'; import { AddApiCaseParams, ApiCaseDetail, ApiDefinitionDetail } from '@/models/apiTest/management';
import { EnvConfig } from '@/models/projectManagement/environmental'; import { EnvConfig } from '@/models/projectManagement/environmental';
import { RequestDefinitionStatus, RequestMethods } from '@/enums/apiEnum'; import { RequestDefinitionStatus, RequestMethods } from '@/enums/apiEnum';
import { casePriorityOptions } from '@/views/api-test/components/config'; import { casePriorityOptions, defaultResponse } from '@/views/api-test/components/config';
const props = defineProps<{ const props = defineProps<{
apiDetail?: RequestParam | ApiDefinitionDetail; apiDetail?: RequestParam | ApiDefinitionDetail;
@ -175,7 +181,6 @@
}); });
const detailForm = ref(cloneDeep(defaultDetail.value)); const detailForm = ref(cloneDeep(defaultDetail.value));
const isEdit = ref(false); const isEdit = ref(false);
const executeRef = ref<InstanceType<typeof execute>>();
async function open(apiId: string, record?: ApiCaseDetail | RequestParam, isCopy?: boolean) { async function open(apiId: string, record?: ApiCaseDetail | RequestParam, isCopy?: boolean) {
apiDefinitionId.value = apiId; apiDefinitionId.value = apiId;
@ -276,6 +281,84 @@
} }
}); });
} }
const executeRef = ref<InstanceType<typeof executeButton>>();
const reportId = ref('');
const websocket = ref<WebSocket>();
const temporaryResponseMap = {}; // websockettab
// websocket
function debugSocket(executeType?: 'localExec' | 'serverExec') {
websocket.value = getSocket(
reportId.value,
executeType === 'localExec' ? '/ws/debug' : '',
executeType === 'localExec' ? executeRef.value?.localExecuteUrl : ''
);
websocket.value.addEventListener('message', (event) => {
const data = JSON.parse(event.data);
if (data.msgType === 'EXEC_RESULT') {
if (detailForm.value.reportId === data.reportId) {
// tabtab
detailForm.value.response = data.taskResult; //
detailForm.value.executeLoading = false;
} else {
// tab
temporaryResponseMap[data.reportId] = data.taskResult;
}
} else if (data.msgType === 'EXEC_END') {
// websocket
websocket.value?.close();
detailForm.value.executeLoading = false;
}
});
}
async function handleExecute(executeType?: 'localExec' | 'serverExec') {
try {
detailForm.value.executeLoading = true;
detailForm.value.response = cloneDeep(defaultResponse);
const makeRequestParams = requestCompositionRef.value?.makeRequestParams(executeType); // reportIdreportId
reportId.value = getGenerateId();
detailForm.value.reportId = reportId.value; // ID
let res;
const params = {
environmentId: environmentId.value as string,
frontendDebug: executeType === 'localExec',
reportId: reportId.value,
apiDefinitionId: detailForm.value.apiDefinitionId,
request: makeRequestParams?.request,
linkFileIds: makeRequestParams?.linkFileIds,
uploadFileIds: makeRequestParams?.uploadFileIds,
};
debugSocket(executeType); // websocket
if (!(detailForm.value.id as string).startsWith('c') && executeType === 'serverExec') {
//
res = await runCase({
id: detailForm.value.id as string,
projectId: detailForm.value.projectId,
...params,
});
} else {
res = await debugCase({
id: `case-${Date.now()}`,
projectId: appStore.currentProjectId,
...params,
});
}
if (executeType === 'localExec') {
await localExecuteApiDebug(executeRef.value?.localExecuteUrl as string, res);
}
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
detailForm.value.executeLoading = false;
}
}
function stopDebug() {
websocket.value?.close();
detailForm.value.executeLoading = false;
}
const environmentSelectRef = ref<InstanceType<typeof environmentSelect>>();
const currentEnvConfigByDrawer = computed<EnvConfig | undefined>(() => environmentSelectRef.value?.currentEnvConfig);
provide('currentEnvConfig', readonly(currentEnvConfigByDrawer));
defineExpose({ defineExpose({
open, open,

View File

@ -13,8 +13,8 @@
</div> </div>
<div v-if="activeApiTab.id !== 'all'" class="flex-1 overflow-hidden"> <div v-if="activeApiTab.id !== 'all'" class="flex-1 overflow-hidden">
<caseDetail <caseDetail
v-model:execute-case="caseExecute"
:detail="activeApiTab" :detail="activeApiTab"
:execute-case="caseExecute"
:module-tree="props.moduleTree" :module-tree="props.moduleTree"
@delete-case="deleteCase" @delete-case="deleteCase"
@update-follow="activeApiTab.follow = !activeApiTab.follow" @update-follow="activeApiTab.follow = !activeApiTab.follow"

View File

@ -82,59 +82,42 @@
<template #status="{ record }"> <template #status="{ record }">
<ExecutionStatus :status="record.status" :module-type="ReportEnum.API_REPORT" /> <ExecutionStatus :status="record.status" :module-type="ReportEnum.API_REPORT" />
</template> </template>
<template #operation="{ record }"> <template #operation="{ record, rowIndex }">
<a-tooltip :disabled="!record.deleted" :content="t('case.detail.report.delete')" position="top"> <a-tooltip :disabled="!record.deleted" :content="t('case.detail.report.delete')" position="top">
<MsButton :disabled="record.deleted" class="!mr-0" @click="showResult(record)" <MsButton :disabled="record.deleted" class="!mr-0" @click="showResult(record, rowIndex)"
>{{ t('apiScenario.executeHistory.execution.operation') }} >{{ t('apiScenario.executeHistory.execution.operation') }}
</MsButton> </MsButton>
</a-tooltip> </a-tooltip>
</template> </template>
</ms-base-table> </ms-base-table>
<a-modal
v-model:visible="showResponse"
class="ms-modal-response ms-modal-response-body"
title-align="start"
:footer="false"
>
<template #title> {{ t('caseManagement.featureCase.tableColumnExecutionResult') }} </template>
<response
v-show="showResponse"
:hide-layout-switch="true"
:is-expanded="true"
:is-http-protocol="props.protocol === 'HTTP'"
:is-priority-local-exec="false"
:active-tab="ResponseComposition.BODY"
:request-result="responseContent?.requestResults[0]"
:console="responseContent?.console"
:is-definition="true"
:is-response-model="true"
></response>
</a-modal>
</div> </div>
<CaseReportDrawer
v-model:visible="showResponse"
:report-id="activeReportId"
:active-report-index="activeReportIndex"
:table-data="propsRes.data"
:page-change="propsEvent.pageChange"
:pagination="propsRes.msPagination!"
/>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { cloneDeep } from 'lodash-es';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import MsButton from '@/components/pure/ms-button/index.vue'; import MsButton from '@/components/pure/ms-button/index.vue';
import MsBaseTable from '@/components/pure/ms-table/base-table.vue'; import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
import { MsTableColumn } from '@/components/pure/ms-table/type'; import { MsTableColumn } from '@/components/pure/ms-table/type';
import useTable from '@/components/pure/ms-table/useTable'; import useTable from '@/components/pure/ms-table/useTable';
import response from '@/views/api-test/components/requestComposition/response/index.vue'; import CaseReportDrawer from '@/views/api-test/report/component/caseReportDrawer.vue';
import ExecutionStatus from '@/views/api-test/report/component/reportStatus.vue'; import ExecutionStatus from '@/views/api-test/report/component/reportStatus.vue';
import { getApiCaseExecuteHistory, getCaseReportDetail, getReportById } from '@/api/modules/api-test/management'; import { getApiCaseExecuteHistory } from '@/api/modules/api-test/management';
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
import useAppStore from '@/store/modules/app'; import useAppStore from '@/store/modules/app';
import { ApiCaseReportDetail, RequestTaskResult } from '@/models/apiTest/common';
import { ApiCaseExecuteHistoryItem } from '@/models/apiTest/management'; import { ApiCaseExecuteHistoryItem } from '@/models/apiTest/management';
import { ResponseComposition } from '@/enums/apiEnum';
import { ReportEnum, ReportStatus, TriggerModeLabel } from '@/enums/reportEnum'; import { ReportEnum, ReportStatus, TriggerModeLabel } from '@/enums/reportEnum';
import { defaultResponse } from '@/views/api-test/components/config';
const triggerModeListFilters = ref<string[]>(Object.keys(TriggerModeLabel)); const triggerModeListFilters = ref<string[]>(Object.keys(TriggerModeLabel));
const triggerModeFilterVisible = ref(false); const triggerModeFilterVisible = ref(false);
const statusFilterVisible = ref(false); const statusFilterVisible = ref(false);
@ -145,8 +128,6 @@
const showResponse = ref(false); const showResponse = ref(false);
const responseContent = ref<RequestTaskResult>();
const props = defineProps<{ const props = defineProps<{
sourceId: string | number; sourceId: string | number;
moduleType: string; moduleType: string;
@ -262,40 +243,21 @@
loadExecuteList(); loadExecuteList();
} }
function loadedReportDetail(detail: ApiCaseReportDetail[]) { const activeReportIndex = ref<number>(0);
responseContent.value = cloneDeep(defaultResponse); const activeReportId = ref('');
const apiCaseReportDetailElement = detail[0]; async function showResult(record: ApiCaseExecuteHistoryItem, rowIndex: number) {
if (apiCaseReportDetailElement.id) { activeReportId.value = record.id;
responseContent.value.requestResults[0] = apiCaseReportDetailElement.content; activeReportIndex.value = rowIndex;
}
}
async function loadedReport(detail: Record<string, any>) {
if (detail.id) {
if (detail.children && detail.children.length > 0) {
try {
const caseReportDetail = await getCaseReportDetail(detail.id, detail.children[0].stepId);
loadedReportDetail(caseReportDetail);
} catch (e) {
console.error(e);
}
}
}
}
async function showResult(record: ApiCaseExecuteHistoryItem) {
try {
showResponse.value = true; showResponse.value = true;
const result = await getReportById(record.id);
await loadedReport(result);
} catch (error) {
console.error(error);
}
} }
onBeforeMount(() => { onBeforeMount(() => {
loadExecuteList(); loadExecuteList();
}); });
defineExpose({
loadExecuteList,
});
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>

View File

@ -10,10 +10,17 @@
> >
<template #label="{ tab }"> <template #label="{ tab }">
<apiMethodName <apiMethodName
v-if="tab.id !== 'all'" v-if="tab.id !== 'all' && tab.type === 'api'"
:method="tab.protocol === 'HTTP' ? tab.method : tab.protocol" :method="tab.protocol === 'HTTP' ? tab.method : tab.protocol"
class="mr-[4px]" class="mr-[4px]"
/> />
<svg-icon
v-if="tab.id !== 'all' && tab.type === 'case'"
width="16px"
height="16px"
:name="'apiCase'"
class="mr-[4px]"
/>
<a-tooltip :content="tab.name || tab.label" :mouse-enter-delay="500"> <a-tooltip :content="tab.name || tab.label" :mouse-enter-delay="500">
<div class="one-line-text max-w-[144px]"> <div class="one-line-text max-w-[144px]">
{{ tab.name || tab.label }} {{ tab.name || tab.label }}
@ -58,14 +65,12 @@
// import MockTable from '@/views/api-test/management/components/management/mock/mockTable.vue'; // import MockTable from '@/views/api-test/management/components/management/mock/mockTable.vue';
import { getProtocolList } from '@/api/modules/api-test/common'; import { getProtocolList } from '@/api/modules/api-test/common';
import { getLocalConfig } from '@/api/modules/user/index';
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
import useAppStore from '@/store/modules/app'; import useAppStore from '@/store/modules/app';
import { ProtocolItem } from '@/models/apiTest/common'; import { ProtocolItem } from '@/models/apiTest/common';
import { ModuleTreeNode } from '@/models/common'; import { ModuleTreeNode } from '@/models/common';
import { EnvConfig } from '@/models/projectManagement/environmental'; import { EnvConfig } from '@/models/projectManagement/environmental';
import { LocalConfig } from '@/models/user';
import { import {
RequestAuthType, RequestAuthType,
RequestComposition, RequestComposition,
@ -277,30 +282,17 @@
} }
} }
const apiLocalExec = ref<Record<string, any> | LocalConfig | undefined>({});
async function initLocalConfig() {
try {
const res = await getLocalConfig();
apiLocalExec.value = res.find((e) => e.type === 'API');
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
}
}
const environmentSelectRef = ref<InstanceType<typeof environmentSelect>>(); const environmentSelectRef = ref<InstanceType<typeof environmentSelect>>();
const currentEnvConfig = computed<EnvConfig | undefined>(() => environmentSelectRef.value?.currentEnvConfig); const currentEnvConfig = computed<EnvConfig | undefined>(() => environmentSelectRef.value?.currentEnvConfig);
onBeforeMount(() => { onBeforeMount(() => {
initProtocolList(); initProtocolList();
initLocalConfig();
}); });
/** 向孙组件提供属性 */ /** 向孙组件提供属性 */
provide('currentEnvConfig', readonly(currentEnvConfig)); provide('currentEnvConfig', readonly(currentEnvConfig));
provide('defaultCaseParams', readonly(defaultCaseParams)); provide('defaultCaseParams', readonly(defaultCaseParams));
provide('protocols', readonly(protocols)); provide('protocols', readonly(protocols));
provide('apiLocalExec', readonly(apiLocalExec));
defineExpose({ defineExpose({
newTab, newTab,

View File

@ -173,6 +173,7 @@ export default {
'case.execute.reportName': 'Report name', 'case.execute.reportName': 'Report name',
'case.execute.pool': 'Resource pool operation', 'case.execute.pool': 'Resource pool operation',
'case.allCase': 'All Case', 'case.allCase': 'All Case',
'case.detail': 'Case Detail',
'case.caseName': 'Case Name', 'case.caseName': 'Case Name',
'case.caseLevel': 'Case Level', 'case.caseLevel': 'Case Level',
'case.caseEnvironment': 'Case Environment', 'case.caseEnvironment': 'Case Environment',

View File

@ -167,6 +167,7 @@ export default {
'case.execute.reportName': '报告名称', 'case.execute.reportName': '报告名称',
'case.execute.pool': '资源池运行', 'case.execute.pool': '资源池运行',
'case.allCase': '全部CASE', 'case.allCase': '全部CASE',
'case.detail': '用例详情',
'case.caseName': '用例名称', 'case.caseName': '用例名称',
'case.caseNameRequired': '用例名称不能为空', 'case.caseNameRequired': '用例名称不能为空',
'case.caseNamePlaceholder': '请输入用例名称', 'case.caseNamePlaceholder': '请输入用例名称',

View File

@ -54,8 +54,7 @@
<executeButton <executeButton
ref="executeRef" ref="executeRef"
class="ml-[16px]" class="ml-[16px]"
is-emit :execute-loading="requestVModel.executeLoading"
:detail="requestVModel"
@execute="handleExecute" @execute="handleExecute"
@stop-debug="stopDebug" @stop-debug="stopDebug"
/> />
@ -99,12 +98,10 @@
uploadTempFileCase, uploadTempFileCase,
} from '@/api/modules/api-test/management'; } from '@/api/modules/api-test/management';
import { getSocket } from '@/api/modules/project-management/commonScript'; import { getSocket } from '@/api/modules/project-management/commonScript';
import { getLocalConfig } from '@/api/modules/user/index';
import { characterLimit, getGenerateId } from '@/utils'; import { characterLimit, getGenerateId } from '@/utils';
import { RequestResult } from '@/models/apiTest/common'; import { RequestResult } from '@/models/apiTest/common';
import { ScenarioStepItem } from '@/models/apiTest/scenario'; import { ScenarioStepItem } from '@/models/apiTest/scenario';
import { LocalConfig } from '@/models/user';
import { import {
RequestAuthType, RequestAuthType,
RequestComposition, RequestComposition,
@ -221,18 +218,6 @@
const requestAndResponseRef = ref<InstanceType<typeof requestAndResponse>>(); const requestAndResponseRef = ref<InstanceType<typeof requestAndResponse>>();
const isPriorityLocalExec = computed(() => executeRef.value?.isPriorityLocalExec ?? false); const isPriorityLocalExec = computed(() => executeRef.value?.isPriorityLocalExec ?? false);
const apiLocalExec = ref<Record<string, any> | LocalConfig | undefined>({});
async function initLocalConfig() {
try {
const res = await getLocalConfig();
apiLocalExec.value = res.find((e) => e.type === 'API');
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
}
}
provide('apiLocalExec', readonly(apiLocalExec));
const isShowEditStepNameInput = ref(false); const isShowEditStepNameInput = ref(false);
const stepNameInputRef = ref<InputInstance>(); const stepNameInputRef = ref<InputInstance>();
function showEditScriptNameInput() { function showEditScriptNameInput() {
@ -369,7 +354,6 @@
// (request.requestrequest null) // (request.requestrequest null)
initQuoteCaseDetail(); initQuoteCaseDetail();
} }
await initLocalConfig();
} }
} }
); );

View File

@ -23,7 +23,6 @@
<executeButton <executeButton
ref="executeButtonRef" ref="executeButtonRef"
:execute-loading="activeScenarioTab.executeLoading" :execute-loading="activeScenarioTab.executeLoading"
is-emit
@execute="handleExecute" @execute="handleExecute"
@stop-debug="handleStopExecute" @stop-debug="handleStopExecute"
/> />