| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div> |
| | | <PanelHeader title="ä¸åæ ¼æ£åå¤çåæ" /> |
| | | <div class="panel-item-customers"> |
| | | <div class="pie-chart-wrapper" ref="pieWrapperRef"> |
| | | <div class="pie-background" ref="pieBackgroundRef"></div> |
| | | <Echarts ref="chart" :chartStyle="chartStyle" :legend="landLegend" :series="computedSeries" |
| | | :tooltip="landTooltip" :color="landColors" :options="pieOptions" style="height: 100%" class="land-chart" /> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, computed, onMounted, onBeforeUnmount } from 'vue' |
| | | import Echarts from '@/components/Echarts/echarts.vue' |
| | | import PanelHeader from './PanelHeader.vue' |
| | | import { unqualifiedProductProcessingAnalysis } from '@/api/viewIndex.js' |
| | | import { useChartBackground } from '@/hooks/useChartBackground.js' |
| | | |
| | | const pieWrapperRef = ref(null) |
| | | const pieBackgroundRef = ref(null) |
| | | const chart = ref(null) |
| | | |
| | | // æ°æ®å表 |
| | | const dataList = ref([]) |
| | | |
| | | // é¢è²å表 |
| | | const landColors = ['#26FFCB', '#24CBFF', '#35FBF4', '#2651FF', '#D1E4F5', '#5782F7', '#2F67EF', '#82BAFF'] |
| | | |
| | | // label å¯ææ¬æ ·å¼ |
| | | const dotRich = landColors.reduce((acc, color, idx) => { |
| | | acc[`dot${idx}`] = { |
| | | width: 8, |
| | | height: 8, |
| | | borderRadius: 8, |
| | | backgroundColor: color, |
| | | align: 'center', |
| | | } |
| | | return acc |
| | | }, {}) |
| | | |
| | | // å¾ä¾é
ç½® |
| | | const landLegend = ref({ |
| | | show: false, |
| | | icon: 'circle', |
| | | data: [], |
| | | right: '8%', |
| | | top: '40%', |
| | | orient: 'vertical', |
| | | textStyle: { |
| | | color: '#fff', |
| | | rich: { |
| | | unit: { color: '#fff', fontSize: 12, padding: [0, 10, 0, 0] }, |
| | | text: { width: 60, color: '#fff', fontSize: 12 }, |
| | | } |
| | | } |
| | | }) |
| | | |
| | | // æç¤ºæ¡é
ç½® |
| | | const landTooltip = { |
| | | trigger: 'item', |
| | | alwaysShowContent: false, |
| | | position: function (pt) { |
| | | return [pt[0], 130] |
| | | }, |
| | | formatter: function (params) { |
| | | // ç¡®ä¿ params.data åå¨ |
| | | if (!params.data) return '' |
| | | const { name, value, rate } = params.data |
| | | return `${name}<br/>æ°éï¼${value}个<br/>å æ¯ï¼${rate}%` |
| | | }, |
| | | } |
| | | |
| | | // 使ç¨è®¡ç®å±æ§å¤ç Series |
| | | const computedSeries = computed(() => { |
| | | return [ |
| | | { |
| | | name: 'ä¸åæ ¼æ£åå¤çåæ', |
| | | type: 'pie', |
| | | radius: ['35%', '55%'], |
| | | center: ['50%', '50%'], |
| | | label: { |
| | | show: true, |
| | | position: 'outside', |
| | | color: '#fff', |
| | | rich: { |
| | | ...dotRich, |
| | | parent: { fontSize: 14, fontWeight: 600, color: '#fff', lineHeight: 20 }, |
| | | child: { fontSize: 12, color: '#fff', lineHeight: 18 }, |
| | | }, |
| | | formatter: function (params) { |
| | | if (!params.data) return '' |
| | | const dotKey = `dot${params.dataIndex % landColors.length}` |
| | | return `{${dotKey}|} {parent|${params.data.name} (${params.data.value}个)}` |
| | | }, |
| | | }, |
| | | labelLine: { |
| | | show: true, |
| | | length: 20, |
| | | lineStyle: { color: '#B8C8E0' }, |
| | | }, |
| | | data: dataList.value, |
| | | }, |
| | | { |
| | | // å
åè£
饰 |
| | | type: 'pie', |
| | | radius: ['35%', '40%'], |
| | | center: ['50%', '50%'], |
| | | silent: true, |
| | | label: { show: false }, |
| | | itemStyle: { color: 'rgba(0, 127, 255, 0.25)' }, |
| | | data: [1], |
| | | }, |
| | | ] |
| | | }) |
| | | |
| | | const chartStyle = { width: '100%', height: '126%' } |
| | | const pieOptions = { backgroundColor: 'transparent' } |
| | | |
| | | // èæ¯å¤çé©å |
| | | const { adjustBackgroundPosition, init: initBackground, cleanup: cleanupBackground } = useChartBackground({ |
| | | wrapperRef: pieWrapperRef, |
| | | backgroundRef: pieBackgroundRef, |
| | | offsetX: '-51.5%', |
| | | offsetY: '-39%', |
| | | watchData: dataList |
| | | }) |
| | | |
| | | const loadData = async () => { |
| | | try { |
| | | const res = await unqualifiedProductProcessingAnalysis() |
| | | if (res && res.code === 200) { |
| | | dataList.value = (res.data || []).map((it) => ({ |
| | | name: it.name, |
| | | value: Number(it.value || 0), |
| | | rate: it.rate, |
| | | })) |
| | | landLegend.value.data = dataList.value.map((d) => d.name) |
| | | |
| | | // æ°æ®æ´æ°åå¾®è°èæ¯ |
| | | setTimeout(() => { |
| | | adjustBackgroundPosition() |
| | | }, 100) |
| | | } |
| | | } catch (e) { |
| | | console.error('è·åæ°æ®å¤±è´¥:', e) |
| | | } |
| | | } |
| | | |
| | | onMounted(() => { |
| | | loadData() |
| | | initBackground() |
| | | }) |
| | | |
| | | onBeforeUnmount(() => { |
| | | cleanupBackground() |
| | | }) |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .panel-item-customers { |
| | | border: 1px solid #1a58b0; |
| | | padding: 18px; |
| | | width: 100%; |
| | | height: 420px; |
| | | } |
| | | |
| | | .pie-chart-wrapper { |
| | | position: relative; |
| | | width: 100%; |
| | | height: 320px; |
| | | } |
| | | |
| | | .pie-background { |
| | | position: absolute; |
| | | width: 360px; |
| | | height: 360px; |
| | | background-image: url('@/assets/BI/ç«ç°å¾è¾¹æ¡.png'); |
| | | background-size: contain; |
| | | background-position: center; |
| | | background-repeat: no-repeat; |
| | | z-index: 1; |
| | | pointer-events: none; |
| | | left: 50%; |
| | | top: 50%; |
| | | transform: translate(-51.5%, -39%); |
| | | } |
| | | </style> |