| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178 |
- <template>
- <div class="chart-wrapper">
- <div class="echarts-container" ref="chartRef"></div>
- <div class="custom-legend">
- <div class="legend-item">
- <span class="dot dot-online"></span>
- <span class="label">在线</span>
- </div>
- <div class="legend-item">
- <span class="dot dot-offline"></span>
- <span class="label">离线</span>
- </div>
- </div>
- </div>
- </template>
- <script>
- import * as echarts from 'echarts';
- // 设定设计稿基准宽度 (与你大屏的设计稿尺寸一致)
- const DESIGN_WIDTH = 1920;
- export default {
- name: 'DeviceDonutChart',
- props: {
- online: { type: Number, required: true },
- total: { type: Number, required: true }
- },
- data() {
- return {
- chart: null,
- resizeTimer: null
- };
- },
- computed: {
- offline() {
- return this.total - this.online;
- },
- percent() {
- return this.total === 0 ? 0 : Math.round((this.online / this.total) * 100);
- }
- },
- watch: {
- online() { this.updateChart(); },
- total() { this.updateChart(); }
- },
- mounted() {
- this.initChart();
- // 监听窗口大小变化
- window.addEventListener('resize', this.handleResize);
- },
- beforeDestroy() {
- window.removeEventListener('resize', this.handleResize);
- if (this.chart) {
- this.chart.dispose();
- this.chart = null;
- }
- },
- methods: {
- // 1. 【新增】:获取当前屏幕真实的缩放比例
- getRealScale() {
- return window.innerWidth / DESIGN_WIDTH;
- },
- initChart() {
- this.chart = echarts.init(this.$refs.chartRef);
- this.updateChart();
- },
- updateChart() {
- if (!this.chart) return;
- // 2. 【新增】:每次更新图表时,获取最新的缩放比例
- const scale = this.getRealScale();
- const option = {
- title: {
- text: `{percent|${this.percent}%}\n{count|${this.online}/${this.total}}`,
- left: 'center',
- top: 'center',
- textStyle: {
- rich: {
- // 3. 【核心修复】:将原本写死的字体大小(28, 14)和边距乘以 scale!
- // 使用 Math.round 保证字体像素是整数,渲染更清晰
- percent: {
- fontSize: Math.round(28 * scale),
- color: '#ffffff',
- fontWeight: 'bold',
- padding: [0, 0, Math.round(8 * scale), 0]
- },
- count: {
- fontSize: Math.round(14 * scale),
- color: '#e2e8f0'
- }
- }
- }
- },
- series: [
- {
- type: 'pie',
- radius: ['65%', '85%'],
- center: ['50%', '50%'],
- avoidLabelOverlap: false,
- label: { show: false },
- labelLine: { show: false },
- data: [
- { value: this.online, name: '在线', itemStyle: { color: '#33ccff' } },
- { value: this.offline, name: '离线', itemStyle: { color: '#ff7744' } }
- ]
- }
- ]
- };
-
- this.chart.setOption(option);
- },
- handleResize() {
- if (this.resizeTimer) clearTimeout(this.resizeTimer);
- this.resizeTimer = setTimeout(() => {
- if (this.chart) {
- // 4. 【核心修复】:窗口缩放时,不仅要重置 Canvas 画布大小
- this.chart.resize();
- // 还要重新执行 updateChart 触发 setOption,这样新计算出来的 scale 字体才能生效!
- this.updateChart();
- }
- }, 100);
- }
- }
- };
- </script>
- <style scoped>
- /* ================== CSS 部分无需修改,由于你使用了 postcss-pxtorem,这里的 px 会自动转为 rem 并自适应 ================== */
- .chart-wrapper {
- display: flex;
- align-items: center;
- width: 100%;
- height: 100%;
- }
- .echarts-container {
- flex: 1;
- height: 100%;
- min-height: 160px;
- }
- .custom-legend {
- width: 120px;
- display: flex;
- flex-direction: column;
- justify-content: center;
- gap: 15px;
- margin-right: 10px;
- }
- .legend-item {
- display: flex;
- align-items: center;
- background: rgba(255, 255, 255, 0.08);
- padding: 8px 15px;
- border-radius: 2px;
- }
- .dot {
- width: 8px;
- height: 8px;
- border-radius: 2px;
- margin-right: 10px;
- }
- .dot-online { background-color: #33ccff; }
- .dot-offline { background-color: #ff7744; }
- .label {
- color: #c0c4cc;
- font-size: 13px;
- }
- </style>
|