| | |
| | | <template> |
| | | <div> |
| | | <div class="panel-root"> |
| | | <PanelHeader title="不合格检品处理分析" /> |
| | | <div class="panel-item-customers"> |
| | | <div class="pie-chart-wrapper" ref="pieWrapperRef"> |
| | | <div class="pie-background" ref="pieBackgroundRef"></div> |
| | | <div class="pie-chart-wrapper"> |
| | | <Echarts ref="chart" :chartStyle="chartStyle" :legend="landLegend" :series="computedSeries" |
| | | :tooltip="landTooltip" :color="landColors" :options="pieOptions" style="height: 100%" class="land-chart" /> |
| | | </div> |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, computed, onMounted, onBeforeUnmount } from 'vue' |
| | | import { ref, computed, onMounted } 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' |
| | | import { BI, baseChartOptions, withTooltip } from '../theme.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'] |
| | | // 颜色列表(大屏统一序列色) |
| | | const landColors = BI.series |
| | | |
| | | // label 富文本样式 |
| | | const dotRich = landColors.reduce((acc, color, idx) => { |
| | |
| | | top: '40%', |
| | | orient: 'vertical', |
| | | textStyle: { |
| | | color: '#fff', |
| | | color: BI.textStrong, |
| | | rich: { |
| | | unit: { color: '#fff', fontSize: 12, padding: [0, 10, 0, 0] }, |
| | | text: { width: 60, color: '#fff', fontSize: 12 }, |
| | | unit: { color: BI.textStrong, fontSize: 12, padding: [0, 10, 0, 0] }, |
| | | text: { width: 60, color: BI.textStrong, fontSize: 12 }, |
| | | } |
| | | } |
| | | }) |
| | | |
| | | // 提示框配置 |
| | | const landTooltip = { |
| | | const landTooltip = withTooltip({ |
| | | trigger: 'item', |
| | | alwaysShowContent: false, |
| | | position: function (pt) { |
| | |
| | | const { name, value, rate } = params.data |
| | | return `${name}<br/>数量:${value}个<br/>占比:${rate}%` |
| | | }, |
| | | } |
| | | }) |
| | | |
| | | // 使用计算属性处理 Series |
| | | const computedSeries = computed(() => { |
| | | const isEmpty = dataList.value.length === 0 |
| | | return [ |
| | | { |
| | | name: '不合格检品处理分析', |
| | | type: 'pie', |
| | | radius: ['35%', '55%'], |
| | | center: ['50%', '50%'], |
| | | silent: isEmpty, |
| | | itemStyle: isEmpty |
| | | ? { color: 'rgba(74, 108, 240, 0.12)', borderWidth: 0 } |
| | | : { |
| | | borderColor: BI.sliceBorder, |
| | | borderWidth: 2, |
| | | borderRadius: 4, |
| | | }, |
| | | label: { |
| | | show: true, |
| | | show: !isEmpty, |
| | | position: 'outside', |
| | | color: '#fff', |
| | | color: BI.textStrong, |
| | | rich: { |
| | | ...dotRich, |
| | | parent: { fontSize: 14, fontWeight: 600, color: '#fff', lineHeight: 20 }, |
| | | child: { fontSize: 12, color: '#fff', lineHeight: 18 }, |
| | | parent: { fontSize: 14, fontWeight: 600, color: BI.textStrong, lineHeight: 20 }, |
| | | child: { fontSize: 12, color: BI.text, lineHeight: 18 }, |
| | | }, |
| | | formatter: function (params) { |
| | | if (!params.data) return '' |
| | |
| | | }, |
| | | }, |
| | | labelLine: { |
| | | show: true, |
| | | show: !isEmpty, |
| | | length: 20, |
| | | lineStyle: { color: '#B8C8E0' }, |
| | | lineStyle: { color: 'rgba(143, 163, 200, 0.4)' }, |
| | | }, |
| | | data: dataList.value, |
| | | data: isEmpty ? [1] : dataList.value, |
| | | }, |
| | | { |
| | | // 内圈装饰 |
| | |
| | | center: ['50%', '50%'], |
| | | silent: true, |
| | | label: { show: false }, |
| | | itemStyle: { color: 'rgba(0, 127, 255, 0.25)' }, |
| | | itemStyle: { color: 'rgba(74, 108, 240, 0.22)' }, |
| | | 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 chartStyle = { width: '100%', height: '100%' } |
| | | const pieOptions = baseChartOptions |
| | | |
| | | const loadData = async () => { |
| | | try { |
| | |
| | | dataList.value = (res.data || []).map((it) => ({ |
| | | name: it.name, |
| | | value: Number(it.value || 0), |
| | | rate: it.rate, |
| | | 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-root { |
| | | flex: 1; |
| | | height: 100%; |
| | | min-height: 0; |
| | | display: flex; |
| | | flex-direction: column; |
| | | } |
| | | |
| | | .panel-item-customers { |
| | | border: 1px solid #1a58b0; |
| | | border: 1px solid var(--bi-panel-border); |
| | | background: var(--bi-panel-bg); |
| | | border-radius: 8px; |
| | | padding: 18px; |
| | | width: 100%; |
| | | height: 449px; |
| | | box-sizing: border-box; |
| | | flex: 1; |
| | | min-height: 0; |
| | | } |
| | | |
| | | .pie-chart-wrapper { |
| | | position: relative; |
| | | width: 100%; |
| | | height: 320px; |
| | | height: 100%; |
| | | min-height: 0; |
| | | } |
| | | |
| | | .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> |
| | | </style> |