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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,6 @@
<template>
<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">
<a-tooltip
v-if="props.rateConfig.tooltipText"
@ -10,7 +10,38 @@
>
<div class="tooltip-rate-tooltip"></div>
</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>
</a-spin>
@ -43,7 +74,7 @@
show: true,
text: '',
left: 'center',
top: 32,
top: 30,
textStyle: {
fontSize: 12,
fontWeight: 'normal',
@ -65,7 +96,9 @@
tooltip: {
show: true,
},
color: [],
legend: {
show: false,
orient: 'vertical',
itemWidth: 8, //
itemHeight: 8, //
@ -102,8 +135,8 @@
series: {
name: '',
type: 'pie',
radius: ['50%', '58%'],
center: ['50%', '32%'],
radius: ['75%', '90%'],
center: ['50%', '50%'],
color: [],
avoidLabelOverlap: false,
label: {
@ -122,31 +155,52 @@
},
data: [],
},
graphic: {
type: 'text',
left: 'center',
bottom: 10,
style: {
text: t('workbench.homePage.notHasResPermission'),
fontSize: 14,
fill: '#959598',
backgroundColor: '#F9F9FE',
padding: [6, 16, 6, 16],
borderRadius: 4,
},
invisible: false,
},
// graphic: {
// type: 'text',
// left: 'center',
// bottom: 10,
// style: {
// text: t('workbench.homePage.notHasResPermission'),
// fontSize: 14,
// fill: '#959598',
// backgroundColor: '#F9F9FE',
// padding: [6, 16, 6, 16],
// borderRadius: 4,
// },
// invisible: false,
// },
});
const legend = ref<{ name: string; value: number; color: string; selected: boolean }[]>([]);
function initOptions() {
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 {
...e,
tooltip: {
...toolTipConfig,
show: !!props.hasPermission,
},
itemStyle: {
borderWidth: pieBorderWidth,
borderColor: '#ffffff',
},
};
})
: [];
legend.value = [...props.data.slice(1)].map((e, i) => {
return {
...e,
tooltip: {
...toolTipConfig,
show: !!props.hasPermission,
},
selected: true,
color: color[i],
};
});
@ -162,13 +216,48 @@
options.value.title.subtext = `-%`;
}
options.value.graphic.invisible = !!props.hasPermission;
options.value.tooltip.show = !!props.hasPermission;
options.value.title.text = name;
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(
() => props.data,
(val) => {
@ -191,15 +280,12 @@
</script>
<style scoped lang="less">
.rate-content {
height: 158px;
}
.tooltip-rate-tooltip {
position: absolute;
top: 10px;
top: 20px;
z-index: 9;
width: 78px;
height: 78px;
width: 60px;
height: 60px;
border-radius: 50%;
}
</style>

View File

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

View File

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

View File

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