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