fix: 修改全局部分bug
This commit is contained in:
parent
fa1016566f
commit
c64b97ba06
|
@ -38,6 +38,7 @@
|
||||||
v-model:model-value="record.expression"
|
v-model:model-value="record.expression"
|
||||||
class="ms-params-input"
|
class="ms-params-input"
|
||||||
:max-length="255"
|
:max-length="255"
|
||||||
|
size="mini"
|
||||||
:disabled="props.disabled"
|
:disabled="props.disabled"
|
||||||
:placeholder="t('apiTestDebug.commonPlaceholder')"
|
:placeholder="t('apiTestDebug.commonPlaceholder')"
|
||||||
@input="() => handleExpressionChange(rowIndex)"
|
@input="() => handleExpressionChange(rowIndex)"
|
||||||
|
@ -133,6 +134,7 @@
|
||||||
:disabled="props.disabled"
|
:disabled="props.disabled"
|
||||||
class="ms-params-input"
|
class="ms-params-input"
|
||||||
:max-length="255"
|
:max-length="255"
|
||||||
|
size="mini"
|
||||||
:placeholder="t('apiTestDebug.commonPlaceholder')"
|
:placeholder="t('apiTestDebug.commonPlaceholder')"
|
||||||
@input="() => handleExpressionChange(rowIndex)"
|
@input="() => handleExpressionChange(rowIndex)"
|
||||||
@change="() => handleExpressionChange(rowIndex)"
|
@change="() => handleExpressionChange(rowIndex)"
|
||||||
|
@ -281,6 +283,7 @@
|
||||||
:disabled="props.disabled"
|
:disabled="props.disabled"
|
||||||
class="ms-params-input"
|
class="ms-params-input"
|
||||||
:max-length="255"
|
:max-length="255"
|
||||||
|
size="mini"
|
||||||
@input="() => handleExpressionChange(rowIndex)"
|
@input="() => handleExpressionChange(rowIndex)"
|
||||||
@change="() => handleExpressionChange(rowIndex)"
|
@change="() => handleExpressionChange(rowIndex)"
|
||||||
>
|
>
|
||||||
|
@ -457,7 +460,6 @@
|
||||||
dataIndex: 'condition',
|
dataIndex: 'condition',
|
||||||
slotName: 'condition',
|
slotName: 'condition',
|
||||||
options: statusCodeOptions,
|
options: statusCodeOptions,
|
||||||
width: 120,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'ms.assertion.matchValue',
|
title: 'ms.assertion.matchValue',
|
||||||
|
|
|
@ -40,15 +40,13 @@
|
||||||
>
|
>
|
||||||
<div class="ms-assertion-body-left-item-row">
|
<div class="ms-assertion-body-left-item-row">
|
||||||
<span class="ms-assertion-body-left-item-row-num">{{ index + 1 }}</span>
|
<span class="ms-assertion-body-left-item-row-num">{{ index + 1 }}</span>
|
||||||
<div class="one-text-line">{{ item.name }}</div>
|
<div class="one-line-text" :class="{ 'text-[rgb(var(--primary-5))]': activeKey === item.id }">{{
|
||||||
|
item.name
|
||||||
|
}}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ms-assertion-body-left-item-switch">
|
<div class="ms-assertion-body-left-item-switch">
|
||||||
<div v-show="!props.disabled" class="ms-assertion-body-left-item-switch-action">
|
<div v-show="!props.disabled" class="ms-assertion-body-left-item-switch-action">
|
||||||
<!-- <MsIcon
|
<icon-drag-dot-vertical class="ms-list-drag-icon sort-handle" />
|
||||||
type="icon-icon_drag"
|
|
||||||
class="action-btn-move sort-handle cursor-move text-[12px] text-[var(--color-text-4)]"
|
|
||||||
/> -->
|
|
||||||
<icon-drag-dot-vertical class="ms-list-drag-icon" />
|
|
||||||
<MsTableMoreAction
|
<MsTableMoreAction
|
||||||
:list="getItemMoreActions(item)"
|
:list="getItemMoreActions(item)"
|
||||||
trigger="click"
|
trigger="click"
|
||||||
|
@ -267,14 +265,21 @@
|
||||||
case ResponseAssertionType.RESPONSE_HEADER:
|
case ResponseAssertionType.RESPONSE_HEADER:
|
||||||
assertions.value.push({
|
assertions.value.push({
|
||||||
...tmpObj,
|
...tmpObj,
|
||||||
assertions: [],
|
assertions: [
|
||||||
|
{
|
||||||
|
header: '',
|
||||||
|
condition: EQUAL.value,
|
||||||
|
expectedValue: '',
|
||||||
|
enable: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
// 状态码
|
// 状态码
|
||||||
case ResponseAssertionType.RESPONSE_CODE:
|
case ResponseAssertionType.RESPONSE_CODE:
|
||||||
assertions.value.push({
|
assertions.value.push({
|
||||||
...tmpObj,
|
...tmpObj,
|
||||||
condition: 'EQUALS',
|
condition: EQUAL.value,
|
||||||
expectedValue: '200',
|
expectedValue: '200',
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -82,16 +82,6 @@
|
||||||
innerKeyword.value = inputVal;
|
innerKeyword.value = inputVal;
|
||||||
}, 300);
|
}, 300);
|
||||||
|
|
||||||
watch(
|
|
||||||
() => props.modelValue,
|
|
||||||
(val) => {
|
|
||||||
if (val) {
|
|
||||||
selectValue.value = val as any;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ immediate: true }
|
|
||||||
);
|
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.keyword,
|
() => props.keyword,
|
||||||
(val) => {
|
(val) => {
|
||||||
|
@ -116,6 +106,9 @@
|
||||||
if (props.options) {
|
if (props.options) {
|
||||||
optionsList.value = props.options;
|
optionsList.value = props.options;
|
||||||
}
|
}
|
||||||
|
if (props.modelValue) {
|
||||||
|
selectValue.value = props.modelValue;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { ExecuteConditionProcessor } from '../apiTest/common';
|
import { EnableKeyValueParam, ExecuteConditionProcessor } from '@/models/apiTest/common';
|
||||||
|
|
||||||
export interface EnvListItem {
|
export interface EnvListItem {
|
||||||
mock?: boolean;
|
mock?: boolean;
|
||||||
|
@ -140,7 +140,7 @@ export interface HttpForm {
|
||||||
description?: string;
|
description?: string;
|
||||||
hostname: string;
|
hostname: string;
|
||||||
type: string;
|
type: string;
|
||||||
headers: Record<string, any>[];
|
headers: EnableKeyValueParam[];
|
||||||
// pathMatchRule: {
|
// pathMatchRule: {
|
||||||
path: string;
|
path: string;
|
||||||
condition: string;
|
condition: string;
|
||||||
|
|
|
@ -113,6 +113,12 @@
|
||||||
return data.value.filter((item: any) => item.processorType === RequestConditionProcessor.EXTRACT).length > 0;
|
return data.value.filter((item: any) => item.processorType === RequestConditionProcessor.EXTRACT).length > 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const hasSql = computed(
|
||||||
|
() =>
|
||||||
|
data.value.filter((item: any) => item.processorType === RequestConditionProcessor.SQL).length > 0 &&
|
||||||
|
props.showPrePostRequest
|
||||||
|
);
|
||||||
|
|
||||||
const itemMoreActions: ActionsItem[] = [
|
const itemMoreActions: ActionsItem[] = [
|
||||||
{
|
{
|
||||||
label: 'common.copy',
|
label: 'common.copy',
|
||||||
|
@ -131,7 +137,7 @@
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
activeItem.value = data.value.find((item) => item.id === props.activeId) || data.value[0] || {};
|
activeItem.value = data.value.find((item) => item.id === props.activeId) || data.value[0] || {};
|
||||||
emit('activeChange', activeItem.value);
|
emit('activeChange', activeItem.value);
|
||||||
if (hasPreAndPost.value || hasEXTRACT.value) {
|
if (hasPreAndPost.value || hasEXTRACT.value || hasSql.value) {
|
||||||
moreActions = itemMoreActions.slice(-1);
|
moreActions = itemMoreActions.slice(-1);
|
||||||
} else {
|
} else {
|
||||||
moreActions = itemMoreActions;
|
moreActions = itemMoreActions;
|
||||||
|
|
|
@ -61,7 +61,16 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</a-popover>
|
</a-popover>
|
||||||
<span v-if="props.showType && props.showType !== 'CASE'">{{ props.environmentName }}</span>
|
<a-popover position="left" content-class="response-popover-content">
|
||||||
|
<div v-if="props.showType && props.showType !== 'CASE'" class="one-line-text max-w-[150px]">{{
|
||||||
|
props.environmentName
|
||||||
|
}}</div>
|
||||||
|
<template #content>
|
||||||
|
<div v-if="props.showType && props.showType !== 'CASE'" class="one-line-text">{{
|
||||||
|
props.environmentName
|
||||||
|
}}</div>
|
||||||
|
</template>
|
||||||
|
</a-popover>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="activeType === 'SubRequest'" class="my-4 flex justify-start">
|
<div v-if="activeType === 'SubRequest'" class="my-4 flex justify-start">
|
||||||
|
@ -112,7 +121,7 @@
|
||||||
|
|
||||||
import { reportCaseStepDetail, reportStepDetail } from '@/api/modules/api-test/report';
|
import { reportCaseStepDetail, reportStepDetail } from '@/api/modules/api-test/report';
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
import { findNodeByKey } from '@/utils';
|
import { findNodeByKey, formatDuration } from '@/utils';
|
||||||
|
|
||||||
import type { ReportStepDetail, ReportStepDetailItem, ScenarioItemType } from '@/models/apiTest/report';
|
import type { ReportStepDetail, ReportStepDetailItem, ScenarioItemType } from '@/models/apiTest/report';
|
||||||
import { ResponseComposition, ScenarioStepType } from '@/enums/apiEnum';
|
import { ResponseComposition, ScenarioStepType } from '@/enums/apiEnum';
|
||||||
|
|
|
@ -421,7 +421,7 @@
|
||||||
dataIndex: 'tags',
|
dataIndex: 'tags',
|
||||||
isTag: true,
|
isTag: true,
|
||||||
isStringTag: true,
|
isStringTag: true,
|
||||||
width: 150,
|
width: 400,
|
||||||
showDrag: true,
|
showDrag: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -482,6 +482,7 @@
|
||||||
isTag: true,
|
isTag: true,
|
||||||
isStringTag: true,
|
isStringTag: true,
|
||||||
showDrag: true,
|
showDrag: true,
|
||||||
|
width: 400,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'case.lastReportStatus',
|
title: 'case.lastReportStatus',
|
||||||
|
|
|
@ -1,74 +1,14 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="report-container h-full">
|
<div class="report-container h-full">
|
||||||
<!-- 报告参数开始 -->
|
<!-- 报告参数开始 -->
|
||||||
<div class="report-header flex items-center justify-between">
|
<ReportDetailHeader :detail="detail" show-type="CASE" />
|
||||||
<span>
|
|
||||||
<span v-if="route.query.shareId" class="font-medium"
|
|
||||||
>报告名称 <span>【{{ detail.name }}】</span>
|
|
||||||
<a-divider direction="vertical" :margin="4" class="!mx-2"></a-divider
|
|
||||||
></span>
|
|
||||||
<a-popover position="left" content-class="response-popover-content">
|
|
||||||
<span> {{ detail.environmentName || t('report.detail.api.defaultEnv') }}</span>
|
|
||||||
<a-divider direction="vertical" :margin="4" class="!mx-2"></a-divider>
|
|
||||||
<template #content>
|
|
||||||
<div class="flex items-center gap-[8px] text-[14px]">
|
|
||||||
<div class="text-[var(--color-text-4)]">{{ t('report.detail.api.executeEnv') }}</div>
|
|
||||||
<span class="mx-1"> {{ detail.environmentName || t('report.detail.api.caseSaveEnv') }}</span>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</a-popover>
|
|
||||||
<a-popover position="bottom" content-class="response-popover-content">
|
|
||||||
<span> {{ detail.poolName || '-' }}</span>
|
|
||||||
<a-divider direction="vertical" :margin="4" class="!mx-2"></a-divider>
|
|
||||||
<template #content>
|
|
||||||
<div class="flex items-center gap-[8px] text-[14px]">
|
|
||||||
<div class="text-[var(--color-text-4)]">{{ t('project.taskCenter.resourcePool') }}</div>
|
|
||||||
<span class="mx-1"> {{ detail.poolName || '-' }}</span>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</a-popover>
|
|
||||||
<a-popover position="left" content-class="response-popover-content">
|
|
||||||
<span v-if="detail.runMode">
|
|
||||||
{{ detail.runMode === 'SERIAL' ? t('case.execute.serial') : t('case.execute.parallel') }}</span
|
|
||||||
>
|
|
||||||
<a-divider v-if="detail.runMode" direction="vertical" :margin="4" class="!mx-2"></a-divider>
|
|
||||||
<template #content>
|
|
||||||
<div class="items-center gap-[8px] text-[14px]">
|
|
||||||
<div class="text-[var(--color-text-4)]">{{ t('report.detail.api.runMode') }}</div>
|
|
||||||
<div class="mx-1 mt-1">
|
|
||||||
{{ detail.runMode === 'SERIAL' ? t('case.execute.serial') : t('case.execute.parallel') }}</div
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</a-popover>
|
|
||||||
|
|
||||||
<a-popover position="bottom" content-class="response-popover-content">
|
|
||||||
<span> {{ detail.creatUserName || '-' }}</span>
|
|
||||||
<template #content>
|
|
||||||
<div class="items-center gap-[8px] text-[14px]">
|
|
||||||
<div class="text-[var(--color-text-4)]">{{ t('report.detail.api.reportCreator') }}</div>
|
|
||||||
<div class="mt-1"> {{ detail.creatUserName || '-' }}</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</a-popover>
|
|
||||||
</span>
|
|
||||||
<span>
|
|
||||||
<span class="text-[var(--color-text-4)]">{{ t('report.detail.api.executionTime') }}</span>
|
|
||||||
{{ detail.startTime ? dayjs(detail.startTime).format('YYYY-MM-DD HH:mm:ss') : '-' }}
|
|
||||||
<span class="text-[var(--color-text-4)]">{{ t('report.detail.api.executionTimeTo') }}</span>
|
|
||||||
{{ detail.endTime ? dayjs(detail.endTime).format('YYYY-MM-DD HH:mm:ss') : '-' }}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<!-- 报告参数结束 -->
|
<!-- 报告参数结束 -->
|
||||||
<!-- 报告分析开始 -->
|
<!-- 报告分析开始 -->
|
||||||
<div class="analyze mb-1">
|
<div class="analyze mb-1">
|
||||||
<!-- 请求分析 -->
|
<!-- 请求分析 -->
|
||||||
<div class="request-analyze min-h-[110px]">
|
<div class="request-analyze min-h-[110px]">
|
||||||
<div class="block-title mb-4">{{ t('report.detail.api.requestAnalysis') }}</div>
|
<div class="block-title mb-4">{{ t('report.detail.api.requestAnalysis') }}</div>
|
||||||
<!-- 独立报告 -->
|
|
||||||
<SetReportChart :legend-data="legendData" :options="charOptions" :request-total="getIndicators(detail.total)" />
|
<SetReportChart :legend-data="legendData" :options="charOptions" :request-total="getIndicators(detail.total)" />
|
||||||
<!-- 集合报告 -->
|
|
||||||
<!-- </div> -->
|
|
||||||
</div>
|
</div>
|
||||||
<!-- 耗时分析 -->
|
<!-- 耗时分析 -->
|
||||||
<div class="time-analyze">
|
<div class="time-analyze">
|
||||||
|
@ -76,15 +16,17 @@
|
||||||
<div class="time-card-item flex h-full">
|
<div class="time-card-item flex h-full">
|
||||||
<MsIcon type="icon-icon_time_outlined" class="mr-[4px] text-[var(--color-text-4)]" size="16" />
|
<MsIcon type="icon-icon_time_outlined" class="mr-[4px] text-[var(--color-text-4)]" size="16" />
|
||||||
<span class="time-card-item-title">{{ t('report.detail.api.totalTime') }}</span>
|
<span class="time-card-item-title">{{ t('report.detail.api.totalTime') }}</span>
|
||||||
<span class="count">{{ getTotalTime.split('-')[0] || '-' }}</span
|
<span class="count">{{ getTotalTime.split('-')[0] || 0 }}</span
|
||||||
><span class="time-card-item-title">{{ getTotalTime.split('-')[1] || 'ms' }}</span>
|
><span class="time-card-item-title">{{ getTotalTime.split('-')[1] || 'ms' }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="time-card-item h-full">
|
<div class="time-card-item h-full">
|
||||||
<MsIcon type="icon-icon_time_outlined" class="mr-[4px] text-[var(--color-text-4)]" size="16" />
|
<MsIcon type="icon-icon_time_outlined" class="mr-[4px] text-[var(--color-text-4)]" size="16" />
|
||||||
<span class="time-card-item-title"> {{ t('report.detail.api.requestTotalTime') }}</span>
|
<span class="time-card-item-title"> {{ t('report.detail.api.requestTotalTime') }}</span>
|
||||||
<span class="count">{{ formatDuration(detail.requestDuration).split('-')[0] || '-' }}</span
|
<span class="count">{{
|
||||||
|
detail.requestDuration !== null ? formatDuration(detail.requestDuration).split('-')[0] : '-'
|
||||||
|
}}</span
|
||||||
><span class="time-card-item-title">{{
|
><span class="time-card-item-title">{{
|
||||||
formatDuration(detail.requestDuration).split('-')[1] || 'ms'
|
detail.requestDuration !== null ? formatDuration(detail.requestDuration).split('-')[1] : 'ms'
|
||||||
}}</span>
|
}}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -132,7 +74,7 @@
|
||||||
<!-- 报告步骤分析结束 -->
|
<!-- 报告步骤分析结束 -->
|
||||||
<!-- 报告明细开始 -->
|
<!-- 报告明细开始 -->
|
||||||
<div class="report-info">
|
<div class="report-info">
|
||||||
<reportInfoHeader v-model:keyword="cascaderKeywords" v-model:active-tab="activeTab" />
|
<reportInfoHeader v-model:keyword="cascaderKeywords" v-model:active-tab="activeTab" show-type="CASE" />
|
||||||
<TiledList
|
<TiledList
|
||||||
:key-words="cascaderKeywords"
|
:key-words="cascaderKeywords"
|
||||||
show-type="CASE"
|
show-type="CASE"
|
||||||
|
@ -147,9 +89,10 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
import dayjs from 'dayjs';
|
import { cloneDeep } from 'lodash-es';
|
||||||
|
|
||||||
import SetReportChart from './case/setReportChart.vue';
|
import SetReportChart from './case/setReportChart.vue';
|
||||||
|
import ReportDetailHeader from './reportDetailHeader.vue';
|
||||||
import reportInfoHeader from './step/reportInfoHeaders.vue';
|
import reportInfoHeader from './step/reportInfoHeaders.vue';
|
||||||
import TiledList from './tiledList.vue';
|
import TiledList from './tiledList.vue';
|
||||||
|
|
||||||
|
@ -329,7 +272,12 @@
|
||||||
rateKey: 'requestPendingRate',
|
rateKey: 'requestPendingRate',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
const validArr = props?.detailInfo?.integrated ? tempArr : tempArr.slice(0, 1);
|
let validArr;
|
||||||
|
if (props?.detailInfo?.integrated) {
|
||||||
|
validArr = cloneDeep(tempArr);
|
||||||
|
} else {
|
||||||
|
validArr = props?.detailInfo?.status === 'SUCCESS' ? [tempArr[0]] : [tempArr[2]];
|
||||||
|
}
|
||||||
charOptions.value.series.data = validArr.map((item: any) => {
|
charOptions.value.series.data = validArr.map((item: any) => {
|
||||||
return {
|
return {
|
||||||
value: detail.value[item.value] || 0,
|
value: detail.value[item.value] || 0,
|
||||||
|
|
|
@ -0,0 +1,102 @@
|
||||||
|
<template>
|
||||||
|
<div class="report-header flex items-center justify-between">
|
||||||
|
<div class="flex items-center">
|
||||||
|
<div v-if="route.query.shareId" class="font-medium"
|
||||||
|
>{{ t('report.name') }}
|
||||||
|
<div class="one-line-text max-w-[150px]">【{{ props.detail.name }}】</div>
|
||||||
|
<a-divider direction="vertical" :margin="4" class="!mx-2"></a-divider
|
||||||
|
></div>
|
||||||
|
<a-popover position="left" content-class="response-popover-content">
|
||||||
|
<div class="one-line-text max-w-[150px]"> {{ props.detail.environmentName || '-' }}</div>
|
||||||
|
<a-divider direction="vertical" :margin="4" class="!mx-2"></a-divider>
|
||||||
|
<template #content>
|
||||||
|
<div class="flex items-center gap-[8px] text-[14px]">
|
||||||
|
<div class="text-[var(--color-text-4)]">{{ t('report.detail.api.executeEnv') }}</div>
|
||||||
|
<div class="mx-1"> {{ props.detail.environmentName || '-' }}</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</a-popover>
|
||||||
|
<a-popover position="bottom" content-class="response-popover-content">
|
||||||
|
<div class="one-line-text max-w-[150px]"> {{ props.detail.poolName || '-' }}</div>
|
||||||
|
<a-divider direction="vertical" :margin="4" class="!mx-2"></a-divider>
|
||||||
|
<template #content>
|
||||||
|
<div class="flex items-center gap-[8px] text-[14px]">
|
||||||
|
<div class="text-[var(--color-text-4)]">{{ t('project.taskCenter.resourcePool') }}</div>
|
||||||
|
<span class="mx-1"> {{ props.detail.poolName || '-' }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</a-popover>
|
||||||
|
|
||||||
|
<a-popover position="left" content-class="response-popover-content">
|
||||||
|
<span v-if="!props.detail.integrated && props.showType === 'API'">
|
||||||
|
{{ props.detail.waitingTime ? formatDuration(props.detail.waitingTime).split('-')[0] : '-' }}
|
||||||
|
<span>{{ props.detail.waitingTime ? formatDuration(props.detail.waitingTime).split('-')[1] : 'ms' }}</span>
|
||||||
|
<a-divider direction="vertical" :margin="4" class="!mx-2"></a-divider>
|
||||||
|
</span>
|
||||||
|
<template #content>
|
||||||
|
<div class="flex items-center gap-[8px] text-[14px]">
|
||||||
|
<div class="text-[var(--color-text-4)]">{{ t('report.detail.api.globalWaitingTime') }}</div>
|
||||||
|
{{ props.detail.waitingTime ? formatDuration(props.detail.waitingTime).split('-')[0] : '-' }}
|
||||||
|
<span class="mx-1">{{
|
||||||
|
props.detail.waitingTime ? formatDuration(props.detail.waitingTime).split('-')[1] : 'ms'
|
||||||
|
}}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</a-popover>
|
||||||
|
<a-popover position="left" content-class="response-popover-content">
|
||||||
|
<span v-if="showRunMode">
|
||||||
|
{{ props.detail.runMode === 'SERIAL' ? t('case.execute.serial') : t('case.execute.parallel') }}</span
|
||||||
|
>
|
||||||
|
<a-divider v-if="showRunMode" direction="vertical" :margin="4" class="!mx-2"></a-divider>
|
||||||
|
<template #content>
|
||||||
|
<div class="items-center gap-[8px] text-[14px]">
|
||||||
|
<div class="text-[var(--color-text-4)]">{{ t('report.detail.api.runMode') }}</div>
|
||||||
|
<div class="mt-1">
|
||||||
|
{{ props.detail.runMode === 'SERIAL' ? t('case.execute.serial') : t('case.execute.parallel') }}</div
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</a-popover>
|
||||||
|
|
||||||
|
<a-popover position="bottom" content-class="response-popover-content">
|
||||||
|
<div class="one-line-text max-w-[150px]"> {{ props.detail.creatUserName || '-' }}</div>
|
||||||
|
<template #content>
|
||||||
|
<div class="items-center gap-[8px] text-[14px]">
|
||||||
|
<div class="text-[var(--color-text-4)]">{{ t('report.detail.api.reportCreator') }}</div>
|
||||||
|
<div class="mx-1 mt-1"> {{ props.detail.creatUserName || '-' }}</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</a-popover>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span class="text-[var(--color-text-4)]">{{ t('report.detail.api.executionTime') }}</span>
|
||||||
|
{{ props.detail.startTime ? dayjs(props.detail.startTime).format('YYYY-MM-DD HH:mm:ss') : '-' }}
|
||||||
|
<span class="text-[var(--color-text-4)]">{{ t('report.detail.api.executionTimeTo') }}</span>
|
||||||
|
{{ props.detail.endTime ? dayjs(props.detail.endTime).format('YYYY-MM-DD HH:mm:ss') : '-' }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import { useRoute } from 'vue-router';
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
|
||||||
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
|
import { formatDuration } from '@/utils';
|
||||||
|
|
||||||
|
import type { ReportDetail } from '@/models/apiTest/report';
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const route = useRoute();
|
||||||
|
const props = defineProps<{
|
||||||
|
detail: ReportDetail;
|
||||||
|
showType: 'API' | 'CASE';
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const showRunMode = computed(() => {
|
||||||
|
return props.showType === 'API' ? props.detail.runMode : props.detail.runMode && props.detail.integrated;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
|
@ -27,7 +27,7 @@
|
||||||
<template #name="{ record, rowIndex }">
|
<template #name="{ record, rowIndex }">
|
||||||
<div
|
<div
|
||||||
type="text"
|
type="text"
|
||||||
class="one-text-line flex w-full text-[rgb(var(--primary-5))]"
|
class="one-line-text flex w-full text-[rgb(var(--primary-5))]"
|
||||||
@click="showReportDetail(record.id, rowIndex, record.integrated)"
|
@click="showReportDetail(record.id, rowIndex, record.integrated)"
|
||||||
>{{ characterLimit(record.name) }}</div
|
>{{ characterLimit(record.name) }}</div
|
||||||
>
|
>
|
||||||
|
@ -87,8 +87,12 @@
|
||||||
</a-button>
|
</a-button>
|
||||||
<template #content>
|
<template #content>
|
||||||
<div class="arco-table-filters-content">
|
<div class="arco-table-filters-content">
|
||||||
<div class="ml-[6px] flex items-center justify-start px-[6px] py-[2px]">
|
<div class="flex items-center justify-center px-[6px] py-[2px]">
|
||||||
<a-checkbox-group v-model:model-value="statusListFilters" direction="vertical" size="small">
|
<a-checkbox-group
|
||||||
|
v-model:model-value="statusListFiltersMap[showType]"
|
||||||
|
direction="vertical"
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
<a-checkbox v-for="key of statusFilters" :key="key" :value="key">
|
<a-checkbox v-for="key of statusFilters" :key="key" :value="key">
|
||||||
<ExecutionStatus :module-type="props.moduleType" :status="key" />
|
<ExecutionStatus :module-type="props.moduleType" :status="key" />
|
||||||
</a-checkbox>
|
</a-checkbox>
|
||||||
|
@ -153,6 +157,7 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { Message } from '@arco-design/web-vue';
|
import { Message } from '@arco-design/web-vue';
|
||||||
|
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';
|
||||||
|
@ -190,7 +195,6 @@
|
||||||
const statusFilterVisible = ref(false);
|
const statusFilterVisible = ref(false);
|
||||||
const triggerModeFilterVisible = ref(false);
|
const triggerModeFilterVisible = ref(false);
|
||||||
|
|
||||||
const statusListFilters = ref<string[]>([]);
|
|
||||||
const triggerModeListFilters = ref<string[]>([]);
|
const triggerModeListFilters = ref<string[]>([]);
|
||||||
|
|
||||||
type ReportShowType = 'All' | 'INDEPENDENT' | 'INTEGRATED';
|
type ReportShowType = 'All' | 'INDEPENDENT' | 'INTEGRATED';
|
||||||
|
@ -251,8 +255,9 @@
|
||||||
slotName: 'createUserName',
|
slotName: 'createUserName',
|
||||||
dataIndex: 'createUserName',
|
dataIndex: 'createUserName',
|
||||||
showInTable: true,
|
showInTable: true,
|
||||||
width: 200,
|
width: 300,
|
||||||
showDrag: true,
|
showDrag: true,
|
||||||
|
showTooltip: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'report.operating',
|
title: 'report.operating',
|
||||||
|
@ -303,6 +308,15 @@
|
||||||
}),
|
}),
|
||||||
rename
|
rename
|
||||||
);
|
);
|
||||||
|
// 全部过滤条件
|
||||||
|
const allListFilters = ref<string[]>([]);
|
||||||
|
const independentListFilters = ref<string[]>([]);
|
||||||
|
const integratedListFilters = ref<string[]>([]);
|
||||||
|
const statusListFiltersMap = ref<Record<string, string[]>>({
|
||||||
|
all: allListFilters.value,
|
||||||
|
INDEPENDENT: independentListFilters.value,
|
||||||
|
INTEGRATED: integratedListFilters.value,
|
||||||
|
});
|
||||||
|
|
||||||
function initData() {
|
function initData() {
|
||||||
setLoadListParams({
|
setLoadListParams({
|
||||||
|
@ -310,7 +324,7 @@
|
||||||
projectId: appStore.currentProjectId,
|
projectId: appStore.currentProjectId,
|
||||||
moduleType: props.moduleType,
|
moduleType: props.moduleType,
|
||||||
filter: {
|
filter: {
|
||||||
status: statusListFilters.value,
|
status: statusListFiltersMap.value[showType.value],
|
||||||
integrated: showType.value === 'All' ? undefined : Array.of((showType.value === 'INTEGRATED').toString()),
|
integrated: showType.value === 'All' ? undefined : Array.of((showType.value === 'INTEGRATED').toString()),
|
||||||
triggerMode: triggerModeListFilters.value,
|
triggerMode: triggerModeListFilters.value,
|
||||||
},
|
},
|
||||||
|
@ -342,7 +356,7 @@
|
||||||
selectIds: params?.selectedIds || [],
|
selectIds: params?.selectedIds || [],
|
||||||
condition: {
|
condition: {
|
||||||
filter: {
|
filter: {
|
||||||
status: statusListFilters.value,
|
status: statusListFiltersMap.value[showType.value],
|
||||||
integrated: showType.value === 'All' ? undefined : Array.of((showType.value === 'INTEGRATED').toString()),
|
integrated: showType.value === 'All' ? undefined : Array.of((showType.value === 'INTEGRATED').toString()),
|
||||||
triggerMode: triggerModeListFilters.value,
|
triggerMode: triggerModeListFilters.value,
|
||||||
},
|
},
|
||||||
|
@ -429,7 +443,7 @@
|
||||||
|
|
||||||
function resetStatusFilter() {
|
function resetStatusFilter() {
|
||||||
statusFilterVisible.value = false;
|
statusFilterVisible.value = false;
|
||||||
statusListFilters.value = [];
|
statusListFiltersMap.value[showType.value] = [];
|
||||||
initData();
|
initData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,78 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="report-container h-full">
|
<div class="report-container h-full">
|
||||||
<!-- 报告参数开始 -->
|
<!-- 报告参数开始 -->
|
||||||
<div class="report-header flex items-center justify-between">
|
<ReportDetailHeader :detail="detail" show-type="API" />
|
||||||
<!-- TODO 虚拟数据替换接口后边 -->
|
|
||||||
<span>
|
|
||||||
<a-popover position="left" content-class="response-popover-content">
|
|
||||||
<span> {{ detail.environmentName || t('report.detail.api.defaultEnv') }}</span>
|
|
||||||
<a-divider direction="vertical" :margin="4" class="!mx-2"></a-divider>
|
|
||||||
<template #content>
|
|
||||||
<div class="flex items-center gap-[8px] text-[14px]">
|
|
||||||
<div class="text-[var(--color-text-4)]">{{ t('report.detail.api.executeEnv') }}</div>
|
|
||||||
<span class="mx-1"> {{ detail.environmentName || t('report.detail.api.scenarioSavedEnv') }}</span>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</a-popover>
|
|
||||||
<a-popover position="bottom" content-class="response-popover-content">
|
|
||||||
<span> {{ detail.poolName || '-' }}</span>
|
|
||||||
<a-divider direction="vertical" :margin="4" class="!mx-2"></a-divider>
|
|
||||||
<template #content>
|
|
||||||
<div class="flex items-center gap-[8px] text-[14px]">
|
|
||||||
<div class="text-[var(--color-text-4)]">{{ t('project.taskCenter.resourcePool') }}</div>
|
|
||||||
<span class="mx-1"> {{ detail.poolName || '-' }}</span>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</a-popover>
|
|
||||||
|
|
||||||
<a-popover position="left" content-class="response-popover-content">
|
|
||||||
<span v-if="!detail.integrated">
|
|
||||||
{{ detail.waitingTime ? formatDuration(detail.waitingTime).split('-')[0] : '-' }}
|
|
||||||
<span>{{ detail.waitingTime ? formatDuration(detail.waitingTime).split('-')[1] : 'ms' }}</span>
|
|
||||||
<a-divider direction="vertical" :margin="4" class="!mx-2"></a-divider>
|
|
||||||
</span>
|
|
||||||
<template #content>
|
|
||||||
<div class="flex items-center gap-[8px] text-[14px]">
|
|
||||||
<div class="text-[var(--color-text-4)]">{{ t('report.detail.api.globalWaitingTime') }}</div>
|
|
||||||
{{ detail.waitingTime ? formatDuration(detail.waitingTime).split('-')[0] : '-' }}
|
|
||||||
<span class="mx-1">{{
|
|
||||||
detail.waitingTime ? formatDuration(detail.waitingTime).split('-')[1] : 'ms'
|
|
||||||
}}</span>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</a-popover>
|
|
||||||
<a-popover position="left" content-class="response-popover-content">
|
|
||||||
<span v-if="detail.runMode">
|
|
||||||
{{ detail.runMode === 'SERIAL' ? t('case.execute.serial') : t('case.execute.parallel') }}</span
|
|
||||||
>
|
|
||||||
<a-divider v-if="detail.runMode" direction="vertical" :margin="4" class="!mx-2"></a-divider>
|
|
||||||
<template #content>
|
|
||||||
<div class="items-center gap-[8px] text-[14px]">
|
|
||||||
<div class="text-[var(--color-text-4)]">{{ t('report.detail.api.runMode') }}</div>
|
|
||||||
<div class="mt-1">
|
|
||||||
{{ detail.runMode === 'SERIAL' ? t('case.execute.serial') : t('case.execute.parallel') }}</div
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</a-popover>
|
|
||||||
|
|
||||||
<a-popover position="bottom" content-class="response-popover-content">
|
|
||||||
<span> {{ detail.creatUserName || '-' }}</span>
|
|
||||||
<template #content>
|
|
||||||
<div class="items-center gap-[8px] text-[14px]">
|
|
||||||
<div class="text-[var(--color-text-4)]">{{ t('report.detail.api.reportCreator') }}</div>
|
|
||||||
<div class="mx-1 mt-1"> {{ detail.creatUserName || '-' }}</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</a-popover>
|
|
||||||
</span>
|
|
||||||
<span>
|
|
||||||
<span class="text-[var(--color-text-4)]">{{ t('report.detail.api.executionTime') }}</span>
|
|
||||||
{{ detail.startTime ? dayjs(detail.startTime).format('YYYY-MM-DD HH:mm:ss') : '-' }}
|
|
||||||
<span class="text-[var(--color-text-4)]">{{ t('report.detail.api.executionTimeTo') }}</span>
|
|
||||||
{{ detail.endTime ? dayjs(detail.endTime).format('YYYY-MM-DD HH:mm:ss') : '-' }}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<!-- 报告参数结束 -->
|
<!-- 报告参数结束 -->
|
||||||
<!-- 报告步骤分析和请求分析开始 -->
|
<!-- 报告步骤分析和请求分析开始 -->
|
||||||
<div class="analyze mb-1">
|
<div class="analyze mb-1">
|
||||||
|
@ -128,10 +57,10 @@
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span class="ml-4 text-[18px] font-medium">{{
|
<span class="ml-4 text-[18px] font-medium">{{
|
||||||
formatDuration(detail.requestDuration).split('-')[0] || '-'
|
detail.requestDuration !== null ? formatDuration(detail.requestDuration).split('-')[0] : '-'
|
||||||
}}</span>
|
}}</span>
|
||||||
<span class="ml-1 text-[var(--color-text-4)]">{{
|
<span class="ml-1 text-[var(--color-text-4)]">{{
|
||||||
formatDuration(detail.requestDuration).split('-')[1] || 'ms'
|
detail.requestDuration !== null ? formatDuration(detail.requestDuration).split('-')[1] : 'ms'
|
||||||
}}</span>
|
}}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -188,7 +117,7 @@
|
||||||
<!-- 报告步骤分析和请求分析结束 -->
|
<!-- 报告步骤分析和请求分析结束 -->
|
||||||
<!-- 报告明细开始 -->
|
<!-- 报告明细开始 -->
|
||||||
<div class="report-info">
|
<div class="report-info">
|
||||||
<reportInfoHeader v-model:keyword="cascaderKeywords" v-model:active-tab="activeTab" />
|
<reportInfoHeader v-model:keyword="cascaderKeywords" v-model:active-tab="activeTab" show-type="API" />
|
||||||
<TiledList :key-words="cascaderKeywords" show-type="API" :active-type="activeTab" :report-detail="detail || []" />
|
<TiledList :key-words="cascaderKeywords" show-type="API" :active-type="activeTab" :report-detail="detail || []" />
|
||||||
</div>
|
</div>
|
||||||
<!-- 报告明细结束 -->
|
<!-- 报告明细结束 -->
|
||||||
|
@ -197,9 +126,11 @@
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
|
import { useRoute } from 'vue-router';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
|
|
||||||
import MsChart from '@/components/pure/chart/index.vue';
|
import MsChart from '@/components/pure/chart/index.vue';
|
||||||
|
import ReportDetailHeader from './reportDetailHeader.vue';
|
||||||
import reportInfoHeader from './step/reportInfoHeaders.vue';
|
import reportInfoHeader from './step/reportInfoHeaders.vue';
|
||||||
import StepProgress from './stepProgress.vue';
|
import StepProgress from './stepProgress.vue';
|
||||||
import TiledList from './tiledList.vue';
|
import TiledList from './tiledList.vue';
|
||||||
|
@ -211,6 +142,8 @@
|
||||||
|
|
||||||
import { getIndicators } from '../utils';
|
import { getIndicators } from '../utils';
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
detailInfo?: ReportDetail;
|
detailInfo?: ReportDetail;
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
option-size="small"
|
option-size="small"
|
||||||
class="w-full"
|
class="w-full"
|
||||||
:multiple="false"
|
:multiple="false"
|
||||||
:options="cascaderOptions || []"
|
:options="filterOptions || []"
|
||||||
:virtual-list-props="{ height: 200 }"
|
:virtual-list-props="{ height: 200 }"
|
||||||
:placeholder="t('report.detail.api.filterPlaceholder')"
|
:placeholder="t('report.detail.api.filterPlaceholder')"
|
||||||
>
|
>
|
||||||
|
@ -49,6 +49,7 @@
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
activeTab: 'tiled' | 'tab';
|
activeTab: 'tiled' | 'tab';
|
||||||
keyword: string;
|
keyword: string;
|
||||||
|
showType: 'API' | 'CASE';
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const emit = defineEmits(['update:activeTab', 'update:keyword']);
|
const emit = defineEmits(['update:activeTab', 'update:keyword']);
|
||||||
|
@ -101,6 +102,9 @@
|
||||||
children: createChildOption(ScenarioStepType.CUSTOM_REQUEST),
|
children: createChildOption(ScenarioStepType.CUSTOM_REQUEST),
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
const filterOptions = computed(() =>
|
||||||
|
props.showType === 'API' ? cascaderOptions.value : cascaderOptions.value.slice(-1)
|
||||||
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="less"></style>
|
<style scoped lang="less"></style>
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
|
|
||||||
import type { ScenarioItemType } from '@/models/apiTest/report';
|
import type { ScenarioItemType } from '@/models/apiTest/report';
|
||||||
|
import { ScenarioStepType } from '@/enums/apiEnum';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
|
@ -65,12 +66,12 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
const showCondition = ref<string[]>([
|
const showCondition = ref<string[]>([
|
||||||
'API',
|
ScenarioStepType.API,
|
||||||
'API_CASE',
|
ScenarioStepType.API_CASE,
|
||||||
' CUSTOM_REQUEST',
|
ScenarioStepType.CUSTOM_REQUEST,
|
||||||
' LOOP_CONTROLLER',
|
ScenarioStepType.LOOP_CONTROLLER,
|
||||||
'IF_CONTROLLER',
|
ScenarioStepType.IF_CONTROLLER,
|
||||||
'ONCE_ONLY_CONTROLLER',
|
ScenarioStepType.ONCE_ONLY_CONTROLLER,
|
||||||
]);
|
]);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -71,7 +71,7 @@
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<stepStatus v-if="step.status" :status="step.status" />
|
<stepStatus :status="step.status || 'PENDING'" />
|
||||||
<!-- 脚本报错 -->
|
<!-- 脚本报错 -->
|
||||||
<a-popover position="left" content-class="response-popover-content">
|
<a-popover position="left" content-class="response-popover-content">
|
||||||
<MsTag
|
<MsTag
|
||||||
|
@ -94,9 +94,13 @@
|
||||||
</a-popover>
|
</a-popover>
|
||||||
<div v-show="showStatus(step)" class="flex">
|
<div v-show="showStatus(step)" class="flex">
|
||||||
<span class="statusCode mx-2">
|
<span class="statusCode mx-2">
|
||||||
<div class="mr-2"> {{ t('report.detail.api.statusCode') }}</div>
|
<div v-if="step.code" class="mr-2"> {{ t('report.detail.api.statusCode') }}</div>
|
||||||
<a-popover position="left" content-class="response-popover-content">
|
<a-popover position="left" content-class="response-popover-content">
|
||||||
<div class="one-line-text max-w-[200px]" :style="{ color: statusCodeColor(step.code) }">
|
<div
|
||||||
|
v-if="step.code"
|
||||||
|
class="one-line-text max-w-[200px]"
|
||||||
|
:style="{ color: statusCodeColor(step.code) }"
|
||||||
|
>
|
||||||
{{ step.code || '-' }}
|
{{ step.code || '-' }}
|
||||||
</div>
|
</div>
|
||||||
<template #content>
|
<template #content>
|
||||||
|
@ -109,25 +113,39 @@
|
||||||
</template>
|
</template>
|
||||||
</a-popover>
|
</a-popover>
|
||||||
</span>
|
</span>
|
||||||
<span class="resTime">
|
|
||||||
|
<span v-if="step.requestTime !== null" class="resTime">
|
||||||
{{ t('report.detail.api.responseTime') }}
|
{{ t('report.detail.api.responseTime') }}
|
||||||
<span class="resTimeCount ml-2"
|
<a-popover position="left" content-class="response-popover-content">
|
||||||
>{{ step.requestTime ? formatDuration(step.requestTime).split('-')[0] : '-'
|
<span class="resTimeCount ml-2"
|
||||||
}}{{ step.requestTime ? formatDuration(step.requestTime).split('-')[1] : 'ms' }}</span
|
>{{ step.requestTime !== null ? formatDuration(step.requestTime).split('-')[0] : '-'
|
||||||
></span
|
}}{{ step.requestTime !== null ? formatDuration(step.requestTime).split('-')[1] : 'ms' }}</span
|
||||||
>
|
|
||||||
<a-popover position="left" content-class="response-popover-content">
|
|
||||||
<span class="resSize">
|
|
||||||
{{ t('report.detail.api.responseSize') }}
|
|
||||||
<span class="resTimeCount ml-2">{{ step.responseSize || 0 }} bytes</span></span
|
|
||||||
>
|
|
||||||
<template #content>
|
|
||||||
<span class="resSize">
|
|
||||||
{{ t('report.detail.api.responseSize') }}
|
|
||||||
<span class="resTimeCount ml-2">{{ step.responseSize || 0 }} bytes</span></span
|
|
||||||
>
|
>
|
||||||
</template>
|
<template #content>
|
||||||
</a-popover>
|
<span v-if="step.requestTime !== null" class="resTime">
|
||||||
|
{{ t('report.detail.api.responseTime') }}
|
||||||
|
<span class="resTimeCount ml-2"
|
||||||
|
>{{ step.requestTime !== null ? formatDuration(step.requestTime).split('-')[0] : '-'
|
||||||
|
}}{{
|
||||||
|
step.requestTime !== null ? formatDuration(step.requestTime).split('-')[1] : 'ms'
|
||||||
|
}}</span
|
||||||
|
></span
|
||||||
|
>
|
||||||
|
</template>
|
||||||
|
</a-popover></span
|
||||||
|
>
|
||||||
|
<span v-if="step.responseSize !== null" class="resSize">
|
||||||
|
{{ t('report.detail.api.responseSize') }}
|
||||||
|
<a-popover position="left" content-class="response-popover-content">
|
||||||
|
<span class="resTimeCount ml-2">{{ step.responseSize || 0 }} bytes</span>
|
||||||
|
<template #content>
|
||||||
|
<span class="resSize">
|
||||||
|
{{ t('report.detail.api.responseSize') }}
|
||||||
|
<span class="resTimeCount ml-2">{{ step.responseSize || 0 }} bytes</span></span
|
||||||
|
>
|
||||||
|
</template>
|
||||||
|
</a-popover></span
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -51,13 +51,13 @@
|
||||||
<div class="ml-[48px] mt-[8px] text-[var(--color-text-4)]">
|
<div class="ml-[48px] mt-[8px] text-[var(--color-text-4)]">
|
||||||
{{ dayjs(item.createTime).format('YYYY-MM-DD HH:mm:ss') }}
|
{{ dayjs(item.createTime).format('YYYY-MM-DD HH:mm:ss') }}
|
||||||
<a-tooltip :content="item.reviewName" :mouse-enter-delay="300">
|
<a-tooltip :content="item.reviewName" :mouse-enter-delay="300">
|
||||||
<span v-if="item.deleted" class="one-text-line ml-[16px] max-w-[300px] break-words break-all">
|
<span v-if="item.deleted" class="one-line-text ml-[16px] max-w-[300px] break-words break-all">
|
||||||
{{ characterLimit(item.reviewName) }}
|
{{ characterLimit(item.reviewName) }}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span
|
<span
|
||||||
v-else
|
v-else
|
||||||
class="one-text-line ml-[16px] max-w-[300px] cursor-pointer break-words break-all text-[rgb(var(--primary-5))]"
|
class="one-line-text ml-[16px] max-w-[300px] cursor-pointer break-words break-all text-[rgb(var(--primary-5))]"
|
||||||
@click="review(item)"
|
@click="review(item)"
|
||||||
>
|
>
|
||||||
{{ characterLimit(item.reviewName) }}
|
{{ characterLimit(item.reviewName) }}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<template #demandName="{ record }">
|
<template #demandName="{ record }">
|
||||||
<span :class="[props.highlightName ? 'text-[rgb(var(--primary-5))]' : '']" @click="emit('open', record)">
|
<span :class="[props.highlightName ? 'text-[rgb(var(--primary-5))]' : '']" @click="emit('open', record)">
|
||||||
{{ characterLimit(record.demandName) }} </span
|
{{ characterLimit(record.demandName) }} </span
|
||||||
><span class="one-text-line text-[rgb(var(--primary-5))]">({{ (record.children || []).length || 0 }})</span>
|
><span class="one-line-text text-[rgb(var(--primary-5))]">({{ (record.children || []).length || 0 }})</span>
|
||||||
</template>
|
</template>
|
||||||
<template #operation="{ record }">
|
<template #operation="{ record }">
|
||||||
<MsButton
|
<MsButton
|
||||||
|
|
|
@ -30,7 +30,6 @@
|
||||||
import useProjectEnvStore from '@/store/modules/setting/useProjectEnvStore';
|
import useProjectEnvStore from '@/store/modules/setting/useProjectEnvStore';
|
||||||
|
|
||||||
import { EnvConfigItem } from '@/models/projectManagement/environmental';
|
import { EnvConfigItem } from '@/models/projectManagement/environmental';
|
||||||
import { TableKeyEnum } from '@/enums/tableEnum';
|
|
||||||
|
|
||||||
const projectEnvStore = useProjectEnvStore();
|
const projectEnvStore = useProjectEnvStore();
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
|
|
|
@ -3,47 +3,30 @@
|
||||||
ref="popoverRef"
|
ref="popoverRef"
|
||||||
:popup-visible="currentVisible"
|
:popup-visible="currentVisible"
|
||||||
position="bottom"
|
position="bottom"
|
||||||
trigger="click"
|
|
||||||
class="ms-pop-confirm--hidden-icon"
|
class="ms-pop-confirm--hidden-icon"
|
||||||
:content-class="props.id ? 'move-left' : ''"
|
|
||||||
:ok-loading="loading"
|
:ok-loading="loading"
|
||||||
|
:on-before-ok="handleBeforeOk"
|
||||||
:cancel-button-props="{ disabled: loading }"
|
:cancel-button-props="{ disabled: loading }"
|
||||||
@popup-visible-change="reset"
|
@popup-visible-change="reset"
|
||||||
>
|
>
|
||||||
<template #content>
|
<template #content>
|
||||||
<div class="mb-[1px] text-[14px] font-medium text-[var(--color-text-1)]">{{
|
<div class="mb-[8px] text-[14px] font-medium text-[var(--color-text-1)]">{{
|
||||||
props.id ? t('system.userGroup.rename') : t('system.userGroup.createUserGroup')
|
props.id ? t('system.userGroup.rename') : t('system.userGroup.createUserGroup')
|
||||||
}}</div>
|
}}</div>
|
||||||
<div v-outer="handleOutsideClick">
|
<div v-outer="handleOutsideClick">
|
||||||
<div class="form">
|
<a-form ref="formRef" :model="form" layout="vertical">
|
||||||
<a-form ref="formRef" :model="form" layout="vertical">
|
<a-form-item class="hidden-item" field="name" :rules="[{ validator: validateName }]">
|
||||||
<a-form-item field="name" :rules="[{ validator: validateName }]">
|
<a-input
|
||||||
<a-input
|
v-model="form.name"
|
||||||
v-model="form.name"
|
class="w-[245px]"
|
||||||
class="w-[245px]"
|
:placeholder="t('system.userGroup.pleaseInputUserGroupName')"
|
||||||
:placeholder="t('system.userGroup.pleaseInputUserGroupName')"
|
allow-clear
|
||||||
allow-clear
|
:max-length="255"
|
||||||
:max-length="255"
|
@press-enter="handleBeforeOk(undefined)"
|
||||||
@press-enter="handleBeforeOk"
|
@keyup.esc="handleCancel"
|
||||||
@keyup.esc="handleCancel"
|
/>
|
||||||
/>
|
</a-form-item>
|
||||||
</a-form-item>
|
</a-form>
|
||||||
</a-form>
|
|
||||||
</div>
|
|
||||||
<!-- <div class="mb-1 mt-4 flex flex-row flex-nowrap justify-end gap-2">
|
|
||||||
<a-button type="secondary" size="mini" :disabled="loading" @click="handleCancel">
|
|
||||||
{{ t('common.cancel') }}
|
|
||||||
</a-button>
|
|
||||||
<a-button
|
|
||||||
type="primary"
|
|
||||||
size="mini"
|
|
||||||
:loading="loading"
|
|
||||||
:disabled="form.name.length === 0"
|
|
||||||
@click="handleBeforeOk"
|
|
||||||
>
|
|
||||||
{{ t('common.confirm') }}
|
|
||||||
</a-button>
|
|
||||||
</div> -->
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
|
@ -118,43 +101,43 @@
|
||||||
emit('cancel', false);
|
emit('cancel', false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleBeforeOk = () => {
|
const handleBeforeOk = (done?: (closed: boolean) => void) => {
|
||||||
formRef.value?.validate(async (errors: undefined | Record<string, ValidatedError>) => {
|
formRef.value?.validate(async (errors: undefined | Record<string, ValidatedError>) => {
|
||||||
if (errors) {
|
if (!errors) {
|
||||||
return false;
|
try {
|
||||||
}
|
loading.value = true;
|
||||||
// let res: EnvListItem;
|
|
||||||
try {
|
|
||||||
loading.value = true;
|
|
||||||
|
|
||||||
if (props.type === EnvAuthScopeEnum.PROJECT) {
|
if (props.type === EnvAuthScopeEnum.PROJECT) {
|
||||||
await updateOrAddEnv({ fileList: [], request: { ...store.currentEnvDetailInfo, name: form.name } });
|
await updateOrAddEnv({ fileList: [], request: { ...store.currentEnvDetailInfo, name: form.name } });
|
||||||
} else {
|
} else {
|
||||||
const id = store.currentGroupId === NEW_ENV_GROUP ? undefined : store.currentGroupId;
|
const id = store.currentGroupId === NEW_ENV_GROUP ? undefined : store.currentGroupId;
|
||||||
if (id) {
|
if (id) {
|
||||||
const detail: Record<string, any> = await getGroupDetailEnv(id);
|
const detail: Record<string, any> = await getGroupDetailEnv(id);
|
||||||
const envGroupProject = detail?.environmentGroupInfo.filter(
|
const envGroupProject = detail?.environmentGroupInfo.filter(
|
||||||
(item: any) => item.projectId && item.environmentId
|
(item: any) => item.projectId && item.environmentId
|
||||||
);
|
);
|
||||||
const params = {
|
const params = {
|
||||||
id,
|
id,
|
||||||
name: form.name,
|
name: form.name,
|
||||||
description: detail.description,
|
description: detail.description,
|
||||||
projectId: appStore.currentProjectId,
|
projectId: appStore.currentProjectId,
|
||||||
envGroupProject,
|
envGroupProject,
|
||||||
};
|
};
|
||||||
|
|
||||||
await groupUpdateEnv(params);
|
await groupUpdateEnv(params);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Message.success(t('project.fileManagement.renameSuccess'));
|
||||||
|
emit('success');
|
||||||
|
handleCancel();
|
||||||
|
} catch (error) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.error(error);
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
}
|
}
|
||||||
Message.success(t('project.fileManagement.renameSuccess'));
|
} else if (done) {
|
||||||
emit('success');
|
done(false);
|
||||||
handleCancel();
|
|
||||||
} catch (error) {
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.error(error);
|
|
||||||
} finally {
|
|
||||||
loading.value = false;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
v-model="keyword"
|
v-model="keyword"
|
||||||
class="w-[240px]"
|
class="w-[240px]"
|
||||||
allow-clear
|
allow-clear
|
||||||
|
:placeholder="t('project.menu.nameSearch')"
|
||||||
@press-enter="fetchData"
|
@press-enter="fetchData"
|
||||||
@search="fetchData"
|
@search="fetchData"
|
||||||
></a-input-search>
|
></a-input-search>
|
||||||
|
|
|
@ -74,6 +74,17 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
<template #empty>
|
||||||
|
<div class="flex w-full items-center justify-center text-[var(--color-text-4)]">
|
||||||
|
<span v-if="hasAnyPermission(['PROJECT_ENVIRONMENT:READ+UPDATE'])">{{
|
||||||
|
t('caseManagement.caseReview.tableNoData')
|
||||||
|
}}</span>
|
||||||
|
<span v-else>{{ t('caseManagement.featureCase.tableNoData') }}</span>
|
||||||
|
<MsButton v-permission="['PROJECT_ENVIRONMENT:READ+UPDATE']" class="ml-[8px]">
|
||||||
|
{{ t('project.environmental.addHttp') }}
|
||||||
|
</MsButton>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
</MsBaseTable>
|
</MsBaseTable>
|
||||||
<AddHttpDrawer
|
<AddHttpDrawer
|
||||||
v-model:visible="addVisible"
|
v-model:visible="addVisible"
|
||||||
|
|
|
@ -94,8 +94,10 @@
|
||||||
<a-form-item
|
<a-form-item
|
||||||
v-if="form.type === 'MODULE'"
|
v-if="form.type === 'MODULE'"
|
||||||
class="mb-[16px]"
|
class="mb-[16px]"
|
||||||
field="description"
|
field="moduleId"
|
||||||
:label="t('project.environmental.http.selectApiModule')"
|
:label="t('project.environmental.http.selectApiModule')"
|
||||||
|
:rules="[{ required: true, message: t('project.environmental.http.selectModule') }]"
|
||||||
|
asterisk-position="end"
|
||||||
>
|
>
|
||||||
<!-- TODO 先做普通树 放在下一个版本 -->
|
<!-- TODO 先做普通树 放在下一个版本 -->
|
||||||
<!-- <ApiTree
|
<!-- <ApiTree
|
||||||
|
@ -161,7 +163,13 @@
|
||||||
</a-input-group>
|
</a-input-group>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-form>
|
</a-form>
|
||||||
<RequestHeader v-model:params="form.headers" :no-param-type="true" />
|
<httpHeader
|
||||||
|
v-model:params="form.headers"
|
||||||
|
:layout="activeLayout"
|
||||||
|
:disabled-param-value="false"
|
||||||
|
:disabled-except-param="false"
|
||||||
|
:second-box-height="secondBoxHeight"
|
||||||
|
/>
|
||||||
</MsDrawer>
|
</MsDrawer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -170,13 +178,10 @@
|
||||||
import { Message } from '@arco-design/web-vue';
|
import { Message } from '@arco-design/web-vue';
|
||||||
|
|
||||||
import MsDrawer from '@/components/pure/ms-drawer/index.vue';
|
import MsDrawer from '@/components/pure/ms-drawer/index.vue';
|
||||||
import MsTableMoreAction from '@/components/pure/ms-table-more-action/index.vue';
|
|
||||||
import type { ActionsItem } from '@/components/pure/ms-table-more-action/types';
|
import type { ActionsItem } from '@/components/pure/ms-table-more-action/types';
|
||||||
import type { MsTreeNodeData } from '@/components/business/ms-tree/types';
|
import type { MsTreeNodeData } from '@/components/business/ms-tree/types';
|
||||||
import RequestHeader from '../../requestHeader/index.vue';
|
|
||||||
|
|
||||||
import { getEnvModules } from '@/api/modules/api-test/management';
|
import { getEnvModules } from '@/api/modules/api-test/management';
|
||||||
// import ApiTree from './apiTree.vue';
|
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
import { useAppStore } from '@/store';
|
import { useAppStore } from '@/store';
|
||||||
import useProjectEnvStore from '@/store/modules/setting/useProjectEnvStore';
|
import useProjectEnvStore from '@/store/modules/setting/useProjectEnvStore';
|
||||||
|
@ -186,6 +191,8 @@
|
||||||
import type { ModuleTreeNode } from '@/models/common';
|
import type { ModuleTreeNode } from '@/models/common';
|
||||||
import { HttpForm } from '@/models/projectManagement/environmental';
|
import { HttpForm } from '@/models/projectManagement/environmental';
|
||||||
|
|
||||||
|
const httpHeader = defineAsyncComponent(() => import('@/views/api-test/components/requestComposition/header.vue'));
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
currentId: string;
|
currentId: string;
|
||||||
isCopy: boolean;
|
isCopy: boolean;
|
||||||
|
@ -236,6 +243,8 @@
|
||||||
|
|
||||||
const form = ref<HttpForm>({ ...initForm });
|
const form = ref<HttpForm>({ ...initForm });
|
||||||
const hostType = ref<string>('http://');
|
const hostType = ref<string>('http://');
|
||||||
|
const secondBoxHeight = ref(0);
|
||||||
|
const activeLayout = ref<'horizontal' | 'vertical'>('vertical');
|
||||||
|
|
||||||
const httpRef = ref();
|
const httpRef = ref();
|
||||||
|
|
||||||
|
@ -307,22 +316,11 @@
|
||||||
store.currentEnvDetailInfo.config.httpConfig.push(httpItem);
|
store.currentEnvDetailInfo.config.httpConfig.push(httpItem);
|
||||||
}
|
}
|
||||||
emit('close');
|
emit('close');
|
||||||
|
resetForm();
|
||||||
};
|
};
|
||||||
|
|
||||||
const envTree = ref<ModuleTreeNode[]>([]);
|
const envTree = ref<ModuleTreeNode[]>([]);
|
||||||
|
|
||||||
const moreActions: ActionsItem[] = [
|
|
||||||
{
|
|
||||||
label: 'caseManagement.featureCase.copyStep',
|
|
||||||
eventTag: 'copyStep',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const selectedKeys = ref<string[]>([]);
|
|
||||||
const focusNodeKey = ref<string>('');
|
|
||||||
|
|
||||||
function handleMoreActionSelect(item: ActionsItem, node: MsTreeNodeData) {}
|
|
||||||
|
|
||||||
const title = ref<string>('');
|
const title = ref<string>('');
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
title.value = props.currentId ? t('project.environmental.http.edit') : t('project.environmental.http.add');
|
title.value = props.currentId ? t('project.environmental.http.edit') : t('project.environmental.http.add');
|
||||||
|
|
|
@ -145,7 +145,7 @@
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
});
|
});
|
||||||
|
|
||||||
const form = ref<DataSourceItem>({
|
const initForm = {
|
||||||
id: '',
|
id: '',
|
||||||
dataSource: '',
|
dataSource: '',
|
||||||
driverId: '',
|
driverId: '',
|
||||||
|
@ -154,6 +154,10 @@
|
||||||
password: '',
|
password: '',
|
||||||
poolMax: 1,
|
poolMax: 1,
|
||||||
timeout: 1000,
|
timeout: 1000,
|
||||||
|
};
|
||||||
|
|
||||||
|
const form = ref<DataSourceItem>({
|
||||||
|
...initForm,
|
||||||
});
|
});
|
||||||
|
|
||||||
const getDriverOption = async () => {
|
const getDriverOption = async () => {
|
||||||
|
@ -196,10 +200,6 @@
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const isXpack = computed(() => {
|
|
||||||
return licenseStore.hasLicense();
|
|
||||||
});
|
|
||||||
|
|
||||||
const formReset = () => {
|
const formReset = () => {
|
||||||
form.value = {
|
form.value = {
|
||||||
id: '',
|
id: '',
|
||||||
|
@ -250,6 +250,7 @@
|
||||||
};
|
};
|
||||||
store.currentEnvDetailInfo.config.dataSources.push(dataSourceItem);
|
store.currentEnvDetailInfo.config.dataSources.push(dataSourceItem);
|
||||||
}
|
}
|
||||||
|
formReset();
|
||||||
currentVisible.value = false;
|
currentVisible.value = false;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
</a-tabs>
|
</a-tabs>
|
||||||
<a-divider margin="0"></a-divider>
|
<a-divider margin="0"></a-divider>
|
||||||
<div v-if="activeTab === 'scenarioProcessorConfig'" class="h-[calc(100vh - 100px)] mt-4">
|
<div v-if="activeTab === 'scenarioProcessorConfig'" class="h-[calc(100vh - 100px)] mt-4">
|
||||||
<a-alert class="mb-4"> {{ t('project.environmental.sceneAlertDesc') }} </a-alert>
|
<a-alert class="mb-4" closable> {{ t('project.environmental.sceneAlertDesc') }} </a-alert>
|
||||||
<a-scrollbar
|
<a-scrollbar
|
||||||
:style="{
|
:style="{
|
||||||
overflow: 'auto',
|
overflow: 'auto',
|
||||||
|
@ -27,7 +27,7 @@
|
||||||
</a-scrollbar>
|
</a-scrollbar>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="activeTab === 'requestProcessorConfig'" class="mt-4 h-full">
|
<div v-if="activeTab === 'requestProcessorConfig'" class="mt-4 h-full">
|
||||||
<a-alert class="mb-4"> {{ t('project.environmental.requestAlertDesc') }} </a-alert>
|
<a-alert class="mb-4" closable> {{ t('project.environmental.requestAlertDesc') }} </a-alert>
|
||||||
<PreTab
|
<PreTab
|
||||||
v-if="props.activeType === 'pre'"
|
v-if="props.activeType === 'pre'"
|
||||||
:show-associated-scene="showAssociatedScene"
|
:show-associated-scene="showAssociatedScene"
|
||||||
|
|
|
@ -1,29 +1,20 @@
|
||||||
<template>
|
<template>
|
||||||
<div v-permission="['PROJECT_ENVIRONMENT:READ+UPDATE']" class="mb-[8px] flex items-center justify-between">
|
<httpHeader
|
||||||
<div class="font-medium">{{ t('apiTestDebug.header') }}</div>
|
|
||||||
<batchAddKeyVal :no-param-type="props.noParamType" :params="innerParams" @apply="handleBatchParamApply" />
|
|
||||||
</div>
|
|
||||||
<paramsTable
|
|
||||||
v-model:params="innerParams"
|
v-model:params="innerParams"
|
||||||
:selectable="true"
|
:layout="activeLayout"
|
||||||
:show-setting="false"
|
:disabled-param-value="props.disabledParamValue"
|
||||||
:columns="columns"
|
:disabled-except-param="props.disabledExceptParam"
|
||||||
:table-key="TableKeyEnum.PROJECT_MANAGEMENT_ENV_ALL_PARAM_HEADER"
|
:second-box-height="secondBoxHeight"
|
||||||
:default-param-item="defaultParamItem"
|
@change="emit('change')"
|
||||||
@change="handleParamTableChange"
|
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useVModel } from '@vueuse/core';
|
import { useVModel } from '@vueuse/core';
|
||||||
|
|
||||||
import batchAddKeyVal from '@/views/api-test/components/batchAddKeyVal.vue';
|
|
||||||
import paramsTable, { type ParamTableColumn } from '@/views/api-test/components/paramTable.vue';
|
|
||||||
|
|
||||||
import { responseHeaderOption } from '@/config/apiTest';
|
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
|
|
||||||
import { TableKeyEnum } from '@/enums/tableEnum';
|
const httpHeader = defineAsyncComponent(() => import('@/views/api-test/components/requestComposition/header.vue'));
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'EnvManangeGloblaRequestHeader',
|
name: 'EnvManangeGloblaRequestHeader',
|
||||||
|
@ -32,67 +23,17 @@
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
params: any[];
|
params: any[];
|
||||||
noParamType?: boolean;
|
noParamType?: boolean;
|
||||||
|
disabledParamValue?: boolean;
|
||||||
|
disabledExceptParam?: boolean; // 除了可以修改参数值其他都禁用
|
||||||
}>();
|
}>();
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: 'update:params', value: any[]): void;
|
(e: 'update:params', value: any[]): void;
|
||||||
(e: 'change'): void; // 数据发生变化
|
(e: 'change'): void; // 数据发生变化
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const { t } = useI18n();
|
|
||||||
|
|
||||||
const innerParams = useVModel(props, 'params', emit);
|
const innerParams = useVModel(props, 'params', emit);
|
||||||
const defaultParamItem = {
|
const secondBoxHeight = ref(0);
|
||||||
key: '',
|
const activeLayout = ref<'horizontal' | 'vertical'>('vertical');
|
||||||
value: '',
|
|
||||||
description: '',
|
|
||||||
};
|
|
||||||
|
|
||||||
const columns: ParamTableColumn[] = [
|
|
||||||
{
|
|
||||||
title: 'apiTestDebug.paramName',
|
|
||||||
dataIndex: 'key',
|
|
||||||
slotName: 'key',
|
|
||||||
permission: ['PROJECT_ENVIRONMENT:READ+UPDATE'],
|
|
||||||
inputType: 'autoComplete',
|
|
||||||
autoCompleteParams: responseHeaderOption,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'apiTestDebug.paramValue',
|
|
||||||
dataIndex: 'value',
|
|
||||||
slotName: 'value',
|
|
||||||
permission: ['PROJECT_ENVIRONMENT:READ+UPDATE'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'apiTestDebug.desc',
|
|
||||||
dataIndex: 'description',
|
|
||||||
slotName: 'description',
|
|
||||||
permission: ['PROJECT_ENVIRONMENT:READ+UPDATE'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '',
|
|
||||||
slotName: 'operation',
|
|
||||||
width: 50,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 批量参数代码转换为参数表格数据
|
|
||||||
*/
|
|
||||||
function handleBatchParamApply(resultArr: any[]) {
|
|
||||||
if (resultArr.length < innerParams.value.length) {
|
|
||||||
innerParams.value.splice(0, innerParams.value.length - 1, ...resultArr);
|
|
||||||
} else {
|
|
||||||
innerParams.value = [...resultArr, innerParams.value[innerParams.value.length - 1]];
|
|
||||||
}
|
|
||||||
emit('change');
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleParamTableChange(resultArr: any[], isInit?: boolean) {
|
|
||||||
innerParams.value = [...resultArr];
|
|
||||||
if (!isInit) {
|
|
||||||
emit('change');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped></style>
|
<style lang="less" scoped></style>
|
||||||
|
|
|
@ -126,4 +126,5 @@ export default {
|
||||||
'Deleting it will cause scenes that reference this environment group to fail to execute properly!',
|
'Deleting it will cause scenes that reference this environment group to fail to execute properly!',
|
||||||
'project.environmental.database.nameIsExist': 'Database name already exists',
|
'project.environmental.database.nameIsExist': 'Database name already exists',
|
||||||
'project.environmental.http.noneDataExist': 'There is already a domain name with an enabled range of none!',
|
'project.environmental.http.noneDataExist': 'There is already a domain name with an enabled range of none!',
|
||||||
|
'project.environmental.http.selectModule': 'Please select module',
|
||||||
};
|
};
|
||||||
|
|
|
@ -130,4 +130,5 @@ export default {
|
||||||
'project.environmental.env.deleteGroupTip': '删除后会导致引用此环境组的场景无法正常执行',
|
'project.environmental.env.deleteGroupTip': '删除后会导致引用此环境组的场景无法正常执行',
|
||||||
'project.environmental.database.nameIsExist': '数据源名称已存在',
|
'project.environmental.database.nameIsExist': '数据源名称已存在',
|
||||||
'project.environmental.http.noneDataExist': '已存在启用范围为无的域名!',
|
'project.environmental.http.noneDataExist': '已存在启用范围为无的域名!',
|
||||||
|
'project.environmental.http.selectModule': '请选择模块',
|
||||||
};
|
};
|
||||||
|
|
|
@ -200,6 +200,7 @@
|
||||||
resetForm();
|
resetForm();
|
||||||
};
|
};
|
||||||
const handlePlatformChange = async (value: SelectValue) => {
|
const handlePlatformChange = async (value: SelectValue) => {
|
||||||
|
platformRules.value = [];
|
||||||
try {
|
try {
|
||||||
if (value) {
|
if (value) {
|
||||||
const res = await getPlatformInfo(value as string, MenuEnum.bugManagement);
|
const res = await getPlatformInfo(value as string, MenuEnum.bugManagement);
|
||||||
|
|
|
@ -171,15 +171,17 @@
|
||||||
title: 'project.taskCenter.resourceID',
|
title: 'project.taskCenter.resourceID',
|
||||||
dataIndex: 'resourceId',
|
dataIndex: 'resourceId',
|
||||||
slotName: 'resourceId',
|
slotName: 'resourceId',
|
||||||
width: 300,
|
width: 200,
|
||||||
showInTable: true,
|
showInTable: true,
|
||||||
|
showTooltip: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'project.taskCenter.resourceName',
|
title: 'project.taskCenter.resourceName',
|
||||||
slotName: 'resourceName',
|
slotName: 'resourceName',
|
||||||
dataIndex: 'resourceName',
|
dataIndex: 'resourceName',
|
||||||
width: 200,
|
width: 300,
|
||||||
showDrag: true,
|
showDrag: true,
|
||||||
|
showTooltip: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'project.taskCenter.executionResult',
|
title: 'project.taskCenter.executionResult',
|
||||||
|
@ -203,16 +205,16 @@
|
||||||
slotName: 'poolName',
|
slotName: 'poolName',
|
||||||
dataIndex: 'poolName',
|
dataIndex: 'poolName',
|
||||||
showInTable: true,
|
showInTable: true,
|
||||||
width: 200,
|
|
||||||
showDrag: true,
|
showDrag: true,
|
||||||
|
showTooltip: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'project.taskCenter.operator',
|
title: 'project.taskCenter.operator',
|
||||||
slotName: 'operationName',
|
slotName: 'operationName',
|
||||||
dataIndex: 'operationName',
|
dataIndex: 'operationName',
|
||||||
showInTable: true,
|
showInTable: true,
|
||||||
width: 300,
|
|
||||||
showDrag: true,
|
showDrag: true,
|
||||||
|
showTooltip: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'project.taskCenter.operating',
|
title: 'project.taskCenter.operating',
|
||||||
|
@ -367,7 +369,7 @@
|
||||||
showDetailDrawer.value = true;
|
showDetailDrawer.value = true;
|
||||||
}
|
}
|
||||||
activeDetailId.value = id;
|
activeDetailId.value = id;
|
||||||
activeReportIndex.value = rowIndex;
|
activeReportIndex.value = rowIndex - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
|
|
|
@ -78,6 +78,7 @@
|
||||||
slotName: 'resourceNum',
|
slotName: 'resourceNum',
|
||||||
width: 300,
|
width: 300,
|
||||||
showInTable: true,
|
showInTable: true,
|
||||||
|
showTooltip: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'project.taskCenter.resourceName',
|
title: 'project.taskCenter.resourceName',
|
||||||
|
@ -85,6 +86,7 @@
|
||||||
dataIndex: 'resourceName',
|
dataIndex: 'resourceName',
|
||||||
width: 200,
|
width: 200,
|
||||||
showDrag: true,
|
showDrag: true,
|
||||||
|
showTooltip: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'project.taskCenter.resourceClassification',
|
title: 'project.taskCenter.resourceClassification',
|
||||||
|
@ -93,6 +95,7 @@
|
||||||
showInTable: true,
|
showInTable: true,
|
||||||
width: 150,
|
width: 150,
|
||||||
showDrag: true,
|
showDrag: true,
|
||||||
|
showTooltip: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'project.taskCenter.operationRule',
|
title: 'project.taskCenter.operationRule',
|
||||||
|
@ -101,6 +104,7 @@
|
||||||
showInTable: true,
|
showInTable: true,
|
||||||
width: 150,
|
width: 150,
|
||||||
showDrag: true,
|
showDrag: true,
|
||||||
|
showTooltip: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'project.taskCenter.operator',
|
title: 'project.taskCenter.operator',
|
||||||
|
@ -109,6 +113,7 @@
|
||||||
showInTable: true,
|
showInTable: true,
|
||||||
width: 200,
|
width: 200,
|
||||||
showDrag: true,
|
showDrag: true,
|
||||||
|
showTooltip: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'project.taskCenter.operating',
|
title: 'project.taskCenter.operating',
|
||||||
|
|
Loading…
Reference in New Issue