feat(工作台): 待办/我的创建/我的关注页面展示逻辑调整

This commit is contained in:
baiqi 2024-11-13 14:39:17 +08:00 committed by Craftsman
parent 35a5b03343
commit 796ae6bb7d
16 changed files with 339 additions and 220 deletions

View File

@ -25,7 +25,7 @@
useDefaultArrowIcon?: boolean; useDefaultArrowIcon?: boolean;
}>(); }>();
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'change', val: string): void; (e: 'change', val: string, project?: ProjectListItem): void;
}>(); }>();
const appStore = useAppStore(); const appStore = useAppStore();
@ -34,6 +34,14 @@
default: () => '', default: () => '',
}); });
function selectProject(
value: string | number | boolean | Record<string, any> | (string | number | boolean | Record<string, any>)[]
) {
project.value = value as string;
const _project = projectList.value.find((item) => item.id === value);
emit('change', value as string, _project);
}
onBeforeMount(async () => { onBeforeMount(async () => {
if (!project.value) { if (!project.value) {
project.value = appStore.currentProjectId; project.value = appStore.currentProjectId;
@ -42,6 +50,7 @@
if (appStore.currentOrgId) { if (appStore.currentOrgId) {
const res = await getProjectList(appStore.getCurrentOrgId); const res = await getProjectList(appStore.getCurrentOrgId);
projectList.value = res; projectList.value = res;
selectProject(project.value);
} else { } else {
projectList.value = []; projectList.value = [];
} }
@ -50,12 +59,6 @@
console.log(error); console.log(error);
} }
}); });
function selectProject(
value: string | number | boolean | Record<string, any> | (string | number | boolean | Record<string, any>)[]
) {
emit('change', value as string);
}
</script> </script>
<style lang="less" scoped></style> <style lang="less" scoped></style>

View File

@ -1,5 +1,5 @@
<template> <template>
<a-popover position="bottom" content-class="p-[16px]"> <a-popover position="bottom" content-class="ms-color-line-popper">
<div class="color-bar" :style="{ borderRadius: props.radius }"> <div class="color-bar" :style="{ borderRadius: props.radius }">
<template v-for="(item, index) in colorData"> <template v-for="(item, index) in colorData">
<div v-if="item.percentage > 0" :key="index" :style="getStyle(item, index)"></div> <div v-if="item.percentage > 0" :key="index" :style="getStyle(item, index)"></div>
@ -34,9 +34,21 @@
}; };
</script> </script>
<style scoped> <style lang="less">
.ms-color-line-popper {
padding: 16px;
.arco-popover-title {
@apply hidden;
}
.arco-popover-content {
@apply mt-0;
}
}
</style>
<style lang="less" scoped>
.color-bar { .color-bar {
@apply flex w-full overflow-hidden; @apply flex w-full overflow-hidden;
background-color: var(--color-text-n8); background-color: var(--color-text-n8);
} }

View File

@ -14,4 +14,5 @@ export interface ProjectListItem {
deleteUser: string; deleteUser: string;
enable: boolean; enable: boolean;
moduleIds: string[]; moduleIds: string[];
moduleSetting: string;
} }

View File

