feat(工作台): 调整优化工作台饼图

This commit is contained in:
xinxin.wu 2024-11-29 14:39:42 +08:00 committed by Craftsman
parent efa4a1f319
commit 8dc9e2b022
12 changed files with 155 additions and 64 deletions

View File

@ -243,8 +243,8 @@ export const commonRatePieOptions = {
title: { title: {
show: true, show: true,
text: '', text: '',
left: 26, left: 40,
top: '20%', top: '26%',
textStyle: { textStyle: {
fontSize: 12, fontSize: 12,
fontWeight: 'normal', fontWeight: 'normal',
@ -276,16 +276,14 @@ export const commonRatePieOptions = {
name: '', name: '',
type: 'pie', type: 'pie',
color: [], color: [],
padAngle: 2, radius: ['65%', '80%'],
radius: ['85%', '100%'], center: [44, '50%'],
center: [30, '50%'],
avoidLabelOverlap: false, avoidLabelOverlap: false,
label: { label: {
show: false, show: false,
position: 'center', position: 'center',
}, },
emphasis: { emphasis: {
scale: false, // 禁用放大效果
label: { label: {
show: false, show: false,
fontSize: 40, fontSize: 40,

View File

@ -173,7 +173,7 @@
const coverTitleConfig = computed(() => { const coverTitleConfig = computed(() => {
return { return {
name: t('workbench.homePage.apiCoverage'), name: t('workbench.homePage.apiCoverage'),
color: ['#EDEDF1', '#00C261'], color: ['#D4D4D8', '#00C261'],
tooltipText: tooltipText:
props.item.key === WorkCardEnum.API_CASE_COUNT props.item.key === WorkCardEnum.API_CASE_COUNT
? t('workbench.homePage.apiCaseCountCoverRateTooltip') ? t('workbench.homePage.apiCaseCountCoverRateTooltip')
@ -185,12 +185,12 @@
return props.item.key === WorkCardEnum.API_CASE_COUNT return props.item.key === WorkCardEnum.API_CASE_COUNT
? { ? {
name: t('workbench.homePage.caseExecutionRate'), name: t('workbench.homePage.caseExecutionRate'),
color: ['#EDEDF1', '#00C261'], color: ['#D4D4D8', '#00C261'],
tooltipText: t('workbench.homePage.apiCaseCountExecuteRateTooltip'), tooltipText: t('workbench.homePage.apiCaseCountExecuteRateTooltip'),
} }
: { : {
name: t('workbench.homePage.sceneExecutionRate'), name: t('workbench.homePage.sceneExecutionRate'),
color: ['#EDEDF1', '#00C261'], color: ['#D4D4D8', '#00C261'],
tooltipText: t('workbench.homePage.scenarioCaseCountExecuteRateTooltip'), tooltipText: t('workbench.homePage.scenarioCaseCountExecuteRateTooltip'),
}; };
}); });

View File

@ -31,7 +31,6 @@
<PassRatePie <PassRatePie
:tooltip-text="tabItem.tooltip" :tooltip-text="tabItem.tooltip"
:options="tabItem.options" :options="tabItem.options"
:size="60"
:loading="tabItem.value === 'cover' ? loading : undefined" :loading="tabItem.value === 'cover' ? loading : undefined"
:has-permission="hasPermission" :has-permission="hasPermission"
:value-list="tabItem.valueList" :value-list="tabItem.valueList"

View File

@ -27,7 +27,6 @@
<PassRatePie <PassRatePie
:options="tabItem.options" :options="tabItem.options"
:tooltip-text="tabItem.tooltip" :tooltip-text="tabItem.tooltip"
:size="60"
:value-list="tabItem.valueList" :value-list="tabItem.valueList"
:has-permission="hasPermission" :has-permission="hasPermission"
/> />

View File

@ -27,7 +27,6 @@
<PassRatePie <PassRatePie
:options="options" :options="options"
tooltip-text="workbench.homePage.caseReviewCoverRateTooltip" tooltip-text="workbench.homePage.caseReviewCoverRateTooltip"
:size="60"
:value-list="coverValueList" :value-list="coverValueList"
:has-permission="hasPermission" :has-permission="hasPermission"
/> />

View File

@ -28,7 +28,6 @@
:has-permission="hasPermission" :has-permission="hasPermission"
:tooltip-text="tooltip" :tooltip-text="tooltip"
:options="legacyOptions" :options="legacyOptions"
:size="60"
:value-list="legacyValueList" :value-list="legacyValueList"
/> />
</div> </div>

View File

@ -8,7 +8,7 @@
<div class="flex w-full flex-col gap-4"> <div class="flex w-full flex-col gap-4">
<div <div
v-for="(ele, i) of currentData" v-for="(ele, i) of currentData"
:key="`ele.status-${i}`" :key="`${ele.status}-${i}`"
class="grid flex-1 grid-cols-3 gap-4" class="grid flex-1 grid-cols-3 gap-4"
@mouseover="handleMouseOver(ele.status)" @mouseover="handleMouseOver(ele.status)"
@mouseout="handleMouseOut(ele.status)" @mouseout="handleMouseOut(ele.status)"

View File

@ -9,7 +9,7 @@
> >
<div class="tooltip-rate h-[50px] w-[50px]"></div> <div class="tooltip-rate h-[50px] w-[50px]"></div>
</a-tooltip> </a-tooltip>
<MsChart :height="`${props.size}px`" :width="`${props.size}px`" :options="props.options" /> <MsChart height="92px" width="92px" :options="props.options" />
</div> </div>
<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">
@ -30,7 +30,6 @@
const props = defineProps<{ const props = defineProps<{
options: Record<string, any>; options: Record<string, any>;
size: number;
tooltipText?: string; tooltipText?: string;
hasPermission: boolean; hasPermission: boolean;
loading?: boolean; loading?: boolean;
@ -43,8 +42,9 @@
<style scoped lang="less"> <style scoped lang="less">
.pass-rate-content { .pass-rate-content {
padding: 16px; padding: 0 16px;
width: 100%; width: 100%;
height: 92px;
border-radius: 6px; border-radius: 6px;
background: var(--color-text-n9); background: var(--color-text-n9);
@apply flex items-center; @apply flex items-center;

View File

@ -1,6 +1,6 @@
<template> <template>
<a-spin class="w-full" :loading="props.loading"> <a-spin class="w-full" :loading="props.loading">
<div class="rate-content relative"> <div class="rate-content relative flex flex-col items-center">
<div class="relative flex h-full w-full items-center justify-center"> <div class="relative flex h-full w-full items-center justify-center">
<a-tooltip <a-tooltip
v-if="props.rateConfig.tooltipText" v-if="props.rateConfig.tooltipText"
@ -10,7 +10,38 @@
> >
<div class="tooltip-rate-tooltip"></div> <div class="tooltip-rate-tooltip"></div>
</a-tooltip> </a-tooltip>
<MsChart :options="options" width="146px" /> <MsChart ref="chartRef" :options="options" width="100px" height="100px" />
</div>
<div class="flex w-full items-center justify-center">
<div class="flex w-[80%] flex-col gap-[8px]">
<template v-if="props.hasPermission">
<div
v-for="(ele, i) of legend"
:key="`${ele.name}-${i}`"
class="flex justify-between"
@mouseover="handleMouseOver(ele.name)"
@mouseout="handleMouseOut(ele.name)"
>
<div class="flex items-center text-left text-[var(--color-text-3)]">
<div
:style="{
background: ele.selected ? `${ele.color}` : '#D4D4D8',
}"
class="mr-[8px] h-[8px] w-[8px] cursor-pointer rounded-lg"
@click="toggleLegend(ele.name, i)"
>
</div>
{{ ele.name }}
</div>
<div class="text-[16px] text-[rgb(var(--primary-5))]">{{ addCommasToNumber(ele.value) }}</div>
</div>
</template>
<div v-else class="mt-[16px] flex h-full flex-1 items-center justify-center">
<div class="rounded bg-[var(--color-text-n9)] px-[16px] py-[4px] text-[var(--color-text-4)]">
{{ t('workbench.homePage.notHasResPermission') }}
</div>
</div>
</div>
</div> </div>
</div> </div>
</a-spin> </a-spin>
@ -43,7 +74,7 @@
show: true, show: true,
text: '', text: '',
left: 'center', left: 'center',
top: 32, top: 30,
textStyle: { textStyle: {
fontSize: 12, fontSize: 12,
fontWeight: 'normal', fontWeight: 'normal',
@ -65,7 +96,9 @@
tooltip: { tooltip: {
show: true, show: true,
}, },
color: [],
legend: { legend: {
show: false,
orient: 'vertical', orient: 'vertical',
itemWidth: 8, // itemWidth: 8, //
itemHeight: 8, // itemHeight: 8, //
@ -102,8 +135,8 @@
series: { series: {
name: '', name: '',
type: 'pie', type: 'pie',
radius: ['50%', '58%'], radius: ['75%', '90%'],
center: ['50%', '32%'], center: ['50%', '50%'],
color: [], color: [],
avoidLabelOverlap: false, avoidLabelOverlap: false,
label: { label: {
@ -122,31 +155,52 @@
}, },
data: [], data: [],
}, },
graphic: { // graphic: {
type: 'text', // type: 'text',
left: 'center', // left: 'center',
bottom: 10, // bottom: 10,
style: { // style: {
text: t('workbench.homePage.notHasResPermission'), // text: t('workbench.homePage.notHasResPermission'),
fontSize: 14, // fontSize: 14,
fill: '#959598', // fill: '#959598',
backgroundColor: '#F9F9FE', // backgroundColor: '#F9F9FE',
padding: [6, 16, 6, 16], // padding: [6, 16, 6, 16],
borderRadius: 4, // borderRadius: 4,
}, // },
invisible: false, // invisible: false,
}, // },
}); });
const legend = ref<{ name: string; value: number; color: string; selected: boolean }[]>([]);
function initOptions() { function initOptions() {
const { name, color } = props.rateConfig; const { name, color } = props.rateConfig;
options.value.series.data = [...props.data.slice(1)].map((e) => { const temData = [...props.data.slice(1)];
const hasDataLength = temData.filter((e) => Number(e.value) > 0).length;
const pieBorderWidth = hasDataLength === 1 ? 0 : 1;
options.value.series.data =
hasDataLength > 0
? temData.map((e) => {
return { return {
...e, ...e,
tooltip: { tooltip: {
...toolTipConfig, ...toolTipConfig,
show: !!props.hasPermission, show: !!props.hasPermission,
}, },
itemStyle: {
borderWidth: pieBorderWidth,
borderColor: '#ffffff',
},
};
})
: [];
legend.value = [...props.data.slice(1)].map((e, i) => {
return {
...e,
selected: true,
color: color[i],
}; };
}); });
@ -162,13 +216,48 @@
options.value.title.subtext = `-%`; options.value.title.subtext = `-%`;
} }
options.value.graphic.invisible = !!props.hasPermission;
options.value.tooltip.show = !!props.hasPermission; options.value.tooltip.show = !!props.hasPermission;
options.value.title.text = name; options.value.title.text = name;
options.value.series.color = color; options.value.series.color = color;
} }
const chartRef = ref<InstanceType<typeof MsChart>>();
function toggleLegend(name: string, index: number) {
const chart = chartRef.value?.chartRef;
if (chart) {
chart.dispatchAction({
type: 'legendToggleSelect',
name,
});
if (legend.value) {
legend.value[index].selected = !legend.value[index].selected;
}
}
}
//
function handleMouseOver(name: string) {
const chart = chartRef.value?.chartRef;
if (chart) {
chart.dispatchAction({
type: 'highlight',
name,
});
}
}
//
function handleMouseOut(name: string) {
const chart = chartRef.value?.chartRef;
if (chart) {
chart.dispatchAction({
type: 'downplay',
name,
});
}
}
watch( watch(
() => props.data, () => props.data,
(val) => { (val) => {
@ -191,15 +280,12 @@
</script> </script>
<style scoped lang="less"> <style scoped lang="less">
.rate-content {
height: 158px;
}
.tooltip-rate-tooltip { .tooltip-rate-tooltip {
position: absolute; position: absolute;
top: 10px; top: 20px;
z-index: 9; z-index: 9;
width: 78px; width: 60px;
height: 78px; height: 60px;
border-radius: 50%; border-radius: 50%;
} }
</style> </style>

View File

@ -27,7 +27,6 @@
:options="relatedOptions" :options="relatedOptions"
:has-permission="hasPermission" :has-permission="hasPermission"
tooltip-text="workbench.homePage.associateCaseCoverRateTooltip" tooltip-text="workbench.homePage.associateCaseCoverRateTooltip"
:size="60"
:value-list="coverRateValueList" :value-list="coverRateValueList"
/> />
</div> </div>

View File

@ -24,12 +24,7 @@
<div class="mt-[16px]"> <div class="mt-[16px]">
<div class="flex gap-[16px]"> <div class="flex gap-[16px]">
<div v-for="tabItem of testPlanTabList" :key="tabItem.label" class="flex-1"> <div v-for="tabItem of testPlanTabList" :key="tabItem.label" class="flex-1">
<PassRatePie <PassRatePie :has-permission="hasPermission" :options="tabItem.options" :value-list="tabItem.valueList" />
:has-permission="hasPermission"
:options="tabItem.options"
:size="60"
:value-list="tabItem.valueList"
/>
</div> </div>
</div> </div>
<div class="mt-[16px] h-[148px]"> <div class="mt-[16px] h-[148px]">

View File

@ -364,7 +364,12 @@ export function handlePieData(
) { ) {
const options: Record<string, any> = getPieCharOptions(key); const options: Record<string, any> = getPieCharOptions(key);
const lastStatusPercentList = statusPercentList ?? []; const lastStatusPercentList = statusPercentList ?? [];
options.series.data = lastStatusPercentList.map((item) => ({ const hasDataLength = lastStatusPercentList.filter((e) => Number(e.count) > 0).length;
const pieBorderWidth = hasDataLength === 1 ? 0 : 2;
options.series.data =
hasDataLength > 0
? lastStatusPercentList.map((item) => ({
name: item.status, name: item.status,
value: item.count, value: item.count,
tooltip: { tooltip: {
@ -372,7 +377,12 @@ export function handlePieData(
position: 'right', position: 'right',
show: !!hasPermission, show: !!hasPermission,
}, },
})); itemStyle: {
borderWidth: pieBorderWidth,
borderColor: '#ffffff',
},
}))
: [];
// 计算总数和图例格式 // 计算总数和图例格式
const tempObject: Record<string, any> = {}; const tempObject: Record<string, any> = {};
@ -407,13 +417,20 @@ export function handleUpdateTabPie(
const countList = list || []; const countList = list || [];
let lastCountList: { value: number | string; label: string; name: string }[] = []; let lastCountList: { value: number | string; label: string; name: string }[] = [];
if (hasPermission) { if (hasPermission) {
const pieBorderWidth = countList.slice(1).filter((e) => Number(e.count) > 0).length === 1 ? 0 : 1;
lastCountList = countList.slice(1).map((item) => { lastCountList = countList.slice(1).map((item) => {
return { return {
value: item.count, value: item.count,
label: item.name, label: item.name,
name: item.name, name: item.name,
itemStyle: {
borderWidth: pieBorderWidth,
borderColor: '#ffffff',
},
}; };
}); });
options.series.data = lastCountList.every((e) => e.value === 0) ? [] : lastCountList; options.series.data = lastCountList.every((e) => e.value === 0) ? [] : lastCountList;
options.title.text = countList[0].name ?? ''; options.title.text = countList[0].name ?? '';