feat(接口测试): 接口测试报告详情页面

This commit is contained in:
xinxin.wu 2024-03-18 19:11:07 +08:00 committed by Craftsman
parent 1e40d132db
commit 39847ccc93
12 changed files with 876 additions and 13 deletions

View File

@ -0,0 +1,15 @@
export interface ScenarioItemType {
stepId: string;
reportId: string;
name: string; // 步骤名称
sort: number; // 序号
stepType: string; // 步骤类型/API/CASE等
parentId: string; // 父级id
status: string; // 结果状态 SUCCESS/ERROR
fakeCode: string; // 误报编号/误报状态独有
requestName: string; // 请求名称
requestTime: number; // 请求耗时
code: string; // 请求响应码
responseSize: number; // 响应内容大小
scriptIdentifier: string; // 脚本标识
}

View File

@ -0,0 +1,47 @@
<template>
<div class="condition-status" :style="getClass"> {{ t(scenarioStepMap[props.status].label) }} </div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { useI18n } from '@/hooks/useI18n';
import { ScenarioStepType } from '@/enums/apiEnum';
const { t } = useI18n();
const props = defineProps<{
status: string;
}>();
//
const scenarioStepMap = {
[ScenarioStepType.QUOTE_API]: { label: 'apiScenario.quoteApi', color: 'rgb(var(--link-7))' },
[ScenarioStepType.COPY_API]: { label: 'apiScenario.copyApi', color: 'rgb(var(--link-7))' },
[ScenarioStepType.QUOTE_CASE]: { label: 'apiScenario.quoteCase', color: 'rgb(var(--success-7))' },
[ScenarioStepType.COPY_CASE]: { label: 'apiScenario.copyCase', color: 'rgb(var(--success-7))' },
[ScenarioStepType.QUOTE_SCENARIO]: { label: 'apiScenario.quoteScenario', color: 'rgb(var(--primary-7))' },
[ScenarioStepType.COPY_SCENARIO]: { label: 'apiScenario.copyScenario', color: 'rgb(var(--primary-7))' },
[ScenarioStepType.WAIT_TIME]: { label: 'apiScenario.waitTime', color: 'rgb(var(--warning-6))' },
[ScenarioStepType.LOOP_CONTROL]: { label: 'apiScenario.loopControl', color: 'rgba(167, 98, 191, 1)' },
[ScenarioStepType.CONDITION_CONTROL]: { label: 'apiScenario.conditionControl', color: 'rgba(238, 80, 163, 1)' },
[ScenarioStepType.ONLY_ONCE_CONTROL]: { label: 'apiScenario.onlyOnceControl', color: 'rgba(211, 68, 0, 1)' },
[ScenarioStepType.SCRIPT_OPERATION]: { label: 'apiScenario.scriptOperation', color: 'rgba(20, 225, 198, 1)' },
[ScenarioStepType.CUSTOM_API]: { label: 'apiScenario.customApi', color: 'rgb(var(--link-4))' },
};
const getClass = computed(() => {
return {
color: scenarioStepMap[props.status].color,
border: `1px solid ${scenarioStepMap[props.status].color}`,
};
});
</script>
<style scoped lang="less">
.condition-status {
padding: 0 2px;
font-size: 12px;
line-height: 16px;
border-radius: 0 12px 12px 0; /* 设置左半边为正常边框 */
}
</style>

View File

@ -99,18 +99,105 @@
</div>
</div>
<StepProgress :report-detail="reportStepDetail" height="8px" radius="var(--border-radius-mini)" />
<div>
<div></div>
<div></div>
<div></div>
<div class="card">
<div class="timer-card mr-2">
<div class="text-[var(--color-text-4)]">
<MsIcon type="icon-icon_time_outlined" class="text-[var(--color-text-4)]x mr-[4px]" size="16" />
总耗时
</div>
<div> <span class="ml-4 text-[18px] font-medium">3</span>s </div>
</div>
<div class="timer-card mr-2">
<div class="text-[var(--color-text-4)]">
<MsIcon type="icon-icon_time_outlined" class="mr-[4px] text-[var(--color-text-4)]" size="16" />
请求总耗时
</div>
<div> <span class="ml-4 text-[18px] font-medium">3</span>s </div>
</div>
<div class="timer-card min-w-[200px]">
<div class="text-[var(--color-text-4)]">
<MsIcon type="icon-icon_yes_outlined" class="mr-[4px] text-[var(--color-text-4)]" size="16" />
断言通过率
</div>
<div class="flex items-center">
<span class="text-[18px] font-medium text-[var(--color-text-1)]">99.99 <span>%</span></span>
<a-divider direction="vertical" :margin="0" class="!mx-1"></a-divider>
<span class="text-[var(--color-text-1)]">1,000</span>
<span class="text-[var(--color-text-4)]">/ 1,000</span>
</div>
</div>
</div>
</div>
<div class="request-analyze"> </div>
<div class="request-analyze">
<div class="block-title">请求分析</div>
<div class="flex min-h-[110px] items-center">
<div class="relative mr-4">
<div class="absolute bottom-0 left-[30%] top-[35%] text-center">
<div class="text-[12px] text-[(var(--color-text-4))]">总数 ()</div>
<div class="text-[18px] font-medium">4</div>
</div>
<MsChart width="110px" height="110px" :options="charOptions" />
</div>
<div class="chart-legend grid flex-1 gap-y-4">
<div class="chart-legend-item">
<div class="chart-flag">
<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>
</div>
<div class="count">24</div>
<div class="count">99.99%</div>
</div>
<div class="chart-legend-item">
<div class="chart-flag">
<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>
</div>
<div class="count">24</div>
<div class="count">99.99%</div>
</div>
<div class="chart-legend-item">
<div class="chart-flag">
<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>
</div>
<div class="count">24</div>
<div class="count">99.99%</div>
</div>
<div class="chart-legend-item">
<div class="chart-flag">
<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>
</div>
<div class="count">24</div>
<div class="count">99.99%</div>
</div>
</div>
</div>
</div>
</div>
<!-- 报告步骤分析和请求分析结束 -->
<!-- 报告明细开始 -->
<div class="report-info"></div>
<div class="report-info">
<div class="mb-4 flex h-[36px] items-center justify-between">
<div class="flex items-center">
<div class="mr-2 font-medium leading-[36px]">报告明细</div>
<a-radio-group v-model:model-value="activeTab" type="button" size="small">
<a-radio v-for="item of methods" :key="item.value" :value="item.value">
{{ t(item.label) }}
</a-radio>
</a-radio-group>
</div>
<a-select v-model="condition" class="w-[240px]" placeholder="请选择过滤条件">
<a-option :key="1" :value="1"> 1 </a-option>
</a-select>
</div>
<TiledList v-show="activeTab === 'tiled'" />
</div>
<!-- 报告明细结束 -->
</div>
</template>
@ -120,10 +207,12 @@
<script setup lang="ts">
import { ref } from 'vue';
import MsChart from '@/components/pure/chart/index.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 TiledList from './tiledList.vue';
import { reportDetail } from '@/api/modules/api-test/report';
import { useI18n } from '@/hooks/useI18n';
@ -174,6 +263,81 @@
pendingCount: 9,
successCount: 9,
});
const charOptions = ref({
tooltip: {
trigger: 'item',
},
legend: {
show: false,
},
series: [
{
name: '',
type: 'pie',
radius: ['65%', '80%'],
avoidLabelOverlap: false,
label: {
show: false,
position: 'center',
},
emphasis: {
label: {
show: false,
fontSize: 40,
fontWeight: 'bold',
},
},
labelLine: {
show: false,
},
data: [
{
value: 1048,
name: '通过',
itemStyle: {
color: '#00C261',
},
},
{
value: 735,
name: '误报',
itemStyle: {
color: '#FFC14E',
},
},
{
value: 580,
name: '失败',
itemStyle: {
color: '#ED0303',
},
},
{
value: 484,
name: '未执行',
itemStyle: {
color: '#D4D4D8',
},
},
],
},
],
});
const activeTab = ref('tiled');
const condition = ref('');
const methods = ref([
{
label: '平铺展示',
value: 'tiled',
},
{
label: 'Tab展示',
value: 'tab',
},
]);
</script>
<style scoped lang="less">
@ -199,13 +363,37 @@
.countItem {
@apply mr-6 flex items-center;
}
.card {
@apply mt-4 flex items-center justify-between;
.timer-card {
border-radius: 6px;
background-color: var(--color-text-n9);
@apply flex flex-1 flex-col p-4;
}
}
}
.request-analyze {
padding: 16px;
border-radius: 4px;
@apply h-full bg-white;
@apply ml-4 h-full flex-grow bg-white;
.chart-legend {
.chart-legend-item {
@apply grid grid-cols-3;
}
.chart-flag {
@apply flex items-center;
.count {
color: var(--color-text-1);
}
}
}
}
}
.report-info {
padding: 16px;
border-radius: 4px;
@apply bg-white;
}
}
.block-title {
@apply mb-4 font-medium;

View File

@ -25,9 +25,12 @@
@batch-action="handleTableBatch"
>
<template #name="{ record, rowIndex }">
<a-button type="text" class="flex w-full" @click="showReportDetail(record.id, rowIndex)">{{
record.name
}}</a-button>
<div
type="text"
class="one-text-line flex w-full text-[rgb(var(--primary-5))]"
@click="showReportDetail(record.id, rowIndex)"
>{{ characterLimit(record.name) }}</div
>
</template>
<!-- 报告类型 -->
<template #integrated="{ record }">

View File

@ -0,0 +1,83 @@
<template>
<div
class="scenario-class cursor-pointer"
:class="[
props.showBorder ? 'border border-solid border-[var(--color-text-n8)]' : '',
props.hasBottomMargin ? 'mb-1' : '',
]"
>
<div class="flex h-[46px] items-center">
<!-- 序号 -->
<span class="index text-[var(--color-text-4)]">{{ props.item.sort }}</span>
<MsIcon type="icon-icon_split_turn-down_arrow" class="mx-[4px] text-[var(--color-text-4)]" size="16" />
<!-- 场景count -->
<span class="mr-2 text-[var(--color-text-4)]">8</span>
<!-- 循环控制器 -->
<ConditionStatus :status="props.item.stepType" />
<span class="ml-2">{{ props.item.name }}</span>
</div>
<div>
<MsTag class="cursor-pointer" :type="props.item.status === 'SUCCESS' ? 'success' : 'danger'" theme="light">
通过
</MsTag>
<span class="statusCode"
>状态码 <span class="code">{{ props.item.code }}</span></span
>
<span class="resTime"
>响应时间 <span class="resTimeCount">{{ props.item.requestTime }}ms</span></span
>
<span class="resSize"
>响应大小 <span class="resTimeCount">{{ props.item.responseSize }} bytes</span></span
>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import MsTag from '@/components/pure/ms-tag/ms-tag.vue';
import ConditionStatus from './conditionStatus.vue';
import { useI18n } from '@/hooks/useI18n';
import type { ScenarioItemType } from '@/models/apiTest/report';
const { t } = useI18n();
const props = withDefaults(
defineProps<{
showBorder?: boolean;
hasBottomMargin?: boolean;
item: ScenarioItemType;
}>(),
{
showBorder: true,
hasBottomMargin: true,
}
);
</script>
<style scoped lang="less">
.scenario-class {
border-radius: 4px;
@apply flex items-center justify-between px-2;
.index {
width: 16px;
height: 16px;
line-height: 16px;
border-radius: 50%;
color: white;
background: var(--color-text-brand);
@apply inline-block text-center;
}
.resTime,
.resSize,
.statusCode {
margin-right: 8px;
color: var(--color-text-4);
.resTimeCount {
color: rgb(var(--success-6));
}
}
}
</style>

