fix(测试用例&测试计划): 用例详情-修复自动下一条顺序不对的缺陷
--bug=1045034 --user=吕梦园 https://www.tapd.cn/55049933/bugtrace/bugs/view/1155049933001045034
This commit is contained in:
parent
48897e83ac
commit
d82745cd98
|
@ -86,192 +86,195 @@
|
||||||
</a-spin>
|
</a-spin>
|
||||||
</div>
|
</div>
|
||||||
<a-spin :loading="caseDetailLoading" class="relative flex flex-1 flex-col overflow-hidden">
|
<a-spin :loading="caseDetailLoading" class="relative flex flex-1 flex-col overflow-hidden">
|
||||||
<div class="content-center">
|
<MsEmpty v-if="!caseList.length" />
|
||||||
<div class="rounded-[var(--border-radius-small)] bg-[var(--color-text-n9)] p-[16px]">
|
<template v-else>
|
||||||
<div class="mb-[12px] flex items-center">
|
<div class="content-center">
|
||||||
<div class="mr-[16px] flex-1 overflow-hidden">
|
<div class="rounded-[var(--border-radius-small)] bg-[var(--color-text-n9)] p-[16px]">
|
||||||
<a-tooltip :content="`【${caseDetail.num}】${caseDetail.name}`">
|
<div class="mb-[12px] flex items-center">
|
||||||
<div
|
<div class="mr-[16px] flex-1 overflow-hidden">
|
||||||
class="one-line-text w-[fit-content] max-w-[100%] cursor-pointer font-medium text-[rgb(var(--primary-5))]"
|
<a-tooltip :content="`【${caseDetail.num}】${caseDetail.name}`">
|
||||||
@click="goCaseDetail"
|
<div
|
||||||
>
|
class="one-line-text w-[fit-content] max-w-[100%] cursor-pointer font-medium text-[rgb(var(--primary-5))]"
|
||||||
【{{ caseDetail.num }}】{{ caseDetail.name }}
|
@click="goCaseDetail"
|
||||||
|
>
|
||||||
|
【{{ caseDetail.num }}】{{ caseDetail.name }}
|
||||||
|
</div>
|
||||||
|
</a-tooltip>
|
||||||
|
</div>
|
||||||
|
<a-button
|
||||||
|
v-permission="['FUNCTIONAL_CASE:READ+UPDATE']"
|
||||||
|
type="outline"
|
||||||
|
size="mini"
|
||||||
|
class="arco-btn-outline--secondary"
|
||||||
|
@click="editCaseVisible = true"
|
||||||
|
>
|
||||||
|
{{ t('common.edit') }}
|
||||||
|
</a-button>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center">
|
||||||
|
<MsIcon type="icon-icon_folder_filled1" class="mr-[4px] text-[var(--color-text-4)]" />
|
||||||
|
<a-tooltip :content="caseDetail.moduleName || t('common.root')">
|
||||||
|
<div class="one-line-text mr-[8px] max-w-[300px] font-medium text-[var(--color-text-000)]">
|
||||||
|
{{ caseDetail.moduleName || t('common.root') }}
|
||||||
</div>
|
</div>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</div>
|
<div class="case-detail-label">
|
||||||
<a-button
|
{{ t('caseManagement.caseReview.caseLevel') }}
|
||||||
v-permission="['FUNCTIONAL_CASE:READ+UPDATE']"
|
|
||||||
type="outline"
|
|
||||||
size="mini"
|
|
||||||
class="arco-btn-outline--secondary"
|
|
||||||
@click="editCaseVisible = true"
|
|
||||||
>
|
|
||||||
{{ t('common.edit') }}
|
|
||||||
</a-button>
|
|
||||||
</div>
|
|
||||||
<div class="flex items-center">
|
|
||||||
<MsIcon type="icon-icon_folder_filled1" class="mr-[4px] text-[var(--color-text-4)]" />
|
|
||||||
<a-tooltip :content="caseDetail.moduleName || t('common.root')">
|
|
||||||
<div class="one-line-text mr-[8px] max-w-[300px] font-medium text-[var(--color-text-000)]">
|
|
||||||
{{ caseDetail.moduleName || t('common.root') }}
|
|
||||||
</div>
|
</div>
|
||||||
</a-tooltip>
|
<div class="case-detail-value">
|
||||||
<div class="case-detail-label">
|
<caseLevel :case-level="caseDetailLevel" />
|
||||||
{{ t('caseManagement.caseReview.caseLevel') }}
|
</div>
|
||||||
</div>
|
<!-- <div class="case-detail-label">
|
||||||
<div class="case-detail-value">
|
|
||||||
<caseLevel :case-level="caseDetailLevel" />
|
|
||||||
</div>
|
|
||||||
<!-- <div class="case-detail-label">
|
|
||||||
{{ t('caseManagement.caseReview.caseVersion') }}
|
{{ t('caseManagement.caseReview.caseVersion') }}
|
||||||
</div>
|
</div>
|
||||||
<div class="case-detail-value">
|
<div class="case-detail-value">
|
||||||
<MsIcon type="icon-icon_version" size="13" class="mr-[4px]" />
|
<MsIcon type="icon-icon_version" size="13" class="mr-[4px]" />
|
||||||
{{ caseDetail.versionName }}
|
{{ caseDetail.versionName }}
|
||||||
</div> -->
|
</div> -->
|
||||||
<div class="case-detail-label">
|
<div class="case-detail-label">
|
||||||
{{ t('caseManagement.caseReview.reviewResult') }}
|
{{ t('caseManagement.caseReview.reviewResult') }}
|
||||||
</div>
|
</div>
|
||||||
<div class="case-detail-value">
|
<div class="case-detail-value">
|
||||||
<ReviewStatusTrigger v-if="reviewDetail.reviewPassRule === 'MULTIPLE'" ref="reviewStatusTriggerRef" />
|
<ReviewStatusTrigger v-if="reviewDetail.reviewPassRule === 'MULTIPLE'" ref="reviewStatusTriggerRef" />
|
||||||
<div
|
<div
|
||||||
v-if="reviewResultMap[activeCaseReviewStatus as ReviewResult] && reviewDetail.reviewPassRule !== 'MULTIPLE'"
|
v-if="reviewResultMap[activeCaseReviewStatus as ReviewResult] && reviewDetail.reviewPassRule !== 'MULTIPLE'"
|
||||||
class="flex items-center gap-[4px]"
|
class="flex items-center gap-[4px]"
|
||||||
>
|
>
|
||||||
<MsIcon
|
<MsIcon
|
||||||
:type="reviewResultMap[activeCaseReviewStatus as ReviewResult].icon"
|
:type="reviewResultMap[activeCaseReviewStatus as ReviewResult].icon"
|
||||||
:style="{
|
:style="{
|
||||||
color: reviewResultMap[activeCaseReviewStatus as ReviewResult].color,
|
color: reviewResultMap[activeCaseReviewStatus as ReviewResult].color,
|
||||||
}"
|
}"
|
||||||
/>
|
/>
|
||||||
{{ t(reviewResultMap[activeCaseReviewStatus as ReviewResult].label) }}
|
{{ t(reviewResultMap[activeCaseReviewStatus as ReviewResult].label) }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<a-tabs v-model:active-key="showTab" class="no-content">
|
||||||
<a-tabs v-model:active-key="showTab" class="no-content">
|
<a-tab-pane :key="tabList[0].key" :title="tabList[0].title" />
|
||||||
<a-tab-pane :key="tabList[0].key" :title="tabList[0].title" />
|
<a-tab-pane :key="tabList[1].key" :title="tabList[1].title" />
|
||||||
<a-tab-pane :key="tabList[1].key" :title="tabList[1].title" />
|
<a-tab-pane :key="tabList[2].key">
|
||||||
<a-tab-pane :key="tabList[2].key">
|
<template #title>
|
||||||
<template #title>
|
<div class="flex items-center">
|
||||||
<div class="flex items-center">
|
{{ tabList[2].title }}
|
||||||
{{ tabList[2].title }}
|
<div
|
||||||
<div
|
v-if="caseDetail.demandCount > 0"
|
||||||
v-if="caseDetail.demandCount > 0"
|
style="min-width: 16px; text-align: center; align-content: center"
|
||||||
style="min-width: 16px; text-align: center; align-content: center"
|
:class="`ml-[4px] h-[16px] rounded-full ${
|
||||||
:class="`ml-[4px] h-[16px] rounded-full ${
|
showTab === tabList[2].key
|
||||||
showTab === tabList[2].key
|
? 'bg-[rgb(var(--primary-9))] text-[rgb(var(--primary-5))]'
|
||||||
? 'bg-[rgb(var(--primary-9))] text-[rgb(var(--primary-5))]'
|
: 'bg-[var(--color-text-brand)] text-white'
|
||||||
: 'bg-[var(--color-text-brand)] text-white'
|
} px-[4px] text-[12px]`"
|
||||||
} px-[4px] text-[12px]`"
|
>
|
||||||
>
|
{{ caseDetail.demandCount > 99 ? '99+' : caseDetail.demandCount }}
|
||||||
{{ caseDetail.demandCount > 99 ? '99+' : caseDetail.demandCount }}
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</template>
|
||||||
</template>
|
</a-tab-pane>
|
||||||
</a-tab-pane>
|
<a-tab-pane :key="tabList[3].key" :title="tabList[3].title" />
|
||||||
<a-tab-pane :key="tabList[3].key" :title="tabList[3].title" />
|
</a-tabs>
|
||||||
</a-tabs>
|
<a-divider class="my-0" />
|
||||||
<a-divider class="my-0" />
|
<MsDescription
|
||||||
<MsDescription
|
v-if="showTab === 'baseInfo'"
|
||||||
v-if="showTab === 'baseInfo'"
|
:descriptions="descriptions"
|
||||||
:descriptions="descriptions"
|
label-width="90px"
|
||||||
label-width="90px"
|
class="mt-[16px]"
|
||||||
class="mt-[16px]"
|
/>
|
||||||
/>
|
<div v-else-if="showTab === 'detail'" class="mt-[16px] h-full">
|
||||||
<div v-else-if="showTab === 'detail'" class="mt-[16px] h-full">
|
<caseTabDetail :form="caseDetail" :allow-edit="false" />
|
||||||
<caseTabDetail :form="caseDetail" :allow-edit="false" />
|
</div>
|
||||||
</div>
|
<div v-else-if="showTab === 'demand'">
|
||||||
<div v-else-if="showTab === 'demand'">
|
<div class="mt-[16px] flex items-center justify-between">
|
||||||
<div class="mt-[16px] flex items-center justify-between">
|
{{ t('caseManagement.caseReview.demandCases') }}
|
||||||
{{ t('caseManagement.caseReview.demandCases') }}
|
<a-input-search
|
||||||
<a-input-search
|
v-model="demandKeyword"
|
||||||
v-model="demandKeyword"
|
:placeholder="t('caseManagement.caseReview.demandSearchPlaceholder')"
|
||||||
:placeholder="t('caseManagement.caseReview.demandSearchPlaceholder')"
|
allow-clear
|
||||||
allow-clear
|
class="w-[300px]"
|
||||||
class="w-[300px]"
|
@press-enter="searchDemand"
|
||||||
@press-enter="searchDemand"
|
@search="searchDemand"
|
||||||
@search="searchDemand"
|
@clear="searchDemand"
|
||||||
@clear="searchDemand"
|
/>
|
||||||
|
</div>
|
||||||
|
<caseTabDemand
|
||||||
|
ref="caseDemandRef"
|
||||||
|
:fun-params="{ projectId: appStore.currentProjectId, caseId: activeCaseId, keyword: demandKeyword }"
|
||||||
|
:show-empty="false"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<caseTabDemand
|
<div v-else class="flex flex-1 flex-col overflow-hidden pl-[16px] pt-[16px]">
|
||||||
ref="caseDemandRef"
|
<div class="ms-comment-list">
|
||||||
:fun-params="{ projectId: appStore.currentProjectId, caseId: activeCaseId, keyword: demandKeyword }"
|
<a-spin :loading="reviewHistoryListLoading" class="h-full w-full">
|
||||||
:show-empty="false"
|
<div v-for="item of reviewHistoryList" :key="item.id" class="ms-comment-list-item">
|
||||||
/>
|
<MSAvatar :avatar="item.userLogo" />
|
||||||
</div>
|
<div class="flex-1 overflow-hidden">
|
||||||
<div v-else class="flex flex-1 flex-col overflow-hidden pl-[16px] pt-[16px]">
|
<div class="flex items-center gap-[8px]">
|
||||||
<div class="ms-comment-list">
|
<div class="flex-1 overflow-hidden">
|
||||||
<a-spin :loading="reviewHistoryListLoading" class="h-full w-full">
|
<a-tooltip :content="item.userName">
|
||||||
<div v-for="item of reviewHistoryList" :key="item.id" class="ms-comment-list-item">
|
<div
|
||||||
<MSAvatar :avatar="item.userLogo" />
|
class="one-line-text w-[fit-content] max-w-[100%] font-medium text-[var(--color-text-1)]"
|
||||||
<div class="flex-1 overflow-hidden">
|
>
|
||||||
<div class="flex items-center gap-[8px]">
|
{{ item.userName }}
|
||||||
<div class="flex-1 overflow-hidden">
|
</div>
|
||||||
<a-tooltip :content="item.userName">
|
</a-tooltip>
|
||||||
<div
|
</div>
|
||||||
class="one-line-text w-[fit-content] max-w-[100%] font-medium text-[var(--color-text-1)]"
|
<div v-if="item.status === 'PASS'" class="flex items-center">
|
||||||
>
|
<MsIcon type="icon-icon_succeed_filled" class="mr-[4px] text-[rgb(var(--success-6))]" />
|
||||||
{{ item.userName }}
|
{{ t('caseManagement.caseReview.pass') }}
|
||||||
</div>
|
</div>
|
||||||
</a-tooltip>
|
<div v-else-if="item.status === 'UN_PASS'" class="flex items-center">
|
||||||
|
<MsIcon type="icon-icon_close_filled" class="mr-[4px] text-[rgb(var(--danger-6))]" />
|
||||||
|
{{ t('caseManagement.caseReview.fail') }}
|
||||||
|
</div>
|
||||||
|
<div v-else-if="item.status === 'UNDER_REVIEWED'" class="flex items-center">
|
||||||
|
<MsIcon type="icon-icon_warning_filled" class="mr-[4px] text-[rgb(var(--warning-6))]" />
|
||||||
|
{{ t('caseManagement.caseReview.suggestion') }}
|
||||||
|
</div>
|
||||||
|
<div v-else-if="item.status === 'RE_REVIEWED'" class="flex items-center">
|
||||||
|
<MsIcon type="icon-icon_resubmit_filled" class="mr-[4px] text-[rgb(var(--warning-6))]" />
|
||||||
|
{{ t('caseManagement.caseReview.reReview') }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="item.status === 'PASS'" class="flex items-center">
|
<div class="markdown-body ml-[48px]" v-html="item.contentText"></div>
|
||||||
<MsIcon type="icon-icon_succeed_filled" class="mr-[4px] text-[rgb(var(--success-6))]" />
|
<div class="mt-[8px] text-[12px] leading-[16px] text-[var(--color-text-4)]">
|
||||||
{{ t('caseManagement.caseReview.pass') }}
|
{{ dayjs(item.createTime).format('YYYY-MM-DD HH:mm:ss') }}
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="item.status === 'UN_PASS'" class="flex items-center">
|
|
||||||
<MsIcon type="icon-icon_close_filled" class="mr-[4px] text-[rgb(var(--danger-6))]" />
|
|
||||||
{{ t('caseManagement.caseReview.fail') }}
|
|
||||||
</div>
|
|
||||||
<div v-else-if="item.status === 'UNDER_REVIEWED'" class="flex items-center">
|
|
||||||
<MsIcon type="icon-icon_warning_filled" class="mr-[4px] text-[rgb(var(--warning-6))]" />
|
|
||||||
{{ t('caseManagement.caseReview.suggestion') }}
|
|
||||||
</div>
|
|
||||||
<div v-else-if="item.status === 'RE_REVIEWED'" class="flex items-center">
|
|
||||||
<MsIcon type="icon-icon_resubmit_filled" class="mr-[4px] text-[rgb(var(--warning-6))]" />
|
|
||||||
{{ t('caseManagement.caseReview.reReview') }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="markdown-body ml-[48px]" v-html="item.contentText"></div>
|
|
||||||
<div class="mt-[8px] text-[12px] leading-[16px] text-[var(--color-text-4)]">
|
|
||||||
{{ dayjs(item.createTime).format('YYYY-MM-DD HH:mm:ss') }}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<MsEmpty v-if="reviewHistoryList.length === 0" />
|
||||||
<MsEmpty v-if="reviewHistoryList.length === 0" />
|
</a-spin>
|
||||||
</a-spin>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="content-footer">
|
||||||
<div class="content-footer">
|
<div class="mb-[12px] flex items-center justify-between">
|
||||||
<div class="mb-[12px] flex items-center justify-between">
|
<div class="font-medium text-[var(--color-text-1)]">
|
||||||
<div class="font-medium text-[var(--color-text-1)]">
|
{{ t('caseManagement.caseReview.startReview') }}
|
||||||
{{ t('caseManagement.caseReview.startReview') }}
|
</div>
|
||||||
</div>
|
<div class="flex items-center">
|
||||||
<div class="flex items-center">
|
<a-switch v-model:model-value="autoNext" class="mx-[8px]" size="small" type="line" />
|
||||||
<a-switch v-model:model-value="autoNext" class="mx-[8px]" size="small" type="line" />
|
<div class="text-[var(--color-text-4)]">{{ t('caseManagement.caseReview.autoNext') }}</div>
|
||||||
<div class="text-[var(--color-text-4)]">{{ t('caseManagement.caseReview.autoNext') }}</div>
|
<a-tooltip position="right">
|
||||||
<a-tooltip position="right">
|
<template #content>
|
||||||
<template #content>
|
<div>{{ t('caseManagement.caseReview.autoNextTip1') }}</div>
|
||||||
<div>{{ t('caseManagement.caseReview.autoNextTip1') }}</div>
|
<div>{{ t('caseManagement.caseReview.autoNextTip2') }}</div>
|
||||||
<div>{{ t('caseManagement.caseReview.autoNextTip2') }}</div>
|
</template>
|
||||||
</template>
|
<icon-question-circle
|
||||||
<icon-question-circle
|
class="mb-[2px] ml-[4px] text-[var(--color-text-4)] hover:text-[rgb(var(--primary-5))]"
|
||||||
class="mb-[2px] ml-[4px] text-[var(--color-text-4)] hover:text-[rgb(var(--primary-5))]"
|
size="16"
|
||||||
size="16"
|
/>
|
||||||
/>
|
</a-tooltip>
|
||||||
</a-tooltip>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<reviewForm
|
||||||
|
:review-id="reviewId"
|
||||||
|
:case-id="activeCaseId"
|
||||||
|
:review-pass-rule="reviewDetail.reviewPassRule"
|
||||||
|
@done="reviewDone"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<reviewForm
|
</template>
|
||||||
:review-id="reviewId"
|
|
||||||
:case-id="activeCaseId"
|
|
||||||
:review-pass-rule="reviewDetail.reviewPassRule"
|
|
||||||
@done="reviewDone"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</a-spin>
|
</a-spin>
|
||||||
</div>
|
</div>
|
||||||
</MsCard>
|
</MsCard>
|
||||||
|
@ -524,6 +527,7 @@
|
||||||
watch(
|
watch(
|
||||||
() => activeCaseId.value,
|
() => activeCaseId.value,
|
||||||
() => {
|
() => {
|
||||||
|
console.log('🤔️ =>', activeCaseId.value);
|
||||||
loadCaseDetail();
|
loadCaseDetail();
|
||||||
initReviewerAndStatus();
|
initReviewerAndStatus();
|
||||||
initReviewHistoryList();
|
initReviewHistoryList();
|
||||||
|
@ -546,10 +550,28 @@
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function reviewDone() {
|
async function reviewDone(status: string) {
|
||||||
if (autoNext.value) {
|
if (autoNext.value) {
|
||||||
// 自动下一个,更改激活的 id会刷新详情
|
// 自动下一个,更改激活的 id会刷新详情
|
||||||
const index = caseList.value.findIndex((e) => e.caseId === activeCaseId.value);
|
const index = caseList.value.findIndex((e) => e.caseId === activeCaseId.value);
|
||||||
|
|
||||||
|
// 如果过滤的状态和评审状态不一样,则这条将从当前列表排除
|
||||||
|
const oneMissingCase = type.value !== '' && status !== type.value;
|
||||||
|
if (oneMissingCase) {
|
||||||
|
if ((pageNation.value.current - 1) * pageNation.value.pageSize + index + 1 < pageNation.value.total) {
|
||||||
|
// 不是最后一个
|
||||||
|
await loadCaseList();
|
||||||
|
activeCaseId.value = caseList.value[index].caseId;
|
||||||
|
} else {
|
||||||
|
// 是最后一个,如果列表还有其他数据,则选中第一条;如果没有其他数据,则显示暂无数据
|
||||||
|
await loadCaseList();
|
||||||
|
if (caseList.value.length > 1) {
|
||||||
|
activeCaseId.value = caseList.value[0].caseId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (index < caseList.value.length - 1) {
|
if (index < caseList.value.length - 1) {
|
||||||
await loadCaseList();
|
await loadCaseList();
|
||||||
activeCaseId.value = caseList.value[index + 1].caseId;
|
activeCaseId.value = caseList.value[index + 1].caseId;
|
||||||
|
|
|
@ -178,7 +178,7 @@
|
||||||
if (typeof done === 'function') {
|
if (typeof done === 'function') {
|
||||||
done(true);
|
done(true);
|
||||||
}
|
}
|
||||||
emit('done');
|
emit('done', params.status);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.log(error);
|
console.log(error);
|
||||||
|
|
|
@ -59,151 +59,156 @@
|
||||||
</div>
|
</div>
|
||||||
<!-- 右侧 -->
|
<!-- 右侧 -->
|
||||||
<a-spin :loading="caseDetailLoading" class="relative flex h-full flex-1 flex-col overflow-hidden">
|
<a-spin :loading="caseDetailLoading" class="relative flex h-full flex-1 flex-col overflow-hidden">
|
||||||
<div class="flex px-[16px] pt-[16px]">
|
<MsEmpty v-if="!caseList.length" />
|
||||||
<div class="mr-[24px] flex flex-1 items-center overflow-hidden">
|
<template v-else>
|
||||||
<MsStatusTag :status="caseDetail.lastExecuteResult || 'PREPARED'" />
|
<div class="flex px-[16px] pt-[16px]">
|
||||||
<div class="ml-[8px] mr-[2px] cursor-pointer font-medium text-[rgb(var(--primary-5))]" @click="goCaseDetail"
|
<div class="mr-[24px] flex flex-1 items-center overflow-hidden">
|
||||||
>[{{ caseDetail.num }}]</div
|
<MsStatusTag :status="caseDetail.lastExecuteResult || 'PREPARED'" />
|
||||||
>
|
<div
|
||||||
<div class="flex-1 overflow-hidden">
|
class="ml-[8px] mr-[2px] cursor-pointer font-medium text-[rgb(var(--primary-5))]"
|
||||||
<a-tooltip :content="caseDetail.name">
|
@click="goCaseDetail"
|
||||||
<div class="one-line-text w-[fit-content] max-w-[100%] font-medium">
|
>[{{ caseDetail.num }}]</div
|
||||||
{{ caseDetail.name }}
|
>
|
||||||
</div>
|
<div class="flex-1 overflow-hidden">
|
||||||
</a-tooltip>
|
<a-tooltip :content="caseDetail.name">
|
||||||
|
<div class="one-line-text w-[fit-content] max-w-[100%] font-medium">
|
||||||
|
{{ caseDetail.name }}
|
||||||
|
</div>
|
||||||
|
</a-tooltip>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<a-button
|
||||||
<a-button
|
v-if="canEdit && hasAnyPermission(['FUNCTIONAL_CASE:READ+UPDATE'])"
|
||||||
v-if="canEdit && hasAnyPermission(['FUNCTIONAL_CASE:READ+UPDATE'])"
|
type="outline"
|
||||||
type="outline"
|
@click="editCaseVisible = true"
|
||||||
@click="editCaseVisible = true"
|
>{{ t('common.edit') }}</a-button
|
||||||
>{{ t('common.edit') }}</a-button
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<MsTab
|
|
||||||
v-model:active-key="activeTab"
|
|
||||||
:content-tab-list="contentTabList"
|
|
||||||
no-content
|
|
||||||
:get-text-func="getTotal"
|
|
||||||
class="relative mx-[16px] border-b"
|
|
||||||
/>
|
|
||||||
<div :class="[' flex-1', activeTab !== 'detail' ? 'tab-content' : 'overflow-hidden']">
|
|
||||||
<MsDescription v-if="activeTab === 'baseInfo'" :descriptions="descriptions" :column="2" one-line-value>
|
|
||||||
<template #value="{ item }">
|
|
||||||
<template v-if="item.key === 'reviewStatus'">
|
|
||||||
<MsIcon
|
|
||||||
:type="statusIconMap[item.value as keyof typeof statusIconMap]?.icon || ''"
|
|
||||||
class="mr-1"
|
|
||||||
:class="[statusIconMap[item.value as keyof typeof statusIconMap].color]"
|
|
||||||
></MsIcon>
|
|
||||||
<span>{{ statusIconMap[item.value as keyof typeof statusIconMap]?.statusText || '' }} </span>
|
|
||||||
</template>
|
|
||||||
</template>
|
|
||||||
</MsDescription>
|
|
||||||
<div v-else-if="activeTab === 'detail'" class="align-content-start flex h-full flex-col">
|
|
||||||
<CaseTabDetail ref="caseTabDetailRef" is-test-plan :form="caseDetail" :is-disabled-test-plan="!canEdit" />
|
|
||||||
<!-- 开始执行 -->
|
|
||||||
<div
|
|
||||||
v-if="canEdit && hasAnyPermission(['PROJECT_TEST_PLAN:READ+EXECUTE'])"
|
|
||||||
class="z-[101] px-[16px] py-[8px] shadow-[0_-1px_4px_rgba(2,2,2,0.1)]"
|
|
||||||
>
|
>
|
||||||
<div class="mb-[12px] flex items-center justify-between">
|
</div>
|
||||||
<div class="font-medium text-[var(--color-text-1)]">
|
<MsTab
|
||||||
{{ t('testPlan.featureCase.startExecution') }}
|
v-model:active-key="activeTab"
|
||||||
</div>
|
:content-tab-list="contentTabList"
|
||||||
<div class="flex items-center">
|
no-content
|
||||||
<a-switch v-model:model-value="autoNext" size="small" />
|
:get-text-func="getTotal"
|
||||||
<div class="mx-[8px]">{{ t('caseManagement.caseReview.autoNext') }}</div>
|
class="relative mx-[16px] border-b"
|
||||||
<a-tooltip position="top">
|
/>
|
||||||
<template #content>
|
<div :class="[' flex-1', activeTab !== 'detail' ? 'tab-content' : 'overflow-hidden']">
|
||||||
<div>{{ t('testPlan.featureCase.autoNextTip1') }}</div>
|
<MsDescription v-if="activeTab === 'baseInfo'" :descriptions="descriptions" :column="2" one-line-value>
|
||||||
<div>{{ t('testPlan.featureCase.autoNextTip2') }}</div>
|
<template #value="{ item }">
|
||||||
</template>
|
<template v-if="item.key === 'reviewStatus'">
|
||||||
<icon-question-circle
|
<MsIcon
|
||||||
class="text-[var(--color-text-brand)] hover:text-[rgb(var(--primary-4))]"
|
:type="statusIconMap[item.value as keyof typeof statusIconMap]?.icon || ''"
|
||||||
size="16"
|
class="mr-1"
|
||||||
/>
|
:class="[statusIconMap[item.value as keyof typeof statusIconMap].color]"
|
||||||
</a-tooltip>
|
></MsIcon>
|
||||||
<MsTag type="danger" theme="light" size="medium" class="ml-4">
|
<span>{{ statusIconMap[item.value as keyof typeof statusIconMap]?.statusText || '' }} </span>
|
||||||
<MsIcon type="icon-icon_defect" class="!text-[14px] text-[rgb(var(--danger-6))]" size="16" />
|
</template>
|
||||||
<span class="ml-1 text-[rgb(var(--danger-6))]"> {{ t('testPlan.featureCase.bug') }}</span>
|
</template>
|
||||||
<span class="ml-1 text-[rgb(var(--danger-6))]">{{ caseDetail.bugListCount }}</span>
|
</MsDescription>
|
||||||
</MsTag>
|
<div v-else-if="activeTab === 'detail'" class="align-content-start flex h-full flex-col">
|
||||||
<a-dropdown @select="handleSelect">
|
<CaseTabDetail ref="caseTabDetailRef" is-test-plan :form="caseDetail" :is-disabled-test-plan="!canEdit" />
|
||||||
<a-button
|
<!-- 开始执行 -->
|
||||||
v-if="hasAllPermission(['PROJECT_BUG:READ', 'PROJECT_TEST_PLAN:READ+EXECUTE'])"
|
<div
|
||||||
type="outline"
|
v-if="canEdit && hasAnyPermission(['PROJECT_TEST_PLAN:READ+EXECUTE'])"
|
||||||
size="small"
|
class="z-[101] px-[16px] py-[8px] shadow-[0_-1px_4px_rgba(2,2,2,0.1)]"
|
||||||
class="ml-1"
|
>
|
||||||
>
|
<div class="mb-[12px] flex items-center justify-between">
|
||||||
<template #icon> <icon-plus class="text-[12px]" /> </template>
|
<div class="font-medium text-[var(--color-text-1)]">
|
||||||
</a-button>
|
{{ t('testPlan.featureCase.startExecution') }}
|
||||||
<template #content>
|
</div>
|
||||||
<a-doption
|
<div class="flex items-center">
|
||||||
v-permission="['PROJECT_BUG:READ+ADD']"
|
<a-switch v-model:model-value="autoNext" size="small" />
|
||||||
:disabled="!hasAnyPermission(['PROJECT_BUG:READ+ADD'])"
|
<div class="mx-[8px]">{{ t('caseManagement.caseReview.autoNext') }}</div>
|
||||||
value="new"
|
<a-tooltip position="top">
|
||||||
>{{ t('common.newCreate') }}</a-doption
|
<template #content>
|
||||||
|
<div>{{ t('testPlan.featureCase.autoNextTip1') }}</div>
|
||||||
|
<div>{{ t('testPlan.featureCase.autoNextTip2') }}</div>
|
||||||
|
</template>
|
||||||
|
<icon-question-circle
|
||||||
|
class="text-[var(--color-text-brand)] hover:text-[rgb(var(--primary-4))]"
|
||||||
|
size="16"
|
||||||
|
/>
|
||||||
|
</a-tooltip>
|
||||||
|
<MsTag type="danger" theme="light" size="medium" class="ml-4">
|
||||||
|
<MsIcon type="icon-icon_defect" class="!text-[14px] text-[rgb(var(--danger-6))]" size="16" />
|
||||||
|
<span class="ml-1 text-[rgb(var(--danger-6))]"> {{ t('testPlan.featureCase.bug') }}</span>
|
||||||
|
<span class="ml-1 text-[rgb(var(--danger-6))]">{{ caseDetail.bugListCount }}</span>
|
||||||
|
</MsTag>
|
||||||
|
<a-dropdown @select="handleSelect">
|
||||||
|
<a-button
|
||||||
|
v-if="hasAllPermission(['PROJECT_BUG:READ', 'PROJECT_TEST_PLAN:READ+EXECUTE'])"
|
||||||
|
type="outline"
|
||||||
|
size="small"
|
||||||
|
class="ml-1"
|
||||||
>
|
>
|
||||||
<a-doption
|
<template #icon> <icon-plus class="text-[12px]" /> </template>
|
||||||
v-if="createdBugCount > 0 && hasAnyPermission(['PROJECT_BUG:READ'])"
|
</a-button>
|
||||||
:disabled="!hasAnyPermission(['PROJECT_BUG:READ'])"
|
<template #content>
|
||||||
value="link"
|
|
||||||
>{{ t('common.associated') }}</a-doption
|
|
||||||
>
|
|
||||||
<a-popover v-else title="" position="left">
|
|
||||||
<a-doption
|
<a-doption
|
||||||
v-if="createdBugCount < 1 && hasAnyPermission(['PROJECT_BUG:READ'])"
|
v-permission="['PROJECT_BUG:READ+ADD']"
|
||||||
|
:disabled="!hasAnyPermission(['PROJECT_BUG:READ+ADD'])"
|
||||||
|
value="new"
|
||||||
|
>{{ t('common.newCreate') }}</a-doption
|
||||||
|
>
|
||||||
|
<a-doption
|
||||||
|
v-if="createdBugCount > 0 && hasAnyPermission(['PROJECT_BUG:READ'])"
|
||||||
:disabled="!hasAnyPermission(['PROJECT_BUG:READ'])"
|
:disabled="!hasAnyPermission(['PROJECT_BUG:READ'])"
|
||||||
value="link"
|
value="link"
|
||||||
>{{ t('common.associated') }}</a-doption
|
>{{ t('common.associated') }}</a-doption
|
||||||
>
|
>
|
||||||
<template #content>
|
<a-popover v-else title="" position="left">
|
||||||
<div class="flex items-center text-[14px]">
|
<a-doption
|
||||||
<span class="text-[var(--color-text-4)]">{{
|
v-if="createdBugCount < 1 && hasAnyPermission(['PROJECT_BUG:READ'])"
|
||||||
t('testPlan.featureCase.noBugDataTooltip')
|
:disabled="!hasAnyPermission(['PROJECT_BUG:READ'])"
|
||||||
}}</span>
|
value="link"
|
||||||
<MsButton
|
>{{ t('common.associated') }}</a-doption
|
||||||
:disabled="!hasAnyPermission(['PROJECT_BUG:READ+ADD'])"
|
>
|
||||||
type="text"
|
<template #content>
|
||||||
@click="handleSelect('new')"
|
<div class="flex items-center text-[14px]">
|
||||||
>
|
<span class="text-[var(--color-text-4)]">{{
|
||||||
{{ t('testPlan.featureCase.noBugDataNewBug') }}
|
t('testPlan.featureCase.noBugDataTooltip')
|
||||||
</MsButton>
|
}}</span>
|
||||||
</div>
|
<MsButton
|
||||||
</template>
|
:disabled="!hasAnyPermission(['PROJECT_BUG:READ+ADD'])"
|
||||||
</a-popover>
|
type="text"
|
||||||
</template>
|
@click="handleSelect('new')"
|
||||||
</a-dropdown>
|
>
|
||||||
|
{{ t('testPlan.featureCase.noBugDataNewBug') }}
|
||||||
|
</MsButton>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</a-popover>
|
||||||
|
</template>
|
||||||
|
</a-dropdown>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<ExecuteSubmit
|
||||||
|
:id="activeId"
|
||||||
|
:case-id="activeCaseId"
|
||||||
|
:test-plan-id="route.query.id as string"
|
||||||
|
:step-execution-result="stepExecutionResult"
|
||||||
|
@done="executeDone"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<ExecuteSubmit
|
|
||||||
:id="activeId"
|
|
||||||
:case-id="activeCaseId"
|
|
||||||
:test-plan-id="route.query.id as string"
|
|
||||||
:step-execution-result="stepExecutionResult"
|
|
||||||
@done="executeDone"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
<BugList
|
||||||
|
v-if="activeTab === 'defectList'"
|
||||||
|
ref="bugRef"
|
||||||
|
:case-id="activeCaseId"
|
||||||
|
:test-plan-case-id="activeId"
|
||||||
|
:can-edit="canEdit && hasAnyPermission(['PROJECT_TEST_PLAN:READ+EXECUTE'])"
|
||||||
|
@link="linkDefect"
|
||||||
|
@new="addBug"
|
||||||
|
@update-count="loadCaseDetail()"
|
||||||
|
/>
|
||||||
|
<ExecutionHistory
|
||||||
|
v-if="activeTab === 'executionHistory'"
|
||||||
|
:execute-list="executeHistoryList"
|
||||||
|
:loading="executeLoading"
|
||||||
|
height="h-[calc(100vh-240px)]"
|
||||||
|
show-step-detail-trigger
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<BugList
|
</template>
|
||||||
v-if="activeTab === 'defectList'"
|
|
||||||
ref="bugRef"
|
|
||||||
:case-id="activeCaseId"
|
|
||||||
:test-plan-case-id="activeId"
|
|
||||||
:can-edit="canEdit && hasAnyPermission(['PROJECT_TEST_PLAN:READ+EXECUTE'])"
|
|
||||||
@link="linkDefect"
|
|
||||||
@new="addBug"
|
|
||||||
@update-count="loadCaseDetail()"
|
|
||||||
/>
|
|
||||||
<ExecutionHistory
|
|
||||||
v-if="activeTab === 'executionHistory'"
|
|
||||||
:execute-list="executeHistoryList"
|
|
||||||
:loading="executeLoading"
|
|
||||||
height="h-[calc(100vh-240px)]"
|
|
||||||
show-step-detail-trigger
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</a-spin>
|
</a-spin>
|
||||||
</div>
|
</div>
|
||||||
</MsCard>
|
</MsCard>
|
||||||
|
@ -451,10 +456,30 @@
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
const autoNext = ref(true);
|
const autoNext = ref(true);
|
||||||
async function executeDone() {
|
async function executeDone(status: LastExecuteResults) {
|
||||||
if (autoNext.value) {
|
if (autoNext.value) {
|
||||||
// 自动下一个,更改激活的 id会刷新详情
|
// 自动下一个,更改激活的 id会刷新详情
|
||||||
const index = caseList.value.findIndex((e) => e.id === activeId.value);
|
const index = caseList.value.findIndex((e) => e.id === activeId.value);
|
||||||
|
|
||||||
|
// 如果过滤的状态和执行状态不一样,则这条将从当前列表排除
|
||||||
|
const oneMissingCase = lastExecResult.value !== '' && status !== lastExecResult.value;
|
||||||
|
if (oneMissingCase) {
|
||||||
|
if ((pageNation.value.current - 1) * pageNation.value.pageSize + index + 1 < pageNation.value.total) {
|
||||||
|
// 不是最后一个
|
||||||
|
await loadCaseList();
|
||||||
|
activeCaseId.value = caseList.value[index].caseId;
|
||||||
|
activeId.value = caseList.value[index].id;
|
||||||
|
} else {
|
||||||
|
// 是最后一个,如果列表还有其他数据,则选中第一条;如果没有其他数据,则显示暂无数据
|
||||||
|
await loadCaseList();
|
||||||
|
if (caseList.value.length > 1) {
|
||||||
|
activeCaseId.value = caseList.value[0].caseId;
|
||||||
|
activeId.value = caseList.value[0].id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (index < caseList.value.length - 1) {
|
if (index < caseList.value.length - 1) {
|
||||||
await loadCaseList();
|
await loadCaseList();
|
||||||
activeCaseId.value = caseList.value[index + 1].caseId;
|
activeCaseId.value = caseList.value[index + 1].caseId;
|
||||||
|
|
Loading…
Reference in New Issue