src/views/reportAnalysis/dataDashboard/components/basic/left-top.vue
@@ -2,8 +2,8 @@
  <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"
@@ -21,10 +21,15 @@
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { ref, onMounted, onBeforeUnmount, inject, watch } 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([])
@@ -170,6 +175,15 @@
  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()
@@ -182,6 +196,8 @@
    }))
    landLegend.data = dataList.value.map((d) => d.name)
    landSeries.value[0].data = dataList.value
    // 数据加载完成后调整背景位置
    adjustBackgroundPosition()
  } catch (e) {
    console.error('获取产品大类分布失败:', e)
    dataList.value = []
@@ -190,8 +206,21 @@
  }
}
const dataDashboardRefreshTick = inject('dataDashboardRefreshTick', null)
if (dataDashboardRefreshTick) {
  watch(dataDashboardRefreshTick, () => {
    loadData()
  })
}
onMounted(() => {
  loadData()
  initBackground()
})
onBeforeUnmount(() => {
  cleanupBackground()
})
</script>
@@ -201,6 +230,32 @@
  padding: 18px;
  width: 100%;
  height: 420px;
  position: relative;
  overflow: hidden;
}
/* 面板角落装饰 */
.panel-item-customers::before,
.panel-item-customers::after {
  content: '';
  position: absolute;
  width: 15px;
  height: 15px;
  border-color: rgba(0, 212, 255, 0.5);
  border-style: solid;
  pointer-events: none;
}
.panel-item-customers::before {
  top: -1px;
  left: -1px;
  border-width: 2px 0 0 2px;
}
.panel-item-customers::after {
  bottom: -1px;
  right: -1px;
  border-width: 0 2px 2px 0;
}
.pie-chart-wrapper {
@@ -208,13 +263,16 @@
  width: 100%;
  height: 320px;
  background: transparent;
  animation: pieFloat 4s ease-in-out infinite;
}
@keyframes pieFloat {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-3px); }
}
.pie-background {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-51.5%, -39%);
  width: 360px;
  height: 360px;
  background-image: url('@/assets/BI/玫瑰图边框.png');
@@ -223,5 +281,15 @@
  background-repeat: no-repeat;
  z-index: 1;
  pointer-events: none;
  /* 默认居中,会在 JS 中动态调整 */
  left: 50%;
  top: 50%;
  transform: translate(-51.5%, -39%);
  animation: pieBgRotate 30s linear infinite;
}
@keyframes pieBgRotate {
  from { transform: translate(-51.5%, -39%) rotate(0deg); }
  to { transform: translate(-51.5%, -39%) rotate(360deg); }
}
</style>