View File

@ -0,0 +1,70 @@
<template>
<ms-base-table ref="tableRef" v-bind="propsRes" no-disable :indent-size="0" v-on="propsEvent">
<template #pass="{ record }">
<MsTag theme="light" :type="record.pass ? 'success' : 'danger'">
{{ record.pass ? '成功' : '失败' }}
</MsTag>
</template>
<template #script="{ record }">
{{ record.script }}
</template>
</ms-base-table>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
import type { MsTableColumn } from '@/components/pure/ms-table/type';
import useTable from '@/components/pure/ms-table/useTable';
import MsTag from '@/components/pure/ms-tag/ms-tag.vue';
import { useI18n } from '@/hooks/useI18n';
const { t } = useI18n();
const props = defineProps<{
data: any[];
}>();
const columns: MsTableColumn = [
{
title: 'report.detail.api.resContent',
dataIndex: 'content',
slotName: 'content',
showTooltip: true,
},
{
title: 'report.detail.api.resContent',
dataIndex: 'pass',
slotName: 'pass',
showTooltip: true,
},
{
title: 'report.detail.api.resContent',
dataIndex: 'script',
slotName: 'script',
showTooltip: true,
},
];
const { propsRes, propsEvent } = useTable(undefined, {
columns,
scroll: { x: 'auto' },
showPagination: false,
hoverable: false,
showExpand: true,
rowKey: 'id',
rowClass: (record: any) => {
if (record.children) {
return 'gray-td-bg';
}
},
});
watchEffect(() => {
propsRes.value.data = props.data;
});
</script>
<style scoped></style>

View File

@ -0,0 +1,36 @@
<template>
<MsCodeEditor
v-model:model-value="innerValue"
:show-theme-change="false"
title=""
width="100%"
height="208px"
:show-language-change="props.language ? true : false"
theme="MS-text"
:language="props.language"
:show-charset-change="props.showCharsetChange"
:read-only="false"
:show-full-screen="false"
/>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { useVModel } from '@vueuse/core';
import MsCodeEditor from '@/components/pure/ms-code-editor/index.vue';
import { CustomTheme, editorProps, Language, LanguageEnum, Theme } from '@/components/pure/ms-code-editor/types';
const props = defineProps<{
script: string;
language?: Language;
showCharsetChange: boolean;
}>();
const emit = defineEmits<{
(e: 'update:script', value: string): void;
}>();
const innerValue = useVModel(props, 'script', emit);
</script>
<style scoped></style>

View File

@ -0,0 +1,269 @@
<template>
<MsDrawer
ref="detailDrawerRef"
v-model:visible="showDrawer"
:width="960"
:footer="false"
:title="t('步骤名称')"
show-full-screen
:unmount-on-close="true"
>
<template #headerLeft>
<div class="scene-type"> API </div>
</template>
<div>
<ms-base-table
ref="tableRef"
v-bind="propsRes"
v-model:expandedKeys="expandedKeys"
no-disable
:indent-size="0"
v-on="propsEvent"
>
<template #titleName>
<div class="flex w-full justify-between">
<div class="font-medium">响应内容</div>
<div class="grid grid-cols-5 gap-2 text-center">
<span>401</span>
<span class="text-[rgb(var(--success-6))]">247ms</span>
<span class="text-[rgb(var(--success-6))]">50bytes</span>
<span>Mock</span>
<span>66</span>
</div>
</div>
</template>
<template #name="{ record }">
<span class="font-medium">
{{ record.name }}
</span>
<div v-if="record.script && !record.isAssertion" class="w-full">
<ResContent :script="record.script" language="JSON" :show-charset-change="record.script" />
</div>
<div v-if="record.isAssertion" class="w-full">
<assertTable :data="record.assertions" />
</div>
</template>
</ms-base-table>
</div>
</MsDrawer>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import MsDrawer from '@/components/pure/ms-drawer/index.vue';
import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
import type { MsPaginationI, MsTableColumn } from '@/components/pure/ms-table/type';
import useTable from '@/components/pure/ms-table/useTable';
import assertTable from './assertTable.vue';
import ResContent from './resContent.vue';
import { reportDetail } from '@/api/modules/api-test/report';
import { useI18n } from '@/hooks/useI18n';
const { t } = useI18n();
const props = defineProps<{
visible: boolean;
stepId: string;
activeStepIndex: number;
}>();
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.stepId);
function loadedStep(detail: Record<string, any>) {
innerFileId.value = detail.id;
}
const tableRef = ref<InstanceType<typeof MsBaseTable> | null>(null);
const expandedKeys = ref<string[]>([]);
const columns: MsTableColumn = [
{
title: 'report.detail.api.resContent',
dataIndex: 'name',
slotName: 'name',
titleSlotName: 'titleName',
fixed: 'left',
headerCellClass: 'titleClass',
bodyCellClass: (record) => {
if (record.children) {
return '';
}
return 'cellClassWrapper';
},
},
];
const { propsRes, propsEvent, loadList, setLoadListParams } = useTable(undefined, {
columns,
scroll: { x: 'auto' },
showPagination: false,
hoverable: false,
showExpand: true,
rowKey: 'id',
rowClass: (record: any) => {
if (record.children) {
return 'gray-td-bg';
}
},
});
const listMap = [
{
title: '响应体',
value: 'body',
},
{
title: '响应头',
value: 'headers',
},
{
title: '实际请求',
value: 'request',
},
{
title: '控制台',
value: 'request',
},
];
onMounted(() => {
//
propsRes.value.data = [
{
id: '1001',
name: '响应体',
script: '',
isAssertion: false,
assertions: [],
children: [
{
script: '1',
isAssertion: false,
assertions: [],
},
],
},
{
id: '1002',
name: '响应头',
script: '',
isAssertion: false,
assertions: [],
children: [
{
script: '2',
isAssertion: false,
assertions: [],
},
],
},
{
id: '1003',
name: '实际请求',
script: '',
isAssertion: false,
assertions: [],
children: [
{
script: '3',
isAssertion: false,
assertions: [],
},
],
},
{
id: '1004',
name: '控制台',
script: '',
isAssertion: false,
assertions: [],
children: [
{
script: '4',
isAssertion: false,
assertions: [],
},
],
},
{
id: '1005',
name: '提取',
script: '',
isAssertion: false,
assertions: [],
children: [
{
script: '1',
isAssertion: false,
assertions: [],
},
],
},
{
id: '1007',
name: '断言',
script: '',
isAssertion: false,
assertions: [],
children: [
{
script: '1',
isAssertion: true,
assertions: [
{
name: 'string',
content: 'string',
script: 'string',
message: 'string',
pass: true,
},
],
},
],
},
];
});
</script>
<style scoped lang="less">
.scene-type {
margin-left: 8px;
padding: 0 2px;
font-size: 12px;
line-height: 16px;
border: 1px solid rgb(var(--link-6));
border-radius: 0 12px 12px 0;
color: rgb(var(--link-6));
}
.resContentHeader {
@apply flex justify-between;
}
:deep(.gray-td-bg) {
td {
background-color: var(--color-text-n9);
}
}
:deep(.titleClass .arco-table-th-title) {
@apply w-full;
}
:deep(.cellClassWrapper .arco-table-cell) {
padding: 0 !important;
span {
padding-left: 0 !important;
}
}
</style>

