feat(工作台): 工作台首页联调部分卡片
This commit is contained in:
parent
61c05433fa
commit
fced7b284f
|
@ -1,6 +1,6 @@
|
||||||
import MSR from '@/api/http/index';
|
import MSR from '@/api/http/index';
|
||||||
|
|
||||||
import type { ApiCaseDetail } from '@/models/apiTest/management';
|
import type { ApiCaseDetail, ApiDefinitionDetail } from '@/models/apiTest/management';
|
||||||
import type { ApiScenarioTableItem } from '@/models/apiTest/scenario';
|
import type { ApiScenarioTableItem } from '@/models/apiTest/scenario';
|
||||||
import type { BugListItem } from '@/models/bug-management';
|
import type { BugListItem } from '@/models/bug-management';
|
||||||
import type { ReviewItem } from '@/models/caseManagement/caseReview';
|
import type { ReviewItem } from '@/models/caseManagement/caseReview';
|
||||||
|
@ -17,6 +17,7 @@ import type {
|
||||||
import {
|
import {
|
||||||
EditDashboardLayoutUrl,
|
EditDashboardLayoutUrl,
|
||||||
GetDashboardLayoutUrl,
|
GetDashboardLayoutUrl,
|
||||||
|
WorkApiChangeListUrl,
|
||||||
WorkAssociateCaseDetailUrl,
|
WorkAssociateCaseDetailUrl,
|
||||||
WorkbenchApiCaseListUrl,
|
WorkbenchApiCaseListUrl,
|
||||||
WorkbenchBugListUrl,
|
WorkbenchBugListUrl,
|
||||||
|
@ -25,10 +26,13 @@ import {
|
||||||
WorkbenchScenarioListUrl,
|
WorkbenchScenarioListUrl,
|
||||||
WorkbenchTestPlanListUrl,
|
WorkbenchTestPlanListUrl,
|
||||||
WorkbenchTestPlanStatisticUrl,
|
WorkbenchTestPlanStatisticUrl,
|
||||||
|
WorkBugHandlerDetailUrl,
|
||||||
WorkCaseCountDetailUrl,
|
WorkCaseCountDetailUrl,
|
||||||
|
WorkCaseReviewDetailUrl,
|
||||||
WorkMemberViewDetailUrl,
|
WorkMemberViewDetailUrl,
|
||||||
WorkMyCreatedDetailUrl,
|
WorkMyCreatedDetailUrl,
|
||||||
WorkProOverviewDetailUrl,
|
WorkProOverviewDetailUrl,
|
||||||
|
WorkReviewListUrl,
|
||||||
WorkTodoBugListUrl,
|
WorkTodoBugListUrl,
|
||||||
WorkTodoPlanListUrl,
|
WorkTodoPlanListUrl,
|
||||||
WorkTodoReviewListUrl,
|
WorkTodoReviewListUrl,
|
||||||
|
@ -100,6 +104,32 @@ export function workAssociateCaseDetail(data: WorkHomePageDetail) {
|
||||||
return MSR.post<PassRateDataType>({ url: WorkAssociateCaseDetailUrl, data });
|
return MSR.post<PassRateDataType>({ url: WorkAssociateCaseDetailUrl, data });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 工作台-首页-用例评审数
|
||||||
|
export function workCaseReviewDetail(data: WorkHomePageDetail) {
|
||||||
|
return MSR.post<PassRateDataType>({ url: WorkCaseReviewDetailUrl, data });
|
||||||
|
}
|
||||||
|
|
||||||
|
// 工作台-首页-缺陷处理人
|
||||||
|
export function workBugHandlerDetail(data: WorkHomePageDetail) {
|
||||||
|
return MSR.post<OverViewOfProject>({ url: WorkBugHandlerDetailUrl, data });
|
||||||
|
}
|
||||||
|
|
||||||
|
// 工作台-首页-接口变更
|
||||||
|
export function workApiChangeList(data: WorkHomePageDetail) {
|
||||||
|
return MSR.post<CommonList<ApiDefinitionDetail>>(
|
||||||
|
{ url: WorkApiChangeListUrl, data },
|
||||||
|
{ ignoreCancelToken: true, errorMessageMode: 'none' }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 工作台-首页-接口变更
|
||||||
|
export function workReviewList(data: WorkHomePageDetail) {
|
||||||
|
return MSR.post<CommonList<ReviewItem>>(
|
||||||
|
{ url: WorkReviewListUrl, data },
|
||||||
|
{ ignoreCancelToken: true, errorMessageMode: 'none' }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// 待办-用例评审列表
|
// 待办-用例评审列表
|
||||||
export function workbenchTodoReviewList(data: TableQueryParams) {
|
export function workbenchTodoReviewList(data: TableQueryParams) {
|
||||||
return MSR.post<CommonList<ReviewItem>>({ url: WorkTodoReviewListUrl, data });
|
return MSR.post<CommonList<ReviewItem>>({ url: WorkTodoReviewListUrl, data });
|
||||||
|
|
|
@ -15,3 +15,7 @@ export const WorkTodoBugListUrl = '/dashboard/todo/bug/page'; // 工作台-待
|
||||||
export const WorkMemberViewDetailUrl = '/dashboard/project_member_view'; // 工作台-首页-人员概览
|
export const WorkMemberViewDetailUrl = '/dashboard/project_member_view'; // 工作台-首页-人员概览
|
||||||
export const WorkCaseCountDetailUrl = '/dashboard/case_count'; // 工作台-首页-用例数量
|
export const WorkCaseCountDetailUrl = '/dashboard/case_count'; // 工作台-首页-用例数量
|
||||||
export const WorkAssociateCaseDetailUrl = '/dashboard/associate_case_count'; // 工作台-首页-关联用例数量
|
export const WorkAssociateCaseDetailUrl = '/dashboard/associate_case_count'; // 工作台-首页-关联用例数量
|
||||||
|
export const WorkBugHandlerDetailUrl = '/dashboard/bug_handle_user'; // 工作台-首页-缺陷处理人
|
||||||
|
export const WorkApiChangeListUrl = '/dashboard/api_change'; // 工作台-首页-接口变更
|
||||||
|
export const WorkCaseReviewDetailUrl = '/dashboard/review_case_count'; // 工作台-首页-用例评审数
|
||||||
|
export const WorkReviewListUrl = '/dashboard/reviewing_by_me'; // 工作台-首页-待我评审
|
||||||
|
|
|
@ -259,11 +259,12 @@ export default function useTableProps<T>(
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// TODO 在这里处理拦截设置表格无资源权限
|
|
||||||
setTableErrorStatus('error');
|
setTableErrorStatus('error');
|
||||||
propsRes.value.data = [];
|
propsRes.value.data = [];
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.log(err);
|
console.log(err);
|
||||||
|
|
||||||
|
throw err; // 将错误抛出
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
// debug 模式下打印属性
|
// debug 模式下打印属性
|
||||||
|
|
|
@ -0,0 +1,301 @@
|
||||||
|
import { cloneDeep } from 'lodash-es';
|
||||||
|
|
||||||
|
import { commonConfig, toolTipConfig } from '@/config/testPlan';
|
||||||
|
|
||||||
|
import type { ModuleCardItem } from '@/models/workbench/homePage';
|
||||||
|
import { WorkCardEnum, WorkOverviewEnum, WorkOverviewIconEnum } from '@/enums/workbenchEnum';
|
||||||
|
|
||||||
|
export const contentTabList: ModuleCardItem[] = [
|
||||||
|
{
|
||||||
|
label: 'workbench.homePage.functionalUseCase',
|
||||||
|
value: WorkOverviewEnum.FUNCTIONAL,
|
||||||
|
icon: WorkOverviewIconEnum.FUNCTIONAL,
|
||||||
|
color: 'rgb(var(--primary-5))',
|
||||||
|
count: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'workbench.homePage.useCaseReview',
|
||||||
|
value: WorkOverviewEnum.CASE_REVIEW,
|
||||||
|
icon: WorkOverviewIconEnum.CASE_REVIEW,
|
||||||
|
color: 'rgb(var(--success-6))',
|
||||||
|
count: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'workbench.homePage.interfaceAPI',
|
||||||
|
value: WorkOverviewEnum.API,
|
||||||
|
icon: WorkOverviewIconEnum.API,
|
||||||
|
color: 'rgb(var(--link-6))',
|
||||||
|
count: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'workbench.homePage.interfaceCASE',
|
||||||
|
value: WorkOverviewEnum.API_CASE,
|
||||||
|
icon: WorkOverviewIconEnum.API_CASE,
|
||||||
|
color: 'rgb(var(--link-6))',
|
||||||
|
count: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'workbench.homePage.interfaceScenario',
|
||||||
|
value: WorkOverviewEnum.API_SCENARIO,
|
||||||
|
icon: WorkOverviewIconEnum.API_SCENARIO,
|
||||||
|
color: 'rgb(var(--link-6))',
|
||||||
|
count: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'workbench.homePage.apiPlan',
|
||||||
|
value: WorkOverviewEnum.TEST_PLAN,
|
||||||
|
icon: WorkOverviewIconEnum.TEST_PLAN,
|
||||||
|
color: 'rgb(var(--link-6))',
|
||||||
|
count: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'workbench.homePage.bugCount',
|
||||||
|
value: WorkOverviewEnum.BUG_COUNT,
|
||||||
|
icon: WorkOverviewIconEnum.BUG_COUNT,
|
||||||
|
color: 'rgb(var(--danger-6))',
|
||||||
|
count: 0,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
// 覆盖率
|
||||||
|
export const defaultCover = [
|
||||||
|
{
|
||||||
|
label: 'workbench.homePage.covered',
|
||||||
|
value: '-',
|
||||||
|
name: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'workbench.homePage.notCover',
|
||||||
|
value: '-',
|
||||||
|
name: '',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
// 评审率
|
||||||
|
export const defaultReview = [
|
||||||
|
{
|
||||||
|
label: 'workbench.homePage.reviewed',
|
||||||
|
value: '-',
|
||||||
|
name: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'workbench.homePage.unReviewed',
|
||||||
|
value: '-',
|
||||||
|
name: '',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
// 通过率
|
||||||
|
export const defaultPass = [
|
||||||
|
{
|
||||||
|
label: 'workbench.homePage.havePassed',
|
||||||
|
value: '-',
|
||||||
|
name: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'workbench.homePage.notPass',
|
||||||
|
value: '-',
|
||||||
|
name: '',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
// 完成率
|
||||||
|
export const defaultComplete = [
|
||||||
|
{
|
||||||
|
label: 'common.completed',
|
||||||
|
value: 10000,
|
||||||
|
name: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'common.inProgress',
|
||||||
|
value: 2000,
|
||||||
|
name: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'workbench.homePage.unFinish',
|
||||||
|
value: 2000,
|
||||||
|
name: '',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
// 执行率
|
||||||
|
export const defaultExecution = [
|
||||||
|
{
|
||||||
|
label: 'common.unExecute',
|
||||||
|
value: 10000,
|
||||||
|
name: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'common.executed',
|
||||||
|
value: 2000,
|
||||||
|
name: '',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
// 遗留率
|
||||||
|
export const defaultLegacy = [
|
||||||
|
{
|
||||||
|
label: 'workbench.homePage.defectTotal',
|
||||||
|
value: 10000,
|
||||||
|
name: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'workbench.homePage.legacyDefectsNumber',
|
||||||
|
value: 2000,
|
||||||
|
name: '',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export const defaultValueMap: Record<string, any> = {
|
||||||
|
// 用例数量
|
||||||
|
[WorkCardEnum.CASE_COUNT]: {
|
||||||
|
review: {
|
||||||
|
defaultList: cloneDeep(defaultCover),
|
||||||
|
color: ['#00C261', '#D4D4D8'],
|
||||||
|
defaultName: 'workbench.homePage.reviewRate',
|
||||||
|
},
|
||||||
|
pass: {
|
||||||
|
defaultList: cloneDeep(defaultPass),
|
||||||
|
color: ['#00C261', '#ED0303'],
|
||||||
|
defaultName: 'workbench.homePage.passRate',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// 关联用例数量
|
||||||
|
[WorkCardEnum.ASSOCIATE_CASE_COUNT]: {
|
||||||
|
cover: {
|
||||||
|
defaultList: cloneDeep(defaultCover),
|
||||||
|
color: ['#00C261', '#D4D4D8'],
|
||||||
|
defaultName: 'workbench.homePage.coverRate',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// 用例评审数
|
||||||
|
[WorkCardEnum.REVIEW_CASE_COUNT]: {
|
||||||
|
cover: {
|
||||||
|
defaultList: cloneDeep(defaultCover),
|
||||||
|
color: ['#00C261', '#D4D4D8'],
|
||||||
|
defaultName: 'workbench.homePage.coverRate',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// 测试计划数
|
||||||
|
[WorkCardEnum.TEST_PLAN_COUNT]: {
|
||||||
|
execute: {
|
||||||
|
defaultList: cloneDeep(defaultExecution),
|
||||||
|
color: ['#D4D4D8', '#00C261'],
|
||||||
|
defaultName: 'workbench.homePage.executeRate',
|
||||||
|
},
|
||||||
|
pass: {
|
||||||
|
defaultList: cloneDeep(defaultPass),
|
||||||
|
color: ['#D4D4D8', '#00C261'],
|
||||||
|
defaultName: 'workbench.homePage.passRate',
|
||||||
|
},
|
||||||
|
complete: {
|
||||||
|
defaultList: cloneDeep(defaultComplete),
|
||||||
|
color: ['#00C261', '#3370FF', '#D4D4D8'],
|
||||||
|
defaultName: 'workbench.homePage.completeRate',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// 测试计划遗留缺陷
|
||||||
|
[WorkCardEnum.PLAN_LEGACY_BUG]: {
|
||||||
|
legacy: {
|
||||||
|
defaultList: cloneDeep(defaultLegacy),
|
||||||
|
color: ['#D4D4D8', '#00C261'],
|
||||||
|
defaultName: 'workbench.homePage.legacyRate',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// 缺陷数
|
||||||
|
[WorkCardEnum.BUG_COUNT]: {
|
||||||
|
legacy: {
|
||||||
|
defaultList: cloneDeep(defaultLegacy),
|
||||||
|
color: ['#D4D4D8', '#00C261'],
|
||||||
|
defaultName: 'workbench.homePage.legacyRate',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// 待我处理的缺陷
|
||||||
|
[WorkCardEnum.HANDLE_BUG_BY_ME]: {
|
||||||
|
legacy: {
|
||||||
|
defaultList: cloneDeep(defaultLegacy),
|
||||||
|
color: ['#D4D4D8', '#00C261'],
|
||||||
|
defaultName: 'workbench.homePage.legacyRate',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// 接口数量
|
||||||
|
[WorkCardEnum.API_COUNT]: {
|
||||||
|
cover: {
|
||||||
|
defaultList: cloneDeep(defaultCover),
|
||||||
|
color: ['#00C261', '#D4D4D8'],
|
||||||
|
defaultName: 'workbench.homePage.coverRate',
|
||||||
|
},
|
||||||
|
complete: {
|
||||||
|
defaultList: cloneDeep(defaultComplete),
|
||||||
|
color: ['#00C261', '#3370FF', '#D4D4D8'],
|
||||||
|
defaultName: 'workbench.homePage.completeRate',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// 我创建的缺陷
|
||||||
|
[WorkCardEnum.CREATE_BUG_BY_ME]: {
|
||||||
|
legacy: {
|
||||||
|
defaultList: cloneDeep(defaultLegacy),
|
||||||
|
color: ['#D4D4D8', '#00C261'],
|
||||||
|
defaultName: 'workbench.homePage.legacyRate',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// XX率饼图配置
|
||||||
|
export const commonRatePieOptions = {
|
||||||
|
...commonConfig,
|
||||||
|
title: {
|
||||||
|
show: true,
|
||||||
|
text: '',
|
||||||
|
left: 26,
|
||||||
|
top: '20%',
|
||||||
|
textStyle: {
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: 'normal',
|
||||||
|
color: '#959598',
|
||||||
|
},
|
||||||
|
triggerEvent: true, // 开启鼠标事件
|
||||||
|
subtext: '0',
|
||||||
|
subtextStyle: {
|
||||||
|
fontSize: 12,
|
||||||
|
color: '#323233',
|
||||||
|
fontWeight: 'bold',
|
||||||
|
align: 'center',
|
||||||
|
lineHeight: 3,
|
||||||
|
},
|
||||||
|
textAlign: 'center',
|
||||||
|
tooltip: {
|
||||||
|
...toolTipConfig,
|
||||||
|
position: 'right',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
...toolTipConfig,
|
||||||
|
position: 'right',
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
show: false,
|
||||||
|
},
|
||||||
|
series: {
|
||||||
|
name: '',
|
||||||
|
type: 'pie',
|
||||||
|
color: [],
|
||||||
|
padAngle: 2,
|
||||||
|
radius: ['85%', '100%'],
|
||||||
|
center: [30, '50%'],
|
||||||
|
avoidLabelOverlap: false,
|
||||||
|
label: {
|
||||||
|
show: false,
|
||||||
|
position: 'center',
|
||||||
|
},
|
||||||
|
emphasis: {
|
||||||
|
scale: false, // 禁用放大效果
|
||||||
|
label: {
|
||||||
|
show: false,
|
||||||
|
fontSize: 40,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
labelLine: {
|
||||||
|
show: false,
|
||||||
|
},
|
||||||
|
data: [],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default {};
|
|
@ -56,7 +56,7 @@ export interface OverViewOfProject {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ModuleCardItem {
|
export interface ModuleCardItem {
|
||||||
label: string | number;
|
label: string;
|
||||||
value: string | number;
|
value: string | number;
|
||||||
count?: number;
|
count?: number;
|
||||||
icon?: string;
|
icon?: string;
|
||||||
|
@ -73,10 +73,13 @@ export type StatusStatisticsMapType = Record<
|
||||||
>;
|
>;
|
||||||
|
|
||||||
export interface PassRateDataType {
|
export interface PassRateDataType {
|
||||||
statusStatisticsMap: StatusStatisticsMapType;
|
statusStatisticsMap: StatusStatisticsMapType | null;
|
||||||
statusPercentList: {
|
statusPercentList:
|
||||||
status: string; // 状态
|
| {
|
||||||
count: number;
|
status: string; // 状态
|
||||||
percentValue: string; // 百分比
|
count: number;
|
||||||
}[];
|
percentValue: string; // 百分比
|
||||||
|
}[]
|
||||||
|
| null;
|
||||||
|
errorCode: number;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
:search-keys="['name']"
|
:search-keys="['name']"
|
||||||
class="!w-[240px]"
|
class="!w-[240px]"
|
||||||
:prefix="t('workbench.homePage.project')"
|
:prefix="t('workbench.homePage.project')"
|
||||||
|
@change="changeProject"
|
||||||
>
|
>
|
||||||
</MsSelect>
|
</MsSelect>
|
||||||
</div>
|
</div>
|
||||||
|
@ -29,7 +30,16 @@
|
||||||
v-on="propsEvent"
|
v-on="propsEvent"
|
||||||
>
|
>
|
||||||
<template #num="{ record }">
|
<template #num="{ record }">
|
||||||
<MsButton type="text">{{ record.num }}</MsButton>
|
<MsButton type="text">{{ record.num || '-' }}</MsButton>
|
||||||
|
</template>
|
||||||
|
<template v-if="isNoPermission" #empty>
|
||||||
|
<div class="w-full">
|
||||||
|
<slot name="empty">
|
||||||
|
<div class="flex h-[40px] flex-col items-center justify-center">
|
||||||
|
<span class="text-[14px] text-[var(--color-text-4)]">{{ t('common.noResource') }}</span>
|
||||||
|
</div>
|
||||||
|
</slot>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</MsBaseTable>
|
</MsBaseTable>
|
||||||
</div>
|
</div>
|
||||||
|
@ -49,6 +59,7 @@
|
||||||
import useTable from '@/components/pure/ms-table/useTable';
|
import useTable from '@/components/pure/ms-table/useTable';
|
||||||
import MsSelect from '@/components/business/ms-select';
|
import MsSelect from '@/components/business/ms-select';
|
||||||
|
|
||||||
|
import { workApiChangeList } from '@/api/modules/workbench';
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
import useAppStore from '@/store/modules/app';
|
import useAppStore from '@/store/modules/app';
|
||||||
|
|
||||||
|
@ -85,8 +96,8 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'project.commonScript.apiName',
|
title: 'project.commonScript.apiName',
|
||||||
slotName: 'apiName',
|
slotName: 'name',
|
||||||
dataIndex: 'apiName',
|
dataIndex: 'name',
|
||||||
width: 200,
|
width: 200,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -98,14 +109,14 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'workbench.homePage.associationCASE',
|
title: 'workbench.homePage.associationCASE',
|
||||||
slotName: 'case',
|
slotName: 'caseTotal',
|
||||||
dataIndex: 'case',
|
dataIndex: 'caseTotal',
|
||||||
width: 200,
|
width: 200,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'workbench.homePage.associatedScene',
|
title: 'workbench.homePage.associatedScene',
|
||||||
slotName: 'associatedScene',
|
slotName: 'scenarioTotal',
|
||||||
dataIndex: 'associatedScene',
|
dataIndex: 'scenarioTotal',
|
||||||
showDrag: true,
|
showDrag: true,
|
||||||
width: 100,
|
width: 100,
|
||||||
},
|
},
|
||||||
|
@ -122,32 +133,43 @@
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
const { propsRes, propsEvent, loadList, setLoadListParams } = useTable(
|
const { propsRes, propsEvent, loadList, setLoadListParams } = useTable(
|
||||||
undefined,
|
workApiChangeList,
|
||||||
{
|
{
|
||||||
columns,
|
columns,
|
||||||
scroll: { x: '100%' },
|
scroll: { x: '100%' },
|
||||||
selectable: false,
|
selectable: false,
|
||||||
heightUsed: 272,
|
heightUsed: 272,
|
||||||
showSelectAll: false,
|
showSelectAll: false,
|
||||||
|
validatePermission: true,
|
||||||
},
|
},
|
||||||
(item) => ({
|
(item) => ({
|
||||||
...item,
|
...item,
|
||||||
updateTime: dayjs(item.updateTime).format('YYYY-MM-DD HH:mm:ss'),
|
updateTime: dayjs(item.updateTime).format('YYYY-MM-DD HH:mm:ss'),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
function initData() {
|
const isNoPermission = ref<boolean>(false);
|
||||||
const { startTime, endTime, dayNumber } = timeForm.value;
|
async function initData() {
|
||||||
setLoadListParams({
|
try {
|
||||||
current: 1,
|
const { startTime, endTime, dayNumber } = timeForm.value;
|
||||||
pageSize: 5,
|
setLoadListParams({
|
||||||
startTime: dayNumber ? null : startTime,
|
startTime: dayNumber ? null : startTime,
|
||||||
endTime: dayNumber ? null : endTime,
|
endTime: dayNumber ? null : endTime,
|
||||||
dayNumber: dayNumber ?? null,
|
dayNumber: dayNumber ?? null,
|
||||||
projectIds: innerProjectIds.value,
|
projectIds: innerProjectIds.value,
|
||||||
organizationId: appStore.currentOrgId,
|
organizationId: appStore.currentOrgId,
|
||||||
handleUsers: [],
|
handleUsers: [],
|
||||||
});
|
});
|
||||||
loadList();
|
await loadList();
|
||||||
|
isNoPermission.value = false;
|
||||||
|
} catch (error) {
|
||||||
|
isNoPermission.value = error === 'no_project_permission';
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeProject() {
|
||||||
|
initData();
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
@ -160,7 +182,6 @@
|
||||||
if (val) {
|
if (val) {
|
||||||
const [newProjectId] = val;
|
const [newProjectId] = val;
|
||||||
projectId.value = newProjectId;
|
projectId.value = newProjectId;
|
||||||
initData();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -170,7 +191,6 @@
|
||||||
(val) => {
|
(val) => {
|
||||||
if (val) {
|
if (val) {
|
||||||
innerProjectIds.value = [val];
|
innerProjectIds.value = [val];
|
||||||
initData();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
:search-keys="['name']"
|
:search-keys="['name']"
|
||||||
class="!w-[240px]"
|
class="!w-[240px]"
|
||||||
:prefix="t('workbench.homePage.project')"
|
:prefix="t('workbench.homePage.project')"
|
||||||
|
@change="changeProject"
|
||||||
>
|
>
|
||||||
</MsSelect>
|
</MsSelect>
|
||||||
</div>
|
</div>
|
||||||
|
@ -24,6 +25,7 @@
|
||||||
:tooltip-text="tabItem.tooltip"
|
:tooltip-text="tabItem.tooltip"
|
||||||
:options="tabItem.options"
|
:options="tabItem.options"
|
||||||
:size="60"
|
:size="60"
|
||||||
|
:has-permission="hasPermission"
|
||||||
:value-list="tabItem.valueList"
|
:value-list="tabItem.valueList"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -51,14 +53,9 @@
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
import useAppStore from '@/store/modules/app';
|
import useAppStore from '@/store/modules/app';
|
||||||
|
|
||||||
import type {
|
import type { PassRateDataType, SelectedCardItem, TimeFormParams } from '@/models/workbench/homePage';
|
||||||
PassRateDataType,
|
|
||||||
SelectedCardItem,
|
|
||||||
StatusStatisticsMapType,
|
|
||||||
TimeFormParams,
|
|
||||||
} from '@/models/workbench/homePage';
|
|
||||||
|
|
||||||
import { commonRatePieOptions, handlePieData } from '../utils';
|
import { handlePieData, handleUpdateTabPie } from '../utils';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
item: SelectedCardItem;
|
item: SelectedCardItem;
|
||||||
|
@ -82,55 +79,20 @@
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
const options = ref(cloneDeep(commonRatePieOptions));
|
const options = ref({});
|
||||||
|
|
||||||
// TODO 假数据
|
// TODO 假数据
|
||||||
const detail = ref<PassRateDataType>({
|
const detail = ref<PassRateDataType>({
|
||||||
statusStatisticsMap: {
|
statusStatisticsMap: null,
|
||||||
cover: [
|
statusPercentList: null,
|
||||||
{ name: '覆盖率', count: 10 },
|
errorCode: 109001,
|
||||||
{ name: '已覆盖', count: 2 },
|
|
||||||
{ name: '未覆盖', count: 1 },
|
|
||||||
],
|
|
||||||
success: [
|
|
||||||
{ name: '覆盖率', count: 10 },
|
|
||||||
{ name: '已覆盖', count: 2 },
|
|
||||||
{ name: '未覆盖', count: 1 },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
statusPercentList: [
|
|
||||||
{ status: 'HTTP', count: 1, percentValue: '10%' },
|
|
||||||
{ status: 'TCP', count: 3, percentValue: '0%' },
|
|
||||||
{ status: 'BBB', count: 6, percentValue: '0%' },
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const coverValueList = ref([
|
const coverValueList = ref<{ value: string | number; label: string; name: string }[]>([]);
|
||||||
{
|
|
||||||
label: t('workbench.homePage.covered'),
|
const passValueList = ref<{ value: string | number; label: string; name: string }[]>([]);
|
||||||
value: 10000,
|
const coverOptions = ref<Record<string, any>>({});
|
||||||
},
|
const completeOptions = ref<Record<string, any>>({});
|
||||||
{
|
|
||||||
label: t('workbench.homePage.notCover'),
|
|
||||||
value: 2000,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
const passValueList = ref([
|
|
||||||
{
|
|
||||||
label: t('common.completed'),
|
|
||||||
value: 10000,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: t('common.inProgress'),
|
|
||||||
value: 2000,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: t('workbench.homePage.unFinish'),
|
|
||||||
value: 2000,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
const coverOptions = ref<Record<string, any>>(cloneDeep(options.value));
|
|
||||||
const completeOptions = ref<Record<string, any>>(cloneDeep(options.value));
|
|
||||||
const apiCountTabList = computed(() => {
|
const apiCountTabList = computed(() => {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
|
@ -152,34 +114,7 @@
|
||||||
|
|
||||||
const apiCountOptions = ref({});
|
const apiCountOptions = ref({});
|
||||||
|
|
||||||
function handlePassRatePercent(data: { name: string; count: number }[]) {
|
const hasPermission = ref<boolean>(false);
|
||||||
return data.slice(1).map((item) => {
|
|
||||||
return {
|
|
||||||
value: item.count,
|
|
||||||
label: item.name,
|
|
||||||
name: item.name,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleRatePieData(statusStatisticsMap: StatusStatisticsMapType) {
|
|
||||||
const { cover, success } = statusStatisticsMap;
|
|
||||||
coverValueList.value = handlePassRatePercent(cover);
|
|
||||||
passValueList.value = handlePassRatePercent(success);
|
|
||||||
|
|
||||||
coverOptions.value.series.data = handlePassRatePercent(cover);
|
|
||||||
completeOptions.value.series.data = handlePassRatePercent(success);
|
|
||||||
|
|
||||||
coverOptions.value.title.text = cover[0].name ?? '';
|
|
||||||
coverOptions.value.title.subtext = `${cover[0].count ?? 0}%`;
|
|
||||||
|
|
||||||
completeOptions.value.title.text = success[0].name ?? '';
|
|
||||||
completeOptions.value.title.subtext = `${success[0].count ?? 0}%`;
|
|
||||||
|
|
||||||
coverOptions.value.series.color = ['#00C261', '#D4D4D8'];
|
|
||||||
completeOptions.value.series.color = ['#00C261', '#ED0303'];
|
|
||||||
}
|
|
||||||
|
|
||||||
function initApiCount() {
|
function initApiCount() {
|
||||||
try {
|
try {
|
||||||
const { startTime, endTime, dayNumber } = timeForm.value;
|
const { startTime, endTime, dayNumber } = timeForm.value;
|
||||||
|
@ -193,14 +128,38 @@
|
||||||
organizationId: appStore.currentOrgId,
|
organizationId: appStore.currentOrgId,
|
||||||
handleUsers: [],
|
handleUsers: [],
|
||||||
};
|
};
|
||||||
const { statusStatisticsMap, statusPercentList } = detail.value;
|
const { statusStatisticsMap, statusPercentList, errorCode } = detail.value;
|
||||||
apiCountOptions.value = handlePieData(props.item.key, statusPercentList);
|
|
||||||
handleRatePieData(statusStatisticsMap);
|
hasPermission.value = errorCode !== 109001;
|
||||||
|
|
||||||
|
apiCountOptions.value = handlePieData(props.item.key, hasPermission.value, statusPercentList);
|
||||||
|
|
||||||
|
// 覆盖率
|
||||||
|
const { options: covOptions, valueList: coverList } = handleUpdateTabPie(
|
||||||
|
statusStatisticsMap?.cover || [],
|
||||||
|
hasPermission.value,
|
||||||
|
`${props.item.key}-cover`
|
||||||
|
);
|
||||||
|
coverValueList.value = coverList;
|
||||||
|
coverOptions.value = covOptions;
|
||||||
|
|
||||||
|
const { options: comOptions, valueList: completedList } = handleUpdateTabPie(
|
||||||
|
statusStatisticsMap?.cover || [],
|
||||||
|
hasPermission.value,
|
||||||
|
`${props.item.key}-complete`
|
||||||
|
);
|
||||||
|
passValueList.value = completedList;
|
||||||
|
completeOptions.value = comOptions;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
console.log(error);
|
console.log(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function changeProject() {
|
||||||
|
initApiCount();
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
initApiCount();
|
initApiCount();
|
||||||
});
|
});
|
||||||
|
@ -211,7 +170,6 @@
|
||||||
if (val) {
|
if (val) {
|
||||||
const [newProjectId] = val;
|
const [newProjectId] = val;
|
||||||
projectId.value = newProjectId;
|
projectId.value = newProjectId;
|
||||||
initApiCount();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -221,7 +179,6 @@
|
||||||
(val) => {
|
(val) => {
|
||||||
if (val) {
|
if (val) {
|
||||||
innerProjectIds.value = [val];
|
innerProjectIds.value = [val];
|
||||||
initApiCount();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
:search-keys="['name']"
|
:search-keys="['name']"
|
||||||
class="!w-[240px]"
|
class="!w-[240px]"
|
||||||
:prefix="t('workbench.homePage.project')"
|
:prefix="t('workbench.homePage.project')"
|
||||||
|
@change="changeProject"
|
||||||
>
|
>
|
||||||
</MsSelect>
|
</MsSelect>
|
||||||
</div>
|
</div>
|
||||||
|
@ -25,6 +26,7 @@
|
||||||
:tooltip-text="tabItem.tooltip"
|
:tooltip-text="tabItem.tooltip"
|
||||||
:size="60"
|
:size="60"
|
||||||
:value-list="tabItem.valueList"
|
:value-list="tabItem.valueList"
|
||||||
|
:has-permission="hasPermission"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -41,7 +43,6 @@
|
||||||
* @desc 用例数量
|
* @desc 用例数量
|
||||||
*/
|
*/
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { cloneDeep } from 'lodash-es';
|
|
||||||
|
|
||||||
import MsChart from '@/components/pure/chart/index.vue';
|
import MsChart from '@/components/pure/chart/index.vue';
|
||||||
import MsSelect from '@/components/business/ms-select';
|
import MsSelect from '@/components/business/ms-select';
|
||||||
|
@ -53,9 +54,8 @@
|
||||||
import useAppStore from '@/store/modules/app';
|
import useAppStore from '@/store/modules/app';
|
||||||
|
|
||||||
import type { SelectedCardItem, TimeFormParams } from '@/models/workbench/homePage';
|
import type { SelectedCardItem, TimeFormParams } from '@/models/workbench/homePage';
|
||||||
import { StatusStatisticsMapType } from '@/models/workbench/homePage';
|
|
||||||
|
|
||||||
import { commonRatePieOptions, handlePieData } from '../utils';
|
import { handlePieData, handleUpdateTabPie } from '../utils';
|
||||||
|
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
@ -79,42 +79,12 @@
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
const options = ref(cloneDeep(commonRatePieOptions));
|
const reviewValueList = ref<{ value: number | string; label: string; name: string }[]>([]);
|
||||||
|
|
||||||
function handlePassRatePercent(data: { name: string; count: number }[]) {
|
const passValueList = ref<{ value: number | string; label: string; name: string }[]>([]);
|
||||||
return data.slice(1).map((item) => {
|
|
||||||
return {
|
|
||||||
value: item.count,
|
|
||||||
label: item.name,
|
|
||||||
name: item.name,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const reviewValueList = ref([
|
const reviewOptions = ref<Record<string, any>>({});
|
||||||
{
|
const passOptions = ref<Record<string, any>>({});
|
||||||
label: t('workbench.homePage.reviewed'),
|
|
||||||
value: 10000,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: t('workbench.homePage.unReviewed'),
|
|
||||||
value: 2000,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
const passValueList = ref([
|
|
||||||
{
|
|
||||||
label: t('workbench.homePage.havePassed'),
|
|
||||||
value: 10000,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: t('workbench.homePage.notPass'),
|
|
||||||
value: 2000,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
const reviewOptions = ref<Record<string, any>>(cloneDeep(options.value));
|
|
||||||
const passOptions = ref<Record<string, any>>(cloneDeep(options.value));
|
|
||||||
const caseCountTabList = computed(() => {
|
const caseCountTabList = computed(() => {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
|
@ -134,24 +104,10 @@
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
|
|
||||||
// 处理X率饼图数据
|
const hasPermission = ref<boolean>(false);
|
||||||
function handleRatePieData(statusStatisticsMap: StatusStatisticsMapType) {
|
|
||||||
const { review, pass } = statusStatisticsMap;
|
|
||||||
reviewValueList.value = handlePassRatePercent(review);
|
|
||||||
passValueList.value = handlePassRatePercent(pass);
|
|
||||||
|
|
||||||
reviewOptions.value.series.data = handlePassRatePercent(review);
|
|
||||||
passOptions.value.series.data = handlePassRatePercent(pass);
|
|
||||||
|
|
||||||
reviewOptions.value.title.text = review[0].name ?? '';
|
|
||||||
reviewOptions.value.title.subtext = `${review[0].count ?? 0}%`;
|
|
||||||
passOptions.value.title.text = pass[0].name ?? '';
|
|
||||||
passOptions.value.title.subtext = `${pass[0].count ?? 0}%`;
|
|
||||||
reviewOptions.value.series.color = ['#00C261', '#D4D4D8'];
|
|
||||||
passOptions.value.series.color = ['#00C261', '#ED0303'];
|
|
||||||
}
|
|
||||||
|
|
||||||
const caseCountOptions = ref<Record<string, any>>({});
|
const caseCountOptions = ref<Record<string, any>>({});
|
||||||
|
|
||||||
async function initCaseCount() {
|
async function initCaseCount() {
|
||||||
try {
|
try {
|
||||||
const { startTime, endTime, dayNumber } = timeForm.value;
|
const { startTime, endTime, dayNumber } = timeForm.value;
|
||||||
|
@ -167,14 +123,35 @@
|
||||||
};
|
};
|
||||||
const detail = await workCaseCountDetail(params);
|
const detail = await workCaseCountDetail(params);
|
||||||
const { statusStatisticsMap, statusPercentList } = detail;
|
const { statusStatisticsMap, statusPercentList } = detail;
|
||||||
caseCountOptions.value = handlePieData(props.item.key, statusPercentList);
|
hasPermission.value = detail.errorCode !== 109001;
|
||||||
handleRatePieData(statusStatisticsMap);
|
caseCountOptions.value = handlePieData(props.item.key, hasPermission.value, statusPercentList);
|
||||||
|
|
||||||
|
const { valueList: reviewValue, options: reviewedOptions } = handleUpdateTabPie(
|
||||||
|
statusStatisticsMap?.review || [],
|
||||||
|
hasPermission.value,
|
||||||
|
`${props.item.key}-review`
|
||||||
|
);
|
||||||
|
|
||||||
|
reviewOptions.value = reviewedOptions;
|
||||||
|
reviewValueList.value = reviewValue;
|
||||||
|
|
||||||
|
const { valueList: passList, options: passOpt } = handleUpdateTabPie(
|
||||||
|
statusStatisticsMap?.pass || [],
|
||||||
|
hasPermission.value,
|
||||||
|
`${props.item.key}-pass`
|
||||||
|
);
|
||||||
|
passOptions.value = passOpt;
|
||||||
|
passValueList.value = passList;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.log(error);
|
console.log(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function changeProject() {
|
||||||
|
initCaseCount();
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
initCaseCount();
|
initCaseCount();
|
||||||
});
|
});
|
||||||
|
@ -185,7 +162,6 @@
|
||||||
if (val) {
|
if (val) {
|
||||||
const [newProjectId] = val;
|
const [newProjectId] = val;
|
||||||
projectId.value = newProjectId;
|
projectId.value = newProjectId;
|
||||||
initCaseCount();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -195,7 +171,6 @@
|
||||||
(val) => {
|
(val) => {
|
||||||
if (val) {
|
if (val) {
|
||||||
innerProjectIds.value = [val];
|
innerProjectIds.value = [val];
|
||||||
initCaseCount();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
:search-keys="['name']"
|
:search-keys="['name']"
|
||||||
class="!w-[240px]"
|
class="!w-[240px]"
|
||||||
:prefix="t('workbench.homePage.project')"
|
:prefix="t('workbench.homePage.project')"
|
||||||
|
@change="changeProject"
|
||||||
>
|
>
|
||||||
</MsSelect>
|
</MsSelect>
|
||||||
</div>
|
</div>
|
||||||
|
@ -24,6 +25,7 @@
|
||||||
tooltip-text="workbench.homePage.caseReviewCoverRateTooltip"
|
tooltip-text="workbench.homePage.caseReviewCoverRateTooltip"
|
||||||
:size="60"
|
:size="60"
|
||||||
:value-list="coverValueList"
|
:value-list="coverValueList"
|
||||||
|
:has-permission="hasPermission"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -39,18 +41,18 @@
|
||||||
* @desc 用例评审数量
|
* @desc 用例评审数量
|
||||||
*/
|
*/
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { cloneDeep } from 'lodash-es';
|
|
||||||
|
|
||||||
import MsChart from '@/components/pure/chart/index.vue';
|
import MsChart from '@/components/pure/chart/index.vue';
|
||||||
import MsSelect from '@/components/business/ms-select';
|
import MsSelect from '@/components/business/ms-select';
|
||||||
import PassRatePie from './passRatePie.vue';
|
import PassRatePie from './passRatePie.vue';
|
||||||
|
|
||||||
|
import { workCaseReviewDetail } from '@/api/modules/workbench';
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
import useAppStore from '@/store/modules/app';
|
import useAppStore from '@/store/modules/app';
|
||||||
|
|
||||||
import type { PassRateDataType, SelectedCardItem, TimeFormParams } from '@/models/workbench/homePage';
|
import type { PassRateDataType, SelectedCardItem, TimeFormParams } from '@/models/workbench/homePage';
|
||||||
|
|
||||||
import { commonRatePieOptions, handlePieData } from '../utils';
|
import { handlePieData, handleUpdateTabPie } from '../utils';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
|
@ -74,54 +76,58 @@
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
const options = ref<Record<string, any>>(cloneDeep(commonRatePieOptions));
|
const options = ref<Record<string, any>>({});
|
||||||
|
|
||||||
const coverValueList = ref([
|
const coverValueList = ref<{ value: number | string; label: string; name: string }[]>([
|
||||||
{
|
{
|
||||||
label: t('workbench.homePage.covered'),
|
label: t('workbench.homePage.covered'),
|
||||||
value: 10000,
|
value: '-',
|
||||||
|
name: '',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: t('workbench.homePage.notCover'),
|
label: t('workbench.homePage.notCover'),
|
||||||
value: 2000,
|
value: '-',
|
||||||
|
name: '',
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// TODO 假数据
|
|
||||||
const detail = ref<PassRateDataType>({
|
|
||||||
statusStatisticsMap: {
|
|
||||||
cover: [
|
|
||||||
{ name: '覆盖率', count: 10 },
|
|
||||||
{ name: '已覆盖', count: 2 },
|
|
||||||
{ name: '未覆盖', count: 1 },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
statusPercentList: [
|
|
||||||
{ status: '未开始', count: 1, percentValue: '10%' },
|
|
||||||
{ status: '进行中', count: 3, percentValue: '0%' },
|
|
||||||
{ status: '已完成', count: 6, percentValue: '0%' },
|
|
||||||
{ status: '已归档', count: 7, percentValue: '0%' },
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
const caseReviewCountOptions = ref<Record<string, any>>({});
|
const caseReviewCountOptions = ref<Record<string, any>>({});
|
||||||
function initApiCount() {
|
|
||||||
const { statusStatisticsMap, statusPercentList } = detail.value;
|
|
||||||
caseReviewCountOptions.value = handlePieData(props.item.key, statusPercentList);
|
|
||||||
const { cover } = statusStatisticsMap;
|
|
||||||
|
|
||||||
coverValueList.value = cover.slice(1).map((item) => {
|
const hasPermission = ref<boolean>(false);
|
||||||
return {
|
async function initApiCount() {
|
||||||
value: item.count,
|
const { startTime, endTime, dayNumber } = timeForm.value;
|
||||||
label: item.name,
|
const params = {
|
||||||
name: item.name,
|
current: 1,
|
||||||
};
|
pageSize: 5,
|
||||||
});
|
startTime: dayNumber ? null : startTime,
|
||||||
|
endTime: dayNumber ? null : endTime,
|
||||||
|
dayNumber: dayNumber ?? null,
|
||||||
|
projectIds: innerProjectIds.value,
|
||||||
|
organizationId: appStore.currentOrgId,
|
||||||
|
handleUsers: [],
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
const detail: PassRateDataType = await workCaseReviewDetail(params);
|
||||||
|
|
||||||
options.value.series.data = coverValueList.value;
|
hasPermission.value = detail.errorCode !== 109001;
|
||||||
options.value.title.text = cover[0].name ?? '';
|
|
||||||
options.value.title.subtext = `${cover[0].count ?? 0}%`;
|
const { statusStatisticsMap, statusPercentList } = detail;
|
||||||
options.value.series.color = ['#00C261', '#D4D4D8'];
|
caseReviewCountOptions.value = handlePieData(props.item.key, hasPermission.value, statusPercentList);
|
||||||
|
const { options: coverOptions, valueList } = handleUpdateTabPie(
|
||||||
|
statusStatisticsMap?.cover || [],
|
||||||
|
hasPermission.value,
|
||||||
|
`${props.item.key}-cover`
|
||||||
|
);
|
||||||
|
coverValueList.value = valueList;
|
||||||
|
options.value = coverOptions;
|
||||||
|
} catch (error) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeProject() {
|
||||||
|
initApiCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
@ -134,7 +140,6 @@
|
||||||
if (val) {
|
if (val) {
|
||||||
const [newProjectId] = val;
|
const [newProjectId] = val;
|
||||||
projectId.value = newProjectId;
|
projectId.value = newProjectId;
|
||||||
initApiCount();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -144,7 +149,6 @@
|
||||||
(val) => {
|
(val) => {
|
||||||
if (val) {
|
if (val) {
|
||||||
innerProjectIds.value = [val];
|
innerProjectIds.value = [val];
|
||||||
initApiCount();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
:search-keys="['name']"
|
:search-keys="['name']"
|
||||||
class="!w-[240px]"
|
class="!w-[240px]"
|
||||||
:prefix="t('workbench.homePage.project')"
|
:prefix="t('workbench.homePage.project')"
|
||||||
|
@change="changeProject"
|
||||||
>
|
>
|
||||||
</MsSelect>
|
</MsSelect>
|
||||||
</div>
|
</div>
|
||||||
|
@ -19,7 +20,13 @@
|
||||||
<div class="mt-[16px]">
|
<div class="mt-[16px]">
|
||||||
<div class="case-count-wrapper">
|
<div class="case-count-wrapper">
|
||||||
<div class="case-count-item mb-[16px]">
|
<div class="case-count-item mb-[16px]">
|
||||||
<PassRatePie :tooltip-text="tooltip" :options="legacyOptions" :size="60" :value-list="valueList" />
|
<PassRatePie
|
||||||
|
:has-permission="hasPermission"
|
||||||
|
:tooltip-text="tooltip"
|
||||||
|
:options="legacyOptions"
|
||||||
|
:size="60"
|
||||||
|
:value-list="legacyValueList"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="h-[148px]">
|
<div class="h-[148px]">
|
||||||
|
@ -34,7 +41,6 @@
|
||||||
* @desc 用于缺陷数量,待我处理的缺陷数量组件
|
* @desc 用于缺陷数量,待我处理的缺陷数量组件
|
||||||
*/
|
*/
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { cloneDeep } from 'lodash-es';
|
|
||||||
|
|
||||||
import MsChart from '@/components/pure/chart/index.vue';
|
import MsChart from '@/components/pure/chart/index.vue';
|
||||||
import MsSelect from '@/components/business/ms-select';
|
import MsSelect from '@/components/business/ms-select';
|
||||||
|
@ -43,15 +49,10 @@
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
import useAppStore from '@/store/modules/app';
|
import useAppStore from '@/store/modules/app';
|
||||||
|
|
||||||
import type {
|
import type { PassRateDataType, SelectedCardItem, TimeFormParams } from '@/models/workbench/homePage';
|
||||||
PassRateDataType,
|
|
||||||
SelectedCardItem,
|
|
||||||
StatusStatisticsMapType,
|
|
||||||
TimeFormParams,
|
|
||||||
} from '@/models/workbench/homePage';
|
|
||||||
import { WorkCardEnum } from '@/enums/workbenchEnum';
|
import { WorkCardEnum } from '@/enums/workbenchEnum';
|
||||||
|
|
||||||
import { commonRatePieOptions, handlePieData } from '../utils';
|
import { handlePieData, handleUpdateTabPie } from '../utils';
|
||||||
|
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
|
|
||||||
|
@ -67,21 +68,7 @@
|
||||||
|
|
||||||
const projectId = ref<string>(innerProjectIds.value[0]);
|
const projectId = ref<string>(innerProjectIds.value[0]);
|
||||||
|
|
||||||
const valueList = ref<
|
const legacyValueList = ref<{ value: number | string; label: string; name: string }[]>([]);
|
||||||
{
|
|
||||||
label: string;
|
|
||||||
value: number;
|
|
||||||
}[]
|
|
||||||
>([
|
|
||||||
{
|
|
||||||
label: t('workbench.homePage.defectTotal'),
|
|
||||||
value: 10000,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: t('workbench.homePage.legacyDefectsNumber'),
|
|
||||||
value: 2000,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
const timeForm = inject<Ref<TimeFormParams>>(
|
const timeForm = inject<Ref<TimeFormParams>>(
|
||||||
'timeForm',
|
'timeForm',
|
||||||
|
@ -92,7 +79,7 @@
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
const legacyOptions = ref<Record<string, any>>(cloneDeep(commonRatePieOptions));
|
const legacyOptions = ref<Record<string, any>>({});
|
||||||
|
|
||||||
// TODO 假数据
|
// TODO 假数据
|
||||||
const detail = ref<PassRateDataType>({
|
const detail = ref<PassRateDataType>({
|
||||||
|
@ -108,26 +95,12 @@
|
||||||
{ status: 'BBB', count: 3, percentValue: '0%' },
|
{ status: 'BBB', count: 3, percentValue: '0%' },
|
||||||
{ status: 'CCC', count: 6, percentValue: '0%' },
|
{ status: 'CCC', count: 6, percentValue: '0%' },
|
||||||
],
|
],
|
||||||
|
errorCode: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
const countOptions = ref({});
|
const countOptions = ref<Record<string, any>>({});
|
||||||
|
|
||||||
function handleRatePieData(statusStatisticsMap: StatusStatisticsMapType) {
|
|
||||||
const { legacy } = statusStatisticsMap;
|
|
||||||
valueList.value = legacy.slice(1).map((item) => {
|
|
||||||
return {
|
|
||||||
value: item.count,
|
|
||||||
label: item.name,
|
|
||||||
name: item.name,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
legacyOptions.value.series.data = valueList.value;
|
|
||||||
|
|
||||||
legacyOptions.value.title.text = legacy[0].name ?? '';
|
|
||||||
legacyOptions.value.title.subtext = `${legacy[0].count ?? 0}%`;
|
|
||||||
legacyOptions.value.series.color = ['#D4D4D8', '#00C261'];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
const hasPermission = ref<boolean>(false);
|
||||||
async function initCount() {
|
async function initCount() {
|
||||||
try {
|
try {
|
||||||
const { startTime, endTime, dayNumber } = timeForm.value;
|
const { startTime, endTime, dayNumber } = timeForm.value;
|
||||||
|
@ -141,9 +114,18 @@
|
||||||
organizationId: appStore.currentOrgId,
|
organizationId: appStore.currentOrgId,
|
||||||
handleUsers: [],
|
handleUsers: [],
|
||||||
};
|
};
|
||||||
const { statusStatisticsMap, statusPercentList } = detail.value;
|
const { statusStatisticsMap, statusPercentList, errorCode } = detail.value;
|
||||||
countOptions.value = handlePieData(props.item.key, statusPercentList);
|
hasPermission.value = errorCode !== 109001;
|
||||||
handleRatePieData(statusStatisticsMap);
|
|
||||||
|
countOptions.value = handlePieData(props.item.key, hasPermission.value, statusPercentList);
|
||||||
|
|
||||||
|
const { options, valueList } = handleUpdateTabPie(
|
||||||
|
statusStatisticsMap?.legacy || [],
|
||||||
|
hasPermission.value,
|
||||||
|
`${props.item.key}-legacy`
|
||||||
|
);
|
||||||
|
legacyValueList.value = valueList;
|
||||||
|
legacyOptions.value = options;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.log(error);
|
console.log(error);
|
||||||
|
@ -154,6 +136,10 @@
|
||||||
return props.item.key === WorkCardEnum.PLAN_LEGACY_BUG ? 'workbench.homePage.planCaseCountLegacyRateTooltip' : '';
|
return props.item.key === WorkCardEnum.PLAN_LEGACY_BUG ? 'workbench.homePage.planCaseCountLegacyRateTooltip' : '';
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function changeProject() {
|
||||||
|
initCount();
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
initCount();
|
initCount();
|
||||||
});
|
});
|
||||||
|
@ -164,7 +150,6 @@
|
||||||
if (val) {
|
if (val) {
|
||||||
const [newProjectId] = val;
|
const [newProjectId] = val;
|
||||||
projectId.value = newProjectId;
|
projectId.value = newProjectId;
|
||||||
initCount();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -174,7 +159,6 @@
|
||||||
(val) => {
|
(val) => {
|
||||||
if (val) {
|
if (val) {
|
||||||
innerProjectIds.value = [val];
|
innerProjectIds.value = [val];
|
||||||
initCount();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -6,13 +6,13 @@
|
||||||
<MsSelect
|
<MsSelect
|
||||||
v-model:model-value="projectId"
|
v-model:model-value="projectId"
|
||||||
:options="appStore.projectList"
|
:options="appStore.projectList"
|
||||||
allow-clear
|
|
||||||
allow-search
|
allow-search
|
||||||
value-key="id"
|
value-key="id"
|
||||||
label-key="name"
|
label-key="name"
|
||||||
:search-keys="['name']"
|
:search-keys="['name']"
|
||||||
class="!w-[240px]"
|
class="!w-[240px]"
|
||||||
:prefix="t('workbench.homePage.project')"
|
:prefix="t('workbench.homePage.project')"
|
||||||
|
@change="changeProject"
|
||||||
>
|
>
|
||||||
</MsSelect>
|
</MsSelect>
|
||||||
<MsSelect
|
<MsSelect
|
||||||
|
@ -25,6 +25,7 @@
|
||||||
:multiple="true"
|
:multiple="true"
|
||||||
:has-all-select="true"
|
:has-all-select="true"
|
||||||
:default-all-select="true"
|
:default-all-select="true"
|
||||||
|
@change="changeMember"
|
||||||
>
|
>
|
||||||
</MsSelect>
|
</MsSelect>
|
||||||
</div>
|
</div>
|
||||||
|
@ -44,12 +45,15 @@
|
||||||
import MsChart from '@/components/pure/chart/index.vue';
|
import MsChart from '@/components/pure/chart/index.vue';
|
||||||
import MsSelect from '@/components/business/ms-select';
|
import MsSelect from '@/components/business/ms-select';
|
||||||
|
|
||||||
|
import { getProjectOptions } from '@/api/modules/project-management/projectMember';
|
||||||
|
import { workBugHandlerDetail } from '@/api/modules/workbench';
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
import useAppStore from '@/store/modules/app';
|
import useAppStore from '@/store/modules/app';
|
||||||
|
import { characterLimit } from '@/utils';
|
||||||
|
|
||||||
import type { SelectedCardItem, TimeFormParams } from '@/models/workbench/homePage';
|
import type { OverViewOfProject, SelectedCardItem, TimeFormParams } from '@/models/workbench/homePage';
|
||||||
|
|
||||||
import { commonColorConfig, getCommonBarOptions } from '../utils';
|
import { commonColorConfig, getCommonBarOptions, handleNoDataDisplay } from '../utils';
|
||||||
import type { SelectOptionData } from '@arco-design/web-vue';
|
import type { SelectOptionData } from '@arco-design/web-vue';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
@ -58,19 +62,18 @@
|
||||||
item: SelectedCardItem;
|
item: SelectedCardItem;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const memberIds = ref('');
|
|
||||||
const innerProjectIds = defineModel<string[]>('projectIds', {
|
const innerProjectIds = defineModel<string[]>('projectIds', {
|
||||||
required: true,
|
required: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
const projectId = computed<string>({
|
const projectId = ref<string>(innerProjectIds.value[0]);
|
||||||
get: () => {
|
|
||||||
const [newProject] = innerProjectIds.value;
|
const innerHandleUsers = defineModel<string[]>('handleUsers', {
|
||||||
return newProject;
|
required: true,
|
||||||
},
|
|
||||||
set: (val) => val,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const memberIds = ref<string[]>(innerHandleUsers.value);
|
||||||
|
|
||||||
const timeForm = inject<Ref<TimeFormParams>>(
|
const timeForm = inject<Ref<TimeFormParams>>(
|
||||||
'timeForm',
|
'timeForm',
|
||||||
ref({
|
ref({
|
||||||
|
@ -83,128 +86,91 @@
|
||||||
const memberOptions = ref<SelectOptionData[]>([]);
|
const memberOptions = ref<SelectOptionData[]>([]);
|
||||||
|
|
||||||
const options = ref<Record<string, any>>({});
|
const options = ref<Record<string, any>>({});
|
||||||
const members = computed(() => ['张三', '李四', '王五', '小王']);
|
|
||||||
const hasRoom = computed(() => members.value.length >= 7);
|
|
||||||
const seriesData = ref<Record<string, any>[]>([
|
|
||||||
{
|
|
||||||
name: '新创建',
|
|
||||||
type: 'bar',
|
|
||||||
barWidth: 12,
|
|
||||||
stack: 'bug',
|
|
||||||
itemStyle: {
|
|
||||||
// borderRadius: [2, 2, 0, 0],
|
|
||||||
},
|
|
||||||
data: [400, 200, 400, 200, 400, 200],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '激活',
|
|
||||||
type: 'bar',
|
|
||||||
barWidth: 12,
|
|
||||||
stack: 'bug',
|
|
||||||
itemStyle: {
|
|
||||||
// borderRadius: [2, 2, 0, 0],
|
|
||||||
},
|
|
||||||
data: [90, 160, 90, 160, 90, 160],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '处理中',
|
|
||||||
type: 'bar',
|
|
||||||
barWidth: 12,
|
|
||||||
stack: 'bug',
|
|
||||||
itemStyle: {
|
|
||||||
// borderRadius: [2, 2, 0, 0],
|
|
||||||
},
|
|
||||||
data: [90, 160, 90, 160, 90, 160],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '已关闭',
|
|
||||||
type: 'bar',
|
|
||||||
barWidth: 12,
|
|
||||||
stack: 'bug',
|
|
||||||
itemStyle: {
|
|
||||||
// borderRadius: [2, 2, 0, 0],
|
|
||||||
},
|
|
||||||
data: [90, 160, 90, 160, 90, 160],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '新创建1',
|
|
||||||
type: 'bar',
|
|
||||||
barWidth: 12,
|
|
||||||
stack: 'bug',
|
|
||||||
itemStyle: {
|
|
||||||
// borderRadius: [2, 2, 0, 0],
|
|
||||||
},
|
|
||||||
data: [400, 200, 400, 200, 400, 200],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '激活1',
|
|
||||||
type: 'bar',
|
|
||||||
barWidth: 12,
|
|
||||||
stack: 'bug',
|
|
||||||
itemStyle: {
|
|
||||||
// borderRadius: [2, 2, 0, 0],
|
|
||||||
},
|
|
||||||
data: [90, 160, 90, 160, 90, 160],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '处理中1',
|
|
||||||
type: 'bar',
|
|
||||||
barWidth: 12,
|
|
||||||
stack: 'bug',
|
|
||||||
itemStyle: {
|
|
||||||
// borderRadius: [2, 2, 0, 0],
|
|
||||||
},
|
|
||||||
data: [90, 160, 90, 160, 90, 160],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '已关闭1',
|
|
||||||
type: 'bar',
|
|
||||||
barWidth: 12,
|
|
||||||
stack: 'bug',
|
|
||||||
itemStyle: {
|
|
||||||
// borderRadius: [2, 2, 0, 0],
|
|
||||||
},
|
|
||||||
data: [90, 160, 90, 160, 90, 160],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '已关闭2',
|
|
||||||
type: 'bar',
|
|
||||||
barWidth: 12,
|
|
||||||
stack: 'bug',
|
|
||||||
itemStyle: {
|
|
||||||
// borderRadius: [2, 2, 0, 0],
|
|
||||||
},
|
|
||||||
data: [90, 160, 90, 160, 90, 160],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '已关闭3',
|
|
||||||
type: 'bar',
|
|
||||||
barWidth: 12,
|
|
||||||
stack: 'bug',
|
|
||||||
itemStyle: {
|
|
||||||
borderRadius: [2, 2, 0, 0],
|
|
||||||
},
|
|
||||||
data: [90, 160, 90, 160, 90, 160],
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
const defectStatusColor = ['#811FA3', '#FFA200', '#3370FF', '#F24F4F'];
|
const defectStatusColor = ['#811FA3', '#FFA200', '#3370FF', '#F24F4F'];
|
||||||
|
|
||||||
function getDefectMemberDetail() {
|
function handleData(detail: OverViewOfProject) {
|
||||||
options.value = getCommonBarOptions(hasRoom.value, [...defectStatusColor, ...commonColorConfig]);
|
options.value = getCommonBarOptions(detail.xaxis.length >= 7, [...defectStatusColor, ...commonColorConfig]);
|
||||||
options.value.xAxis.data = members.value;
|
const { invisible, text } = handleNoDataDisplay(detail.xaxis, detail.projectCountList);
|
||||||
options.value.series = seriesData.value;
|
options.value.graphic.invisible = invisible;
|
||||||
|
options.value.graphic.style.text = text;
|
||||||
|
options.value.xAxis.data = detail.xaxis.map((e) => characterLimit(e, 10));
|
||||||
|
options.value.series = detail.projectCountList.map((item) => {
|
||||||
|
return {
|
||||||
|
name: item.name,
|
||||||
|
type: 'bar',
|
||||||
|
stack: 'bugMember',
|
||||||
|
barWidth: 12,
|
||||||
|
data: item.count,
|
||||||
|
itemStyle: {
|
||||||
|
borderRadius: [2, 2, 0, 0],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
async function getDefectMemberDetail() {
|
||||||
|
try {
|
||||||
|
const { startTime, endTime, dayNumber } = timeForm.value;
|
||||||
|
const detail = await workBugHandlerDetail({
|
||||||
|
current: 1,
|
||||||
|
pageSize: 5,
|
||||||
|
startTime: dayNumber ? null : startTime,
|
||||||
|
endTime: dayNumber ? null : endTime,
|
||||||
|
dayNumber: dayNumber ?? null,
|
||||||
|
projectIds: innerProjectIds.value,
|
||||||
|
organizationId: appStore.currentOrgId,
|
||||||
|
handleUsers: innerHandleUsers.value,
|
||||||
|
});
|
||||||
|
handleData(detail);
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getMemberOptions() {
|
||||||
|
const [newProjectId] = innerProjectIds.value;
|
||||||
|
const res = await getProjectOptions(newProjectId);
|
||||||
|
memberOptions.value = res.map((e: any) => ({
|
||||||
|
label: e.name,
|
||||||
|
value: e.id,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeProject() {
|
||||||
|
memberIds.value = [];
|
||||||
|
getMemberOptions();
|
||||||
getDefectMemberDetail();
|
getDefectMemberDetail();
|
||||||
});
|
}
|
||||||
|
|
||||||
|
function changeMember() {
|
||||||
|
getDefectMemberDetail();
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => innerProjectIds.value,
|
||||||
|
(val) => {
|
||||||
|
if (val) {
|
||||||
|
const [newProjectId] = val;
|
||||||
|
projectId.value = newProjectId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => projectId.value,
|
() => projectId.value,
|
||||||
(val) => {
|
(val) => {
|
||||||
if (val) {
|
if (val) {
|
||||||
innerProjectIds.value = [val];
|
innerProjectIds.value = [val];
|
||||||
getDefectMemberDetail();
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => memberIds.value,
|
||||||
|
(val) => {
|
||||||
|
if (val) {
|
||||||
|
innerHandleUsers.value = val;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -220,6 +186,11 @@
|
||||||
deep: true,
|
deep: true,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getMemberOptions();
|
||||||
|
getDefectMemberDetail();
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped></style>
|
<style scoped></style>
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
import TabCard from './tabCard.vue';
|
import TabCard from './tabCard.vue';
|
||||||
|
|
||||||
import { workMyCreatedDetail, workProOverviewDetail } from '@/api/modules/workbench';
|
import { workMyCreatedDetail, workProOverviewDetail } from '@/api/modules/workbench';
|
||||||
|
import { contentTabList } from '@/config/workbench';
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
import useAppStore from '@/store/modules/app';
|
import useAppStore from '@/store/modules/app';
|
||||||
|
|
||||||
|
@ -53,7 +54,7 @@
|
||||||
} from '@/models/workbench/homePage';
|
} from '@/models/workbench/homePage';
|
||||||
import { WorkCardEnum, WorkOverviewEnum } from '@/enums/workbenchEnum';
|
import { WorkCardEnum, WorkOverviewEnum } from '@/enums/workbenchEnum';
|
||||||
|
|
||||||
import { commonColorConfig, contentTabList, getCommonBarOptions, handleNoDataDisplay } from '../utils';
|
import { commonColorConfig, getCommonBarOptions, handleNoDataDisplay } from '../utils';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
@ -92,9 +93,10 @@
|
||||||
function handleData(detail: OverViewOfProject) {
|
function handleData(detail: OverViewOfProject) {
|
||||||
// 处理模块顺序
|
// 处理模块顺序
|
||||||
const tempAxisData = detail.xaxis.map((xAxisKey) => {
|
const tempAxisData = detail.xaxis.map((xAxisKey) => {
|
||||||
const data = contentTabList.value.find((e) => e.value === xAxisKey);
|
const data = contentTabList.find((e) => e.value === xAxisKey);
|
||||||
return {
|
return {
|
||||||
...data,
|
...data,
|
||||||
|
label: t(data?.label || ''),
|
||||||
count: detail.caseCountMap[xAxisKey as WorkOverviewEnum],
|
count: detail.caseCountMap[xAxisKey as WorkOverviewEnum],
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
:search-keys="['name']"
|
:search-keys="['name']"
|
||||||
class="!w-[240px]"
|
class="!w-[240px]"
|
||||||
:prefix="t('workbench.homePage.project')"
|
:prefix="t('workbench.homePage.project')"
|
||||||
|
@change="changeProject"
|
||||||
>
|
>
|
||||||
</MsSelect>
|
</MsSelect>
|
||||||
<MsSelect
|
<MsSelect
|
||||||
|
@ -48,13 +49,14 @@
|
||||||
|
|
||||||
import { getProjectOptions } from '@/api/modules/project-management/projectMember';
|
import { getProjectOptions } from '@/api/modules/project-management/projectMember';
|
||||||
import { workMemberViewDetail } from '@/api/modules/workbench';
|
import { workMemberViewDetail } from '@/api/modules/workbench';
|
||||||
|
import { contentTabList } from '@/config/workbench';
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
import useAppStore from '@/store/modules/app';
|
import useAppStore from '@/store/modules/app';
|
||||||
import { characterLimit } from '@/utils';
|
import { characterLimit } from '@/utils';
|
||||||
|
|
||||||
import type { OverViewOfProject, SelectedCardItem, TimeFormParams } from '@/models/workbench/homePage';
|
import type { OverViewOfProject, SelectedCardItem, TimeFormParams } from '@/models/workbench/homePage';
|
||||||
|
|
||||||
import { commonColorConfig, contentTabList, getCommonBarOptions, handleNoDataDisplay } from '../utils';
|
import { commonColorConfig, getCommonBarOptions, handleNoDataDisplay } from '../utils';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
|
@ -82,19 +84,18 @@
|
||||||
endTime: 0,
|
endTime: 0,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
const hasRoom = computed(() => memberIds.value.length >= 7);
|
|
||||||
const memberOptions = ref<{ label: string; value: string }[]>([]);
|
|
||||||
|
|
||||||
|
const memberOptions = ref<{ label: string; value: string }[]>([]);
|
||||||
const options = ref<Record<string, any>>({});
|
const options = ref<Record<string, any>>({});
|
||||||
function handleData(detail: OverViewOfProject) {
|
function handleData(detail: OverViewOfProject) {
|
||||||
options.value = getCommonBarOptions(hasRoom.value, commonColorConfig);
|
options.value = getCommonBarOptions(detail.xaxis.length >= 7, commonColorConfig);
|
||||||
const { invisible, text } = handleNoDataDisplay(detail.xaxis, detail.projectCountList);
|
const { invisible, text } = handleNoDataDisplay(detail.xaxis, detail.projectCountList);
|
||||||
options.value.graphic.invisible = invisible;
|
options.value.graphic.invisible = invisible;
|
||||||
options.value.graphic.style.text = text;
|
options.value.graphic.style.text = text;
|
||||||
options.value.xAxis.data = detail.xaxis.map((e) => characterLimit(e, 10));
|
options.value.xAxis.data = detail.xaxis.map((e) => characterLimit(e, 10));
|
||||||
options.value.series = detail.projectCountList.map((item, index) => {
|
options.value.series = detail.projectCountList.map((item, index) => {
|
||||||
return {
|
return {
|
||||||
name: contentTabList.value[index].label,
|
name: t(contentTabList[index].label),
|
||||||
type: 'bar',
|
type: 'bar',
|
||||||
stack: 'member',
|
stack: 'member',
|
||||||
barWidth: 12,
|
barWidth: 12,
|
||||||
|
@ -122,6 +123,7 @@
|
||||||
const detail = await workMemberViewDetail(params);
|
const detail = await workMemberViewDetail(params);
|
||||||
handleData(detail);
|
handleData(detail);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
console.log(error);
|
console.log(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -135,6 +137,11 @@
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function changeProject() {
|
||||||
|
getMemberOptions();
|
||||||
|
initOverViewMemberDetail();
|
||||||
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => innerProjectIds.value,
|
() => innerProjectIds.value,
|
||||||
(val) => {
|
(val) => {
|
||||||
|
@ -142,8 +149,6 @@
|
||||||
const [newProjectId] = val;
|
const [newProjectId] = val;
|
||||||
projectId.value = newProjectId;
|
projectId.value = newProjectId;
|
||||||
memberIds.value = [];
|
memberIds.value = [];
|
||||||
getMemberOptions();
|
|
||||||
initOverViewMemberDetail();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -181,6 +186,7 @@
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getMemberOptions();
|
getMemberOptions();
|
||||||
|
initOverViewMemberDetail();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
<div class="pass-rate-title flex-1">
|
<div class="pass-rate-title flex-1">
|
||||||
<div v-for="item of props.valueList" :key="item.label" class="flex-1">
|
<div v-for="item of props.valueList" :key="item.label" class="flex-1">
|
||||||
<div class="mb-[8px] text-[var(--color-text-4)]">{{ item.label }}</div>
|
<div class="mb-[8px] text-[var(--color-text-4)]">{{ item.label }}</div>
|
||||||
<div class="pass-rate-count">{{ addCommasToNumber(item.value) }}</div>
|
<div class="pass-rate-count">{{ hasPermission ? addCommasToNumber(item.value as number) : '-' }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -34,9 +34,10 @@
|
||||||
options: Record<string, any>;
|
options: Record<string, any>;
|
||||||
size: number;
|
size: number;
|
||||||
tooltipText?: string;
|
tooltipText?: string;
|
||||||
|
hasPermission: boolean;
|
||||||
valueList: {
|
valueList: {
|
||||||
label: string;
|
label: string;
|
||||||
value: number;
|
value: number | string;
|
||||||
}[];
|
}[];
|
||||||
}>();
|
}>();
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -83,7 +83,7 @@
|
||||||
name: '',
|
name: '',
|
||||||
type: 'pie',
|
type: 'pie',
|
||||||
padAngle: 1,
|
padAngle: 1,
|
||||||
radius: ['46%', '56%'],
|
radius: ['50%', '58%'],
|
||||||
center: ['50%', '32%'],
|
center: ['50%', '32%'],
|
||||||
color: [],
|
color: [],
|
||||||
avoidLabelOverlap: false,
|
avoidLabelOverlap: false,
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
:search-keys="['name']"
|
:search-keys="['name']"
|
||||||
class="!w-[240px]"
|
class="!w-[240px]"
|
||||||
:prefix="t('workbench.homePage.project')"
|
:prefix="t('workbench.homePage.project')"
|
||||||
|
@change="changeProject"
|
||||||
>
|
>
|
||||||
</MsSelect>
|
</MsSelect>
|
||||||
</div>
|
</div>
|
||||||
|
@ -19,7 +20,8 @@
|
||||||
<div class="case-count-wrapper">
|
<div class="case-count-wrapper">
|
||||||
<div class="case-count-item">
|
<div class="case-count-item">
|
||||||
<PassRatePie
|
<PassRatePie
|
||||||
:options="options"
|
:options="relatedOptions"
|
||||||
|
:has-permission="hasPermission"
|
||||||
tooltip-text="workbench.homePage.associateCaseCoverRateTooltip"
|
tooltip-text="workbench.homePage.associateCaseCoverRateTooltip"
|
||||||
:size="60"
|
:size="60"
|
||||||
:value-list="coverRateValueList"
|
:value-list="coverRateValueList"
|
||||||
|
@ -35,7 +37,6 @@
|
||||||
* @desc 关联用例数量
|
* @desc 关联用例数量
|
||||||
*/
|
*/
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { cloneDeep } from 'lodash-es';
|
|
||||||
|
|
||||||
import MsSelect from '@/components/business/ms-select';
|
import MsSelect from '@/components/business/ms-select';
|
||||||
import PassRatePie from './passRatePie.vue';
|
import PassRatePie from './passRatePie.vue';
|
||||||
|
@ -44,9 +45,9 @@
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
import useAppStore from '@/store/modules/app';
|
import useAppStore from '@/store/modules/app';
|
||||||
|
|
||||||
import type { SelectedCardItem, TimeFormParams } from '@/models/workbench/homePage';
|
import type { PassRateDataType, SelectedCardItem, TimeFormParams } from '@/models/workbench/homePage';
|
||||||
|
|
||||||
import { commonRatePieOptions } from '../utils';
|
import { handleUpdateTabPie } from '../utils';
|
||||||
|
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
|
|
||||||
|
@ -71,14 +72,26 @@
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
const options = ref<Record<string, any>>(cloneDeep(commonRatePieOptions));
|
const relatedOptions = ref<Record<string, any>>({});
|
||||||
|
const hasPermission = ref<boolean>(false);
|
||||||
|
|
||||||
const coverRateValueList = ref<{ value: number; label: string; name: string }[]>([]);
|
const coverRateValueList = ref<{ value: number | string; label: string; name: string }[]>([
|
||||||
|
{
|
||||||
|
label: t('workbench.homePage.covered'),
|
||||||
|
value: '-',
|
||||||
|
name: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('workbench.homePage.notCover'),
|
||||||
|
value: '-',
|
||||||
|
name: '',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
async function getRelatedCaseCount() {
|
async function getRelatedCaseCount() {
|
||||||
try {
|
try {
|
||||||
const { startTime, endTime, dayNumber } = timeForm.value;
|
const { startTime, endTime, dayNumber } = timeForm.value;
|
||||||
const detail = await workAssociateCaseDetail({
|
const detail: PassRateDataType = await workAssociateCaseDetail({
|
||||||
current: 1,
|
current: 1,
|
||||||
pageSize: 5,
|
pageSize: 5,
|
||||||
startTime: dayNumber ? null : startTime,
|
startTime: dayNumber ? null : startTime,
|
||||||
|
@ -88,24 +101,28 @@
|
||||||
organizationId: appStore.currentOrgId,
|
organizationId: appStore.currentOrgId,
|
||||||
handleUsers: [],
|
handleUsers: [],
|
||||||
});
|
});
|
||||||
const { cover } = detail.statusStatisticsMap;
|
|
||||||
coverRateValueList.value = cover.slice(1).map((item) => {
|
hasPermission.value = detail.errorCode !== 109001;
|
||||||
return {
|
|
||||||
value: item.count,
|
const { statusStatisticsMap } = detail;
|
||||||
label: item.name,
|
|
||||||
name: item.name,
|
const { options, valueList } = handleUpdateTabPie(
|
||||||
};
|
statusStatisticsMap?.cover || [],
|
||||||
});
|
hasPermission.value,
|
||||||
options.value.series.data = coverRateValueList.value;
|
`${props.item.key}-cover`
|
||||||
options.value.title.text = cover[0].name ?? '';
|
);
|
||||||
options.value.title.subtext = `${cover[0].count ?? 0}%`;
|
relatedOptions.value = options;
|
||||||
options.value.series.color = ['#00C261', '#D4D4D8'];
|
coverRateValueList.value = valueList;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.log(error);
|
console.log(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function changeProject() {
|
||||||
|
getRelatedCaseCount();
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getRelatedCaseCount();
|
getRelatedCaseCount();
|
||||||
});
|
});
|
||||||
|
@ -125,7 +142,6 @@
|
||||||
(val) => {
|
(val) => {
|
||||||
if (val) {
|
if (val) {
|
||||||
innerProjectIds.value = [val];
|
innerProjectIds.value = [val];
|
||||||
getRelatedCaseCount();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
contentTabList: {
|
contentTabList: {
|
||||||
label: string | number;
|
label: string;
|
||||||
value: string | number;
|
value: string | number;
|
||||||
count?: number;
|
count?: number;
|
||||||
icon?: string;
|
icon?: string;
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
:search-keys="['name']"
|
:search-keys="['name']"
|
||||||
class="!w-[240px]"
|
class="!w-[240px]"
|
||||||
:prefix="t('workbench.homePage.project')"
|
:prefix="t('workbench.homePage.project')"
|
||||||
|
@change="changeProject"
|
||||||
>
|
>
|
||||||
</MsSelect>
|
</MsSelect>
|
||||||
</div>
|
</div>
|
||||||
|
@ -22,7 +23,12 @@
|
||||||
<TabCard :content-tab-list="testPlanTabList" not-has-padding hidden-border min-width="270px">
|
<TabCard :content-tab-list="testPlanTabList" not-has-padding hidden-border min-width="270px">
|
||||||
<template #item="{ item: tabItem }">
|
<template #item="{ item: tabItem }">
|
||||||
<div class="w-full">
|
<div class="w-full">
|
||||||
<PassRatePie :options="tabItem.options" :size="60" :value-list="tabItem.valueList" />
|
<PassRatePie
|
||||||
|
:has-permission="hasPermission"
|
||||||
|
:options="tabItem.options"
|
||||||
|
:size="60"
|
||||||
|
:value-list="tabItem.valueList"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</TabCard>
|
</TabCard>
|
||||||
|
@ -38,7 +44,6 @@
|
||||||
* @desc 测试计划数量
|
* @desc 测试计划数量
|
||||||
*/
|
*/
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { cloneDeep } from 'lodash-es';
|
|
||||||
|
|
||||||
import MsChart from '@/components/pure/chart/index.vue';
|
import MsChart from '@/components/pure/chart/index.vue';
|
||||||
import MsSelect from '@/components/business/ms-select';
|
import MsSelect from '@/components/business/ms-select';
|
||||||
|
@ -48,14 +53,9 @@
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
import useAppStore from '@/store/modules/app';
|
import useAppStore from '@/store/modules/app';
|
||||||
|
|
||||||
import type {
|
import type { PassRateDataType, SelectedCardItem, TimeFormParams } from '@/models/workbench/homePage';
|
||||||
PassRateDataType,
|
|
||||||
SelectedCardItem,
|
|
||||||
StatusStatisticsMapType,
|
|
||||||
TimeFormParams,
|
|
||||||
} from '@/models/workbench/homePage';
|
|
||||||
|
|
||||||
import { commonRatePieOptions, handlePieData } from '../utils';
|
import { handlePieData, handleUpdateTabPie } from '../utils';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
item: SelectedCardItem;
|
item: SelectedCardItem;
|
||||||
|
@ -103,51 +103,20 @@
|
||||||
{ status: 'TCP', count: 3, percentValue: '0%' },
|
{ status: 'TCP', count: 3, percentValue: '0%' },
|
||||||
{ status: 'BBB', count: 6, percentValue: '0%' },
|
{ status: 'BBB', count: 6, percentValue: '0%' },
|
||||||
],
|
],
|
||||||
|
errorCode: 109001,
|
||||||
});
|
});
|
||||||
|
|
||||||
const options = ref(cloneDeep(commonRatePieOptions));
|
const executionOptions = ref<Record<string, any>>({});
|
||||||
const executionOptions = ref<Record<string, any>>(cloneDeep(options.value));
|
const passOptions = ref<Record<string, any>>({});
|
||||||
const passOptions = ref<Record<string, any>>(cloneDeep(options.value));
|
const completeOptions = ref<Record<string, any>>({});
|
||||||
const completeOptions = ref<Record<string, any>>(cloneDeep(options.value));
|
|
||||||
|
|
||||||
// 执行率
|
// 执行率
|
||||||
const executionValueList = ref([
|
const executionValueList = ref<{ value: number | string; label: string; name: string }[]>([]);
|
||||||
{
|
|
||||||
label: t('common.unExecute'),
|
|
||||||
value: 10000,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: t('common.executed'),
|
|
||||||
value: 2000,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
// 通过率
|
// 通过率
|
||||||
const passValueList = ref([
|
const passValueList = ref<{ value: number | string; label: string; name: string }[]>([]);
|
||||||
{
|
|
||||||
label: t('workbench.homePage.havePassed'),
|
|
||||||
value: 10000,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: t('workbench.homePage.notPass'),
|
|
||||||
value: 2000,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
// 完成率
|
// 完成率
|
||||||
const completeValueList = ref([
|
const completeValueList = ref<{ value: number | string; label: string; name: string }[]>([]);
|
||||||
{
|
|
||||||
label: t('common.completed'),
|
|
||||||
value: 10000,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: t('common.inProgress'),
|
|
||||||
value: 2000,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: t('workbench.homePage.unFinish'),
|
|
||||||
value: 2000,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
const testPlanTabList = computed(() => {
|
const testPlanTabList = computed(() => {
|
||||||
return [
|
return [
|
||||||
|
@ -172,41 +141,8 @@
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
|
|
||||||
function handlePassRatePercent(data: { name: string; count: number }[]) {
|
|
||||||
return data.slice(1).map((item) => {
|
|
||||||
return {
|
|
||||||
value: item.count,
|
|
||||||
label: item.name,
|
|
||||||
name: item.name,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleRatePieData(statusStatisticsMap: StatusStatisticsMapType) {
|
|
||||||
const { execute, pass, complete } = statusStatisticsMap;
|
|
||||||
executionValueList.value = handlePassRatePercent(execute);
|
|
||||||
passValueList.value = handlePassRatePercent(pass);
|
|
||||||
completeValueList.value = handlePassRatePercent(complete);
|
|
||||||
|
|
||||||
executionOptions.value.series.data = handlePassRatePercent(execute);
|
|
||||||
passOptions.value.series.data = handlePassRatePercent(pass);
|
|
||||||
completeOptions.value.series.data = handlePassRatePercent(complete);
|
|
||||||
|
|
||||||
executionOptions.value.title.text = execute[0].name ?? '';
|
|
||||||
executionOptions.value.title.subtext = `${execute[0].count ?? 0}%`;
|
|
||||||
|
|
||||||
passOptions.value.title.text = pass[0].name ?? '';
|
|
||||||
passOptions.value.title.subtext = `${pass[0].count ?? 0}%`;
|
|
||||||
|
|
||||||
completeOptions.value.title.text = complete[0].name ?? '';
|
|
||||||
completeOptions.value.title.subtext = `${complete[0].count ?? 0}%`;
|
|
||||||
|
|
||||||
executionOptions.value.series.color = ['#D4D4D8', '#00C261'];
|
|
||||||
passOptions.value.series.color = ['#D4D4D8', '#00C261'];
|
|
||||||
completeOptions.value.series.color = ['#00C261', '#3370FF', '#D4D4D8'];
|
|
||||||
}
|
|
||||||
|
|
||||||
const testPlanCountOptions = ref({});
|
const testPlanCountOptions = ref({});
|
||||||
|
const hasPermission = ref<boolean>(false);
|
||||||
async function initTestPlanCount() {
|
async function initTestPlanCount() {
|
||||||
try {
|
try {
|
||||||
const { startTime, endTime, dayNumber } = timeForm.value;
|
const { startTime, endTime, dayNumber } = timeForm.value;
|
||||||
|
@ -220,18 +156,47 @@
|
||||||
organizationId: appStore.currentOrgId,
|
organizationId: appStore.currentOrgId,
|
||||||
handleUsers: [],
|
handleUsers: [],
|
||||||
};
|
};
|
||||||
const { statusStatisticsMap, statusPercentList } = detail.value;
|
const { statusStatisticsMap, statusPercentList, errorCode } = detail.value;
|
||||||
|
|
||||||
testPlanCountOptions.value = handlePieData(props.item.key, statusPercentList);
|
hasPermission.value = errorCode !== 109001;
|
||||||
handleRatePieData(statusStatisticsMap);
|
testPlanCountOptions.value = handlePieData(props.item.key, hasPermission.value, statusPercentList);
|
||||||
|
|
||||||
|
// 执行率
|
||||||
|
const { options: executedOptions, valueList: executedList } = handleUpdateTabPie(
|
||||||
|
statusStatisticsMap?.execute || [],
|
||||||
|
hasPermission.value,
|
||||||
|
`${props.item.key}-execute`
|
||||||
|
);
|
||||||
|
|
||||||
|
// 通过率
|
||||||
|
const { options: passedOptions, valueList: passList } = handleUpdateTabPie(
|
||||||
|
statusStatisticsMap?.pass || [],
|
||||||
|
hasPermission.value,
|
||||||
|
`${props.item.key}-pass`
|
||||||
|
);
|
||||||
|
|
||||||
|
// 完成率
|
||||||
|
const { options: comOptions, valueList: completeList } = handleUpdateTabPie(
|
||||||
|
statusStatisticsMap?.complete || [],
|
||||||
|
hasPermission.value,
|
||||||
|
`${props.item.key}-complete`
|
||||||
|
);
|
||||||
|
|
||||||
|
executionValueList.value = executedList;
|
||||||
|
passValueList.value = passList;
|
||||||
|
completeValueList.value = completeList;
|
||||||
|
|
||||||
|
executionOptions.value = executedOptions;
|
||||||
|
passOptions.value = passedOptions;
|
||||||
|
completeOptions.value = comOptions;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
function changeProject() {
|
||||||
initTestPlanCount();
|
initTestPlanCount();
|
||||||
});
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
initTestPlanCount();
|
initTestPlanCount();
|
||||||
|
@ -242,7 +207,6 @@
|
||||||
(val) => {
|
(val) => {
|
||||||
if (val) {
|
if (val) {
|
||||||
innerProjectIds.value = [val];
|
innerProjectIds.value = [val];
|
||||||
initTestPlanCount();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -253,7 +217,6 @@
|
||||||
if (val) {
|
if (val) {
|
||||||
const [newProjectId] = val;
|
const [newProjectId] = val;
|
||||||
projectId.value = newProjectId;
|
projectId.value = newProjectId;
|
||||||
initTestPlanCount();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
:search-keys="['name']"
|
:search-keys="['name']"
|
||||||
class="!w-[240px]"
|
class="!w-[240px]"
|
||||||
:prefix="t('workbench.homePage.project')"
|
:prefix="t('workbench.homePage.project')"
|
||||||
|
@change="changeProject"
|
||||||
>
|
>
|
||||||
</MsSelect>
|
</MsSelect>
|
||||||
</div>
|
</div>
|
||||||
|
@ -57,6 +58,15 @@
|
||||||
}}
|
}}
|
||||||
</a-tag>
|
</a-tag>
|
||||||
</template>
|
</template>
|
||||||
|
<template v-if="isNoPermission" #empty>
|
||||||
|
<div class="w-full">
|
||||||
|
<slot name="empty">
|
||||||
|
<div class="flex h-[40px] flex-col items-center justify-center">
|
||||||
|
<span class="text-[14px] text-[var(--color-text-4)]">{{ t('common.noResource') }}</span>
|
||||||
|
</div>
|
||||||
|
</slot>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
</MsBaseTable>
|
</MsBaseTable>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -74,6 +84,7 @@
|
||||||
import MsSelect from '@/components/business/ms-select';
|
import MsSelect from '@/components/business/ms-select';
|
||||||
import passRateLine from '@/views/case-management/caseReview/components/passRateLine.vue';
|
import passRateLine from '@/views/case-management/caseReview/components/passRateLine.vue';
|
||||||
|
|
||||||
|
import { workReviewList } from '@/api/modules/workbench';
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
import useAppStore from '@/store/modules/app';
|
import useAppStore from '@/store/modules/app';
|
||||||
|
|
||||||
|
@ -130,7 +141,7 @@
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const { propsRes, propsEvent, loadList, setLoadListParams } = useTable(undefined, {
|
const { propsRes, propsEvent, loadList, setLoadListParams } = useTable(workReviewList, {
|
||||||
columns,
|
columns,
|
||||||
scroll: { x: '100%' },
|
scroll: { x: '100%' },
|
||||||
selectable: false,
|
selectable: false,
|
||||||
|
@ -138,19 +149,28 @@
|
||||||
showSelectAll: false,
|
showSelectAll: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
function initData() {
|
const isNoPermission = ref<boolean>(false);
|
||||||
const { startTime, endTime, dayNumber } = timeForm.value;
|
|
||||||
setLoadListParams({
|
async function initData() {
|
||||||
current: 1,
|
try {
|
||||||
pageSize: 5,
|
const { startTime, endTime, dayNumber } = timeForm.value;
|
||||||
startTime: dayNumber ? null : startTime,
|
setLoadListParams({
|
||||||
endTime: dayNumber ? null : endTime,
|
startTime: dayNumber ? null : startTime,
|
||||||
dayNumber: dayNumber ?? null,
|
endTime: dayNumber ? null : endTime,
|
||||||
projectIds: innerProjectIds.value,
|
dayNumber: dayNumber ?? null,
|
||||||
organizationId: appStore.currentOrgId,
|
projectIds: innerProjectIds.value,
|
||||||
handleUsers: [],
|
organizationId: appStore.currentOrgId,
|
||||||
});
|
handleUsers: [],
|
||||||
loadList();
|
});
|
||||||
|
await loadList();
|
||||||
|
} catch (error) {
|
||||||
|
isNoPermission.value = error === 'no_project_permission';
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeProject() {
|
||||||
|
initData();
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
@ -162,7 +182,6 @@
|
||||||
(val) => {
|
(val) => {
|
||||||
if (val) {
|
if (val) {
|
||||||
innerProjectIds.value = [val];
|
innerProjectIds.value = [val];
|
||||||
initData();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -93,6 +93,7 @@
|
||||||
<DefectMemberBar
|
<DefectMemberBar
|
||||||
v-else-if="item.key === WorkCardEnum.BUG_HANDLE_USER"
|
v-else-if="item.key === WorkCardEnum.BUG_HANDLE_USER"
|
||||||
v-model:projectIds="item.projectIds"
|
v-model:projectIds="item.projectIds"
|
||||||
|
v-model:handleUsers="item.handleUsers"
|
||||||
:item="item"
|
:item="item"
|
||||||
/>
|
/>
|
||||||
<DefectCount
|
<DefectCount
|
||||||
|
|
|
@ -106,4 +106,10 @@ export default {
|
||||||
'Scenario Pass Rate: Last successful execution scenarios / Total scenarios * 100%',
|
'Scenario Pass Rate: Last successful execution scenarios / Total scenarios * 100%',
|
||||||
'workbench.homePage.planCaseCountLegacyRateTooltip':
|
'workbench.homePage.planCaseCountLegacyRateTooltip':
|
||||||
'Legacy Rate: Unresolved defects / All associated defects * 100%',
|
'Legacy Rate: Unresolved defects / All associated defects * 100%',
|
||||||
|
'workbench.homePage.reviewRate': 'Review Rate',
|
||||||
|
'workbench.homePage.passRate': 'Pass Rate',
|
||||||
|
'workbench.homePage.coverRate': 'Coverage Rate',
|
||||||
|
'workbench.homePage.executeRate': 'Execution Rate',
|
||||||
|
'workbench.homePage.completeRate': 'Completion Rate',
|
||||||
|
'workbench.homePage.legacyRate': 'Legacy Rate',
|
||||||
};
|
};
|
||||||
|
|
|
@ -92,4 +92,10 @@ export default {
|
||||||
'workbench.homePage.scenarioCaseCountExecuteRateTooltip': '场景执行率:执行过的场景/所有场景 * 100%',
|
'workbench.homePage.scenarioCaseCountExecuteRateTooltip': '场景执行率:执行过的场景/所有场景 * 100%',
|
||||||
'workbench.homePage.scenarioCaseCountPassRateTooltip': '场景通过率:最后一次执行成功的场景/场景总数*100%',
|
'workbench.homePage.scenarioCaseCountPassRateTooltip': '场景通过率:最后一次执行成功的场景/场景总数*100%',
|
||||||
'workbench.homePage.planCaseCountLegacyRateTooltip': '遗留率:未关闭缺陷/所有关联的缺陷*100%',
|
'workbench.homePage.planCaseCountLegacyRateTooltip': '遗留率:未关闭缺陷/所有关联的缺陷*100%',
|
||||||
|
'workbench.homePage.reviewRate': '评审率',
|
||||||
|
'workbench.homePage.passRate': '通过率',
|
||||||
|
'workbench.homePage.coverRate': '覆盖率',
|
||||||
|
'workbench.homePage.executeRate': '执行率',
|
||||||
|
'workbench.homePage.completeRate': '完成率',
|
||||||
|
'workbench.homePage.legacyRate': '遗留率',
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
import { commonConfig, toolTipConfig } from '@/config/testPlan';
|
import { cloneDeep } from 'lodash-es';
|
||||||
|
|
||||||
|
import { toolTipConfig } from '@/config/testPlan';
|
||||||
|
import { commonRatePieOptions, defaultValueMap } from '@/config/workbench';
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
import { addCommasToNumber } from '@/utils';
|
import { addCommasToNumber } from '@/utils';
|
||||||
|
|
||||||
import type { ModuleCardItem } from '@/models/workbench/homePage';
|
import { WorkCardEnum } from '@/enums/workbenchEnum';
|
||||||
import { WorkCardEnum, WorkOverviewEnum, WorkOverviewIconEnum } from '@/enums/workbenchEnum';
|
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
// 通用颜色配置
|
// 通用颜色配置
|
||||||
|
@ -37,7 +39,7 @@ export const commonColorConfig = [
|
||||||
export const colorMapConfig: Record<string, string[]> = {
|
export const colorMapConfig: Record<string, string[]> = {
|
||||||
[WorkCardEnum.CASE_COUNT]: ['#ED0303', '#FFA200', '#3370FF', '#D4D4D8'],
|
[WorkCardEnum.CASE_COUNT]: ['#ED0303', '#FFA200', '#3370FF', '#D4D4D8'],
|
||||||
[WorkCardEnum.ASSOCIATE_CASE_COUNT]: ['#00C261', '#3370FF'],
|
[WorkCardEnum.ASSOCIATE_CASE_COUNT]: ['#00C261', '#3370FF'],
|
||||||
[WorkCardEnum.REVIEW_CASE_COUNT]: ['#9441B1', '#3370FF', '#00C261', '#D4D4D8'],
|
[WorkCardEnum.REVIEW_CASE_COUNT]: ['#9441B1', '#00C261', '#D4D4D8', '#3370FF'],
|
||||||
[WorkCardEnum.TEST_PLAN_COUNT]: ['#9441B1', '#3370FF', '#00C261', '#D4D4D8'],
|
[WorkCardEnum.TEST_PLAN_COUNT]: ['#9441B1', '#3370FF', '#00C261', '#D4D4D8'],
|
||||||
[WorkCardEnum.PLAN_LEGACY_BUG]: ['#9441B1', '#3370FF', '#00C261', '#D4D4D8'],
|
[WorkCardEnum.PLAN_LEGACY_BUG]: ['#9441B1', '#3370FF', '#00C261', '#D4D4D8'],
|
||||||
[WorkCardEnum.BUG_COUNT]: ['#FFA200', '#00C261', '#D4D4D8'],
|
[WorkCardEnum.BUG_COUNT]: ['#FFA200', '#00C261', '#D4D4D8'],
|
||||||
|
@ -100,13 +102,14 @@ export function getCommonBarOptions(hasRoom: boolean, color: string[]): Record<s
|
||||||
],
|
],
|
||||||
color,
|
color,
|
||||||
grid: {
|
grid: {
|
||||||
top: '36px',
|
top: 36,
|
||||||
left: '10px',
|
left: 0,
|
||||||
right: '10px',
|
right: 0,
|
||||||
bottom: hasRoom ? '54px' : '5px',
|
bottom: hasRoom ? 54 : 5,
|
||||||
containLabel: true,
|
containLabel: true,
|
||||||
},
|
},
|
||||||
xAxis: {
|
xAxis: {
|
||||||
|
show: true,
|
||||||
splitLine: false,
|
splitLine: false,
|
||||||
boundaryGap: true,
|
boundaryGap: true,
|
||||||
type: 'category',
|
type: 'category',
|
||||||
|
@ -128,7 +131,7 @@ export function getCommonBarOptions(hasRoom: boolean, color: string[]): Record<s
|
||||||
{
|
{
|
||||||
type: 'value',
|
type: 'value',
|
||||||
name: '单位:个', // 设置单位
|
name: '单位:个', // 设置单位
|
||||||
nameLocation: 'end',
|
position: 'left',
|
||||||
nameTextStyle: {
|
nameTextStyle: {
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
color: '#AEAEB2', // 自定义字体大小和颜色
|
color: '#AEAEB2', // 自定义字体大小和颜色
|
||||||
|
@ -143,6 +146,8 @@ export function getCommonBarOptions(hasRoom: boolean, color: string[]): Record<s
|
||||||
type: 'dashed', // 水平线线型,可选 'solid'、'dashed'、'dotted'
|
type: 'dashed', // 水平线线型,可选 'solid'、'dashed'、'dotted'
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
min: 0,
|
||||||
|
max: 1,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
graphic: {
|
graphic: {
|
||||||
|
@ -159,7 +164,6 @@ export function getCommonBarOptions(hasRoom: boolean, color: string[]): Record<s
|
||||||
},
|
},
|
||||||
invisible: true,
|
invisible: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
colorBy: 'series',
|
colorBy: 'series',
|
||||||
series: [],
|
series: [],
|
||||||
barCategoryGap: '50%', // 控制 X 轴分布居中效果
|
barCategoryGap: '50%', // 控制 X 轴分布居中效果
|
||||||
|
@ -194,60 +198,8 @@ export function getCommonBarOptions(hasRoom: boolean, color: string[]): Record<s
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const contentTabList = ref<ModuleCardItem[]>([
|
|
||||||
{
|
|
||||||
label: t('workbench.homePage.functionalUseCase'),
|
|
||||||
value: WorkOverviewEnum.FUNCTIONAL,
|
|
||||||
icon: WorkOverviewIconEnum.FUNCTIONAL,
|
|
||||||
color: 'rgb(var(--primary-5))',
|
|
||||||
count: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: t('workbench.homePage.useCaseReview'),
|
|
||||||
value: WorkOverviewEnum.CASE_REVIEW,
|
|
||||||
icon: WorkOverviewIconEnum.CASE_REVIEW,
|
|
||||||
color: 'rgb(var(--success-6))',
|
|
||||||
count: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: t('workbench.homePage.interfaceAPI'),
|
|
||||||
value: WorkOverviewEnum.API,
|
|
||||||
icon: WorkOverviewIconEnum.API,
|
|
||||||
color: 'rgb(var(--link-6))',
|
|
||||||
count: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: t('workbench.homePage.interfaceCASE'),
|
|
||||||
value: WorkOverviewEnum.API_CASE,
|
|
||||||
icon: WorkOverviewIconEnum.API_CASE,
|
|
||||||
color: 'rgb(var(--link-6))',
|
|
||||||
count: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: t('workbench.homePage.interfaceScenario'),
|
|
||||||
value: WorkOverviewEnum.API_SCENARIO,
|
|
||||||
icon: WorkOverviewIconEnum.API_SCENARIO,
|
|
||||||
color: 'rgb(var(--link-6))',
|
|
||||||
count: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: t('workbench.homePage.apiPlan'),
|
|
||||||
value: WorkOverviewEnum.TEST_PLAN,
|
|
||||||
icon: WorkOverviewIconEnum.TEST_PLAN,
|
|
||||||
color: 'rgb(var(--link-6))',
|
|
||||||
count: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: t('workbench.homePage.bugCount'),
|
|
||||||
value: WorkOverviewEnum.BUG_COUNT,
|
|
||||||
icon: WorkOverviewIconEnum.BUG_COUNT,
|
|
||||||
color: 'rgb(var(--danger-6))',
|
|
||||||
count: 0,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
// 下方饼图配置
|
// 下方饼图配置
|
||||||
export function getPieCharOptions(key: WorkCardEnum) {
|
export function getPieCharOptions(key: WorkCardEnum, hasPermission: boolean) {
|
||||||
return {
|
return {
|
||||||
title: {
|
title: {
|
||||||
show: true,
|
show: true,
|
||||||
|
@ -272,6 +224,7 @@ export function getPieCharOptions(key: WorkCardEnum) {
|
||||||
tooltip: {
|
tooltip: {
|
||||||
...toolTipConfig,
|
...toolTipConfig,
|
||||||
position: 'right',
|
position: 'right',
|
||||||
|
show: !!hasPermission,
|
||||||
},
|
},
|
||||||
legend: {
|
legend: {
|
||||||
width: '100%',
|
width: '100%',
|
||||||
|
@ -387,6 +340,20 @@ export function getPieCharOptions(key: WorkCardEnum) {
|
||||||
},
|
},
|
||||||
data: [],
|
data: [],
|
||||||
},
|
},
|
||||||
|
graphic: {
|
||||||
|
type: 'text',
|
||||||
|
left: 'center',
|
||||||
|
top: 'middle',
|
||||||
|
style: {
|
||||||
|
text: t('workbench.homePage.notHasResPermission'),
|
||||||
|
fontSize: 14,
|
||||||
|
fill: '#959598',
|
||||||
|
backgroundColor: '#F9F9FE',
|
||||||
|
padding: [6, 16, 6, 16],
|
||||||
|
borderRadius: 4,
|
||||||
|
},
|
||||||
|
invisible: !!hasPermission,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -418,108 +385,21 @@ export function handleNoDataDisplay(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// XX率饼图配置
|
|
||||||
export const commonRatePieOptions = {
|
|
||||||
...commonConfig,
|
|
||||||
title: {
|
|
||||||
show: true,
|
|
||||||
text: '',
|
|
||||||
left: 26,
|
|
||||||
top: '20%',
|
|
||||||
textStyle: {
|
|
||||||
fontSize: 12,
|
|
||||||
fontWeight: 'normal',
|
|
||||||
color: '#959598',
|
|
||||||
},
|
|
||||||
triggerEvent: true, // 开启鼠标事件
|
|
||||||
subtext: '0',
|
|
||||||
subtextStyle: {
|
|
||||||
fontSize: 12,
|
|
||||||
color: '#323233',
|
|
||||||
fontWeight: 'bold',
|
|
||||||
align: 'center',
|
|
||||||
lineHeight: 3,
|
|
||||||
},
|
|
||||||
textAlign: 'center',
|
|
||||||
tooltip: {
|
|
||||||
...toolTipConfig,
|
|
||||||
position: 'right',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
tooltip: {
|
|
||||||
...toolTipConfig,
|
|
||||||
position: 'right',
|
|
||||||
},
|
|
||||||
legend: {
|
|
||||||
show: false,
|
|
||||||
},
|
|
||||||
series: {
|
|
||||||
name: '',
|
|
||||||
type: 'pie',
|
|
||||||
color: [],
|
|
||||||
padAngle: 2,
|
|
||||||
radius: ['85%', '100%'],
|
|
||||||
center: [30, '50%'],
|
|
||||||
avoidLabelOverlap: false,
|
|
||||||
label: {
|
|
||||||
show: false,
|
|
||||||
position: 'center',
|
|
||||||
},
|
|
||||||
emphasis: {
|
|
||||||
scale: false, // 禁用放大效果
|
|
||||||
label: {
|
|
||||||
show: false,
|
|
||||||
fontSize: 40,
|
|
||||||
fontWeight: 'bold',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
labelLine: {
|
|
||||||
show: false,
|
|
||||||
},
|
|
||||||
data: [],
|
|
||||||
},
|
|
||||||
// graphic: [
|
|
||||||
// {
|
|
||||||
// type: 'text',
|
|
||||||
// left: 'center',
|
|
||||||
// top: '5%',
|
|
||||||
// style: {
|
|
||||||
// text: '饼图标题',
|
|
||||||
// fontSize: 18,
|
|
||||||
// fontWeight: 'bold',
|
|
||||||
// fill: '#333',
|
|
||||||
// cursor: 'pointer'
|
|
||||||
// },
|
|
||||||
// onmouseover (params) {
|
|
||||||
// // 悬浮到标题上时显示提示信息
|
|
||||||
// // chart.dispatchAction({
|
|
||||||
// // type: 'showTip',
|
|
||||||
// // position: [params.event.offsetX, params.event.offsetY],
|
|
||||||
// // // 配置提示内容
|
|
||||||
// // formatter: '这是饼图标题的提示内容'
|
|
||||||
// // });
|
|
||||||
// },
|
|
||||||
// onmouseout () {
|
|
||||||
// // 离开标题时隐藏提示信息
|
|
||||||
// // chart.dispatchAction({
|
|
||||||
// // type: 'hideTip'
|
|
||||||
// // });
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// ]
|
|
||||||
};
|
|
||||||
|
|
||||||
// 统一处理下方饼图数据结构
|
// 统一处理下方饼图数据结构
|
||||||
export function handlePieData(
|
export function handlePieData(
|
||||||
key: WorkCardEnum,
|
key: WorkCardEnum,
|
||||||
statusPercentList: {
|
hasPermission: boolean,
|
||||||
status: string; // 状态
|
statusPercentList:
|
||||||
count: number;
|
| {
|
||||||
percentValue: string; // 百分比
|
status: string; // 状态
|
||||||
}[]
|
count: number;
|
||||||
|
percentValue: string; // 百分比
|
||||||
|
}[]
|
||||||
|
| null = []
|
||||||
) {
|
) {
|
||||||
const options: Record<string, any> = getPieCharOptions(key);
|
const options: Record<string, any> = getPieCharOptions(key, hasPermission);
|
||||||
options.series.data = statusPercentList.map((item) => ({
|
const lastStatusPercentList = statusPercentList ?? [];
|
||||||
|
options.series.data = lastStatusPercentList.map((item) => ({
|
||||||
name: item.status,
|
name: item.status,
|
||||||
value: item.count,
|
value: item.count,
|
||||||
}));
|
}));
|
||||||
|
@ -527,11 +407,17 @@ export function handlePieData(
|
||||||
// 计算总数和图例格式
|
// 计算总数和图例格式
|
||||||
const tempObject: Record<string, any> = {};
|
const tempObject: Record<string, any> = {};
|
||||||
let totalCount = 0;
|
let totalCount = 0;
|
||||||
statusPercentList.forEach((item) => {
|
lastStatusPercentList.forEach((item) => {
|
||||||
tempObject[item.status] = item;
|
tempObject[item.status] = item;
|
||||||
totalCount += item.count;
|
totalCount += item.count;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 设置副标题为总数
|
||||||
|
options.title.subtext = addCommasToNumber(totalCount);
|
||||||
|
if (!hasPermission) {
|
||||||
|
options.title.subtext = '-';
|
||||||
|
}
|
||||||
|
|
||||||
// 设置图例的格式化函数,显示百分比
|
// 设置图例的格式化函数,显示百分比
|
||||||
options.legend.formatter = (name: string) => {
|
options.legend.formatter = (name: string) => {
|
||||||
return `{a|${tempObject[name].status}} {b|${addCommasToNumber(tempObject[name].count)}} {c|${
|
return `{a|${tempObject[name].status}} {b|${addCommasToNumber(tempObject[name].count)}} {c|${
|
||||||
|
@ -539,8 +425,51 @@ export function handlePieData(
|
||||||
}}`;
|
}}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 设置副标题为总数
|
|
||||||
options.title.subtext = addCommasToNumber(totalCount);
|
|
||||||
|
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 更新options
|
||||||
|
export function handleUpdateTabPie(
|
||||||
|
list: {
|
||||||
|
name: string;
|
||||||
|
count: number;
|
||||||
|
}[],
|
||||||
|
hasPermission: boolean, // 是否有权限
|
||||||
|
key: string
|
||||||
|
) {
|
||||||
|
const options: Record<string, any> = cloneDeep(commonRatePieOptions);
|
||||||
|
const typeKey = key.split('-')[0];
|
||||||
|
const valueKey = key.split('-')[1];
|
||||||
|
const countList = list || [];
|
||||||
|
let lastCountList: { value: number | string; label: string; name: string }[] = [];
|
||||||
|
if (hasPermission) {
|
||||||
|
lastCountList = countList.slice(1).map((item) => {
|
||||||
|
return {
|
||||||
|
value: item.count,
|
||||||
|
label: item.name,
|
||||||
|
name: item.name,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
options.series.data = lastCountList;
|
||||||
|
|
||||||
|
options.title.text = countList[0].name ?? '';
|
||||||
|
options.title.subtext = `${countList[0].count ?? 0}%`;
|
||||||
|
} else {
|
||||||
|
options.series.data = [];
|
||||||
|
lastCountList = defaultValueMap[typeKey][valueKey].defaultList.map((e: any) => {
|
||||||
|
return {
|
||||||
|
...e,
|
||||||
|
label: t(e.label),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
options.title.text = t(defaultValueMap[typeKey][valueKey].defaultName);
|
||||||
|
options.title.subtext = '-%';
|
||||||
|
}
|
||||||
|
|
||||||
|
options.series.color = defaultValueMap[typeKey][valueKey].color;
|
||||||
|
|
||||||
|
return {
|
||||||
|
valueList: lastCountList,
|
||||||
|
options,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue