fix: 修改全部部分bug(环境管理)&(前后置)&(报告)

This commit is contained in:
xinxin.wu 2024-04-01 22:52:58 +08:00 committed by Craftsman
parent 4afdfcf3f4
commit 6daaa10055
17 changed files with 147 additions and 50 deletions

View File

@ -51,7 +51,7 @@
<div>{{ t('apiTestDebug.expressionTip2') }}</div>
<div>{{ t('apiTestDebug.expressionTip3') }}</div>
</template>
<MsIcon
<!-- <MsIcon
:disabled="props.disabled"
type="icon-icon_flashlamp"
:size="15"
@ -61,7 +61,7 @@
: 'ms-params-input-suffix-icon'
"
@click.stop="() => showFastExtraction(record, RequestExtractExpressionEnum.JSON_PATH)"
/>
/> -->
</a-tooltip>
</template>
</a-input>
@ -146,7 +146,7 @@
<div>{{ t('apiTestDebug.expressionTip2') }}</div>
<div>{{ t('apiTestDebug.expressionTip3') }}</div>
</template>
<MsIcon
<!-- <MsIcon
type="icon-icon_flashlamp"
:disabled="props.disabled"
:size="15"
@ -156,7 +156,7 @@
: 'ms-params-input-suffix-icon'
"
@click.stop="() => showFastExtraction(record, RequestExtractExpressionEnum.X_PATH)"
/>
/> -->
</a-tooltip>
</template>
</a-input>

View File

@ -15,6 +15,7 @@
<script setup lang="ts">
import { useVModel } from '@vueuse/core';
import { EQUAL } from '@/components/pure/ms-advance-filter/index';
import paramsTable, { type ParamTableColumn } from '@/views/api-test/components/paramTable.vue';
import { responseHeaderOption } from '@/config/apiTest';
@ -41,7 +42,7 @@
const defaultParamItem = {
header: '',
condition: '',
condition: EQUAL.value,
expectedValue: '',
enable: true,
};

View File