@ -63,6 +63,15 @@
</template> </template>
<span v-else>-</span> <span v-else>-</span>
</template> </template>
<template #lineNum="{ record }">
<a-tooltip
v-if="record.errorMessage || !record.lineNum"
:content="!record.lineNum ? t('ms.taskCenter.taskDetailErrorMsg') : record.errorMessage"
>
<icon-exclamation-circle-fill class="min-w-[18px] !text-[rgb(var(--warning-6))]" />
</a-tooltip>
<div v-else>{{ record.lineNum }}</div>
</template>
<template #action="{ record }"> <template #action="{ record }">
<MsButton <MsButton
v-if="[ExecuteStatusEnum.RUNNING, ExecuteStatusEnum.RERUNNING].includes(record.status)" v-if="[ExecuteStatusEnum.RUNNING, ExecuteStatusEnum.RERUNNING].includes(record.status)"
@ -266,6 +275,7 @@
{ {
title: 'ms.taskCenter.queue', title: 'ms.taskCenter.queue',
dataIndex: 'lineNum', dataIndex: 'lineNum',
slotName: 'lineNum',
width: 100, width: 100,
showDrag: true, showDrag: true,
}, },
@ -631,7 +641,11 @@
const res = await currentQueueRequest(ids); const res = await currentQueueRequest(ids);
propsRes.value.data.forEach((item) => { propsRes.value.data.forEach((item) => {
const queue = res[item.id]; const queue = res[item.id];
if (queue) { if (item.errorMessage) {
item.lineNum = '';
} else if (queue === -1) {
item.lineNum = t('ms.taskCenter.waitQueue');
} else if (queue) {
item.lineNum = queue; item.lineNum = queue;
} else if ( } else if (
[ExecuteStatusEnum.COMPLETED, ExecuteStatusEnum.STOPPED, ExecuteStatusEnum.RUNNING].includes(item.status) || [ExecuteStatusEnum.COMPLETED, ExecuteStatusEnum.STOPPED, ExecuteStatusEnum.RUNNING].includes(item.status) ||
@ -639,7 +653,7 @@
) { ) {
item.lineNum = '-'; item.lineNum = '-';
} else { } else {
item.lineNum = t('ms.taskCenter.waitQueue'); item.lineNum = '';
} }
}); });
} catch (error) { } catch (error) {

View File

@ -45,63 +45,11 @@
{{ t(executeMethodMap[record.triggerMode]) }} {{ t(executeMethodMap[record.triggerMode]) }}
</template> </template>
<template #executeRate="{ record }"> <template #executeRate="{ record }">
<a-popover <executeRatePopper
v-model:popup-visible="record.executeRatePopVisible" v-model:visible="record.executeRatePopVisible"
trigger="hover" :record="record"
position="bottom" :execute-task-statistics-request="currentExecuteTaskStatistics"
:disabled="record.caseTotal === 0 || record.status === ExecuteStatusEnum.PENDING" />
@popup-visible-change="($event) => handleExecuteRatePopVisibleChange($event, record)"
>
<div>{{ record.executeRate || '0.00' }}%</div>
<template #content>
<a-spin :loading="record.loading" class="flex w-[130px] flex-col gap-[8px]">
<div class="ms-taskCenter-execute-rate-item">
<div class="ms-taskCenter-execute-rate-item-label">
{{ t('ms.taskCenter.executeFinishedRate') }}
</div>
<div class="ms-taskCenter-execute-rate-item-value">
{{ `${record.executeRate}%` }}
</div>
</div>
<div class="ms-taskCenter-execute-rate-item">
<div class="ms-taskCenter-execute-rate-item-label">
<div
:class="`ms-taskCenter-execute-rate-item-label-point bg-[${executeFinishedRateMap.UN_EXECUTE.color}]`"
></div>
{{ t(executeFinishedRateMap.UN_EXECUTE.label) }}
</div>
<div class="ms-taskCenter-execute-rate-item-value">{{ record.pendingCount }}</div>
</div>
<div class="ms-taskCenter-execute-rate-item">
<div class="ms-taskCenter-execute-rate-item-label">
<div
:class="`ms-taskCenter-execute-rate-item-label-point bg-[${executeFinishedRateMap.SUCCESS.color}]`"
></div>
{{ t(executeFinishedRateMap.SUCCESS.label) }}
</div>
<div class="ms-taskCenter-execute-rate-item-value">{{ record.successCount }}</div>
</div>
<div class="ms-taskCenter-execute-rate-item">
<div class="ms-taskCenter-execute-rate-item-label">
<div
:class="`ms-taskCenter-execute-rate-item-label-point bg-[${executeFinishedRateMap.FAKE_ERROR.color}]`"
></div>
{{ t(executeFinishedRateMap.FAKE_ERROR.label) }}
</div>
<div class="ms-taskCenter-execute-rate-item-value">{{ record.fakeErrorCount }}</div>
</div>
<div class="ms-taskCenter-execute-rate-item">
<div class="ms-taskCenter-execute-rate-item-label">
<div
:class="`ms-taskCenter-execute-rate-item-label-point bg-[${executeFinishedRateMap.ERROR.color}]`"
></div>
{{ t(executeFinishedRateMap.ERROR.label) }}
</div>
<div class="ms-taskCenter-execute-rate-item-value">{{ record.errorCount }}</div>
</div>
</a-spin>
</template>
</a-popover>
</template> </template>
<template #action="{ record }"> <template #action="{ record }">
<MsButton <MsButton
@ -178,6 +126,7 @@
import MsTag from '@/components/pure/ms-tag/ms-tag.vue'; import MsTag from '@/components/pure/ms-tag/ms-tag.vue';
import batchTaskReportDrawer from './batchTaskReportDrawer.vue'; import batchTaskReportDrawer from './batchTaskReportDrawer.vue';
import execStatus from './execStatus.vue'; import execStatus from './execStatus.vue';
import executeRatePopper from './executeRatePopper.vue';
import executionStatus from './executionStatus.vue'; import executionStatus from './executionStatus.vue';
import CaseReportDrawer from '@/views/api-test/report/component/caseReportDrawer.vue'; import CaseReportDrawer from '@/views/api-test/report/component/caseReportDrawer.vue';
import ReportDetailDrawer from '@/views/api-test/report/component/reportDetailDrawer.vue'; import ReportDetailDrawer from '@/views/api-test/report/component/reportDetailDrawer.vue';
@ -225,7 +174,7 @@
import { FilterSlotNameEnum } from '@/enums/tableFilterEnum'; import { FilterSlotNameEnum } from '@/enums/tableFilterEnum';
import { ExecuteStatusEnum, ExecuteTaskType } from '@/enums/taskCenter'; import { ExecuteStatusEnum, ExecuteTaskType } from '@/enums/taskCenter';
import { executeFinishedRateMap, executeMethodMap, executeResultMap, executeStatusMap } from './config'; import { executeMethodMap, executeResultMap, executeStatusMap } from './config';
const props = defineProps<{ const props = defineProps<{
type: 'system' | 'project' | 'org'; type: 'system' | 'project' | 'org';
@ -538,26 +487,6 @@
initTaskStatistics(); initTaskStatistics();
} }
async function handleExecuteRatePopVisibleChange(visible: boolean, record: TaskCenterTaskItem) {
if (visible) {
try {
record.loading = true;
const res = await currentExecuteTaskStatistics([record.id]);
record.executeRate = res[0].executeRate;
record.pendingCount = res[0].pendingCount;
record.successCount = res[0].successCount;
record.fakeErrorCount = res[0].fakeErrorCount;
record.errorCount = res[0].errorCount;
record.caseTotal = res[0].caseTotal;
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
} finally {
record.loading = false;
}
}
}
function showTaskDetail(id: string) { function showTaskDetail(id: string) {
emit('goDetail', id); emit('goDetail', id);
} }
@ -816,23 +745,4 @@
await tableStore.initColumn(TableKeyEnum.TASK_CENTER_CASE_TASK, columns, 'drawer'); await tableStore.initColumn(TableKeyEnum.TASK_CENTER_CASE_TASK, columns, 'drawer');
</script> </script>
<style lang="less"> <style lang="less"></style>
.ms-taskCenter-execute-rate-item {
@apply flex items-center justify-between;
.ms-taskCenter-execute-rate-item-label {
@apply flex items-center;
gap: 4px;
color: var(--color-text-4);
.ms-taskCenter-execute-rate-item-label-point {
width: 6px;
height: 6px;
border-radius: 100%;
}
}
.ms-taskCenter-execute-rate-item-value {
font-weight: 500;
color: var(--color-text-1);
}
}
</style>

View File

@ -0,0 +1,122 @@
<template>
<a-popover
v-model:popup-visible="visible"
trigger="hover"
position="bottom"
:disabled="record.caseTotal === 0 || record.status === ExecuteStatusEnum.PENDING"
@popup-visible-change="($event) => handleExecuteRatePopVisibleChange($event)"
>
<div>{{ record.executeRate || '0.00' }}%</div>
<template #content>
<a-spin :loading="record.loading" class="flex w-[130px] flex-col gap-[8px]">
<div class="ms-taskCenter-execute-rate-item">
<div class="ms-taskCenter-execute-rate-item-label">
{{ t('ms.taskCenter.executeFinishedRate') }}
</div>
<div class="ms-taskCenter-execute-rate-item-value">
{{ `${record.executeRate}%` }}
</div>
</div>
<div class="ms-taskCenter-execute-rate-item">
<div class="ms-taskCenter-execute-rate-item-label">
<div
:class="`ms-taskCenter-execute-rate-item-label-point bg-[${executeFinishedRateMap.UN_EXECUTE.color}]`"
></div>
{{ t(executeFinishedRateMap.UN_EXECUTE.label) }}
</div>
<div class="ms-taskCenter-execute-rate-item-value">{{ record.pendingCount }}</div>
</div>
<div class="ms-taskCenter-execute-rate-item">
<div class="ms-taskCenter-execute-rate-item-label">
<div
:class="`ms-taskCenter-execute-rate-item-label-point bg-[${executeFinishedRateMap.SUCCESS.color}]`"
></div>
{{ t(executeFinishedRateMap.SUCCESS.label) }}
</div>
<div class="ms-taskCenter-execute-rate-item-value">{{ record.successCount }}</div>
</div>
<div class="ms-taskCenter-execute-rate-item">
<div class="ms-taskCenter-execute-rate-item-label">
<div
:class="`ms-taskCenter-execute-rate-item-label-point bg-[${executeFinishedRateMap.FAKE_ERROR.color}]`"
></div>
{{ t(executeFinishedRateMap.FAKE_ERROR.label) }}
</div>
<div class="ms-taskCenter-execute-rate-item-value">{{ record.fakeErrorCount }}</div>
</div>
<div class="ms-taskCenter-execute-rate-item">
<div class="ms-taskCenter-execute-rate-item-label">
<div
:class="`ms-taskCenter-execute-rate-item-label-point bg-[${executeFinishedRateMap.ERROR.color}]`"
></div>
{{ t(executeFinishedRateMap.ERROR.label) }}
</div>
<div class="ms-taskCenter-execute-rate-item-value">{{ record.errorCount }}</div>
</div>
</a-spin>
</template>
</a-popover>
</template>
<script setup lang="ts">
import { useI18n } from '@/hooks/useI18n';
import { TaskCenterStatisticsItem, TaskCenterTaskItem } from '@/models/taskCenter';
import { ExecuteStatusEnum } from '@/enums/taskCenter';
import { executeFinishedRateMap } from './config';
const props = defineProps<{
executeTaskStatisticsRequest: (ids: string[]) => Promise<TaskCenterStatisticsItem[]>;
}>();
const { t } = useI18n();
const visible = defineModel<boolean>('visible', {
required: true,
});
const record = defineModel<TaskCenterTaskItem>('record', {
required: true,
});
async function handleExecuteRatePopVisibleChange(_visible: boolean) {
if (_visible) {
try {
record.value.loading = true;
const res = await props.executeTaskStatisticsRequest([record.value.id]);
record.value.executeRate = res[0].executeRate;
record.value.pendingCount = res[0].pendingCount;
record.value.successCount = res[0].successCount;
record.value.fakeErrorCount = res[0].fakeErrorCount;
record.value.errorCount = res[0].errorCount;
record.value.caseTotal = res[0].caseTotal;
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
} finally {
record.value.loading = false;
}
}
}
</script>
<style lang="less">
.ms-taskCenter-execute-rate-item {
@apply flex items-center justify-between;
.ms-taskCenter-execute-rate-item-label {
@apply flex items-center;
gap: 4px;
color: var(--color-text-4);
.ms-taskCenter-execute-rate-item-label-point {
width: 6px;
height: 6px;
border-radius: 100%;
}
}
.ms-taskCenter-execute-rate-item-value {
font-weight: 500;
color: var(--color-text-1);
}
}
</style>

View File

@ -58,4 +58,5 @@ export default {
'ms.taskCenter.closeTaskSuccess': 'Task closed successfully', 'ms.taskCenter.closeTaskSuccess': 'Task closed successfully',
'ms.taskCenter.waitQueue': 'Waiting in line', 'ms.taskCenter.waitQueue': 'Waiting in line',
'ms.taskCenter.caseName': 'Case name', 'ms.taskCenter.caseName': 'Case name',
'ms.taskCenter.taskDetailErrorMsg': 'The resource pool is unavailable/restarted, please restart the task execution',
}; };