View File

@ -0,0 +1,147 @@
<template>
<div class="tiled-wrap">
<ScenarioItem :item="scenario" :show-border="false" />
<a-divider :margin="0" class="!mb-4"></a-divider>
<div class="pl-[32px] pr-4">
<MsList
v-model:data="tiledList"
mode="static"
item-key-field="stepId"
:item-border="false"
class="w-full rounded-[var(--border-radius-small)]"
:no-more-data="noMoreData"
:draggable="false"
:virtual-list-props="{
height: 'calc(100vh - 438px)',
}"
>
<template #item="{ item }">
<ScenarioItem :item="item" @click="showDetail(item)" />
</template>
</MsList>
</div>
<StepDrawer v-model:visible="showStepDrawer" :step-id="activeDetailId" :active-step-index="activeStepIndex" />
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import MsList from '@/components/pure/ms-list/index.vue';
import ScenarioItem from './scenarioItem.vue';
import StepDrawer from './step/stepDrawer.vue';
import type { ScenarioItemType } from '@/models/apiTest/report';
const noMoreData = ref<boolean>(false);
const tiledList = ref<ScenarioItemType[]>([
{
stepId: '步骤id',
reportId: '报告id',
name: '场景名称',
sort: 0,
stepType: 'QUOTE_API',
parentId: 'string',
status: 'SUCCESS',
fakeCode: 'string',
requestName: 'string',
requestTime: 3000,
code: '200',
responseSize: 234543,
scriptIdentifier: 'string',
},
{
stepId: '步骤id1',
reportId: '报告id',
name: '场景名称',
sort: 0,
stepType: 'LOOP_CONTROL',
parentId: 'string',
status: 'SUCCESS',
fakeCode: 'string',
requestName: 'string',
requestTime: 3000,
code: '200',
responseSize: 234543,
scriptIdentifier: 'string',
},
{
stepId: '步骤id1',
reportId: '报告id',
name: '场景名称',
sort: 0,
stepType: 'CONDITION_CONTROL',
parentId: 'string',
status: 'ERROR',
fakeCode: 'string',
requestName: 'string',
requestTime: 3000,
code: '200',
responseSize: 234543,
scriptIdentifier: 'string',
},
{
stepId: '步骤id1',
reportId: '报告id',
name: '场景名称',
sort: 0,
stepType: 'ONLY_ONCE_CONTROL',
parentId: 'string',
status: 'SUCCESS',
fakeCode: 'string',
requestName: 'string',
requestTime: 3000,
code: '200',
responseSize: 234543,
scriptIdentifier: 'string',
},
{
stepId: '步骤id1',
reportId: '报告id',
name: '场景名称',
sort: 0,
stepType: 'ONLY_ONCE_CONTROL',
parentId: 'string',
status: 'ERROR',
fakeCode: 'string',
requestName: 'string',
requestTime: 3000,
code: '200',
responseSize: 234543,
scriptIdentifier: 'string',
},
]);
const scenario = ref<ScenarioItemType>({
stepId: '步骤id1',
reportId: '报告id',
name: '场景名称',
sort: 0,
stepType: 'ONLY_ONCE_CONTROL',
parentId: 'string',
status: 'string',
fakeCode: 'string',
requestName: 'string',
requestTime: 3000,
code: '200',
responseSize: 234543,
scriptIdentifier: 'string',
});
const showStepDrawer = ref<boolean>(false);
const activeDetailId = ref<string>('');
const activeStepIndex = ref<number>(0);
function showDetail(item: ScenarioItemType) {
showStepDrawer.value = true;
activeDetailId.value = item.stepId;
activeStepIndex.value = item.sort;
}
</script>
<style scoped lang="less">
.tiled-wrap {
min-height: 300px;
border: 1px solid var(--color-text-n8);
border-radius: 4px;
}
</style>

View File

@ -32,4 +32,5 @@ export default {
'report.detail.scenario.errorTip':
'There is a pre/post script running error in the execution step of the current scenario.',
'report.detail.api.errorTip': 'There are pre/post script running errors in the current use case execution.',
'report.detail.api.resContent': 'Response content',
};

View File

@ -31,4 +31,5 @@ export default {
'report.detail.script.error': '脚本失败',
'report.detail.scenario.errorTip': '当前场景的执行步骤中存在 前/后置脚本运行错误',
'report.detail.api.errorTip': '当前用例执行存在 前/后置脚本运行错误',
'report.detail.api.resContent': '响应内容',
};

View File

@ -48,9 +48,12 @@
<span type="text" class="px-0" @click="showCaseDetail(record.id, rowIndex)">{{ record.num }}</span>
</template>
<template #name="{ record, rowIndex }">
<a-button type="text" class="flex w-full" @click="showCaseDetail(record.id, rowIndex)">{{
characterLimit(record.name)
}}</a-button>
<div
type="text"
class="one-line-text text-[rgb(var(--primary-5))]"
@click="showCaseDetail(record.id, rowIndex)"
>{{ characterLimit(record.name) }}</div
>
</template>
<template #updateUserName="{ record }">
<span type="text" class="px-0">{{ record.updateUserName || '-' }}</span>