Merge remote-tracking branch 'origin/dev_New' into dev_New
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, onMounted, onBeforeUnmount, watchEffect } from 'vue' |
| | | import { ref, onMounted, onBeforeUnmount, nextTick } from 'vue' |
| | | import * as echarts from 'echarts' |
| | | |
| | | const emit = defineEmits(['finished']) |
| | | |
| | | // Props |
| | | const props = defineProps({ |
| | |
| | | // Refs |
| | | const chartRef = ref(null) |
| | | let chartInstance = null |
| | | let finishedHandler = null |
| | | let initTimer = null |
| | | let initAttempts = 0 |
| | | |
| | | function clearInitTimer() { |
| | | if (initTimer) { |
| | | clearTimeout(initTimer) |
| | | initTimer = null |
| | | } |
| | | } |
| | | |
| | | function isContainerReady() { |
| | | const el = chartRef.value |
| | | if (!el) return false |
| | | // offsetWidth/offsetHeight æ´è´´è¿çå®å¸å±ï¼ä¸º 0 å¾å¾ä»£è¡¨è¿æ²¡å¸å±/ä¸å¯è§ï¼ |
| | | return el.offsetWidth > 0 && el.offsetHeight > 0 |
| | | } |
| | | |
| | | function initChartWhenReady() { |
| | | clearInitTimer() |
| | | initAttempts += 1 |
| | | |
| | | if (!isContainerReady()) { |
| | | // ç容å¨çæ£æå°ºå¯¸ï¼é¿å
é¦å±åå§ååç§»/空ç½ï¼çæ´æ°åææ£å¸¸çæ
åµï¼ |
| | | // æå¤éè¯çº¦ 3 ç§ï¼é¿å
æ éå¾ªç¯ |
| | | if (initAttempts < 60) { |
| | | initTimer = setTimeout(initChartWhenReady, 50) |
| | | } |
| | | return |
| | | } |
| | | |
| | | if (chartInstance) return |
| | | chartInstance = echarts.init(chartRef.value) |
| | | finishedHandler = () => emit('finished') |
| | | chartInstance.on('finished', finishedHandler) |
| | | renderChart() |
| | | // setOption åè¡¥ä¸æ¬¡ resizeï¼ç¡®ä¿é¦å±å°ºå¯¸æ£ç¡® |
| | | nextTick(() => { |
| | | if (chartInstance) chartInstance.resize() |
| | | }) |
| | | } |
| | | |
| | | // Methods |
| | | function generateChart(option) { |
| | |
| | | |
| | | // Lifecycle hooks |
| | | onMounted(() => { |
| | | chartInstance = echarts.init(chartRef.value) |
| | | renderChart() |
| | | initAttempts = 0 |
| | | initChartWhenReady() |
| | | window.addEventListener('resize', windowResizeListener) |
| | | }) |
| | | |
| | | onBeforeUnmount(() => { |
| | | if (chartInstance) { |
| | | window.removeEventListener('resize', windowResizeListener) |
| | | if (finishedHandler) { |
| | | chartInstance.off('finished', finishedHandler) |
| | | finishedHandler = null |
| | | } |
| | | chartInstance.dispose() |
| | | chartInstance = null |
| | | } |
| | | clearInitTimer() |
| | | }) |
| | | |
| | | // Watch all reactive props that affect the chart |
| | | watch( |
| | | () => [props.xAxis, props.yAxis, props.series, props.legend, props.tooltip, props.visualMap], |
| | | () => { |
| | | if (chartInstance) { |
| | | renderChart() |
| | | // 妿é¦å±è¿æ²¡åå§åæåï¼çå¾
å®¹å¨ ready å忏²æ |
| | | if (!chartInstance) { |
| | | initChartWhenReady() |
| | | return |
| | | } |
| | | renderChart() |
| | | // æ°æ®åååè¡¥ä¸æ¬¡ resizeï¼é¿å
å¸å±åå导è´çåç§» |
| | | nextTick(() => { |
| | | if (chartInstance) chartInstance.resize() |
| | | }) |
| | | }, |
| | | { deep: true, immediate: true } |
| | | ) |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import { ref, onMounted, onBeforeUnmount, nextTick, watch } from 'vue' |
| | | |
| | | /** |
| | | * å¾è¡¨èæ¯ä½ç½®è°æ´ composable |
| | | * @param {Object} options é
ç½®é项 |
| | | * @param {Ref} options.wrapperRef - å¾è¡¨å®¹å¨ç ref |
| | | * @param {Ref} options.backgroundRef - èæ¯å
ç´ ç ref |
| | | * @param {String} options.left - èæ¯ left ä½ç½®ï¼å¦ '25%' æ '50%'ï¼é»è®¤ '50%' |
| | | * @param {String} options.top - èæ¯ top ä½ç½®ï¼å¦ '50%'ï¼é»è®¤ '50%' |
| | | * @param {String} options.offsetX - X è½´åç§»å¼ï¼å¦ '-51.5%' æ '-50%'ï¼é»è®¤ '-50%' |
| | | * @param {String} options.offsetY - Y è½´åç§»å¼ï¼å¦ '-39%' æ '-50%'ï¼é»è®¤ '-50%' |
| | | * @param {Ref} options.watchData - å¯éï¼çå¬çæ°æ®ååï¼æ°æ®ååæ¶éæ°è°æ´ä½ç½® |
| | | * @returns {Function} adjustBackgroundPosition - æå¨è°æ´èæ¯ä½ç½®çæ¹æ³ |
| | | */ |
| | | export function useChartBackground(options = {}) { |
| | | const { |
| | | wrapperRef, |
| | | backgroundRef, |
| | | left = '50%', |
| | | top = '50%', |
| | | offsetX = '-50%', |
| | | offsetY = '-50%', |
| | | watchData = null |
| | | } = options |
| | | |
| | | let resizeObserver = null |
| | | let intersectionObserver = null |
| | | let retryTimers = [] |
| | | |
| | | const clearRetryTimers = () => { |
| | | if (!retryTimers.length) return |
| | | retryTimers.forEach((t) => clearTimeout(t)) |
| | | retryTimers = [] |
| | | } |
| | | |
| | | // è°æ´èæ¯ä½ç½® |
| | | const adjustBackgroundPosition = () => { |
| | | nextTick(() => { |
| | | if (!wrapperRef?.value || !backgroundRef?.value) { |
| | | return |
| | | } |
| | | |
| | | // åå§åé¶æ®µç»å¸¸åºç°ï¼å®¹å¨å°æªå¯è§/尺寸为 0ï¼éå
¨å±ãtabãå¨ç»çï¼ |
| | | // è¿ç§æ
åµä¸å
ä¸å¯¹é½ï¼ç ResizeObserver / IntersectionObserver å触å |
| | | const rect = wrapperRef.value.getBoundingClientRect() |
| | | if (!rect.width || !rect.height) return |
| | | |
| | | const background = backgroundRef.value |
| | | |
| | | // 使ç¨ç¾åæ¯å®ä½ + transform å¾®è°ï¼è¿æ¯æå¯é çæ¹å¼ï¼ |
| | | background.style.left = left |
| | | background.style.top = top |
| | | background.style.transform = `translate(${offsetX}, ${offsetY})` |
| | | }) |
| | | } |
| | | |
| | | // åå§åé¶æ®µå¤æ¬¡âè¡¥å¿å¯¹é½âï¼è¦ç Echarts 馿¬¡æ¸²æ/å¨ç»é æçå»¶è¿å¸å± |
| | | const scheduleKickAlign = () => { |
| | | clearRetryTimers() |
| | | ;[0, 60, 180, 360, 800].forEach((ms) => { |
| | | retryTimers.push( |
| | | setTimeout(() => { |
| | | adjustBackgroundPosition() |
| | | }, ms) |
| | | ) |
| | | }) |
| | | } |
| | | |
| | | // çªå£ resize å¤ç |
| | | const resizeHandler = () => { |
| | | adjustBackgroundPosition() |
| | | } |
| | | |
| | | // 妿æä¾äº watchDataï¼ç嬿°æ®ååï¼éè¦å¨ setup é¶æ®µåå»ºï¼ |
| | | if (watchData) { |
| | | watch(watchData, () => { |
| | | adjustBackgroundPosition() |
| | | }, { deep: true }) |
| | | } |
| | | |
| | | // åå§å |
| | | const init = () => { |
| | | // çå¬çªå£ resize |
| | | window.addEventListener('resize', resizeHandler) |
| | | |
| | | // ä½¿ç¨ ResizeObserver çå¬å®¹å¨å°ºå¯¸åå |
| | | nextTick(() => { |
| | | if (wrapperRef?.value && window.ResizeObserver) { |
| | | resizeObserver = new ResizeObserver(() => { |
| | | adjustBackgroundPosition() |
| | | }) |
| | | resizeObserver.observe(wrapperRef.value) |
| | | } |
| | | |
| | | // çå¬âä»ä¸å¯è§å°å¯è§âï¼è§£å³åå§åæ¶æªå¯¹é½ä½çæ´æ°åæ£å¸¸çé®é¢ |
| | | if (wrapperRef?.value && window.IntersectionObserver) { |
| | | intersectionObserver = new IntersectionObserver( |
| | | (entries) => { |
| | | const entry = entries?.[0] |
| | | if (entry?.isIntersecting) { |
| | | scheduleKickAlign() |
| | | } |
| | | }, |
| | | { threshold: 0.01 } |
| | | ) |
| | | intersectionObserver.observe(wrapperRef.value) |
| | | } |
| | | |
| | | // åå§å夿¬¡è¡¥å¿å¯¹é½ï¼ç¡®ä¿å¾è¡¨æ¸²æå®æ |
| | | scheduleKickAlign() |
| | | }) |
| | | } |
| | | |
| | | // æ¸
ç |
| | | const cleanup = () => { |
| | | window.removeEventListener('resize', resizeHandler) |
| | | clearRetryTimers() |
| | | if (resizeObserver) { |
| | | resizeObserver.disconnect() |
| | | resizeObserver = null |
| | | } |
| | | if (intersectionObserver) { |
| | | intersectionObserver.disconnect() |
| | | intersectionObserver = null |
| | | } |
| | | } |
| | | |
| | | return { |
| | | adjustBackgroundPosition, |
| | | init, |
| | | cleanup |
| | | } |
| | | } |
| | |
| | | <PanelHeader title="éè´ååå¸" /> |
| | | <div class="main-panel panel-item-customers"> |
| | | <CarouselCards :items="cardItems" :visible-count="3" /> |
| | | <div class="pie-chart-wrapper"> |
| | | <div class="pie-background"></div> |
| | | <div class="pie-chart-wrapper" ref="pieWrapperRef"> |
| | | <div class="pie-background" ref="pieBackgroundRef"></div> |
| | | <Echarts |
| | | ref="chart" |
| | | :chartStyle="chartStyle" |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, onMounted, computed } from 'vue' |
| | | import { ref, onMounted, onBeforeUnmount, computed } from 'vue' |
| | | import Echarts from '@/components/Echarts/echarts.vue' |
| | | import PanelHeader from './PanelHeader.vue' |
| | | import CarouselCards from './CarouselCards.vue' |
| | | import { rawMaterialPurchaseAmountRatio } from '@/api/viewIndex.js' |
| | | import { useChartBackground } from '@/hooks/useChartBackground.js' |
| | | |
| | | const pieWrapperRef = ref(null) |
| | | const pieBackgroundRef = ref(null) |
| | | |
| | | /** |
| | | * @introduction ææ°ç»ä¸keyå¼ç¸åçé£ä¸é¡¹æååºæ¥ï¼ç»æä¸ä¸ªå¯¹è±¡ |
| | |
| | | textStyle: { color: '#B8C8E0' }, |
| | | } |
| | | |
| | | // 使ç¨å°è£
çèæ¯ä½ç½®è°æ´æ¹æ³ |
| | | // å¾è¡¨ä¸å¿æ¯ ['25%', '50%']ï¼èæ¯éè¦å¯¹é½å°è¿ä¸ªä½ç½® |
| | | 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: dataList // ç嬿°æ®ååï¼èªå¨è°æ´ä½ç½® |
| | | }) |
| | | |
| | | const fetchData = () => { |
| | | rawMaterialPurchaseAmountRatio() |
| | | .then((res) => { |
| | |
| | | |
| | | onMounted(() => { |
| | | fetchData() |
| | | initBackground() |
| | | }) |
| | | |
| | | onBeforeUnmount(() => { |
| | | cleanupBackground() |
| | | }) |
| | | </script> |
| | | |
| | |
| | | |
| | | .pie-background { |
| | | position: absolute; |
| | | left: 25%; |
| | | top: 50%; |
| | | transform: translate(-51.5%, -50%); |
| | | width: 310px; |
| | | height: 310px; |
| | | background-image: url('@/assets/BI/ç«ç°å¾è¾¹æ¡.png'); |
| | |
| | | background-repeat: no-repeat; |
| | | z-index: 1; |
| | | pointer-events: none; |
| | | /* ä½ç½®ç± JS å¨æè®¾ç½®ï¼é»è®¤å±
ä¸ */ |
| | | left: 25%; |
| | | top: 50%; |
| | | transform: translate(-51.5%, -50%); |
| | | } |
| | | </style> |
| | |
| | | <PanelHeader title="éå®ååå¸" /> |
| | | <div class="main-panel panel-item-customers"> |
| | | <CarouselCards :items="cardItems" :visible-count="3" /> |
| | | <div class="pie-chart-wrapper"> |
| | | <div class="pie-background"></div> |
| | | <div class="pie-chart-wrapper" ref="pieWrapperRef"> |
| | | <div class="pie-background" ref="pieBackgroundRef"></div> |
| | | <Echarts |
| | | ref="echartsRef" |
| | | :chartStyle="chartStyle" |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, onMounted, computed } from 'vue' |
| | | import { ref, onMounted, onBeforeUnmount, 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) |
| | | |
| | | /** |
| | | * @introduction ææ°ç»ä¸keyå¼ç¸åçé£ä¸é¡¹æååºæ¥ï¼ç»æä¸ä¸ªå¯¹è±¡ |
| | |
| | | |
| | | 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() |
| | | .then((res) => { |
| | |
| | | |
| | | onMounted(() => { |
| | | fetchData() |
| | | initBackground() |
| | | }) |
| | | |
| | | onBeforeUnmount(() => { |
| | | cleanupBackground() |
| | | }) |
| | | </script> |
| | | |
| | |
| | | <div> |
| | | <PanelHeader title="产å大类" /> |
| | | <div class="panel-item-customers"> |
| | | <div class="pie-chart-wrapper"> |
| | | <div class="pie-background"></div> |
| | | <div class="pie-chart-wrapper" ref="pieWrapperRef"> |
| | | <div class="pie-background" ref="pieBackgroundRef"></div> |
| | | <Echarts |
| | | ref="chart" |
| | | :chartStyle="chartStyle" |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, onMounted } from 'vue' |
| | | import { ref, onMounted, onBeforeUnmount } from 'vue' |
| | | import Echarts from '@/components/Echarts/echarts.vue' |
| | | import PanelHeader from '../PanelHeader.vue' |
| | | import { productCategoryDistribution } 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([]) |
| | |
| | | textStyle: { color: '#B8C8E0' }, |
| | | } |
| | | |
| | | // 使ç¨å°è£
çèæ¯ä½ç½®è°æ´æ¹æ³ï¼å¯èªå®ä¹åç§»å¼ |
| | | const { adjustBackgroundPosition, init: initBackground, cleanup: cleanupBackground } = useChartBackground({ |
| | | wrapperRef: pieWrapperRef, |
| | | backgroundRef: pieBackgroundRef, |
| | | offsetX: '-51.5%', // X è½´åç§»ï¼å¯å¨æè°æ´ |
| | | offsetY: '-39%', // Y è½´åç§»ï¼å¯å¨æè°æ´ |
| | | watchData: dataList // ç嬿°æ®ååï¼èªå¨è°æ´ä½ç½® |
| | | }) |
| | | |
| | | const loadData = async () => { |
| | | try { |
| | | const res = await productCategoryDistribution() |
| | |
| | | })) |
| | | landLegend.data = dataList.value.map((d) => d.name) |
| | | landSeries.value[0].data = dataList.value |
| | | // æ°æ®å è½½å®æåè°æ´èæ¯ä½ç½® |
| | | adjustBackgroundPosition() |
| | | } catch (e) { |
| | | console.error('è·å产å大类åå¸å¤±è´¥:', e) |
| | | dataList.value = [] |
| | |
| | | } |
| | | } |
| | | |
| | | |
| | | onMounted(() => { |
| | | loadData() |
| | | initBackground() |
| | | }) |
| | | |
| | | onBeforeUnmount(() => { |
| | | cleanupBackground() |
| | | }) |
| | | </script> |
| | | |
| | |
| | | |
| | | .pie-background { |
| | | position: absolute; |
| | | left: 50%; |
| | | top: 50%; |
| | | transform: translate(-51.5%, -39%); |
| | | width: 360px; |
| | | height: 360px; |
| | | background-image: url('@/assets/BI/ç«ç°å¾è¾¹æ¡.png'); |
| | |
| | | background-repeat: no-repeat; |
| | | z-index: 1; |
| | | pointer-events: none; |
| | | /* é»è®¤å±
ä¸ï¼ä¼å¨ JS ä¸å¨æè°æ´ */ |
| | | left: 50%; |
| | | top: 50%; |
| | | transform: translate(-51.5%, -39%); |
| | | } |
| | | </style> |
| | |
| | | /> |
| | | </div> |
| | | <!-- <CarouselCards :items="cardItems" :visible-count="3" /> --> |
| | | <div class="pie-chart-wrapper"> |
| | | <div class="pie-background"></div> |
| | | <div class="pie-chart-wrapper" ref="pieWrapperRef"> |
| | | <div class="pie-background" ref="pieBackgroundRef"></div> |
| | | <Echarts |
| | | ref="chart" |
| | | :chartStyle="chartStyle" |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, onMounted, computed } from 'vue' |
| | | import { ref, onMounted, onBeforeUnmount, computed } from 'vue' |
| | | import Echarts from '@/components/Echarts/echarts.vue' |
| | | import PanelHeader from './PanelHeader.vue' |
| | | import ProductTypeSwitch from './ProductTypeSwitch.vue' |
| | | import { expenseCompositionAnalysis } from '@/api/viewIndex.js' |
| | | import { useChartBackground } from '@/hooks/useChartBackground.js' |
| | | |
| | | const pieWrapperRef = ref(null) |
| | | const pieBackgroundRef = ref(null) |
| | | |
| | | /** |
| | | * @introduction ææ°ç»ä¸keyå¼ç¸åçé£ä¸é¡¹æååºæ¥ï¼ç»æä¸ä¸ªå¯¹è±¡ |
| | |
| | | textStyle: { color: '#B8C8E0' }, |
| | | } |
| | | |
| | | // 使ç¨å°è£
çèæ¯ä½ç½®è°æ´æ¹æ³ |
| | | // å¾è¡¨ä¸å¿æ¯ ['25%', '50%']ï¼èæ¯éè¦å¯¹é½å°è¿ä¸ªä½ç½® |
| | | 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: dataList // ç嬿°æ®ååï¼èªå¨è°æ´ä½ç½® |
| | | }) |
| | | |
| | | const fetchData = () => { |
| | | expenseCompositionAnalysis({ type: amountType.value }) |
| | | .then((res) => { |
| | |
| | | |
| | | onMounted(() => { |
| | | fetchData() |
| | | initBackground() |
| | | }) |
| | | |
| | | onBeforeUnmount(() => { |
| | | cleanupBackground() |
| | | }) |
| | | </script> |
| | | |
| | |
| | | |
| | | .pie-background { |
| | | position: absolute; |
| | | left: 25%; |
| | | top: 50%; |
| | | transform: translate(-51.5%, -50%); |
| | | width: 310px; |
| | | height: 310px; |
| | | background-image: url('@/assets/BI/ç«ç°å¾è¾¹æ¡.png'); |
| | |
| | | background-repeat: no-repeat; |
| | | z-index: 1; |
| | | pointer-events: none; |
| | | /* ä½ç½®ç± JS å¨æè®¾ç½®ï¼é»è®¤å±
ä¸ */ |
| | | left: 25%; |
| | | top: 50%; |
| | | transform: translate(-51.5%, -50%); |
| | | } |
| | | </style> |
| | |
| | | <div class="filters-row"> |
| | | <DateTypeSwitch v-model="dateType" @change="handleDateTypeChange" /> |
| | | </div> |
| | | <div class="pie-chart-wrapper"> |
| | | <div class="pie-background"></div> |
| | | <div class="pie-chart-wrapper" ref="pieWrapperRef"> |
| | | <div class="pie-background" ref="pieBackgroundRef"></div> |
| | | <Echarts |
| | | ref="echartsRef" |
| | | :chartStyle="chartStyle" |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, onMounted, computed } from 'vue' |
| | | import { ref, onMounted, onBeforeUnmount, computed } from 'vue' |
| | | import { productSalesAnalysis } from '@/api/viewIndex.js' |
| | | import PanelHeader from './PanelHeader.vue' |
| | | import Echarts from '@/components/Echarts/echarts.vue' |
| | | import DateTypeSwitch from '@/views/reportAnalysis/financialAnalysis/components/DateTypeSwitch.vue' |
| | | import { useChartBackground } from '@/hooks/useChartBackground.js' |
| | | |
| | | const pieWrapperRef = ref(null) |
| | | const pieBackgroundRef = ref(null) |
| | | |
| | | const dateType = ref(1) // 1=å¨ 2=æ 3=å£åº¦ |
| | | |
| | |
| | | textStyle: { color: '#B8C8E0' }, |
| | | } |
| | | |
| | | // 使ç¨å°è£
çèæ¯ä½ç½®è°æ´æ¹æ³ |
| | | // å¾è¡¨ä¸å¿æ¯ ['25%', '50%']ï¼èæ¯éè¦å¯¹é½å°è¿ä¸ªä½ç½® |
| | | 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() |
| | | .then((res) => { |
| | |
| | | |
| | | onMounted(() => { |
| | | fetchData() |
| | | initBackground() |
| | | }) |
| | | |
| | | onBeforeUnmount(() => { |
| | | cleanupBackground() |
| | | }) |
| | | </script> |
| | | |
| | |
| | | |
| | | .pie-background { |
| | | position: absolute; |
| | | left: 25%; |
| | | top: 50%; |
| | | transform: translate(-51.5%, -50%); |
| | | width: 310px; |
| | | height: 310px; |
| | | background-image: url('@/assets/BI/ç«ç°å¾è¾¹æ¡.png'); |
| | |
| | | background-repeat: no-repeat; |
| | | z-index: 1; |
| | | pointer-events: none; |
| | | /* ä½ç½®ç± JS å¨æè®¾ç½®ï¼é»è®¤å±
ä¸ */ |
| | | left: 25%; |
| | | top: 50%; |
| | | transform: translate(-51.5%, -50%); |
| | | } |
| | | </style> |