View File

@ -58,4 +58,5 @@ export default {
'ms.taskCenter.closeTaskSuccess': '任务关闭成功', 'ms.taskCenter.closeTaskSuccess': '任务关闭成功',
'ms.taskCenter.waitQueue': '等待排队', 'ms.taskCenter.waitQueue': '等待排队',
'ms.taskCenter.caseName': '用例名称', 'ms.taskCenter.caseName': '用例名称',
'ms.taskCenter.taskDetailErrorMsg': '资源池不可用/重启,请重新发起任务执行',
}; };

View File

@ -0,0 +1,85 @@
<template>
<a-popover position="bottom" content-class="testPlanTable-caseCount-popper" :disabled="getFunctionalCount(id) < 1">
<div>{{ getFunctionalCount(id) }}</div>
<template #content>
<table class="min-w-[140px] max-w-[176px]">
<tr>
<td class="popover-label-td !pt-0">
<div>{{ t('testPlan.testPlanIndex.TotalCases') }}</div>
</td>
<td class="popover-value-td !pt-0">
{{ defaultCountDetailMap[id]?.caseTotal ?? '0' }}
</td>
</tr>
<tr>
<td class="popover-label-td">
<div class="text-[var(--color-text-1)]">{{ t('testPlan.testPlanIndex.functionalUseCase') }}</div>
</td>
<td class="popover-value-td">
{{ defaultCountDetailMap[id]?.functionalCaseCount ?? '0' }}
</td>
</tr>
<tr>
<td class="popover-label-td">
<div class="text-[var(--color-text-1)]">{{ t('testPlan.testPlanIndex.apiCase') }}</div>
</td>
<td class="popover-value-td">
{{ defaultCountDetailMap[id]?.apiCaseCount ?? '0' }}
</td>
</tr>
<tr>
<td class="popover-label-td">
<div class="text-[var(--color-text-1)]">{{ t('testPlan.testPlanIndex.apiScenarioCase') }}</div>
</td>
<td class="popover-value-td">
{{ defaultCountDetailMap[id]?.apiScenarioCount ?? '0' }}
</td>
</tr>
</table>
</template>
</a-popover>
</template>
<script setup lang="ts">
import { useI18n } from '@/hooks/useI18n';
import { PassRateCountDetail } from '@/models/testPlan/testPlan';
const props = defineProps<{
id: string;
defaultCountDetailMap: Record<string, PassRateCountDetail>;
}>();
const { t } = useI18n();
function getFunctionalCount(id: string) {
return props.defaultCountDetailMap[id]?.caseTotal ?? 0;
}
</script>
<style lang="less">
.testPlanTable-caseCount-popper {
padding: 16px;
.arco-popover-title {
@apply hidden;
}
.arco-popover-content {
@apply mt-0;
}
}
</style>
<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 text-right font-medium;
padding-top: 8px;
color: var(--color-text-1);
}
</style>

View File

@ -179,45 +179,7 @@
</div> </div>
</template> </template>
<template #functionalCaseCount="{ record }"> <template #functionalCaseCount="{ record }">
<a-popover position="bottom" content-class="p-[16px]" :disabled="getFunctionalCount(record.id) < 1"> <caseCountPopper :id="record.id" :default-count-detail-map="defaultCountDetailMap" />
<div>{{ getFunctionalCount(record.id) }}</div>
<template #content>
<table class="min-w-[140px] max-w-[176px]">
<tr>
<td class="popover-label-td">
<div>{{ t('testPlan.testPlanIndex.TotalCases') }}</div>
</td>
<td class="popover-value-td">
{{ defaultCountDetailMap[record.id]?.caseTotal ?? '0' }}
</td>
</tr>
<tr>
<td class="popover-label-td">
<div class="text-[var(--color-text-1)]">{{ t('testPlan.testPlanIndex.functionalUseCase') }}</div>
</td>
<td class="popover-value-td">
{{ defaultCountDetailMap[record.id]?.functionalCaseCount ?? '0' }}
</td>
</tr>
<tr>
<td class="popover-label-td">
<div class="text-[var(--color-text-1)]">{{ t('testPlan.testPlanIndex.apiCase') }}</div>
</td>
<td class="popover-value-td">
{{ defaultCountDetailMap[record.id]?.apiCaseCount ?? '0' }}
</td>
</tr>
<tr>
<td class="popover-label-td">
<div class="text-[var(--color-text-1)]">{{ t('testPlan.testPlanIndex.apiScenarioCase') }}</div>
</td>
<td class="popover-value-td">
{{ defaultCountDetailMap[record.id]?.apiScenarioCount ?? '0' }}
</td>
</tr>
</table>
</template>
</a-popover>
</template> </template>
<template #operation="{ record }"> <template #operation="{ record }">
@ -384,6 +346,7 @@
import ActionModal from './actionModal.vue'; import ActionModal from './actionModal.vue';
import BatchEditModal from './batchEditModal.vue'; import BatchEditModal from './batchEditModal.vue';
import BatchMoveOrCopy from './batchMoveOrCopy.vue'; import BatchMoveOrCopy from './batchMoveOrCopy.vue';
import caseCountPopper from './caseCountPopper.vue';
import ScheduledModal from './scheduledModal.vue'; import ScheduledModal from './scheduledModal.vue';
import StatusProgress from './statusProgress.vue'; import StatusProgress from './statusProgress.vue';
import PlanExpandRow from '@/views/test-plan/testPlan/components/planExpandRow.vue'; import PlanExpandRow from '@/views/test-plan/testPlan/components/planExpandRow.vue';
@ -1745,16 +1708,4 @@
:deep(.arco-table-cell-align-left) > span:first-child { :deep(.arco-table-cell-align-left) > span:first-child {
padding-left: 0 !important; padding-left: 0 !important;
} }
.popover-label-td {
@apply flex items-center;
padding: 8px 8px 0 0;
color: var(--color-text-4);
}
.popover-value-td {
@apply text-right font-medium;
padding-top: 8px;
color: var(--color-text-1);
}
</style> </style>

View File

@ -3,10 +3,10 @@
<template #popoverContent> <template #popoverContent>
<table class="min-w-[144px]"> <table class="min-w-[144px]">
<tr v-if="props.type === testPlanTypeEnum.TEST_PLAN"> <tr v-if="props.type === testPlanTypeEnum.TEST_PLAN">
<td class="popover-label-td"> <td class="popover-label-td !pt-0">
<div>{{ t('testPlan.testPlanIndex.threshold') }}</div> <div>{{ t('testPlan.testPlanIndex.threshold') }}</div>
</td> </td>
<td class="popover-value-td"> {{ detailCount.passThreshold }}% </td> <td class="popover-value-td !pt-0"> {{ detailCount.passThreshold }}% </td>
</tr> </tr>
<tr> <tr>
<td class="popover-label-td"> <td class="popover-label-td">

View File

@ -0,0 +1,12 @@
import { FeatureEnum } from '@/enums/workbenchEnum';
export const featuresMap = {
[FeatureEnum.API_CASE]: 'apiTest',
[FeatureEnum.API_SCENARIO]: 'apiTest',
[FeatureEnum.CASE_REVIEW]: 'caseManagement',
[FeatureEnum.TEST_CASE]: 'caseManagement',
[FeatureEnum.TEST_PLAN]: 'testPlan',
[FeatureEnum.BUG]: 'bugManagement',
};
export default {};

View File

@ -74,45 +74,7 @@
</div> </div>
</template> </template>
<template #functionalCaseCount="{ record }"> <template #functionalCaseCount="{ record }">
<a-popover position="bottom" content-class="p-[16px]" :disabled="getFunctionalCount(record.id) < 1"> <caseCountPopper :id="record.id" :default-count-detail-map="defaultCountDetailMap" />
<div>{{ getFunctionalCount(record.id) }}</div>
<template #content>
<table class="min-w-[140px] max-w-[176px]">
<tr>
<td class="popover-label-td">
<div>{{ t('testPlan.testPlanIndex.TotalCases') }}</div>
</td>
<td class="popover-value-td">
{{ defaultCountDetailMap[record.id]?.caseTotal ?? '0' }}
</td>
</tr>
<tr>
<td class="popover-label-td">
<div class="text-[var(--color-text-1)]">{{ t('testPlan.testPlanIndex.functionalUseCase') }}</div>
</td>
<td class="popover-value-td">
{{ defaultCountDetailMap[record.id]?.functionalCaseCount ?? '0' }}
</td>
</tr>
<tr>
<td class="popover-label-td">
<div class="text-[var(--color-text-1)]">{{ t('testPlan.testPlanIndex.apiCase') }}</div>
</td>
<td class="popover-value-td">
{{ defaultCountDetailMap[record.id]?.apiCaseCount ?? '0' }}
</td>
</tr>
<tr>
<td class="popover-label-td">
<div class="text-[var(--color-text-1)]">{{ t('testPlan.testPlanIndex.apiScenarioCase') }}</div>
</td>
<td class="popover-value-td">
{{ defaultCountDetailMap[record.id]?.apiScenarioCount ?? '0' }}
</td>
</tr>
</table>
</template>
</a-popover>
</template> </template>
</MsBaseTable> </MsBaseTable>
</MsCard> </MsCard>
@ -126,6 +88,7 @@
import { MsTableColumn, MsTableProps } from '@/components/pure/ms-table/type'; import { MsTableColumn, MsTableProps } from '@/components/pure/ms-table/type';
import useTable from '@/components/pure/ms-table/useTable'; import useTable from '@/components/pure/ms-table/useTable';
import MsStatusTag from '@/components/business/ms-status-tag/index.vue'; import MsStatusTag from '@/components/business/ms-status-tag/index.vue';
import caseCountPopper from '@/views/test-plan/testPlan/components/caseCountPopper.vue';
import PlanExpandRow from '@/views/test-plan/testPlan/components/planExpandRow.vue'; import PlanExpandRow from '@/views/test-plan/testPlan/components/planExpandRow.vue';
import StatusProgress from '@/views/test-plan/testPlan/components/statusProgress.vue'; import StatusProgress from '@/views/test-plan/testPlan/components/statusProgress.vue';
@ -158,10 +121,6 @@
const defaultCountDetailMap = ref<Record<string, PassRateCountDetail>>({}); const defaultCountDetailMap = ref<Record<string, PassRateCountDetail>>({});
function getFunctionalCount(id: string) {
return defaultCountDetailMap.value[id]?.caseTotal ?? 0;
}
function getStatus(id: string) { function getStatus(id: string) {
return defaultCountDetailMap.value[id]?.status; return defaultCountDetailMap.value[id]?.status;
} }
@ -325,4 +284,8 @@
}); });
</script> </script>
<style lang="less" scoped></style> <style lang="less" scoped>
:deep(.arco-table-cell-expand-icon .arco-table-cell-inline-icon) {
display: none;
}
</style>

View File

@ -23,7 +23,7 @@
:has-all-select="true" :has-all-select="true"
:default-all-select="true" :default-all-select="true"
/> />
<a-button type="outline" class="arco-btn-outline--secondary p-[10px]" @click="handleRefresh"> <a-button type="outline" class="arco-btn-outline--secondary p-[10px]" @click="() => handleRefresh()">
<MsIcon type="icon-icon_reset_outlined" size="14" /> <MsIcon type="icon-icon_reset_outlined" size="14" />
</a-button> </a-button>
</div> </div>
@ -70,6 +70,8 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { SelectOptionData } from '@arco-design/web-vue';
import MsIcon from '@/components/pure/ms-icon-font/index.vue'; import MsIcon from '@/components/pure/ms-icon-font/index.vue';
import MsProjectSelect from '@/components/business/ms-project-select/index.vue'; import MsProjectSelect from '@/components/business/ms-project-select/index.vue';
import MsSelect from '@/components/business/ms-select'; import MsSelect from '@/components/business/ms-select';
@ -85,20 +87,31 @@
import useAppStore from '@/store/modules/app'; import useAppStore from '@/store/modules/app';
import { getGenerateId } from '@/utils'; import { getGenerateId } from '@/utils';
import { ProjectListItem } from '@/models/setting/project';
import { FeatureEnum } from '@/enums/workbenchEnum'; import { FeatureEnum } from '@/enums/workbenchEnum';
import { featuresMap } from '../components/config';
const { t } = useI18n(); const { t } = useI18n();
const appStore = useAppStore(); const appStore = useAppStore();
const currentProject = ref(appStore.currentProjectId); const currentProject = ref(appStore.currentProjectId);
const features = ref<FeatureEnum[]>(Object.values(FeatureEnum)); const features = ref<FeatureEnum[]>([]);
const featureOptions = Object.keys(FeatureEnum).map((key) => ({ const fullFeaturesOptions = Object.keys(FeatureEnum).map((key) => ({
label: t(`ms.workbench.myFollowed.feature.${key}`), label: t(`ms.workbench.myFollowed.feature.${key}`),
value: key as FeatureEnum, value: key as FeatureEnum,
})); }));
const featureOptions = ref<SelectOptionData[]>([]);
const refreshId = ref(''); const refreshId = ref('');
function handleRefresh() { function handleRefresh(val?: string, _project?: ProjectListItem) {
if (_project) {
const _currentProjectFeatures = JSON.parse(_project.moduleSetting);
featureOptions.value = fullFeaturesOptions.filter((item) =>
_currentProjectFeatures.includes(featuresMap[item.value])
);
features.value = featureOptions.value.map((item) => item.value as FeatureEnum);
}
refreshId.value = getGenerateId(); refreshId.value = getGenerateId();
} }
</script> </script>

View File

@ -23,7 +23,7 @@
:has-all-select="true" :has-all-select="true"
:default-all-select="true" :default-all-select="true"
/> />
<a-button type="outline" class="arco-btn-outline--secondary p-[10px]" @click="handleRefresh"> <a-button type="outline" class="arco-btn-outline--secondary p-[10px]" @click="() => handleRefresh()">
<MsIcon type="icon-icon_reset_outlined" size="14" /> <MsIcon type="icon-icon_reset_outlined" size="14" />
</a-button> </a-button>
</div> </div>
@ -69,6 +69,8 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { SelectOptionData } from '@arco-design/web-vue';
import MsIcon from '@/components/pure/ms-icon-font/index.vue'; import MsIcon from '@/components/pure/ms-icon-font/index.vue';
import MsProjectSelect from '@/components/business/ms-project-select/index.vue'; import MsProjectSelect from '@/components/business/ms-project-select/index.vue';
import MsSelect from '@/components/business/ms-select'; import MsSelect from '@/components/business/ms-select';
@ -84,20 +86,31 @@
import useAppStore from '@/store/modules/app'; import useAppStore from '@/store/modules/app';
import { getGenerateId } from '@/utils'; import { getGenerateId } from '@/utils';
import { ProjectListItem } from '@/models/setting/project';
import { FeatureEnum } from '@/enums/workbenchEnum'; import { FeatureEnum } from '@/enums/workbenchEnum';
import { featuresMap } from '../components/config';
const { t } = useI18n(); const { t } = useI18n();
const appStore = useAppStore(); const appStore = useAppStore();
const currentProject = ref(appStore.currentProjectId); const currentProject = ref(appStore.currentProjectId);
const features = ref<FeatureEnum[]>(Object.values(FeatureEnum)); const features = ref<FeatureEnum[]>([]);
const featureOptions = Object.keys(FeatureEnum).map((key) => ({ const fullFeaturesOptions = Object.keys(FeatureEnum).map((key) => ({
label: t(`ms.workbench.myFollowed.feature.${key}`), label: t(`ms.workbench.myFollowed.feature.${key}`),
value: key as FeatureEnum, value: key as FeatureEnum,
})); }));
const featureOptions = ref<SelectOptionData[]>([]);
const refreshId = ref(''); const refreshId = ref('');
function handleRefresh() { function handleRefresh(val?: string, _project?: ProjectListItem) {
if (_project) {
const _currentProjectFeatures = JSON.parse(_project.moduleSetting);
featureOptions.value = fullFeaturesOptions.filter((item) =>
_currentProjectFeatures.includes(featuresMap[item.value])
);
features.value = featureOptions.value.map((item) => item.value as FeatureEnum);
}
refreshId.value = getGenerateId(); refreshId.value = getGenerateId();
} }
</script> </script>

