helongyang
5 天以前 753361f589444455fe1b20476c658201ccd92c38
´úÂë¹ÜÀí/LargeScreen/CP-Screen/src/views/indexs/station-two.vue
@@ -1,289 +1,97 @@
<template>
  <div class="tech-chart-container">
    <Echart
      :options="options"
      :autoresize="true"
      style="width: 100%; height: 100%"
    />
  <div id="name" style="width: 100%; height: 100%">
    <!-- æ¸²æŸ“ ECharts é¥¼å›¾ -->
    <Echart :options="options" style="width: 100%; height: 100%"></Echart>
  </div>
</template>
<script>
import { currentGET } from "api/modules";
import { GetCPLargeStockCount } from "@/api/http.js";
import * as echarts from 'echarts';
export default {
  data() {
    return {
      options: {
        backgroundColor: 'transparent',
        title: {
          text: '成品产品库存总数',
          subtext: '加载中...',
          textStyle: {
            color: '#00b5f3',
            fontSize: 14,
          },
          subtextStyle: {
            align: 'center',
            fontSize: 28,
            color: '#4be1ff',
            fontWeight: 'bold',
            textShadow: '0 0 15px rgba(75, 225, 255, 0.7)'
          },
          x: 'center',
          y: 'center',
        },
        tooltip: {
          show: false // å®Œå…¨ç¦ç”¨tooltip
        },
        series: [
          {
            name: '库存数量',
            type: 'pie',
            radius: ['65%', '85%'],
            center: ['50%', '50%'],
            hoverAnimation: false, // ç¦ç”¨æ‚¬åœåŠ¨ç”»
            silent: true, // ç¦ç”¨æ‰€æœ‰äº¤äº’
            label: {
              show: false
            },
            labelLine: {
              show: false
            },
            itemStyle: {
              borderWidth: 0,
              shadowBlur: 20,
              shadowColor: 'rgba(0, 150, 255, 0.5)'
            },
            data: [{
              value: 0,
              name: '',
              itemStyle: {
                // é’蓝色到蓝白色渐变,添加动态效果
                color: {
                  type: 'linear',
                  x: 0,
                  y: 0,
                  x2: 0,
                  y2: 1,
                  colorStops: [
                    { offset: 0, color: '#00ffcc' },
                    { offset: 0.5, color: '#00b4ff' },
                    { offset: 1, color: '#0062ff' }
                  ],
                  global: false
                }
              }
            }]
          },
          // æ·»åŠ å¤–å‘å…‰åœ†çŽ¯
          {
            type: 'pie',
            radius: ['85%', '87%'],
            center: ['50%', '50%'],
            hoverAnimation: false,
            silent: true,
            label: { show: false },
            labelLine: { show: false },
            itemStyle: {
              // é’蓝色到蓝白色渐变,添加动态效果
              color: {
                type: 'linear',
                x: 0,
                y: 0,
                x2: 0,
                y2: 1,
                colorStops: [
                  { offset: 0, color: '#00ffcc' },
                  { offset: 0.5, color: '#00b4ff' },
                  { offset: 1, color: '#0062ff' }
                ],
                global: false
              }
            },
            data: [{
              value: 1,
              name: ''
            }]
          },
          // æ·»åŠ å†…å‘å…‰åœ†çŽ¯
          {
            type: 'pie',
            radius: ['63%', '65%'],
            center: ['50%', '50%'],
            hoverAnimation: false,
            silent: true,
            label: { show: false },
            labelLine: { show: false },
            itemStyle: {
              // é’蓝色到蓝白色渐变,添加动态效果
              color: {
                type: 'linear',
                x: 0,
                y: 0,
                x2: 0,
                y2: 1,
                colorStops: [
                  { offset: 0, color: '#00ffcc' },
                  { offset: 0.5, color: '#00b4ff' },
                  { offset: 1, color: '#0062ff' }
                ],
                global: false
              }
            },
            data: [{
              value: 1,
              name: ''
            }]
          },
          // æ·»åŠ åŠ¨æ€ç²’å­æ•ˆæžœ
          {
            type: 'scatter',
            coordinateSystem: 'none',
            data: this.generateParticles(30),
            symbolSize: (val) => {
              return val[2] * 2;
            },
            itemStyle: {
              color: new echarts.graphic.RadialGradient(0.4, 0.3, 1, [
                { offset: 0, color: 'rgba(0, 255, 255, 0.8)' },
                { offset: 1, color: 'rgba(0, 255, 255, 0)' }
              ])
            },
            // æ·»åŠ ç²’å­é—ªçƒæ•ˆæžœ
            effect: {
              show: true,
              period: 2,
              trailLength: 0.1,
              symbol: 'circle',
              symbolSize: 0
            }
          }
        ]
      },
      timer: null,
      particleTimer: null,
      gradientTimer: null
      pageflag: true,
      options: {}, // å­˜å‚¨ ECharts é…ç½®
      timer: null // å®šæ—¶å™¨æ ‡è¯†
    };
  },
  mounted() {
    this.fetchData();
    this.startAutoRefresh();
    this.startParticleAnimation();
    this.startGradientAnimation();
  },
  beforeDestroy() {
    this.stopAutoRefresh();
    this.stopParticleAnimation();
    this.stopGradientAnimation();
  created() {
    this.getData();
  },
  methods: {
    generateParticles(count) {
      const particles = [];
      for (let i = 0; i < count; i++) {
        const angle = Math.random() * Math.PI * 2;
        const radius = 0.7 + Math.random() * 0.2;
        particles.push([
          Math.cos(angle) * radius,
          Math.sin(angle) * radius,
          Math.random() * 2 + 1
        ]);
      }
      return particles;
    async getData() {
      const rep = await GetCPLargeStockCount();
      // ç»„装饼图数据:[{value: æ•°é‡, name: äº§å“ç¼–码}, ...]
      const pieData = rep.map(item => ({
        value: item.qtys,
        name: item.pCode
      }));
      // è®¡ç®—总和,用于计算百分比
      const total = pieData.reduce((acc, cur) => acc + cur.value, 0);
      // é…ç½® ECharts é¥¼å›¾
      this.options = {
        backgroundColor: '#000',
        tooltip: {
          trigger: 'item', // é¼ æ ‡æ‚¬æµ®æç¤ºï¼Œè§¦å‘方式为“item”(针对饼图扇区)
        },
        series: [
          {
            name: '客户代码',
            type: 'pie',
            radius: ['40%', '70%'], // é¥¼å›¾å†…外半径,实现环形/扇形效果
            center: ['50%', '50%'], // é¥¼å›¾åœ¨å®¹å™¨ä¸­çš„中心位置
            color: [
              'rgba(135,183,255, 1)', // å¯¹åº”示例饼图颜色,可按需调整
              'rgba(248,195,248, 1)',
              'rgba(100,255,249, 1)',
              'rgba(100,255,249, 1)',
              'rgba(248,195,248, 1)'
            ],
            label: {
              show: true,
              position: 'outside',
              textStyle: {
                color: '#b3ccf8',
                fontSize: 14,
                fontFamily: 'PingFangSC-Regular'
              },
              // æ ¼å¼åŒ–标签,显示名称和百分比
              formatter: (params) => {
                const percent = ((params.value / total) * 100).toFixed(2) + '%';
                return `${params.name}\n${percent}`;
              }
            },
            data: pieData,
          },
        ],
      };
    },
    async fetchData() {
      try {
        const response = await GetCPLargeStockCount({});
        const stockCount = response.stockCount || 0;
        this.updateChart(stockCount);
      } catch (error) {
        console.error('获取库存总数失败:', error);
        this.options.title.subtext = '数据异常';
        this.options.title.subtextStyle.color = '#ff4d4f';
      }
    // è½®è¯¢ï¼ˆæ¯éš”一天请求一次数据)
    switper() {
      if (this.timer) return;
      // æ¯éš”一天(86400000 æ¯«ç§’)执行一次 getData
      this.timer = setInterval(() => {
        this.getData();
      }, 86400000);
    },
    updateChart(count) {
      this.options.series[0].data[0].value = count;
      this.options.title.subtext = count + '种';
      this.options.title.subtextStyle.color = count > 0? '#4be1ff' : '#ff4d4f';
    },
    startAutoRefresh() {
      this.stopAutoRefresh();
      this.timer = setInterval(() => {
        this.fetchData();
      }, 3000);
    },
    stopAutoRefresh() {
      if (this.timer) clearInterval(this.timer);
    },
    startParticleAnimation() {
      this.stopParticleAnimation();
      this.particleTimer = setInterval(() => {
        this.options.series[3].data = this.generateParticles(30);
        this.options = {...this.options }; // è§¦å‘视图更新
      }, 2000);
    },
    stopParticleAnimation() {
      if (this.particleTimer) clearInterval(this.particleTimer);
    },
    startGradientAnimation() {
      this.stopGradientAnimation();
      this.gradientTimer = setInterval(() => {
        const offset = Math.random();
        this.options.series.forEach(series => {
          if (series.itemStyle.color.type === 'linear') {
            series.itemStyle.color.colorStops.forEach(stop => {
              stop.offset = (stop.offset + offset) % 1;
            });
          }
        });
        this.options = {...this.options }; // è§¦å‘视图更新
      }, 1000);
    },
    stopGradientAnimation() {
      if (this.gradientTimer) clearInterval(this.gradientTimer);
  },
  beforeDestroy() {
    // ç»„件销毁时清除定时器
    if (this.timer) {
      clearInterval(this.timer);
      this.timer = null;
    }
  },
  mounted() {
    this.switper(); // æŒ‚载后启动定时器
  }
};
</script>
<style lang="scss" scoped>
.tech-chart-container {
  width: 100%;
  height: 100%;
  position: relative;
  background: radial-gradient(circle at center, #021228 0%, #000810 100%);
  border-radius: 8px;
  overflow: hidden;
  box-shadow: 0 0 30px rgba(0, 100, 255, 0.2);
  &::before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background:
      radial-gradient(circle at 20% 30%, rgba(0, 150, 255, 0.1) 0%, transparent 50%),
      radial-gradient(circle at 80% 70%, rgba(0, 200, 255, 0.1) 0%, transparent 50%);
    z-index: 0;
    animation: pulse 8s infinite alternate;
  }
}
@keyframes pulse {
  0% {
    opacity: 0.3;
  }
  100% {
    opacity: 0.7;
  }
}
::v-deep .echarts {
  position: relative;
  z-index: 1;
}
<style lang='scss' scoped>
/* è‹¥æ— éœ€ç‰¹æ®Šæ ·å¼ï¼Œå¯ç®€åŒ–或删除 */
</style>