feat(项目管理): 环境管理相关问题修复和调整交互
This commit is contained in:
parent
44f998dc25
commit
fdabab9052
|
@ -36,4 +36,9 @@ export function reportBathDelete(moduleType: string, data: TableQueryParams) {
|
||||||
return MSR.post({ url: reportUrl.ApiBatchDeleteUrl, data });
|
return MSR.post({ url: reportUrl.ApiBatchDeleteUrl, data });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 报告详情
|
||||||
|
export function reportDetail(reportId: string) {
|
||||||
|
return MSR.get<Record<string, any>>({ url: `${reportUrl.ScenarioReportDetailUrl}/${reportId}` });
|
||||||
|
}
|
||||||
|
|
||||||
export default {};
|
export default {};
|
||||||
|
|
|
@ -88,6 +88,10 @@ export function groupDeleteEnv(data: EnvListItem) {
|
||||||
export function groupProjectEnv(organizationId: string) {
|
export function groupProjectEnv(organizationId: string) {
|
||||||
return MSR.get<ProjectOptionItem[]>({ url: envURL.groupProjectEnvUrl + organizationId });
|
return MSR.get<ProjectOptionItem[]>({ url: envURL.groupProjectEnvUrl + organizationId });
|
||||||
}
|
}
|
||||||
|
// 获取项目组的项目
|
||||||
|
export function groupCategoryEnvList(projectId: string) {
|
||||||
|
return MSR.get<ProjectOptionItem[]>({ url: `${envURL.getProjectEnvCategoryUrl}/${projectId}` });
|
||||||
|
}
|
||||||
|
|
||||||
/** 项目管理-环境-全局参数-更新or新增 */
|
/** 项目管理-环境-全局参数-更新or新增 */
|
||||||
export function updateOrAddGlobalParam(data: GlobalParams) {
|
export function updateOrAddGlobalParam(data: GlobalParams) {
|
||||||
|
|
|
@ -15,3 +15,6 @@ export const ApiReportRenameUrl = '/api/report/case/rename';
|
||||||
export const ApiDeleteUrl = '/api/report/case/delete';
|
export const ApiDeleteUrl = '/api/report/case/delete';
|
||||||
// 批量删除接口用例报告
|
// 批量删除接口用例报告
|
||||||
export const ApiBatchDeleteUrl = '/api/report/case/batch/delete';
|
export const ApiBatchDeleteUrl = '/api/report/case/batch/delete';
|
||||||
|
|
||||||
|
// 场景报告拔高详情获取
|
||||||
|
export const ScenarioReportDetailUrl = '/api/report/scenario/get';
|
||||||
|
|
|
@ -24,3 +24,5 @@ export const addGlobalParamUrl = '/project/global/params/add';
|
||||||
export const importGlobalParamUrl = '/project/global/params/import';
|
export const importGlobalParamUrl = '/project/global/params/import';
|
||||||
export const detailGlobalParamUrl = '/project/global/params/get/';
|
export const detailGlobalParamUrl = '/project/global/params/get/';
|
||||||
export const exportGlobalParamUrl = '/project/global/params/export/';
|
export const exportGlobalParamUrl = '/project/global/params/export/';
|
||||||
|
// 获取环境目录列表
|
||||||
|
export const getProjectEnvCategoryUrl = '/project/environment/get-options';
|
||||||
|
|
|
@ -386,7 +386,6 @@
|
||||||
getCurrentItemState.value =
|
getCurrentItemState.value =
|
||||||
assertions.value.find((item: any) => item.id === activeKey.value) || assertions.value[0] || {};
|
assertions.value.find((item: any) => item.id === activeKey.value) || assertions.value[0] || {};
|
||||||
activeKey.value = getCurrentItemState.value.id;
|
activeKey.value = getCurrentItemState.value.id;
|
||||||
console.log(getCurrentItemState.value, 'getCurrentItemState.value');
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -372,9 +372,10 @@ export default defineComponent(
|
||||||
}
|
}
|
||||||
emit('update:modelValue', value);
|
emit('update:modelValue', value);
|
||||||
emit('change', value);
|
emit('change', value);
|
||||||
|
|
||||||
emit(
|
emit(
|
||||||
'changeObject',
|
'changeObject',
|
||||||
remoteOriginOptions.value.filter((e) => value === e[props.valueKey || 'value'])
|
remoteOriginOptions.value.find((e) => value === e[props.valueKey || 'value'])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -73,7 +73,7 @@
|
||||||
function selectItem(index: any) {
|
function selectItem(index: any) {
|
||||||
const item = props.items[index];
|
const item = props.items[index];
|
||||||
if (item) {
|
if (item) {
|
||||||
props.command({ id: item.id, label: `${item.name}` } as any);
|
props.command({ id: item.id, label: `${item.name}`, style: 'color:blur' } as any);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -77,7 +77,7 @@
|
||||||
const isError = computed(
|
const isError = computed(
|
||||||
() =>
|
() =>
|
||||||
innerInputValue.value.length > props.maxLength ||
|
innerInputValue.value.length > props.maxLength ||
|
||||||
innerModelValue.value.some((item) => item.toString().length > props.maxLength)
|
(innerModelValue.value || []).some((item) => item.toString().length > props.maxLength)
|
||||||
);
|
);
|
||||||
watch(
|
watch(
|
||||||
() => props.modelValue,
|
() => props.modelValue,
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
size="16"
|
size="16"
|
||||||
/>
|
/>
|
||||||
<template #content>
|
<template #content>
|
||||||
<div>{{ t('apiTestDebug.batchAddParamsTip1') }}</div>
|
<div>{{ props?.addTypeText || t('apiTestDebug.batchAddParamsTip1') }}</div>
|
||||||
<div v-if="!props.noParamType">{{ t('apiTestDebug.batchAddParamsTip2') }}</div>
|
<div v-if="!props.noParamType">{{ t('apiTestDebug.batchAddParamsTip2') }}</div>
|
||||||
<div>{{ t('apiTestDebug.batchAddParamsTip3') }}</div>
|
<div>{{ t('apiTestDebug.batchAddParamsTip3') }}</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -53,6 +53,7 @@
|
||||||
params: Record<string, any>[];
|
params: Record<string, any>[];
|
||||||
defaultParamItem?: Record<string, any>; // 默认参数项
|
defaultParamItem?: Record<string, any>; // 默认参数项
|
||||||
noParamType?: boolean; // 是否有参数类型
|
noParamType?: boolean; // 是否有参数类型
|
||||||
|
addTypeText?: string; // 添加类型文案
|
||||||
}>(),
|
}>(),
|
||||||
{
|
{
|
||||||
noParamType: false,
|
noParamType: false,
|
||||||
|
|
|
@ -138,7 +138,7 @@
|
||||||
{{ t('common.clear') }}
|
{{ t('common.clear') }}
|
||||||
</a-button>
|
</a-button>
|
||||||
<a-button
|
<a-button
|
||||||
v-if="!props.isBuildIn"
|
v-if="!props.isBuildIn && !props.showPrePostRequest"
|
||||||
type="outline"
|
type="outline"
|
||||||
class="arco-btn-outline--secondary p-[0_8px]"
|
class="arco-btn-outline--secondary p-[0_8px]"
|
||||||
size="mini"
|
size="mini"
|
||||||
|
|
|
@ -211,7 +211,7 @@
|
||||||
<template #tag="{ record, columnConfig, rowIndex }">
|
<template #tag="{ record, columnConfig, rowIndex }">
|
||||||
<a-popover
|
<a-popover
|
||||||
position="tl"
|
position="tl"
|
||||||
:disabled="record[columnConfig.dataIndex as string].length === 0"
|
:disabled="(record[columnConfig.dataIndex as string]||[]).length === 0"
|
||||||
class="ms-params-input-popover"
|
class="ms-params-input-popover"
|
||||||
>
|
>
|
||||||
<template #content>
|
<template #content>
|
||||||
|
@ -307,15 +307,13 @@
|
||||||
<template #arrow-icon>
|
<template #arrow-icon>
|
||||||
<icon-caret-down />
|
<icon-caret-down />
|
||||||
</template>
|
</template>
|
||||||
<a-tooltip
|
|
||||||
v-for="project of appStore.projectList"
|
<a-tooltip v-for="project of disProjectList" :key="project.id" :mouse-enter-delay="500" :content="project.name">
|
||||||
:key="project.id"
|
|
||||||
:mouse-enter-delay="500"
|
|
||||||
:content="project.name"
|
|
||||||
>
|
|
||||||
<a-option
|
<a-option
|
||||||
|
:key="project.id"
|
||||||
:value="project.id"
|
:value="project.id"
|
||||||
:class="project.id === appStore.currentProjectId ? 'arco-select-option-selected' : ''"
|
:class="project.id === appStore.currentProjectId ? 'arco-select-option-selected' : ''"
|
||||||
|
:disabled="project.disabled"
|
||||||
>
|
>
|
||||||
{{ project.name }}
|
{{ project.name }}
|
||||||
</a-option>
|
</a-option>
|
||||||
|
@ -343,17 +341,13 @@
|
||||||
<span v-else></span>
|
<span v-else></span>
|
||||||
</template>
|
</template>
|
||||||
<template #host="{ record }">
|
<template #host="{ record }">
|
||||||
<span v-if="!record.domain || record.domain.length === 0"></span>
|
<MsTagGroup
|
||||||
<span v-else-if="Array.isArray(record.domain) && record.domain.length === 1" class="text-[var(--color-text-4)]">{{
|
v-if="Array.isArray(record.domain)"
|
||||||
record.domain[0].protocol + '://' + (record.domain[0].hostname || '')
|
:tag-list="getDomain(record.domain)"
|
||||||
}}</span>
|
size="small"
|
||||||
<span
|
|
||||||
v-if="Array.isArray(record.domain) && record.domain.length > 1"
|
|
||||||
class="cursor-pointer text-[var(--color-text-4)]"
|
|
||||||
@click="showHostModal(record)"
|
@click="showHostModal(record)"
|
||||||
>
|
/>
|
||||||
{{ t('common.more') }}
|
<div v-else class="text-[var(--color-text-1)]">{{ '-' }}</div>
|
||||||
</span>
|
|
||||||
</template>
|
</template>
|
||||||
<template #operation="{ record, rowIndex, columnConfig }">
|
<template #operation="{ record, rowIndex, columnConfig }">
|
||||||
<div class="flex flex-row items-center" :class="{ 'justify-end': columnConfig.align === 'right' }">
|
<div class="flex flex-row items-center" :class="{ 'justify-end': columnConfig.align === 'right' }">
|
||||||
|
@ -450,9 +444,10 @@
|
||||||
:max-length="1000"
|
:max-length="1000"
|
||||||
></a-textarea>
|
></a-textarea>
|
||||||
</a-modal>
|
</a-modal>
|
||||||
<a-modal v-model:visible="hostVisible" :title="t('project.environmental.host')" @close="hostModalClose">
|
<!-- <a-modal v-model:visible="hostVisible" :title="t('project.environmental.host')" @close="hostModalClose">
|
||||||
<a-table :columns="hostColumn" :data="hostData" />
|
<a-table :columns="hostColumn" :data="hostData" />
|
||||||
</a-modal>
|
</a-modal> -->
|
||||||
|
<DomainModal v-model:visible="hostVisible" :data="hostData" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script async setup lang="ts">
|
<script async setup lang="ts">
|
||||||
|
@ -464,18 +459,20 @@
|
||||||
import MsFormTable, { FormTableColumn } from '@/components/pure/ms-form-table/index.vue';
|
import MsFormTable, { FormTableColumn } from '@/components/pure/ms-form-table/index.vue';
|
||||||
import MsTableMoreAction from '@/components/pure/ms-table-more-action/index.vue';
|
import MsTableMoreAction from '@/components/pure/ms-table-more-action/index.vue';
|
||||||
import { ActionsItem } from '@/components/pure/ms-table-more-action/types';
|
import { ActionsItem } from '@/components/pure/ms-table-more-action/types';
|
||||||
|
import MsTagGroup from '@/components/pure/ms-tag/ms-tag-group.vue';
|
||||||
import MsTagsGroup from '@/components/pure/ms-tag/ms-tag-group.vue';
|
import MsTagsGroup from '@/components/pure/ms-tag/ms-tag-group.vue';
|
||||||
import MsTagsInput from '@/components/pure/ms-tags-input/index.vue';
|
import MsTagsInput from '@/components/pure/ms-tags-input/index.vue';
|
||||||
import { MsFileItem } from '@/components/pure/ms-upload/types';
|
import { MsFileItem } from '@/components/pure/ms-upload/types';
|
||||||
import MsSelect from '@/components/business/ms-select/index';
|
import MsSelect from '@/components/business/ms-select/index';
|
||||||
import paramDescInput from './paramDescInput.vue';
|
import paramDescInput from './paramDescInput.vue';
|
||||||
|
import DomainModal from '@/views/project-management/environmental/components/envParams/popUp/domain.vue';
|
||||||
|
|
||||||
import { groupProjectEnv, listEnv } from '@/api/modules/project-management/envManagement';
|
import { groupCategoryEnvList, groupProjectEnv } from '@/api/modules/project-management/envManagement';
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
import useAppStore from '@/store/modules/app';
|
import useAppStore from '@/store/modules/app';
|
||||||
|
|
||||||
import { ModuleTreeNode, TransferFileParams } from '@/models/common';
|
import { ModuleTreeNode, TransferFileParams } from '@/models/common';
|
||||||
import { ProjectOptionItem } from '@/models/projectManagement/environmental';
|
import { HttpForm, ProjectOptionItem } from '@/models/projectManagement/environmental';
|
||||||
import { RequestBodyFormat, RequestContentTypeEnum, RequestParamsType } from '@/enums/apiEnum';
|
import { RequestBodyFormat, RequestContentTypeEnum, RequestParamsType } from '@/enums/apiEnum';
|
||||||
import { TableKeyEnum } from '@/enums/tableEnum';
|
import { TableKeyEnum } from '@/enums/tableEnum';
|
||||||
|
|
||||||
|
@ -645,15 +642,18 @@
|
||||||
const res = await groupProjectEnv(appStore.currentOrgId);
|
const res = await groupProjectEnv(appStore.currentOrgId);
|
||||||
sourceProjectOptions.value = res;
|
sourceProjectOptions.value = res;
|
||||||
};
|
};
|
||||||
|
// 获取所有环境目录
|
||||||
|
const envDomainList = ref<ProjectOptionItem[]>([]);
|
||||||
// 获取环境的options
|
// 获取环境的options
|
||||||
const initEnvOptions = async (params: Record<string, any>) => {
|
const initEnvOptions = async (params: Record<string, any>) => {
|
||||||
const { projectId, keyword } = params;
|
const { projectId } = params;
|
||||||
const res = await listEnv({ projectId, keyword });
|
const res = await groupCategoryEnvList(projectId);
|
||||||
|
envDomainList.value = res;
|
||||||
return res;
|
return res;
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleEnvironment = (obj: Record<string, any>, record: Record<string, any>) => {
|
const handleEnvironment = (obj: Record<string, any>, record: Record<string, any>) => {
|
||||||
record.domain = {};
|
record.domain = obj.domain;
|
||||||
emitChange('handleEnvironment');
|
emitChange('handleEnvironment');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -663,6 +663,8 @@
|
||||||
{
|
{
|
||||||
title: t('project.environmental.http.host'),
|
title: t('project.environmental.http.host'),
|
||||||
dataIndex: 'host',
|
dataIndex: 'host',
|
||||||
|
showTooltip: true,
|
||||||
|
width: 300,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t('project.environmental.http.desc'),
|
title: t('project.environmental.http.desc'),
|
||||||
|
@ -672,10 +674,6 @@
|
||||||
|
|
||||||
const showHostModal = (record: Record<string, any>) => {
|
const showHostModal = (record: Record<string, any>) => {
|
||||||
hostVisible.value = true;
|
hostVisible.value = true;
|
||||||
record.domain?.forEach((e: any) => {
|
|
||||||
e.host = `${e.protocol} :// ${e.hostname || ''}`;
|
|
||||||
});
|
|
||||||
|
|
||||||
hostData.value = record.domain || [];
|
hostData.value = record.domain || [];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -899,6 +897,29 @@
|
||||||
addTableLine(rowIndex);
|
addTableLine(rowIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const disProjectList = computed(() => {
|
||||||
|
const selectProjectIds = (props.params || []).map((item) => item.projectId).filter((item) => item);
|
||||||
|
return appStore.projectList.map((item: any) => {
|
||||||
|
if (selectProjectIds.includes(item.id)) {
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
disabled: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
function getDomain(domain: HttpForm[]) {
|
||||||
|
return (domain || []).map((item: any) => {
|
||||||
|
return {
|
||||||
|
id: item.id,
|
||||||
|
name: item.hostname,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
addTableLine,
|
addTableLine,
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,205 @@
|
||||||
|
<template>
|
||||||
|
<MsDetailDrawer
|
||||||
|
ref="detailDrawerRef"
|
||||||
|
v-model:visible="showDrawer"
|
||||||
|
:width="960"
|
||||||
|
:footer="false"
|
||||||
|
:title="t('project.fileManagement.detail')"
|
||||||
|
:detail-id="props.reportId"
|
||||||
|
:detail-index="props.activeReportIndex"
|
||||||
|
:get-detail-func="reportDetail"
|
||||||
|
:pagination="props.pagination"
|
||||||
|
:table-data="props.tableData"
|
||||||
|
:page-change="props.pageChange"
|
||||||
|
show-full-screen
|
||||||
|
:unmount-on-close="true"
|
||||||
|
@loaded="loadedReport"
|
||||||
|
>
|
||||||
|
<template #titleRight="{ loading }">
|
||||||
|
<div class="rightButtons flex items-center">
|
||||||
|
<MsButton
|
||||||
|
type="icon"
|
||||||
|
status="secondary"
|
||||||
|
class="mr-4 !rounded-[var(--border-radius-small)]"
|
||||||
|
:disabled="loading"
|
||||||
|
:loading="shareLoading"
|
||||||
|
@click="shareHandler"
|
||||||
|
>
|
||||||
|
<MsIcon type="icon-icon_share1" class="mr-2 font-[16px]" />
|
||||||
|
{{ t('common.share') }}
|
||||||
|
</MsButton>
|
||||||
|
<MsButton
|
||||||
|
type="icon"
|
||||||
|
status="secondary"
|
||||||
|
class="mr-4 !rounded-[var(--border-radius-small)]"
|
||||||
|
:disabled="loading"
|
||||||
|
:loading="exportLoading"
|
||||||
|
@click="exportHandler"
|
||||||
|
>
|
||||||
|
<MsIcon type="icon-icon_move_outlined" class="mr-2 font-[16px]" />
|
||||||
|
{{ t('common.export') }}
|
||||||
|
</MsButton>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #default>
|
||||||
|
<div class="report-container h-full">
|
||||||
|
<!-- 报告参数开始 -->
|
||||||
|
<div class="report-header flex items-center justify-between">
|
||||||
|
<!-- TODO 虚拟数据替换接口后边 -->
|
||||||
|
<span>
|
||||||
|
dev环境
|
||||||
|
<a-divider direction="vertical" :margin="4"></a-divider>
|
||||||
|
66 资源池
|
||||||
|
<a-divider direction="vertical" :margin="4"></a-divider>
|
||||||
|
1000ms
|
||||||
|
<a-divider direction="vertical" :margin="4"></a-divider>
|
||||||
|
admin
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
<span class="text-[var(--color-text-4)]">执行时间</span>
|
||||||
|
2023-08-10 17:53:03
|
||||||
|
<span class="text-[var(--color-text-4)]">至</span>
|
||||||
|
2023-08-10 17:53:03
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<!-- 报告参数结束 -->
|
||||||
|
<!-- 报告步骤分析和请求分析开始 -->
|
||||||
|
<div class="analyze">
|
||||||
|
<div class="step-analyze min-w-[522px]">
|
||||||
|
<div class="block-title">步骤分析</div>
|
||||||
|
<div class="mb-2 flex items-center">
|
||||||
|
<!-- 总数 -->
|
||||||
|
<div class="countItem">
|
||||||
|
<span class="mr-2 text-[var(--color-text-4)]"> {{ t('report.detail.stepTotal') }}</span>
|
||||||
|
{{ reportStepDetail.stepTotal }}
|
||||||
|
</div>
|
||||||
|
<!-- 通过 -->
|
||||||
|
<div class="countItem">
|
||||||
|
<div class="mb-[2px] mr-[4px] h-[6px] w-[6px] rounded-full bg-[rgb(var(--success-6))]"></div>
|
||||||
|
<div class="mr-2 text-[var(--color-text-4)]">{{ t('report.detail.successCount') }}</div>
|
||||||
|
{{ reportStepDetail.successCount }}
|
||||||
|
</div>
|
||||||
|
<!-- 误报 -->
|
||||||
|
<div class="countItem">
|
||||||
|
<div class="mb-[2px] mr-[4px] h-[6px] w-[6px] rounded-full bg-[rgb(var(--warning-6))]"></div>
|
||||||
|
<div class="mr-2 text-[var(--color-text-4)]">{{ t('report.detail.fakeErrorCount') }}</div>
|
||||||
|
{{ reportStepDetail.fakeErrorCount }}
|
||||||
|
</div>
|
||||||
|
<!-- 失败 -->
|
||||||
|
<div class="countItem">
|
||||||
|
<div class="mb-[2px] mr-[4px] h-[6px] w-[6px] rounded-full bg-[rgb(var(--danger-6))]"></div>
|
||||||
|
<div class="mr-2 text-[var(--color-text-4)]">{{ t('report.detail.errorCount') }}</div>
|
||||||
|
{{ reportStepDetail.errorCount }}
|
||||||
|
</div>
|
||||||
|
<!-- 未执行 -->
|
||||||
|
<div class="countItem">
|
||||||
|
<div class="mb-[2px] mr-[4px] h-[6px] w-[6px] rounded-full bg-[var(--color-text-input-border)]"></div>
|
||||||
|
<div class="mr-2 text-[var(--color-text-4)]">{{ t('report.detail.pendingCount') }}</div>
|
||||||
|
{{ reportStepDetail.pendingCount }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<StepProgress :report-detail="reportStepDetail" height="8px" radius="var(--border-radius-mini)" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="request-analyze"></div>
|
||||||
|
</div>
|
||||||
|
<!-- 报告步骤分析和请求分析结束 -->
|
||||||
|
<!-- 报告明细开始 -->
|
||||||
|
<div class="report-info"></div>
|
||||||
|
<!-- 报告明细结束 -->
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</MsDetailDrawer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
|
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||||
|
import type { MsPaginationI } from '@/components/pure/ms-table/type';
|
||||||
|
import MsDetailDrawer from '@/components/business/ms-detail-drawer/index.vue';
|
||||||
|
import StepProgress from './stepProgress.vue';
|
||||||
|
|
||||||
|
import { reportDetail } from '@/api/modules/api-test/report';
|
||||||
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const props = defineProps<{
|
||||||
|
visible: boolean;
|
||||||
|
reportId: string;
|
||||||
|
activeReportIndex: number;
|
||||||
|
tableData: any[];
|
||||||
|
pagination: MsPaginationI;
|
||||||
|
pageChange: (page: number) => Promise<void>;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'update:visible', val: boolean): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const showDrawer = computed({
|
||||||
|
get() {
|
||||||
|
return props.visible;
|
||||||
|
},
|
||||||
|
set(val) {
|
||||||
|
emit('update:visible', val);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const innerFileId = ref(props.reportId);
|
||||||
|
function loadedReport(detail: Record<string, any>) {
|
||||||
|
innerFileId.value = detail.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分享share
|
||||||
|
*/
|
||||||
|
const shareLoading = ref<boolean>(false);
|
||||||
|
function shareHandler() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导出
|
||||||
|
*/
|
||||||
|
const exportLoading = ref<boolean>(false);
|
||||||
|
function exportHandler() {}
|
||||||
|
|
||||||
|
const reportStepDetail = ref({
|
||||||
|
stepTotal: 8,
|
||||||
|
errorCount: 2,
|
||||||
|
fakeErrorCount: 8,
|
||||||
|
pendingCount: 9,
|
||||||
|
successCount: 9,
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="less">
|
||||||
|
.report-container {
|
||||||
|
padding: 16px;
|
||||||
|
height: calc(100vh - 56px);
|
||||||
|
background: var(--color-text-n9);
|
||||||
|
.report-header {
|
||||||
|
padding: 0 16px;
|
||||||
|
height: 54px;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: white;
|
||||||
|
@apply mb-4 bg-white;
|
||||||
|
}
|
||||||
|
.analyze {
|
||||||
|
padding: 16px;
|
||||||
|
min-height: 196px;
|
||||||
|
border-radius: 4px;
|
||||||
|
@apply flex justify-between bg-white;
|
||||||
|
.step-analyze {
|
||||||
|
@apply mb-4 h-full;
|
||||||
|
.countItem {
|
||||||
|
@apply mr-6 flex items-center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.request-analyze {
|
||||||
|
@apply h-full;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.block-title {
|
||||||
|
@apply mb-4 font-medium;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -24,6 +24,11 @@
|
||||||
v-on="propsEvent"
|
v-on="propsEvent"
|
||||||
@batch-action="handleTableBatch"
|
@batch-action="handleTableBatch"
|
||||||
>
|
>
|
||||||
|
<template #name="{ record, rowIndex }">
|
||||||
|
<a-button type="text" class="flex w-full" @click="showReportDetail(record.id, rowIndex)">{{
|
||||||
|
record.name
|
||||||
|
}}</a-button>
|
||||||
|
</template>
|
||||||
<!-- 报告类型 -->
|
<!-- 报告类型 -->
|
||||||
<template #integrated="{ record }">
|
<template #integrated="{ record }">
|
||||||
<MsTag theme="light" :type="record.integrated ? 'primary' : undefined">
|
<MsTag theme="light" :type="record.integrated ? 'primary' : undefined">
|
||||||
|
@ -101,6 +106,14 @@
|
||||||
>
|
>
|
||||||
</template>
|
</template>
|
||||||
</ms-base-table>
|
</ms-base-table>
|
||||||
|
<ReportDetailDrawer
|
||||||
|
v-model:visible="showDetailDrawer"
|
||||||
|
:report-id="activeDetailId"
|
||||||
|
:active-report-index="activeReportIndex"
|
||||||
|
:table-data="propsRes.data"
|
||||||
|
:page-change="propsEvent.pageChange"
|
||||||
|
:pagination="propsRes.msPagination!"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -114,6 +127,7 @@
|
||||||
import type { BatchActionParams, BatchActionQueryParams, MsTableColumn } from '@/components/pure/ms-table/type';
|
import type { BatchActionParams, BatchActionQueryParams, MsTableColumn } from '@/components/pure/ms-table/type';
|
||||||
import useTable from '@/components/pure/ms-table/useTable';
|
import useTable from '@/components/pure/ms-table/useTable';
|
||||||
import MsTag from '@/components/pure/ms-tag/ms-tag.vue';
|
import MsTag from '@/components/pure/ms-tag/ms-tag.vue';
|
||||||
|
import ReportDetailDrawer from './reportDetailDrawer.vue';
|
||||||
import ExecutionStatus from '@/views/api-test/report/component/reportStatus.vue';
|
import ExecutionStatus from '@/views/api-test/report/component/reportStatus.vue';
|
||||||
|
|
||||||
import { reportBathDelete, reportDelete, reportList, reportRename } from '@/api/modules/api-test/report';
|
import { reportBathDelete, reportDelete, reportList, reportRename } from '@/api/modules/api-test/report';
|
||||||
|
@ -361,6 +375,18 @@
|
||||||
initData();
|
initData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 报告详情 showReportDetail
|
||||||
|
*/
|
||||||
|
const activeDetailId = ref<string>('');
|
||||||
|
const activeReportIndex = ref<number>(0);
|
||||||
|
const showDetailDrawer = ref<boolean>(false);
|
||||||
|
function showReportDetail(id: string, rowIndex: number) {
|
||||||
|
showDetailDrawer.value = true;
|
||||||
|
activeDetailId.value = id;
|
||||||
|
activeReportIndex.value = rowIndex;
|
||||||
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.moduleType,
|
() => props.moduleType,
|
||||||
(val) => {
|
(val) => {
|
||||||
|
|
|
@ -0,0 +1,116 @@
|
||||||
|
<template>
|
||||||
|
<MsColorLine :color-data="colorData" :height="props.height" :radius="props.radius">
|
||||||
|
<template #popoverContent>
|
||||||
|
<table class="min-w-[144px]">
|
||||||
|
<tr>
|
||||||
|
<td class="popover-label-td">
|
||||||
|
<div class="mb-[2px] mr-[4px] h-[6px] w-[6px] rounded-full bg-[rgb(var(--success-6))]"></div>
|
||||||
|
<div>{{ t('report.detail.successCount') }}</div>
|
||||||
|
</td>
|
||||||
|
<td class="popover-value-td">
|
||||||
|
{{ props.reportDetail.successCount }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="popover-label-td">
|
||||||
|
<div class="mb-[2px] mr-[4px] h-[6px] w-[6px] rounded-full bg-[rgb(var(--warning-6))]"></div>
|
||||||
|
<div>{{ t('report.detail.fakeErrorCount') }}</div>
|
||||||
|
</td>
|
||||||
|
<td class="popover-value-td">
|
||||||
|
{{ props.reportDetail.fakeErrorCount }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="popover-label-td">
|
||||||
|
<div class="mb-[2px] mr-[4px] h-[6px] w-[6px] rounded-full bg-[rgb(var(--danger-6))]"></div>
|
||||||
|
<div>{{ t('report.detail.errorCount') }}</div>
|
||||||
|
</td>
|
||||||
|
<td class="popover-value-td">
|
||||||
|
{{ props.reportDetail.errorCount }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="popover-label-td">
|
||||||
|
<div class="mb-[2px] mr-[4px] h-[6px] w-[6px] rounded-full bg-[var(--color-text-input-border)]"></div>
|
||||||
|
<div>{{ t('report.detail.pendingCount') }}</div>
|
||||||
|
</td>
|
||||||
|
<td class="popover-value-td">
|
||||||
|
{{ props.reportDetail.pendingCount }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</template>
|
||||||
|
</MsColorLine>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
|
import MsColorLine from '@/components/pure/ms-color-line/index.vue';
|
||||||
|
|
||||||
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
reportDetail: {
|
||||||
|
stepTotal: number;
|
||||||
|
errorCount: number;
|
||||||
|
fakeErrorCount: number;
|
||||||
|
pendingCount: number;
|
||||||
|
successCount: number;
|
||||||
|
[key: string]: any;
|
||||||
|
};
|
||||||
|
height: string;
|
||||||
|
radius?: string;
|
||||||
|
}>();
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
const colorData = computed(() => {
|
||||||
|
if (
|
||||||
|
props.reportDetail.status === 'ERROR' ||
|
||||||
|
(props.reportDetail.successCount === 0 &&
|
||||||
|
props.reportDetail.errorCount === 0 &&
|
||||||
|
props.reportDetail.fakeErrorCount === 0 &&
|
||||||
|
props.reportDetail.pendingCount === 0)
|
||||||
|
) {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
percentage: 100,
|
||||||
|
color: 'var(--color-text-n8)',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
percentage: (props.reportDetail.successCount / props.reportDetail.stepTotal) * 100,
|
||||||
|
color: 'rgb(var(--success-6))',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
percentage: (props.reportDetail.errorCount / props.reportDetail.stepTotal) * 100,
|
||||||
|
color: 'rgb(var(--danger-6))',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
percentage: (props.reportDetail.fakeErrorCount / props.reportDetail.stepTotal) * 100,
|
||||||
|
color: 'rgb(var(--warning-6))',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
percentage: (props.reportDetail.pendingCount / props.reportDetail.stepTotal) * 100,
|
||||||
|
color: 'var(--color-text-input-border)',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.popover-label-td {
|
||||||
|
@apply flex items-center;
|
||||||
|
|
||||||
|
padding: 8px 8px 0 0;
|
||||||
|
color: var(--color-text-4);
|
||||||
|
}
|
||||||
|
.popover-value-td {
|
||||||
|
@apply font-medium;
|
||||||
|
|
||||||
|
padding-top: 8px;
|
||||||
|
color: var(--color-text-1);
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -23,4 +23,9 @@ export default {
|
||||||
'report.trigger.interface': 'API',
|
'report.trigger.interface': 'API',
|
||||||
'report.trigger.batch.execution': 'Batch',
|
'report.trigger.batch.execution': 'Batch',
|
||||||
'report.delete.tip': 'Are you sure you want to delete {count} selected reports?',
|
'report.delete.tip': 'Are you sure you want to delete {count} selected reports?',
|
||||||
|
'report.detail.successCount': 'pass',
|
||||||
|
'report.detail.errorCount': 'Failure',
|
||||||
|
'report.detail.fakeErrorCount': 'False alarm',
|
||||||
|
'report.detail.pendingCount': 'Not executed',
|
||||||
|
'report.detail.stepTotal': 'total',
|
||||||
};
|
};
|
||||||
|
|
|
@ -23,4 +23,9 @@ export default {
|
||||||
'report.trigger.interface': 'API 执行',
|
'report.trigger.interface': 'API 执行',
|
||||||
'report.trigger.batch.execution': '批量执行',
|
'report.trigger.batch.execution': '批量执行',
|
||||||
'report.delete.tip': '确认删除已选中的 {count} 个报告吗?',
|
'report.delete.tip': '确认删除已选中的 {count} 个报告吗?',
|
||||||
|
'report.detail.successCount': '通过',
|
||||||
|
'report.detail.errorCount': '失败',
|
||||||
|
'report.detail.fakeErrorCount': '误报',
|
||||||
|
'report.detail.pendingCount': '未执行',
|
||||||
|
'report.detail.stepTotal': '总数',
|
||||||
};
|
};
|
||||||
|
|
|
@ -91,13 +91,15 @@
|
||||||
title: 'project.environmental.env',
|
title: 'project.environmental.env',
|
||||||
dataIndex: 'environmentId',
|
dataIndex: 'environmentId',
|
||||||
slotName: 'environment',
|
slotName: 'environment',
|
||||||
width: 200,
|
width: 300,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'project.environmental.host',
|
title: 'project.environmental.host',
|
||||||
dataIndex: 'host',
|
dataIndex: 'host',
|
||||||
slotName: 'host',
|
slotName: 'host',
|
||||||
width: 200,
|
showTooltip: true,
|
||||||
|
isTag: true,
|
||||||
|
width: 456,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'project.environmental.desc',
|
title: 'project.environmental.desc',
|
||||||
|
|
|
@ -94,11 +94,14 @@
|
||||||
|
|
||||||
import { getEnvPlugin, updateOrAddEnv } from '@/api/modules/project-management/envManagement';
|
import { getEnvPlugin, updateOrAddEnv } from '@/api/modules/project-management/envManagement';
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
|
import useLeaveUnSaveTip from '@/hooks/useLeaveUnSaveTip';
|
||||||
import { useAppStore } from '@/store';
|
import { useAppStore } from '@/store';
|
||||||
import useProjectEnvStore from '@/store/modules/setting/useProjectEnvStore';
|
import useProjectEnvStore from '@/store/modules/setting/useProjectEnvStore';
|
||||||
|
|
||||||
import { ContentTabItem, EnvPluginListItem } from '@/models/projectManagement/environmental';
|
import { ContentTabItem, EnvPluginListItem } from '@/models/projectManagement/environmental';
|
||||||
|
|
||||||
|
const { setState } = useLeaveUnSaveTip();
|
||||||
|
setState(false);
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: 'ok'): void;
|
(e: 'ok'): void;
|
||||||
(e: 'resetEnv'): void;
|
(e: 'resetEnv'): void;
|
||||||
|
@ -200,6 +203,7 @@
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
store.currentEnvDetailInfo.mock = true;
|
store.currentEnvDetailInfo.mock = true;
|
||||||
await updateOrAddEnv({ fileList: [], request: store.currentEnvDetailInfo });
|
await updateOrAddEnv({ fileList: [], request: store.currentEnvDetailInfo });
|
||||||
|
setState(true);
|
||||||
Message.success(t('common.saveSuccess'));
|
Message.success(t('common.saveSuccess'));
|
||||||
emit('ok');
|
emit('ok');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
|
@ -14,14 +14,19 @@
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</a-input-search>
|
</a-input-search>
|
||||||
<batchAddKeyVal :params="innerParams" @apply="handleBatchParamApply" />
|
<batchAddKeyVal
|
||||||
|
:add-type-text="t('project.environmental.env.constantBatchAddTip')"
|
||||||
|
:params="innerParams"
|
||||||
|
no-param-type
|
||||||
|
@apply="handleBatchParamApply"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<paramsTable
|
<paramsTable
|
||||||
v-model:params="innerParams"
|
v-model:params="innerParams"
|
||||||
:table-key="props.tableKey"
|
:table-key="props.tableKey"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
show-setting
|
show-setting
|
||||||
:selectable="false"
|
:selectable="true"
|
||||||
:default-param-item="defaultParamItem"
|
:default-param-item="defaultParamItem"
|
||||||
@change="handleParamTableChange"
|
@change="handleParamTableChange"
|
||||||
/>
|
/>
|
||||||
|
@ -67,6 +72,7 @@
|
||||||
value: '',
|
value: '',
|
||||||
description: '',
|
description: '',
|
||||||
tags: [],
|
tags: [],
|
||||||
|
enable: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
const columns: ParamTableColumn[] = [
|
const columns: ParamTableColumn[] = [
|
||||||
|
@ -84,7 +90,7 @@
|
||||||
slotName: 'paramType',
|
slotName: 'paramType',
|
||||||
showInTable: true,
|
showInTable: true,
|
||||||
showDrag: true,
|
showDrag: true,
|
||||||
hasRequired: true,
|
hasRequired: false,
|
||||||
columnSelectorDisabled: true,
|
columnSelectorDisabled: true,
|
||||||
typeOptions: [
|
typeOptions: [
|
||||||
{
|
{
|
||||||
|
@ -162,7 +168,9 @@
|
||||||
if (!searchValue.value) {
|
if (!searchValue.value) {
|
||||||
innerParams.value = [...backupParams.value];
|
innerParams.value = [...backupParams.value];
|
||||||
} else {
|
} else {
|
||||||
const result = backupParams.value.filter((item) => item.key.includes(searchValue.value));
|
const result = backupParams.value.filter(
|
||||||
|
(item) => item.key.includes(searchValue.value) || item.tags.includes(searchValue.value)
|
||||||
|
);
|
||||||
innerParams.value = [...result];
|
innerParams.value = [...result];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,18 +23,26 @@
|
||||||
t('project.environmental.nonClose')
|
t('project.environmental.nonClose')
|
||||||
}}</span></a-divider
|
}}</span></a-divider
|
||||||
>
|
>
|
||||||
<div v-for="element in couldCloseColumn" :key="element.value" class="column-drag-item">
|
<VueDraggable
|
||||||
<div class="flex w-[90%] items-center">
|
v-model="couldCloseColumn"
|
||||||
<span class="ml-[8px]">{{ t(element.label) }}</span>
|
class="ms-assertion-body-left"
|
||||||
|
ghost-class="ghost"
|
||||||
|
handle=".column-drag-item"
|
||||||
|
>
|
||||||
|
<div v-for="element in couldCloseColumn" :key="element.value" class="column-drag-item">
|
||||||
|
<div class="flex w-[90%] items-center">
|
||||||
|
<span class="ml-[8px]">{{ t(element.label) }}</span>
|
||||||
|
</div>
|
||||||
|
<a-switch v-model="element.isShow" size="small" type="line" @change="handleSwitchChange" />
|
||||||
</div>
|
</div>
|
||||||
<a-switch v-model="element.isShow" size="small" type="line" @change="handleSwitchChange" />
|
</VueDraggable>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</MsDrawer>
|
</MsDrawer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { defineModel, onBeforeMount, ref } from 'vue';
|
import { defineModel, onBeforeMount, ref } from 'vue';
|
||||||
|
import { VueDraggable } from 'vue-draggable-plus';
|
||||||
|
|
||||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||||
import MsDrawer from '@/components/pure/ms-drawer/index.vue';
|
import MsDrawer from '@/components/pure/ms-drawer/index.vue';
|
||||||
|
|
|
@ -10,14 +10,14 @@
|
||||||
t('project.environmental.addHttp')
|
t('project.environmental.addHttp')
|
||||||
}}</a-button>
|
}}</a-button>
|
||||||
<div class="flex flex-row gap-[8px]">
|
<div class="flex flex-row gap-[8px]">
|
||||||
<a-input-number v-model:model-value="form.requestTimeout" class="w-[180px]">
|
<a-input-number v-model:model-value="form.requestTimeout" :min="0" class="w-[180px]">
|
||||||
<template #prefix>
|
<template #prefix>
|
||||||
<span class="text-[var(--color-text-3)]">{{ t('project.environmental.http.linkTimeOut') }}</span>
|
<span class="text-[var(--color-text-3)]">{{ t('project.environmental.http.linkTimeOut') }}</span>
|
||||||
</template>
|
</template>
|
||||||
</a-input-number>
|
</a-input-number>
|
||||||
<a-input-number v-model:model-value="form.responseTimeout" class="w-[180px]">
|
<a-input-number v-model:model-value="form.responseTimeout" :min="0" class="w-[180px]">
|
||||||
<template #prefix>
|
<template #prefix>
|
||||||
<span class="text-[var(--color-text-3)]">{{ t('project.environmental.http.linkTimeOut') }}</span>
|
<span class="text-[var(--color-text-3)]">{{ t('project.environmental.http.resTimeOut') }}</span>
|
||||||
</template>
|
</template>
|
||||||
</a-input-number>
|
</a-input-number>
|
||||||
<!-- TOTO 第一个版本不做 -->
|
<!-- TOTO 第一个版本不做 -->
|
||||||
|
@ -130,11 +130,11 @@
|
||||||
];
|
];
|
||||||
await tableStore.initColumn(TableKeyEnum.PROJECT_MANAGEMENT_ENV_ENV_HTTP, columns);
|
await tableStore.initColumn(TableKeyEnum.PROJECT_MANAGEMENT_ENV_ENV_HTTP, columns);
|
||||||
const { propsRes, propsEvent } = useTable(undefined, {
|
const { propsRes, propsEvent } = useTable(undefined, {
|
||||||
tableKey: TableKeyEnum.PROJECT_MANAGEMENT_ENV_ENV_HTTP,
|
columns,
|
||||||
scroll: { x: '100%' },
|
scroll: { x: '100%' },
|
||||||
selectable: false,
|
selectable: false,
|
||||||
noDisable: true,
|
noDisable: true,
|
||||||
showSetting: true,
|
showSetting: false,
|
||||||
showPagination: false,
|
showPagination: false,
|
||||||
enableDrag: true,
|
enableDrag: true,
|
||||||
showMode: false,
|
showMode: false,
|
||||||
|
@ -255,12 +255,30 @@
|
||||||
}
|
}
|
||||||
await initModuleTree();
|
await initModuleTree();
|
||||||
|
|
||||||
|
const OPERATOR_MAP = [
|
||||||
|
{
|
||||||
|
value: 'CONTAINS',
|
||||||
|
label: '包含',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'EQUALS',
|
||||||
|
label: '等于',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
function getCondition(condition: string) {
|
||||||
|
return OPERATOR_MAP.find((item) => item.value === condition)?.label;
|
||||||
|
}
|
||||||
|
|
||||||
function getModuleName(record: HttpForm) {
|
function getModuleName(record: HttpForm) {
|
||||||
if (record.type === 'MODULE') {
|
if (record.type === 'MODULE') {
|
||||||
const moduleIds: string[] = record.moduleMatchRule.modules.map((item) => item.moduleId);
|
const moduleIds: string[] = record.moduleMatchRule.modules.map((item) => item.moduleId);
|
||||||
const result = findNodeNames(moduleTree.value, moduleIds);
|
const result = findNodeNames(moduleTree.value, moduleIds);
|
||||||
return result.join(',');
|
return result.join(',');
|
||||||
}
|
}
|
||||||
|
if (record.type === 'PATH') {
|
||||||
|
return `${getCondition(record.pathMatchRule.condition)}${record.pathMatchRule.path}`;
|
||||||
|
}
|
||||||
return '-';
|
return '-';
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -155,7 +155,7 @@
|
||||||
</a-input-group>
|
</a-input-group>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-form>
|
</a-form>
|
||||||
<RequestHeader v-model:params="form.headers" />
|
<RequestHeader v-model:params="form.headers" :no-param-type="true" />
|
||||||
</MsDrawer>
|
</MsDrawer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,173 @@
|
||||||
|
<template>
|
||||||
|
<a-modal
|
||||||
|
v-model:visible="innerVisible"
|
||||||
|
class="ms-modal-form ms-modal-large"
|
||||||
|
title-align="start"
|
||||||
|
:ok-text="t('system.userGroup.add')"
|
||||||
|
unmount-on-close
|
||||||
|
@cancel="handleCancel"
|
||||||
|
>
|
||||||
|
<template #title> 域名列表 </template>
|
||||||
|
<div>
|
||||||
|
<MsBaseTable class="mt-[16px]" v-bind="propsRes" v-on="propsEvent">
|
||||||
|
<template #type="{ record }">
|
||||||
|
<span>{{ getEnableScope(record.type) }}</span>
|
||||||
|
</template>
|
||||||
|
<template #moduleValue="{ record }">
|
||||||
|
<a-tooltip :content="getModuleName(record)" position="left">
|
||||||
|
<span class="one-line-text max-w-[300px]">{{ getModuleName(record) }}</span>
|
||||||
|
</a-tooltip>
|
||||||
|
</template>
|
||||||
|
</MsBaseTable>
|
||||||
|
</div>
|
||||||
|
<template #footer>
|
||||||
|
<a-button type="secondary" @click="handleCancel">
|
||||||
|
{{ t('common.cancel') }}
|
||||||
|
</a-button>
|
||||||
|
<a-button type="primary" @click="handleCancel">
|
||||||
|
{{ t('common.confirm') }}
|
||||||
|
</a-button>
|
||||||
|
</template>
|
||||||
|
</a-modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import { useVModel } from '@vueuse/core';
|
||||||
|
|
||||||
|
import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
|
||||||
|
import { MsTableColumn } from '@/components/pure/ms-table/type';
|
||||||
|
import useTable from '@/components/pure/ms-table/useTable';
|
||||||
|
|
||||||
|
import { getEnvModules } from '@/api/modules/api-test/management';
|
||||||
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
|
import { useAppStore, useTableStore } from '@/store';
|
||||||
|
import { findNodeNames } from '@/utils';
|
||||||
|
|
||||||
|
import type { ModuleTreeNode } from '@/models/common';
|
||||||
|
import { HttpForm } from '@/models/projectManagement/environmental';
|
||||||
|
|
||||||
|
const appStore = useAppStore();
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const props = defineProps<{
|
||||||
|
visible: boolean;
|
||||||
|
data: HttpForm[];
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'update:visible', val: boolean);
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const innerVisible = useVModel(props, 'visible', emit);
|
||||||
|
|
||||||
|
function handleCancel() {
|
||||||
|
innerVisible.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const columns: MsTableColumn = [
|
||||||
|
{
|
||||||
|
title: 'project.environmental.http.host',
|
||||||
|
dataIndex: 'hostname',
|
||||||
|
slotName: 'hostname',
|
||||||
|
showTooltip: true,
|
||||||
|
showDrag: true,
|
||||||
|
showInTable: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'project.environmental.http.desc',
|
||||||
|
dataIndex: 'description',
|
||||||
|
showDrag: true,
|
||||||
|
showInTable: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'project.environmental.http.enableScope',
|
||||||
|
dataIndex: 'type',
|
||||||
|
slotName: 'type',
|
||||||
|
showDrag: true,
|
||||||
|
showInTable: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'project.environmental.http.value',
|
||||||
|
dataIndex: 'value',
|
||||||
|
slotName: 'moduleValue',
|
||||||
|
showTooltip: false,
|
||||||
|
showDrag: true,
|
||||||
|
showInTable: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const { propsRes, propsEvent } = useTable(undefined, {
|
||||||
|
columns,
|
||||||
|
scroll: { x: '100%' },
|
||||||
|
selectable: false,
|
||||||
|
noDisable: true,
|
||||||
|
showSetting: false,
|
||||||
|
showPagination: false,
|
||||||
|
enableDrag: false,
|
||||||
|
showMode: false,
|
||||||
|
heightUsed: 644,
|
||||||
|
debug: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
function getEnableScope(type: string) {
|
||||||
|
switch (type) {
|
||||||
|
case 'NONE':
|
||||||
|
return t('project.environmental.http.none');
|
||||||
|
case 'MODULE':
|
||||||
|
return t('project.environmental.http.module');
|
||||||
|
case 'PATH':
|
||||||
|
return t('project.environmental.http.path');
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const moduleTree = ref<ModuleTreeNode[]>([]);
|
||||||
|
async function initModuleTree() {
|
||||||
|
try {
|
||||||
|
const res = await getEnvModules({
|
||||||
|
projectId: appStore.currentProjectId,
|
||||||
|
});
|
||||||
|
moduleTree.value = res.moduleTree;
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const OPERATOR_MAP = [
|
||||||
|
{
|
||||||
|
value: 'CONTAINS',
|
||||||
|
label: '包含',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'EQUALS',
|
||||||
|
label: '等于',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
function getCondition(condition: string) {
|
||||||
|
return OPERATOR_MAP.find((item) => item.value === condition)?.label;
|
||||||
|
}
|
||||||
|
function getModuleName(record: HttpForm) {
|
||||||
|
if (record.type === 'MODULE') {
|
||||||
|
const moduleIds: string[] = record.moduleMatchRule.modules.map((item) => item.moduleId);
|
||||||
|
const result = findNodeNames(moduleTree.value, moduleIds);
|
||||||
|
return result.join(',');
|
||||||
|
}
|
||||||
|
if (record.type === 'PATH') {
|
||||||
|
return `${getCondition(record.pathMatchRule.condition)}${record.pathMatchRule.path}`;
|
||||||
|
}
|
||||||
|
return '-';
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.data,
|
||||||
|
(val) => {
|
||||||
|
if (val) {
|
||||||
|
propsRes.value.data = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="mb-[8px] flex items-center justify-between">
|
<div class="mb-[8px] flex items-center justify-between">
|
||||||
<div class="font-medium">{{ t('apiTestDebug.header') }}</div>
|
<div class="font-medium">{{ t('apiTestDebug.header') }}</div>
|
||||||
<batchAddKeyVal :params="innerParams" @apply="handleBatchParamApply" />
|
<batchAddKeyVal :no-param-type="props.noParamType" :params="innerParams" @apply="handleBatchParamApply" />
|
||||||
</div>
|
</div>
|
||||||
<paramsTable
|
<paramsTable
|
||||||
v-model:params="innerParams"
|
v-model:params="innerParams"
|
||||||
|
@ -30,6 +30,7 @@
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
params: any[];
|
params: any[];
|
||||||
|
noParamType?: boolean;
|
||||||
}>();
|
}>();
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: 'update:params', value: any[]): void;
|
(e: 'update:params', value: any[]): void;
|
||||||
|
|
|
@ -41,7 +41,7 @@ export default {
|
||||||
'project.environmental.httpNoWarning': 'No warning',
|
'project.environmental.httpNoWarning': 'No warning',
|
||||||
'project.environmental.addHttp': 'Add HTTP',
|
'project.environmental.addHttp': 'Add HTTP',
|
||||||
'project.environmental.http.linkTimeOut': 'Link Timeout (ms):',
|
'project.environmental.http.linkTimeOut': 'Link Timeout (ms):',
|
||||||
'project.environmental.http.timeTimeOut': 'Timeout Time (ms):',
|
'project.environmental.http.resTimeOut': 'Response timeout (ms) :',
|
||||||
'project.environmental.http.authType': 'Authentication Type:',
|
'project.environmental.http.authType': 'Authentication Type:',
|
||||||
'project.environmental.http.host': 'Host',
|
'project.environmental.http.host': 'Host',
|
||||||
'project.environmental.http.desc': 'Description',
|
'project.environmental.http.desc': 'Description',
|
||||||
|
@ -96,11 +96,11 @@ export default {
|
||||||
'project.environmental.postScriptBefore': 'Post script front',
|
'project.environmental.postScriptBefore': 'Post script front',
|
||||||
'project.environmental.postScriptAfter': 'After the script',
|
'project.environmental.postScriptAfter': 'After the script',
|
||||||
'project.environmental.http.preTextPreTip':
|
'project.environmental.http.preTextPreTip':
|
||||||
'Before pre script, environment scripts executed before buy scripts in the request;',
|
'Before the pre-script, the script in the environment is executed before the requested pre-script is executed.',
|
||||||
'project.environmental.http.preTextPostTip':
|
'project.environmental.http.preTextPostTip':
|
||||||
'After the preset script, the script in the environment is executed after the requested preset script is executed;',
|
'After the preset script, the script in the environment is executed after the requested preset script is executed;',
|
||||||
'project.environmental.http.postTextPreTip':
|
'project.environmental.http.postTextPreTip':
|
||||||
'The script in the environment is executed before the requested script is executed.',
|
'The script in the environment is executed before the requested postscript is executed;',
|
||||||
'project.environmental.http.postTextPostTip':
|
'project.environmental.http.postTextPostTip':
|
||||||
'After rear script, environment a prerequisite for the script in the request after the script execution;',
|
'After rear script, environment a prerequisite for the script in the request after the script execution;',
|
||||||
'project.environmental.preOrPost.ignoreProtocols': 'Ignore request:',
|
'project.environmental.preOrPost.ignoreProtocols': 'Ignore request:',
|
||||||
|
@ -111,4 +111,5 @@ export default {
|
||||||
'project.environmental.env.selectableTitle': 'Optional Environments',
|
'project.environmental.env.selectableTitle': 'Optional Environments',
|
||||||
'project.environmental.env.systemTitle': 'environment',
|
'project.environmental.env.systemTitle': 'environment',
|
||||||
'project.environmental.env.selectedTitle': 'Selected environment',
|
'project.environmental.env.selectedTitle': 'Selected environment',
|
||||||
|
'project.environmental.env.constantBatchAddTip': 'Only supports batch adding const type',
|
||||||
};
|
};
|
||||||
|
|
|
@ -45,8 +45,8 @@ export default {
|
||||||
'project.environmental.httpTitle': '当满足多个启用条件时,按从上到下的顺序匹配',
|
'project.environmental.httpTitle': '当满足多个启用条件时,按从上到下的顺序匹配',
|
||||||
'project.environmental.httpNoWarning': '不在提醒',
|
'project.environmental.httpNoWarning': '不在提醒',
|
||||||
'project.environmental.addHttp': '添加 HTTP',
|
'project.environmental.addHttp': '添加 HTTP',
|
||||||
'project.environmental.http.linkTimeOut': '链接超时(ms):',
|
'project.environmental.http.linkTimeOut': '连接超时(ms):',
|
||||||
'project.environmental.http.timeTimeOut': '超时时间(ms):',
|
'project.environmental.http.resTimeOut': '响应超时(ms):',
|
||||||
'project.environmental.http.authType': '认证方式:',
|
'project.environmental.http.authType': '认证方式:',
|
||||||
'project.environmental.http.host': '域名',
|
'project.environmental.http.host': '域名',
|
||||||
'project.environmental.http.desc': '描述',
|
'project.environmental.http.desc': '描述',
|
||||||
|
@ -109,9 +109,9 @@ export default {
|
||||||
'project.environmental.preScriptAfter': '前置脚本后',
|
'project.environmental.preScriptAfter': '前置脚本后',
|
||||||
'project.environmental.postScriptBefore': '后置脚本前',
|
'project.environmental.postScriptBefore': '后置脚本前',
|
||||||
'project.environmental.postScriptAfter': '后置脚本后',
|
'project.environmental.postScriptAfter': '后置脚本后',
|
||||||
'project.environmental.http.preTextPreTip': '前置脚本前,环境中脚本在请求的置脚本执行前执行;',
|
'project.environmental.http.preTextPreTip': '前置脚本前,环境中脚本在请求的前置脚本执行前执行;',
|
||||||
'project.environmental.http.preTextPostTip': '前置置脚本后,环境中脚本在请求的前置脚本执行后执行;',
|
'project.environmental.http.preTextPostTip': '前置置脚本后,环境中脚本在请求的前置脚本执行后执行;',
|
||||||
'project.environmental.http.postTextPreTip': '后置脚本前,环境中脚本在请求的置脚本执行前执行;',
|
'project.environmental.http.postTextPreTip': '后置脚本前,环境中脚本在请求的后置脚本执行前执行;',
|
||||||
'project.environmental.http.postTextPostTip': '后置脚本后,环境中脚本在请求的前置脚本执行后执行;',
|
'project.environmental.http.postTextPostTip': '后置脚本后,环境中脚本在请求的前置脚本执行后执行;',
|
||||||
'project.environmental.preOrPost.ignoreProtocols': '忽略请求:',
|
'project.environmental.preOrPost.ignoreProtocols': '忽略请求:',
|
||||||
'project.environmental.preOrPost.pre': '脚本前',
|
'project.environmental.preOrPost.pre': '脚本前',
|
||||||
|
@ -122,4 +122,5 @@ export default {
|
||||||
'project.environmental.env.selectableTitle': '可选环境',
|
'project.environmental.env.selectableTitle': '可选环境',
|
||||||
'project.environmental.env.systemTitle': '环境',
|
'project.environmental.env.systemTitle': '环境',
|
||||||
'project.environmental.env.selectedTitle': '已选环境',
|
'project.environmental.env.selectedTitle': '已选环境',
|
||||||
|
'project.environmental.env.constantBatchAddTip': '只支持常量类型批量添加',
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue