mirror of
https://gitee.com/fit2cloud-feizhiyun/MeterSphere.git
synced 2024-12-02 03:58:33 +08:00
feat(工作台): 待办/我的创建/我的关注页面展示逻辑调整
This commit is contained in:
parent
35a5b03343
commit
796ae6bb7d
@ -25,7 +25,7 @@
|
||||
useDefaultArrowIcon?: boolean;
|
||||
}>();
|
||||
const emit = defineEmits<{
|
||||
(e: 'change', val: string): void;
|
||||
(e: 'change', val: string, project?: ProjectListItem): void;
|
||||
}>();
|
||||
|
||||
const appStore = useAppStore();
|
||||
@ -34,6 +34,14 @@
|
||||
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 () => {
|
||||
if (!project.value) {
|
||||
project.value = appStore.currentProjectId;
|
||||
@ -42,6 +50,7 @@
|
||||
if (appStore.currentOrgId) {
|
||||
const res = await getProjectList(appStore.getCurrentOrgId);
|
||||
projectList.value = res;
|
||||
selectProject(project.value);
|
||||
} else {
|
||||
projectList.value = [];
|
||||
}
|
||||
@ -50,12 +59,6 @@
|
||||
console.log(error);
|
||||
}
|
||||
});
|
||||
|
||||
function selectProject(
|
||||
value: string | number | boolean | Record<string, any> | (string | number | boolean | Record<string, any>)[]
|
||||
) {
|
||||
emit('change', value as string);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<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 }">
|
||||
<template v-for="(item, index) in colorData">
|
||||
<div v-if="item.percentage > 0" :key="index" :style="getStyle(item, index)"></div>
|
||||
@ -34,9 +34,21 @@
|
||||
};
|
||||
</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 {
|
||||
@apply flex w-full overflow-hidden;
|
||||
@apply flex w-full overflow-hidden;
|
||||
|
||||
background-color: var(--color-text-n8);
|
||||
}
|
||||
|
@ -14,4 +14,5 @@ export interface ProjectListItem {
|
||||
deleteUser: string;
|
||||
enable: boolean;
|
||||
moduleIds: string[];
|
||||
moduleSetting: string;
|
||||
}
|
||||
|
@ -63,6 +63,15 @@
|
||||
</template>
|
||||
<span v-else>-</span>
|
||||
</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 }">
|
||||
<MsButton
|
||||
v-if="[ExecuteStatusEnum.RUNNING, ExecuteStatusEnum.RERUNNING].includes(record.status)"
|
||||
@ -266,6 +275,7 @@
|
||||
{
|
||||
title: 'ms.taskCenter.queue',
|
||||
dataIndex: 'lineNum',
|
||||
slotName: 'lineNum',
|
||||
width: 100,
|
||||
showDrag: true,
|
||||
},
|
||||
@ -631,7 +641,11 @@
|
||||
const res = await currentQueueRequest(ids);
|
||||
propsRes.value.data.forEach((item) => {
|
||||
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;
|
||||
} else if (
|
||||
[ExecuteStatusEnum.COMPLETED, ExecuteStatusEnum.STOPPED, ExecuteStatusEnum.RUNNING].includes(item.status) ||
|
||||
@ -639,7 +653,7 @@
|
||||
) {
|
||||
item.lineNum = '-';
|
||||
} else {
|
||||
item.lineNum = t('ms.taskCenter.waitQueue');
|
||||
item.lineNum = '';
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
|
@ -45,63 +45,11 @@
|
||||
{{ t(executeMethodMap[record.triggerMode]) }}
|
||||
</template>
|
||||
<template #executeRate="{ record }">
|
||||
<a-popover
|
||||
v-model:popup-visible="record.executeRatePopVisible"
|
||||
trigger="hover"
|
||||
position="bottom"
|
||||
: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>
|
||||
<executeRatePopper
|
||||
v-model:visible="record.executeRatePopVisible"
|
||||
:record="record"
|
||||
:execute-task-statistics-request="currentExecuteTaskStatistics"
|
||||
/>
|
||||
</template>
|
||||
<template #action="{ record }">
|
||||
<MsButton
|
||||
@ -178,6 +126,7 @@
|
||||
import MsTag from '@/components/pure/ms-tag/ms-tag.vue';
|
||||
import batchTaskReportDrawer from './batchTaskReportDrawer.vue';
|
||||
import execStatus from './execStatus.vue';
|
||||
import executeRatePopper from './executeRatePopper.vue';
|
||||
import executionStatus from './executionStatus.vue';
|
||||
import CaseReportDrawer from '@/views/api-test/report/component/caseReportDrawer.vue';
|
||||
import ReportDetailDrawer from '@/views/api-test/report/component/reportDetailDrawer.vue';
|
||||
@ -225,7 +174,7 @@
|
||||
import { FilterSlotNameEnum } from '@/enums/tableFilterEnum';
|
||||
import { ExecuteStatusEnum, ExecuteTaskType } from '@/enums/taskCenter';
|
||||
|
||||
import { executeFinishedRateMap, executeMethodMap, executeResultMap, executeStatusMap } from './config';
|
||||
import { executeMethodMap, executeResultMap, executeStatusMap } from './config';
|
||||
|
||||
const props = defineProps<{
|
||||
type: 'system' | 'project' | 'org';
|
||||
@ -538,26 +487,6 @@
|
||||
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) {
|
||||
emit('goDetail', id);
|
||||
}
|
||||
@ -816,23 +745,4 @@
|
||||
await tableStore.initColumn(TableKeyEnum.TASK_CENTER_CASE_TASK, columns, 'drawer');
|
||||
</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>
|
||||
<style lang="less"></style>
|
||||
|
122
frontend/src/views/taskCenter/component/executeRatePopper.vue
Normal file
122
frontend/src/views/taskCenter/component/executeRatePopper.vue
Normal 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>
|
@ -58,4 +58,5 @@ export default {
|
||||
'ms.taskCenter.closeTaskSuccess': 'Task closed successfully',
|
||||
'ms.taskCenter.waitQueue': 'Waiting in line',
|
||||
'ms.taskCenter.caseName': 'Case name',
|
||||
'ms.taskCenter.taskDetailErrorMsg': 'The resource pool is unavailable/restarted, please restart the task execution',
|
||||
};
|
||||
|
@ -58,4 +58,5 @@ export default {
|
||||
'ms.taskCenter.closeTaskSuccess': '任务关闭成功',
|
||||
'ms.taskCenter.waitQueue': '等待排队',
|
||||
'ms.taskCenter.caseName': '用例名称',
|
||||
'ms.taskCenter.taskDetailErrorMsg': '资源池不可用/重启,请重新发起任务执行',
|
||||
};
|
||||
|
@ -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>
|
@ -179,45 +179,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<template #functionalCaseCount="{ record }">
|
||||
<a-popover position="bottom" content-class="p-[16px]" :disabled="getFunctionalCount(record.id) < 1">
|
||||
<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>
|
||||
<caseCountPopper :id="record.id" :default-count-detail-map="defaultCountDetailMap" />
|
||||
</template>
|
||||
|
||||
<template #operation="{ record }">
|
||||
@ -384,6 +346,7 @@
|
||||
import ActionModal from './actionModal.vue';
|
||||
import BatchEditModal from './batchEditModal.vue';
|
||||
import BatchMoveOrCopy from './batchMoveOrCopy.vue';
|
||||
import caseCountPopper from './caseCountPopper.vue';
|
||||
import ScheduledModal from './scheduledModal.vue';
|
||||
import StatusProgress from './statusProgress.vue';
|
||||
import PlanExpandRow from '@/views/test-plan/testPlan/components/planExpandRow.vue';
|
||||
@ -1745,16 +1708,4 @@
|
||||
:deep(.arco-table-cell-align-left) > span:first-child {
|
||||
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>
|
||||
|
@ -3,10 +3,10 @@
|
||||
<template #popoverContent>
|
||||
<table class="min-w-[144px]">
|
||||
<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>
|
||||
</td>
|
||||
<td class="popover-value-td"> {{ detailCount.passThreshold }}% </td>
|
||||
<td class="popover-value-td !pt-0"> {{ detailCount.passThreshold }}% </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="popover-label-td">
|
||||
|
12
frontend/src/views/workbench/components/config.ts
Normal file
12
frontend/src/views/workbench/components/config.ts
Normal 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 {};
|
@ -74,45 +74,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<template #functionalCaseCount="{ record }">
|
||||
<a-popover position="bottom" content-class="p-[16px]" :disabled="getFunctionalCount(record.id) < 1">
|
||||
<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>
|
||||
<caseCountPopper :id="record.id" :default-count-detail-map="defaultCountDetailMap" />
|
||||
</template>
|
||||
</MsBaseTable>
|
||||
</MsCard>
|
||||
@ -126,6 +88,7 @@
|
||||
import { MsTableColumn, MsTableProps } from '@/components/pure/ms-table/type';
|
||||
import useTable from '@/components/pure/ms-table/useTable';
|
||||
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 StatusProgress from '@/views/test-plan/testPlan/components/statusProgress.vue';
|
||||
|
||||
@ -158,10 +121,6 @@
|
||||
|
||||
const defaultCountDetailMap = ref<Record<string, PassRateCountDetail>>({});
|
||||
|
||||
function getFunctionalCount(id: string) {
|
||||
return defaultCountDetailMap.value[id]?.caseTotal ?? 0;
|
||||
}
|
||||
|
||||
function getStatus(id: string) {
|
||||
return defaultCountDetailMap.value[id]?.status;
|
||||
}
|
||||
@ -325,4 +284,8 @@
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
||||
<style lang="less" scoped>
|
||||
:deep(.arco-table-cell-expand-icon .arco-table-cell-inline-icon) {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
|
@ -23,7 +23,7 @@
|
||||
:has-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" />
|
||||
</a-button>
|
||||
</div>
|
||||
@ -70,6 +70,8 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { SelectOptionData } from '@arco-design/web-vue';
|
||||
|
||||
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
|
||||
import MsProjectSelect from '@/components/business/ms-project-select/index.vue';
|
||||
import MsSelect from '@/components/business/ms-select';
|
||||
@ -85,20 +87,31 @@
|
||||
import useAppStore from '@/store/modules/app';
|
||||
import { getGenerateId } from '@/utils';
|
||||
|
||||
import { ProjectListItem } from '@/models/setting/project';
|
||||
import { FeatureEnum } from '@/enums/workbenchEnum';
|
||||
|
||||
import { featuresMap } from '../components/config';
|
||||
|
||||
const { t } = useI18n();
|
||||
const appStore = useAppStore();
|
||||
|
||||
const currentProject = ref(appStore.currentProjectId);
|
||||
const features = ref<FeatureEnum[]>(Object.values(FeatureEnum));
|
||||
const featureOptions = Object.keys(FeatureEnum).map((key) => ({
|
||||
const features = ref<FeatureEnum[]>([]);
|
||||
const fullFeaturesOptions = Object.keys(FeatureEnum).map((key) => ({
|
||||
label: t(`ms.workbench.myFollowed.feature.${key}`),
|
||||
value: key as FeatureEnum,
|
||||
}));
|
||||
const featureOptions = ref<SelectOptionData[]>([]);
|
||||
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();
|
||||
}
|
||||
</script>
|
||||
|
@ -23,7 +23,7 @@
|
||||
:has-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" />
|
||||
</a-button>
|
||||
</div>
|
||||
@ -69,6 +69,8 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { SelectOptionData } from '@arco-design/web-vue';
|
||||
|
||||
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
|
||||
import MsProjectSelect from '@/components/business/ms-project-select/index.vue';
|
||||
import MsSelect from '@/components/business/ms-select';
|
||||
@ -84,20 +86,31 @@
|
||||
import useAppStore from '@/store/modules/app';
|
||||
import { getGenerateId } from '@/utils';
|
||||
|
||||
import { ProjectListItem } from '@/models/setting/project';
|
||||
import { FeatureEnum } from '@/enums/workbenchEnum';
|
||||
|
||||
import { featuresMap } from '../components/config';
|
||||
|
||||
const { t } = useI18n();
|
||||
const appStore = useAppStore();
|
||||
|
||||
const currentProject = ref(appStore.currentProjectId);
|
||||
const features = ref<FeatureEnum[]>(Object.values(FeatureEnum));
|
||||
const featureOptions = Object.keys(FeatureEnum).map((key) => ({
|
||||
const features = ref<FeatureEnum[]>([]);
|
||||
const fullFeaturesOptions = Object.keys(FeatureEnum).map((key) => ({
|
||||
label: t(`ms.workbench.myFollowed.feature.${key}`),
|
||||
value: key as FeatureEnum,
|
||||
}));
|
||||
const featureOptions = ref<SelectOptionData[]>([]);
|
||||
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();
|
||||
}
|
||||
</script>
|
||||
|
@ -2,7 +2,12 @@
|
||||
<div class="flex flex-col gap-[16px]">
|
||||
<template v-if="appStore.projectList.length > 0">
|
||||
<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>
|
||||
{{ t('menu.projectManagementShort') }}
|
||||
</template>
|
||||
@ -18,7 +23,7 @@
|
||||
:has-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" />
|
||||
</a-button>
|
||||
</div>
|
||||
@ -47,6 +52,8 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { SelectOptionData } from '@arco-design/web-vue';
|
||||
|
||||
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
|
||||
import MsProjectSelect from '@/components/business/ms-project-select/index.vue';
|
||||
import MsSelect from '@/components/business/ms-select';
|
||||
@ -59,22 +66,33 @@
|
||||
import useAppStore from '@/store/modules/app';
|
||||
import { getGenerateId } from '@/utils';
|
||||
|
||||
import { ProjectListItem } from '@/models/setting/project';
|
||||
import { FeatureEnum } from '@/enums/workbenchEnum';
|
||||
|
||||
import { featuresMap } from '../components/config';
|
||||
|
||||
const { t } = useI18n();
|
||||
const appStore = useAppStore();
|
||||
|
||||
const currentProject = ref(appStore.currentProjectId);
|
||||
const features = ref<FeatureEnum[]>(Object.values(FeatureEnum));
|
||||
const featureOptions = Object.keys(FeatureEnum)
|
||||
const features = ref<FeatureEnum[]>([]);
|
||||
const fullFeaturesOptions = Object.keys(FeatureEnum)
|
||||
.filter((e) => [FeatureEnum.TEST_PLAN, FeatureEnum.CASE_REVIEW, FeatureEnum.BUG].includes(e as FeatureEnum))
|
||||
.map((key) => ({
|
||||
label: t(`ms.workbench.myFollowed.feature.${key}`),
|
||||
value: key as FeatureEnum,
|
||||
}));
|
||||
const featureOptions = ref<SelectOptionData[]>([]);
|
||||
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();
|
||||
}
|
||||
</script>
|
||||
|
Loading…
Reference in New Issue
Block a user