92 lines
2.3 KiB
Vue

<template>
<div class="donut-wrap">
<v-chart class="chart" :option="option" autoresize />
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import { use } from 'echarts/core'
import { CanvasRenderer } from 'echarts/renderers'
import { PieChart } from 'echarts/charts'
import { TooltipComponent, LegendComponent } from 'echarts/components'
import type { EChartsOption } from 'echarts'
import VChart from 'vue-echarts'
import type { PositionRow } from '../../types'
use([CanvasRenderer, PieChart, TooltipComponent, LegendComponent])
const props = withDefaults(
defineProps<{
list: PositionRow[]
valueKey?: keyof PositionRow
}>(),
{ valueKey: 'qty' },
)
const colors = ['#7c3aed', '#f59e0b', '#eab308', '#14b8a6', '#3b82f6', '#94a3b8']
interface TooltipParam {
name?: string
value?: string | number
percent?: number
}
const option = computed((): EChartsOption => {
const key = props.valueKey
const top = props.list.slice(0, 5)
const rest = props.list.slice(5)
const otherQty = rest.reduce((s, x) => s + Number(x[key]), 0)
const data = top.map((x) => ({ name: x.name, value: Number(x[key]) }))
if (otherQty > 0) data.push({ name: '其他', value: otherQty })
return {
color: colors,
tooltip: {
trigger: 'item',
formatter: (p) => {
const param = (Array.isArray(p) ? p[0] : p) as TooltipParam
const row = props.list.find((x) => x.name === param.name)
const change = row ? row.change : 0
const sign = change > 0 ? '+' : ''
return `${param.name}<br/>数量: ${param.value}<br/>增减: ${sign}${change}<br/>占比: ${param.percent}%`
},
},
legend: {
orient: 'vertical',
right: 0,
top: 'middle',
textStyle: { fontSize: 11 },
formatter: (name: string) => {
const item = data.find((d) => d.name === name)
if (!item) return name
const total = data.reduce((s, d) => s + d.value, 0)
const pct = ((item.value / total) * 100).toFixed(2)
return `${name} ${pct}%`
},
},
series: [
{
type: 'pie',
radius: ['48%', '72%'],
center: ['32%', '50%'],
avoidLabelOverlap: true,
label: { show: false },
data,
},
],
}
})
</script>
<style scoped>
.donut-wrap {
height: 220px;
}
.chart {
height: 100%;
width: 100%;
}
</style>