| | |
| | | <PanelHeader title="销售品分布" /> |
| | | <div class="main-panel panel-item-customers"> |
| | | <CarouselCards :items="cardItems" :visible-count="3" /> |
| | | <div class="pie-chart-wrapper" ref="pieWrapperRef"> |
| | | <div class="pie-background" ref="pieBackgroundRef"></div> |
| | | <div class="pie-chart-wrapper"> |
| | | <div class="pie-center"> |
| | | <span class="pie-center-value">{{ totalAmount }}</span> |
| | | <span class="pie-center-label">合计(元)</span> |
| | | </div> |
| | | <Echarts |
| | | ref="echartsRef" |
| | | :chartStyle="chartStyle" |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, onMounted, onBeforeUnmount, computed } from 'vue' |
| | | import { ref, onMounted, computed } from 'vue' |
| | | import { productSalesAnalysis } from '@/api/viewIndex.js' |
| | | import PanelHeader from './PanelHeader.vue' |
| | | import CarouselCards from './CarouselCards.vue' |
| | | import Echarts from '@/components/Echarts/echarts.vue' |
| | | import { useChartBackground } from '@/hooks/useChartBackground.js' |
| | | |
| | | const pieWrapperRef = ref(null) |
| | | const pieBackgroundRef = ref(null) |
| | | import { BI, baseChartOptions, withTooltip, formatAmount } from '../theme.js' |
| | | |
| | | /** |
| | | * @introduction 把数组中key值相同的那一项提取出来,组成一个对象 |
| | |
| | | |
| | | const echartsRef = ref(null) |
| | | const pieDatas = ref([]) |
| | | const pieColors = ['#D1E4F5', '#5782F7', '#2F67EF', '#82BAFF', '#43e8fc', '#27EBE7'] |
| | | const pieColors = BI.series |
| | | |
| | | const pieObjData = computed(() => array2obj(pieDatas.value, 'name')) |
| | | |
| | | const totalAmount = computed(() => |
| | | formatAmount(pieDatas.value.reduce((sum, d) => sum + (Number(d.value) || 0), 0)) |
| | | ) |
| | | |
| | | const pieLegend = computed(() => { |
| | | const data = pieDatas.value.map((d, idx) => ({ |
| | | name: d.name, |
| | | icon: 'circle', |
| | | textStyle: { |
| | | fontSize: 18, |
| | | fontSize: 14, |
| | | color: pieColors[idx % pieColors.length], |
| | | }, |
| | | })) |
| | |
| | | orient: 'vertical', |
| | | top: 'center', |
| | | left: '52%', |
| | | itemGap: 30, |
| | | itemGap: 24, |
| | | data: data, |
| | | formatter: function (name) { |
| | | const item = pieObjData.value[name] |
| | | if (!item) return name |
| | | return `{title|${name}}{value|${item.value}}{unit|元}{percent|${item.rate}}{unit|%}` |
| | | return `{title|${name}}{value|${formatAmount(item.value)}}{percent|${item.rate}}{unit|%}` |
| | | }, |
| | | textStyle: { |
| | | rich: { |
| | | value: { |
| | | color: '#43e8fc', |
| | | title: { |
| | | fontSize: 14, |
| | | fontWeight: 600, |
| | | padding: [0, 0, 0, 10], |
| | | }, |
| | | unit: { |
| | | color: '#82baff', |
| | | fontSize: 12, |
| | | fontWeight: 600, |
| | | padding: [0, 10, 0, 0], |
| | | }, |
| | | percent: { |
| | | color: '#43e8fc', |
| | | fontSize: 14, |
| | | fontWeight: 600, |
| | | color: BI.text, |
| | | padding: [0, 0, 0, 0], |
| | | }, |
| | | title: { |
| | | value: { |
| | | color: BI.textStrong, |
| | | fontSize: 14, |
| | | fontWeight: 600, |
| | | padding: [0, 6, 0, 10], |
| | | }, |
| | | percent: { |
| | | color: BI.accentBright, |
| | | fontSize: 14, |
| | | fontWeight: 600, |
| | | padding: [0, 0, 0, 6], |
| | | }, |
| | | unit: { |
| | | color: BI.text, |
| | | fontSize: 12, |
| | | padding: [0, 0, 0, 0], |
| | | }, |
| | |
| | | } |
| | | }) |
| | | |
| | | const pieTooltip = { |
| | | const pieTooltip = withTooltip({ |
| | | trigger: 'item', |
| | | formatter: '{a} <br/>{b} : {c}元 ({d}%)', |
| | | } |
| | | }) |
| | | |
| | | const pieSeries = computed(() => [ |
| | | { |
| | | name: '产品销售金额分析', |
| | | type: 'pie', |
| | | radius: '60%', |
| | | radius: ['48%', '68%'], |
| | | center: ['25%', '50%'], |
| | | itemStyle: { |
| | | borderColor: '#0a1c3a', |
| | | borderColor: BI.sliceBorder, |
| | | borderWidth: 2, |
| | | borderRadius: 4, |
| | | }, |
| | | label: { |
| | | show: false |
| | |
| | | }, |
| | | ]) |
| | | |
| | | const pieOptions = { |
| | | backgroundColor: 'transparent', |
| | | textStyle: { color: '#B8C8E0' }, |
| | | } |
| | | const pieOptions = baseChartOptions |
| | | |
| | | const cardItems = ref([]) |
| | | |
| | | // 使用封装的背景位置调整方法(与其他文件保持一致) |
| | | const { init: initBackground, cleanup: cleanupBackground } = useChartBackground({ |
| | | wrapperRef: pieWrapperRef, |
| | | backgroundRef: pieBackgroundRef, |
| | | left: '25%', // 图表中心 X 是 25% |
| | | top: '50%', // 图表中心 Y 是 50% |
| | | offsetX: '-51.5%', // X 轴偏移 |
| | | offsetY: '-50%', // Y 轴偏移 |
| | | watchData: pieDatas // 监听数据变化,自动调整位置 |
| | | }) |
| | | |
| | | const fetchData = () => { |
| | | productSalesAnalysis() |
| | |
| | | |
| | | onMounted(() => { |
| | | fetchData() |
| | | initBackground() |
| | | }) |
| | | |
| | | onBeforeUnmount(() => { |
| | | cleanupBackground() |
| | | }) |
| | | </script> |
| | | |
| | |
| | | } |
| | | |
| | | .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; |
| | | } |
| | | |
| | | .pie-chart-wrapper { |
| | | position: relative; |
| | | width: 100%; |
| | | height: 320px; |
| | | } |
| | | .pie-background { |
| | | |
| | | .pie-center { |
| | | position: absolute; |
| | | left: 25%; |
| | | top: 50%; |
| | | transform: translate(-51.5%, -50%); |
| | | width: 310px; |
| | | height: 310px; |
| | | background-image: url('@/assets/BI/玫瑰图边框.png'); |
| | | background-size: contain; |
| | | background-position: center; |
| | | background-repeat: no-repeat; |
| | | z-index: 1; |
| | | transform: translate(-50%, -50%); |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | gap: 4px; |
| | | pointer-events: none; |
| | | z-index: 2; |
| | | } |
| | | |
| | | .pie-center-value { |
| | | font-weight: 600; |
| | | font-size: 20px; |
| | | color: var(--bi-text-strong); |
| | | font-variant-numeric: tabular-nums; |
| | | } |
| | | |
| | | .pie-center-label { |
| | | font-size: 12px; |
| | | color: var(--bi-text); |
| | | } |
| | | </style> |