View File

@ -2,7 +2,12 @@
<div class="flex flex-col gap-[16px]"> <div class="flex flex-col gap-[16px]">
<template v-if="appStore.projectList.length > 0"> <template v-if="appStore.projectList.length > 0">
<div class="flex items-center justify-end gap-[12px]"> <div class="flex items-center justify-end gap-[12px]">
<MsProjectSelect v-model:project="currentProject" class="w-[240px]" use-default-arrow-icon> <MsProjectSelect
v-model:project="currentProject"
class="w-[240px]"
use-default-arrow-icon
@change="handleRefresh"
>
<template #prefix> <template #prefix>
{{ t('menu.projectManagementShort') }} {{ t('menu.projectManagementShort') }}
</template> </template>
@ -18,7 +23,7 @@
:has-all-select="true" :has-all-select="true"
:default-all-select="true" :default-all-select="true"
/> />
<a-button type="outline" class="arco-btn-outline--secondary p-[10px]" @click="handleRefresh"> <a-button type="outline" class="arco-btn-outline--secondary p-[10px]" @click="() => handleRefresh()">
<MsIcon type="icon-icon_reset_outlined" size="14" /> <MsIcon type="icon-icon_reset_outlined" size="14" />
</a-button> </a-button>
</div> </div>
@ -47,6 +52,8 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { SelectOptionData } from '@arco-design/web-vue';
import MsIcon from '@/components/pure/ms-icon-font/index.vue'; import MsIcon from '@/components/pure/ms-icon-font/index.vue';
import MsProjectSelect from '@/components/business/ms-project-select/index.vue'; import MsProjectSelect from '@/components/business/ms-project-select/index.vue';
import MsSelect from '@/components/business/ms-select'; import MsSelect from '@/components/business/ms-select';
@ -59,22 +66,33 @@
import useAppStore from '@/store/modules/app'; import useAppStore from '@/store/modules/app';
import { getGenerateId } from '@/utils'; import { getGenerateId } from '@/utils';
import { ProjectListItem } from '@/models/setting/project';
import { FeatureEnum } from '@/enums/workbenchEnum'; import { FeatureEnum } from '@/enums/workbenchEnum';
import { featuresMap } from '../components/config';
const { t } = useI18n(); const { t } = useI18n();
const appStore = useAppStore(); const appStore = useAppStore();
const currentProject = ref(appStore.currentProjectId); const currentProject = ref(appStore.currentProjectId);
const features = ref<FeatureEnum[]>(Object.values(FeatureEnum)); const features = ref<FeatureEnum[]>([]);
const featureOptions = Object.keys(FeatureEnum) const fullFeaturesOptions = Object.keys(FeatureEnum)
.filter((e) => [FeatureEnum.TEST_PLAN, FeatureEnum.CASE_REVIEW, FeatureEnum.BUG].includes(e as FeatureEnum)) .filter((e) => [FeatureEnum.TEST_PLAN, FeatureEnum.CASE_REVIEW, FeatureEnum.BUG].includes(e as FeatureEnum))
.map((key) => ({ .map((key) => ({
label: t(`ms.workbench.myFollowed.feature.${key}`), label: t(`ms.workbench.myFollowed.feature.${key}`),
value: key as FeatureEnum, value: key as FeatureEnum,
})); }));
const featureOptions = ref<SelectOptionData[]>([]);
const refreshId = ref(''); const refreshId = ref('');
function handleRefresh() { function handleRefresh(val?: string, _project?: ProjectListItem) {
if (_project) {
const _currentProjectFeatures = JSON.parse(_project.moduleSetting);
featureOptions.value = fullFeaturesOptions.filter((item) =>
_currentProjectFeatures.includes(featuresMap[item.value])
);
features.value = featureOptions.value.map((item) => item.value as FeatureEnum);
}
refreshId.value = getGenerateId(); refreshId.value = getGenerateId();
} }
</script> </script>