Преглед изворни кода

还原DynamicDonuChart的代码;修改状态监控页面的弹窗大小来显示全部的圆饼图;

画安 пре 3 дана
родитељ
комит
9a0afd7489

+ 1 - 1
src/components/ui/DeviceStatusPanel.vue

@@ -96,6 +96,6 @@ export default {
   height: 100%;
   display: flex;
   flex-direction: column;
-  box-sizing: border-box;
+  /* box-sizing: border-box; */
 }
 </style>

+ 49 - 97
src/components/ui/DynamicDonutChart.vue

@@ -1,12 +1,5 @@
 <template>
-    <div 
-        class="donut-chart-wrapper" 
-        :style="{ 
-            height: finalHeight, 
-            width: finalWidth,
-            '--chart-scale': scale 
-        }"
-    >
+    <div class="donut-chart-wrapper">
         <div class="custom-legend">
             <div class="legend-box" v-for="(item, index) in chartData" :key="index">
                 <span class="color-dot" :style="{ backgroundColor: item.color }"></span>
@@ -20,79 +13,44 @@
 
 <script>
 import * as echarts from 'echarts';
-import echartsResize from '@/mixins/echartsResize.js';
+// 1. 引入你的全局自适应 Mixin 和像素转换工具
+import echartsResize, { px2echarts } from '@/mixins/echartsResize.js';
 
 export default {
     name: 'DynamicDonutChart',
+    // 2. 注册混入,自动接管自适应逻辑
     mixins: [echartsResize],
     props: {
+        // 传入的图表数据:[{ name: '正常', value: 425, color: '#32F6F8' }, ...]
         chartData: {
             type: Array,
             required: true
         },
+        // 圆环中间的大字(如 98%)
         centerTitle: {
             type: String,
             default: ''
         },
+        // 圆环中间的小字(如 980/1000)
         centerSubTitle: {
             type: String,
             default: ''
-        },
-        // 默认高度 163px
-        customHeight: {
-            type: [String, Number],
-            default: '163px'
-        },
-        // 默认宽度为空,用于判断用户是否传入
-        customWidth: {
-            type: [String, Number],
-            default: ''
-        }
-    },
-    computed: {
-        // 解析传入的高度数值
-        parsedHeight() {
-            return this.getPxValue(this.customHeight) || 163;
-        },
-        // 解析或计算宽度数值
-        parsedWidth() {
-            // 如果用户传入了宽度,直接解析
-            if (this.customWidth) {
-                return this.getPxValue(this.customWidth) || 376;
-            }
-            // 【核心逻辑】:如果只传入高度,根据默认比例 (376 / 163) 自动计算宽度
-            return this.parsedHeight * (376 / 163);
-        },
-        // 最终绑定到 style 的高度
-        finalHeight() {
-            return this.formatSize(this.customHeight, this.parsedHeight);
-        },
-        // 最终绑定到 style 的宽度
-        finalWidth() {
-            return this.customWidth 
-                ? this.formatSize(this.customWidth, this.parsedWidth)
-                : `${this.parsedWidth}px`;
-        },
-        // 【核心计算】:计算缩放因子
-        scale() {
-            const scaleW = this.parsedWidth / 376;
-            const scaleH = this.parsedHeight / 163;
-            
-            // 按照宽高比来等比例缩放:取宽、高中缩放比例较小的一个
-            // 这样能保证内容完整包裹在设定的宽高内而不发生溢出或变形
-            return Math.min(scaleW, scaleH);
         }
     },
     watch: {
+        // 深度监听数组变化,触发重绘
         chartData: {
             deep: true,
             handler() {
                 this.$nextTick(() => {
-                    if (this.$_chart) this.$_chart.resize();
+                    if (this.$_chart) {
+                        this.$_chart.resize(); // 在更新数据前,先强制重算尺寸
+                    }
                     this.updateChart();
                 });
             }
         },
+        // 监听标题变化
         centerTitle() {
             this.$nextTick(() => {
                 if (this.$_chart) this.$_chart.resize();
@@ -104,64 +62,54 @@ export default {
                 if (this.$_chart) this.$_chart.resize();
                 this.updateChart();
             });
-        },
-        // 监听缩放比例变化,触发重绘
-        scale() {
-            this.$nextTick(() => {
-                if (this.$_chart) this.$_chart.resize();
-                this.updateChart();
-            });
         }
     },
     mounted() {
         this.initChart();
     },
+    beforeDestroy() {
+        // 别忘了销毁监听器,防止内存泄漏
+        if (this.resizeObserver) {
+            this.resizeObserver.disconnect();
+        }
+        if (this.$_chart) {
+            this.$_chart.dispose();
+        }
+    },
     methods: {
-        // 提取数值的辅助函数
-        getPxValue(val) {
-            if (!val) return null;
-            if (typeof val === 'number') return val;
-            if (typeof val === 'string' && val.endsWith('px')) {
-                return parseFloat(val);
-            }
-            return null; // 无法解析(例如传入 100%)时返回 null
-        },
-        // 格式化输出 CSS 的尺寸值
-        formatSize(originalVal, parsedVal) {
-            // 如果包含 %,直接返回原始值(保留原生弹性),否则返回 px 字符串
-            if (typeof originalVal === 'string' && originalVal.includes('%')) {
-                return originalVal;
-            }
-            return `${parsedVal}px`;
-        },
         initChart() {
+            // 3. 按照 mixin 约定,将实例挂载到 this.$_chart
             this.$_chart = echarts.init(this.$refs.chartRef);
             this.updateChart();
         },
+
+        // 4. Mixin 会在窗口变化时自动静默调用此方法
         updateChart() {
             if (!this.$_chart) return;
 
             const colorPalette = this.chartData.map(item => item.color);
-            const scale = this.scale;
 
             const option = {
                 color: colorPalette,
                 title: {
+                    // 【核心改造】:使用富文本结构,用 \n 换行
                     text: `{main|${this.centerTitle}}\n{sub|${this.centerSubTitle}}`,
                     left: 'center',
                     top: 'center',
                     textStyle: {
                         rich: {
+                            // 全面使用 px2echarts 包裹尺寸数值
                             main: {
-                                fontSize: 26 * scale,
+                                fontSize: px2echarts(26),
                                 color: '#ffffff',
                                 fontWeight: 'bold',
                                 fontFamily: 'Arial',
-                                padding: [0, 0, 6 * scale, 0]
+                                // 用 padding 的 bottom 值代替原来的 itemGap,实现精准缩放
+                                padding: [0, 0, px2echarts(6), 0]
                             },
                             sub: {
-                                fontSize: 14 * scale,
-                                lineHeight: 18 * scale,
+                                fontSize: px2echarts(14),
+                                lineHeight: px2echarts(18),
                                 color: '#cccccc'
                             }
                         }
@@ -170,6 +118,8 @@ export default {
                 series: [
                     {
                         type: 'pie',
+                        // 半径原则上也可以写成具体像素如 [px2echarts(60), px2echarts(80)]
+                        // 但写成百分比原生就自带外层容器的自适应,通常保留百分比即可
                         radius: ['60%', '80%'],
                         center: ['50%', '50%'],
                         avoidLabelOverlap: false,
@@ -188,47 +138,49 @@ export default {
 
 <style scoped>
 .donut-chart-wrapper {
-    --chart-scale: 1; 
     display: flex;
     align-items: center;
-    /* 取消写死的 100%,由内联 style 动态接管 */
+    width: 100%;
+    height: 100%;
 }
 
+/* 左侧图例样式 */
 .custom-legend {
     display: flex;
     flex-direction: column;
     justify-content: center;
-    gap: calc(12px * var(--chart-scale));
+    gap: 12px;
     width: 35%;
-    margin-right: calc(8px * var(--chart-scale));
+    margin-right: 8px;
 }
 
 .legend-box {
     display: flex;
     align-items: center;
-    background: linear-gradient(90deg, #2D426C 0%, rgba(45,66,108,0) 100%);
-    height: calc(40px * var(--chart-scale));
+    background: linear-gradient( 90deg, #2D426C 0%, rgba(45,66,108,0) 100%);
+    height: 40px;
 }
 
 .color-dot {
-    width: calc(8px * var(--chart-scale));
-    height: calc(8px * var(--chart-scale));
-    margin-right: calc(8px * var(--chart-scale));
-    margin-left: calc(16px * var(--chart-scale));
+    width: 8px;
+    height: 8px;
+    margin-right: 8px;
+    margin-left: 16px;
     flex-shrink: 0;
-    border-radius: calc(2px * var(--chart-scale));
+    border-radius: 2px;
 }
 
 .legend-name {
     font-weight: 400;
-    font-size: calc(12px * var(--chart-scale));
+    font-size: 12px;
     color: rgba(255, 255, 255, 0.60);
-    line-height: calc(18px * var(--chart-scale));
+    line-height: 18px;
 }
 
+/* 右侧图表样式 */
 .echarts-container {
     width: 65%;
     height: 100%;
-    min-height: 0;
+    min-height: 160px;
 }
 </style>

+ 3 - 3
src/views/Home.vue

@@ -60,15 +60,15 @@
             <TechTabs v-model="onlineStatusActiveTab" type="segmented" autoPlay @tab-click="handleTabClick">
               <TechTabPane label="信号机" name="signalMachine" style="height: 100%;">
                 <DynamicDonutChart v-if="onlineStatusDisplayData" :chartData="onlineStatusDisplayData.chartData"
-                  :centerTitle="onlineStatusDisplayData.centerTitle" :centerSubTitle="onlineStatusDisplayData.centerSubTitle" customHeight="163px"/>
+                  :centerTitle="onlineStatusDisplayData.centerTitle" :centerSubTitle="onlineStatusDisplayData.centerSubTitle"/>
               </TechTabPane>
               <TechTabPane label="检测器" name="detector">
                 <DynamicDonutChart v-if="onlineStatusDisplayData" :chartData="onlineStatusDisplayData.chartData"
-                  :centerTitle="onlineStatusDisplayData.centerTitle" :centerSubTitle="onlineStatusDisplayData.centerSubTitle" customHeight="163px"/>
+                  :centerTitle="onlineStatusDisplayData.centerTitle" :centerSubTitle="onlineStatusDisplayData.centerSubTitle"/>
               </TechTabPane>
               <TechTabPane label="红路灯" name="trafficLight">
                 <DynamicDonutChart v-if="onlineStatusDisplayData" :chartData="onlineStatusDisplayData.chartData"
-                  :centerTitle="onlineStatusDisplayData.centerTitle" :centerSubTitle="onlineStatusDisplayData.centerSubTitle" customHeight="163px"/>
+                  :centerTitle="onlineStatusDisplayData.centerTitle" :centerSubTitle="onlineStatusDisplayData.centerSubTitle"/>
               </TechTabPane>
             </TechTabs>
   

+ 2 - 4
src/views/StatusMonitoring.vue

@@ -254,8 +254,6 @@ export default {
                 showClose: config.showClose !== false, // 是否显示关闭按钮
                 data: config.data || {}            // 传给内部组件的业务数据
             });
-
-            window.dispatchEvent(new Event('resize'));
         },
 
         /**
@@ -275,7 +273,7 @@ export default {
                 title: '',
                 component: 'DeviceStatusPanel', // 对应 components 里注册的名字
                 width: 300,
-                height: 200,
+                height: 240,
                 center: false,
                 position: { x: 400, y: 200 }, // 直接指定坐标,SmartDialog 内部会自动转换成 left/top
                 showClose: false, // 是否显示关闭按钮
@@ -286,7 +284,7 @@ export default {
                 title: '',
                 component: 'DeviceStatusPanel', // 对应 components 里注册的名字
                 width: 300,
-                height: 200,
+                height: 240,
                 center: false,
                 position: { x: 1600, y: 100 }, // 直接指定坐标,SmartDialog 内部会自动转换成 left/top
                 showClose: false, // 是否显示关闭按钮