@ -3,7 +3,7 @@
<div>
<div class="mb-[8px]">{{ t('ms.assertion.statusCode') }}</div>
<a-select v-model="condition.condition" :disabled="props.disabled" class="w-[157px]" @change="clearExpectedValue">
<a-option v-for="item in statusCodeOptions" :key="item.value" :value="item.value">
<a-option v-for="item in codeOptions" :key="item.value" :value="item.value">
{{ t(item.label) }}
</a-option>
</a-select>
@ -34,7 +34,7 @@
import { useI18n } from '@/hooks/useI18n';
import { statusCodeOptions } from './utils';
import { codeOptions } from './utils';
const { t } = useI18n();
interface Param {

View File

@ -3,6 +3,7 @@ import {
EMPTY,
END_WITH,
EQUAL,
NO_CHECK,
NO_CONTAINS,
NOT_EMPTY,
NOT_EQUAL,
@ -11,5 +12,6 @@ import {
} from '@/components/pure/ms-advance-filter/index';
export const statusCodeOptions = [CONTAINS, NO_CONTAINS, EQUAL, NOT_EQUAL];
export const codeOptions = [CONTAINS, NO_CONTAINS, EQUAL, NOT_EQUAL, NO_CHECK];
export default {};

View File

@ -469,6 +469,7 @@
<script setup lang="ts">
import { useClipboard, useVModel } from '@vueuse/core';
import { InputInstance, Message } from '@arco-design/web-vue';
import { cloneDeep } from 'lodash-es';
import MsButton from '@/components/pure/ms-button/index.vue';
import MsCodeEditor from '@/components/pure/ms-code-editor/index.vue';
@ -857,13 +858,31 @@ if (!result){
extractParamsTableRef.value?.addTableLine(rowIndex);
}
function copyItem(record: ExpressionConfig) {
if (condition.value.extractors) {
const currentIndex = condition.value.extractors.findIndex((item: ExpressionConfig) => item.id === record.id);
const currentExtractorsItem = cloneDeep(record);
if (currentIndex > -1) {
condition.value.extractors.splice(currentIndex, 0, {
...currentExtractorsItem,
id: new Date().getTime().toString(),
});
const temList = cloneDeep(condition.value?.extractors);
condition.value.extractors = temList;
}
}
}
/**
* 处理提取参数表格更多操作
*/
function handleExtractParamMoreActionSelect(event: ActionsItem, record: ExpressionConfig) {
activeRecord.value = { ...record };
if (event.eventTag === 'copy') {
emit('copy');
// emit('copy');
//
copyItem(record);
} else if (event.eventTag === 'setting') {
record.moreSettingPopoverVisible = true;
}

View File

@ -176,9 +176,12 @@
id: new Date().getTime(),
};
data.value.push(copyItem);
activeItem.value = copyItem;
emit('activeChange', activeItem.value);
const copyIndex = data.value.findIndex((e: ExecuteConditionProcessor) => e.id === item.id);
if (copyIndex > -1) {
data.value.splice(copyIndex, 0, copyItem);
activeItem.value = copyItem;
emit('activeChange', activeItem.value);
}
}
/**

View File

@ -173,7 +173,7 @@
<template #extractScope="{ record, columnConfig, rowIndex }">
<a-select
v-model:model-value="record.extractScope"
:disabled="props.disabledExceptParam"
:disabled="props.disabledExceptParam || record.extractType !== RequestExtractExpressionEnum.REGEX"
:options="columnConfig.typeOptions || []"
class="ms-form-table-input w-[180px]"
size="mini"
@ -370,10 +370,10 @@
</a-tooltip>
<a-input
v-model="record.expectedValue"
:disabled="props.disabledExceptParam"
size="mini"
class="ms-form-table-input"
:placeholder="t('apiTestDebug.commonPlaceholder')"
:disabled="isDisabledCondition.includes(record.condition) || props.disabledExceptParam"
@change="() => addTableLine(rowIndex, columnConfig.addLineDisabled)"
/>
</template>
@ -542,6 +542,7 @@
import { TableColumnData, TableData } from '@arco-design/web-vue';
import { cloneDeep } from 'lodash-es';
import { NO_CHECK } from '@/components/pure/ms-advance-filter/index';
import MsButton from '@/components/pure/ms-button/index.vue';
import MsCodeEditor from '@/components/pure/ms-code-editor/index.vue';
import MsFormTable, { FormTableColumn } from '@/components/pure/ms-form-table/index.vue';
@ -560,7 +561,12 @@
import { ModuleTreeNode, TransferFileParams } from '@/models/common';
import { HttpForm, ProjectOptionItem } from '@/models/projectManagement/environmental';
import { RequestBodyFormat, RequestContentTypeEnum, RequestParamsType } from '@/enums/apiEnum';
import {
RequestBodyFormat,
RequestContentTypeEnum,
RequestExtractExpressionEnum,
RequestParamsType,
} from '@/enums/apiEnum';
import { TableKeyEnum } from '@/enums/tableEnum';
import { filterKeyValParams } from './utils';
@ -1040,6 +1046,8 @@
record[item.dataIndex as string] = val;
}
const isDisabledCondition = ref([NO_CHECK.value]);
defineExpose({
addTableLine,
});

View File

@ -325,7 +325,7 @@
*/
function loadControlLoop() {
if (isShowLoopControl.value) {
const loopStepId = props?.stepItem?.children[controlCurrent.value - 1].stepId;
const loopStepId = props.stepItem?.children[controlCurrent.value - 1].stepId;
if (loopStepId) {
getStepDetail(loopStepId);
}
@ -335,11 +335,11 @@
const originStepId = ref<string | undefined>('');
watch(
() => props?.stepItem?.stepId,
() => props.stepItem?.stepId,
(val) => {
if (val) {
if (isShowLoopControl.value) {
getStepDetail(props?.stepItem?.children[controlCurrent.value - 1].stepId as string);
getStepDetail(props.stepItem?.children[controlCurrent.value - 1].stepId as string);
} else {
getStepDetail(val);
}

View File

@ -4,7 +4,8 @@
<div v-if="route.query.shareId" class="flex items-center font-medium"
>{{ t('report.name') }}
<a-tooltip :content="props.detail.name" :mouse-enter-delay="300"
><div class="one-line-text max-w-[300px]">{{ props.detail.name }}</div>
><div class="one-line-text max-w-[300px]">{{ props.detail.name }}</div
>
</a-tooltip>
<a-divider direction="vertical" :margin="4" class="!mx-2"></a-divider
></div>
@ -13,9 +14,11 @@
<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 class="max-w-[400px] items-center gap-[8px] text-[14px]">
<div class="flex-shrink-0 text-[var(--color-text-4)]">{{ t('report.detail.api.executeEnv') }}</div>
<div>
{{ props.detail.environmentName || '-' }}
</div>
</div>
</template>
</a-popover>
@ -23,9 +26,9 @@
<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="max-w-[400px] 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> {{ props.detail.poolName || '-' }}</div>
</div>
</template>
</a-popover>
@ -64,9 +67,9 @@
<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="max-w-[400px] 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 class="mt-1"> {{ props.detail.creatUserName || '-' }}</div>
</div>
</template>
</a-popover>

View File

@ -28,7 +28,7 @@
<div
type="text"
class="one-line-text flex w-full text-[rgb(var(--primary-5))]"
@click="showReportDetail(record.id, rowIndex, record.integrated)"
@click="showReportDetail(record.id, rowIndex)"
>{{ characterLimit(record.name) }}</div
>
</template>
@ -150,7 +150,6 @@
:table-data="propsRes.data"
:page-change="propsEvent.pageChange"
:pagination="propsRes.msPagination!"
:show-type="activeCaseReportType"
:share-time="shareTime"
/>
</div>
@ -158,6 +157,7 @@
<script setup lang="ts">
import { ref } from 'vue';
import { useRoute } from 'vue-router';
import { Message } from '@arco-design/web-vue';
import { cloneDeep } from 'lodash-es';
import dayjs from 'dayjs';
@ -193,6 +193,7 @@
const appStore = useAppStore();
const tableStore = useTableStore();
const route = useRoute();
const { t } = useI18n();
const props = defineProps<{
@ -467,16 +468,14 @@
const activeReportIndex = ref<number>(0);
const showDetailDrawer = ref<boolean>(false);
const showCaseDetailDrawer = ref<boolean>(false);
const activeCaseReportType = ref('');
function showReportDetail(id: string, rowIndex: number, integrated: boolean) {
function showReportDetail(id: string, rowIndex: number) {
activeDetailId.value = id;
activeReportIndex.value = rowIndex - 1;
if (props.moduleType === ReportEnum.API_SCENARIO_REPORT) {
showDetailDrawer.value = true;
} else {
showCaseDetailDrawer.value = true;
activeCaseReportType.value = integrated ? 'INTEGRATED' : 'INDEPENDENT';
}
}
@ -500,7 +499,21 @@
console.log(error);
}
}
function showDetail() {
if (route.query.reportId && route.query.type) {
activeDetailId.value = route.query.reportId as string;
activeReportIndex.value = 0;
if (route.query.type === 'API_SCENARIO') {
showDetailDrawer.value = true;
} else {
showCaseDetailDrawer.value = true;
}
}
}
onMounted(() => {
showDetail();
getTime();
});

View File

@ -89,7 +89,7 @@
</template>
</MsTag>
<template #content>
<div>{{ step.scriptIdentifier }}</div>
<div class="max-w-[400px]">{{ step.scriptIdentifier }}</div>
</template>
</a-popover>
<div v-show="showStatus(step)" class="flex">
@ -223,7 +223,7 @@
* 处理步骤展开折叠
*/
function handleStepExpand(data: MsTreeExpandedData) {
const realStep = findNodeByKey<ScenarioItemType>(steps.value, data.node?.id, 'id');
const realStep = findNodeByKey<ScenarioItemType>(steps.value, data.node?.stepId, 'stepId');
if (realStep) {
realStep.expanded = !realStep.expanded;
}

View File

@ -4,11 +4,12 @@
<script setup lang="ts">
import { ref } from 'vue';
import { useRoute } from 'vue-router';
import { useRoute, useRouter } from 'vue-router';
import caseReportCom from './component/caseReportCom.vue';
import { getShareReportInfo, reportCaseDetail } from '@/api/modules/api-test/report';
import { NO_RESOURCE_ROUTE_NAME } from '@/router/constants';
import type { ReportDetail } from '@/models/apiTest/report';
@ -16,10 +17,17 @@
const route = useRoute();
const router = useRouter();
async function getDetail() {
try {
const res = await getShareReportInfo(route.query.shareId as string);
detail.value = await reportCaseDetail(res.reportId, route.query.shareId as string);
if (res.deleted) {
router.push({
name: NO_RESOURCE_ROUTE_NAME,
});
} else {
detail.value = await reportCaseDetail(res.reportId, route.query.shareId as string);
}
} catch (error) {
console.log(error);
}

View File

@ -4,22 +4,29 @@
<script setup lang="ts">
import { ref } from 'vue';
import { useRoute } from 'vue-router';
import { useRoute, useRouter } from 'vue-router';
import ShareCom from './component/scenarioCom.vue';
import { getShareReportInfo, reportScenarioDetail } from '@/api/modules/api-test/report';
import { NO_RESOURCE_ROUTE_NAME } from '@/router/constants';
import type { ReportDetail } from '@/models/apiTest/report';
const detail = ref<ReportDetail>();
const router = useRouter();
const route = useRoute();
async function getDetail() {
try {
const res = await getShareReportInfo(route.query.shareId as string);
detail.value = await reportScenarioDetail(res.reportId, route.query.shareId as string);
if (res.deleted) {
router.push({
name: NO_RESOURCE_ROUTE_NAME,
});
} else {
detail.value = await reportScenarioDetail(res.reportId, route.query.shareId as string);
}
} catch (error) {
console.log(error);
}

View File

@ -78,6 +78,7 @@
<script lang="ts" setup>
import { Message } from '@arco-design/web-vue';
import { cloneDeep } from 'lodash-es';
import TabSettingDrawer from './common/TabSettingDrawer.vue';
import AssertTab from './envParams/AssertTab.vue';
@ -97,6 +98,9 @@
import { ContentTabItem, EnvPluginListItem } from '@/models/projectManagement/environmental';
import { defaultHeaderParamsItem } from '@/views/api-test/components/config';
import { filterKeyValParams } from '@/views/api-test/components/utils';
const { setState } = useLeaveUnSaveTip();
setState(false);
const emit = defineEmits<{
@ -194,13 +198,32 @@
emit('resetEnv');
};
function getParameters() {
const paramsConfig = cloneDeep(store.currentEnvDetailInfo.config);
const httpConfigList = paramsConfig.httpConfig.map((e) => {
return {
...e,
headers: filterKeyValParams(e.headers, defaultHeaderParamsItem, true).validParams,
};
});
return {
...cloneDeep(store.currentEnvDetailInfo),
config: {
...paramsConfig,
httpConfig: httpConfigList,
},
};
}
const handleSave = async () => {
await envForm.value?.validate(async (valid) => {
if (!valid) {
try {
loading.value = true;
store.currentEnvDetailInfo.mock = true;
await updateOrAddEnv({ fileList: [], request: store.currentEnvDetailInfo });
getParameters();
await updateOrAddEnv({ fileList: [], request: getParameters() });
setState(true);
Message.success(store.currentEnvDetailInfo.id ? t('common.updateSuccess') : t('common.saveSuccess'));

View File

@ -36,7 +36,7 @@
t('caseManagement.caseReview.tableNoData')
}}</span>
<span v-else>{{ t('caseManagement.featureCase.tableNoData') }}</span>
<MsButton v-permission="['PROJECT_ENVIRONMENT:READ+UPDATE']" class="ml-[8px]">
<MsButton v-permission="['PROJECT_ENVIRONMENT:READ+UPDATE']" class="ml-[8px]" @click="handleAdd">
{{ t('project.environmental.database.addDatabase') }}
</MsButton>
</div>

View File

@ -80,7 +80,7 @@
t('caseManagement.caseReview.tableNoData')
}}</span>
<span v-else>{{ t('caseManagement.featureCase.tableNoData') }}</span>
<MsButton v-permission="['PROJECT_ENVIRONMENT:READ+UPDATE']" class="ml-[8px]">
<MsButton v-permission="['PROJECT_ENVIRONMENT:READ+UPDATE']" class="ml-[8px]" @click="handleAddHttp">
{{ t('project.environmental.addHttp') }}
</MsButton>
</div>

View File

@ -6,7 +6,7 @@
:mask="false"
destroy-on-close
@confirm="handleAddOrUpdate"
@cancel="emit('close')"
@cancel="handleCancel"
>
<template #title>
<div>{{ title }}</div>
@ -135,6 +135,7 @@
key: 'id',
children: 'children',
}"
tree-checked-strategy="child"
:tree-props="{
virtualListProps: {
height: 200,
@ -188,7 +189,6 @@
import useProjectEnvStore from '@/store/modules/setting/useProjectEnvStore';
import { getGenerateId } from '@/utils';
import type { EnvModule } from '@/models/apiTest/management';
import type { ModuleTreeNode } from '@/models/common';
import { HttpForm } from '@/models/projectManagement/environmental';
@ -229,12 +229,7 @@
protocol: 'http',
moduleId: [],
moduleMatchRule: {
modules: [
// {
// moduleId: '',
// containChildModule: false,
// },
],
modules: [],
},
pathMatchRule: {
path: '',
@ -327,7 +322,8 @@
const envTree = ref<ModuleTreeNode[]>([]);
const title = ref<string>('');
watchEffect(() => {
function initHttpDetail() {
title.value = props.currentId ? t('project.environmental.http.edit') : t('project.environmental.http.add');
if (props.isCopy) {
title.value = t('project.environmental.http.copy');
@ -350,7 +346,7 @@
} else {
resetForm();
}
});
}
async function initModuleTree() {
try {
@ -363,6 +359,20 @@
}
}
watch(
() => visible.value,
(val) => {
if (val) {
initHttpDetail();
}
}
);
const handleCancel = () => {
visible.value = false;
resetForm();
};
onBeforeMount(() => {
initModuleTree();
});