refactor: migrate charts from echarts to @antv/g2 and drop legacy vite plugins for vite 8

This commit is contained in:
pnoker
2026-04-29 22:51:24 +08:00
parent b9d00b9f57
commit 4c7ad46d4f
10 changed files with 89 additions and 1685 deletions
+1 -7
View File
@@ -47,7 +47,7 @@
"@tauri-apps/plugin-shell": "^2.3.5",
"axios": "^1.15.2",
"clipboard": "^2.0.11",
"echarts": "^6.0.0",
"dayjs": "^1.11.20",
"element-plus": "^2.13.7",
"highlight.js": "^11.11.1",
"js-base64": "^3.7.8",
@@ -56,7 +56,6 @@
"json-bigint": "^1.0.0",
"marked": "^18.0.2",
"mitt": "^3.0.1",
"moment": "^2.30.1",
"nprogress": "^0.2.0",
"pinia": "^3.0.4",
"screenfull": "^6.0.2",
@@ -72,11 +71,8 @@
"@types/nprogress": "^0.2.3",
"@typescript-eslint/eslint-plugin": "^8.59.1",
"@typescript-eslint/parser": "^8.59.1",
"@vitejs/plugin-legacy": "^8.0.1",
"@vitejs/plugin-vue": "^6.0.6",
"@vue/eslint-config-typescript": "^14.7.0",
"core-js": "^3.49.0",
"dotenv": "^17.4.2",
"eslint": "^10.2.1",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-prettier": "^5.5.5",
@@ -84,10 +80,8 @@
"globals": "^17.5.0",
"husky": "^9.1.7",
"lint-staged": "^16.4.0",
"minimist": "^1.2.8",
"prettier": "^3.8.3",
"sass": "^1.99.0",
"terser": "^5.46.2",
"typescript": "~6.0.3",
"unplugin-auto-import": "^21.0.0",
"unplugin-vue-components": "^32.0.0",
+12 -1455
View File
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -30,16 +30,16 @@
</el-menu-item>
<template v-for="menusItem in menus">
<el-sub-menu v-if="menusItem.children" :key="`${menusItem.path}-submenu`" :index="menusItem.path">
<template #title>{{ (menusItem.meta as any).title }}</template>
<template #title>{{ menusItem.meta?.title }}</template>
<el-menu-item v-for="item in menusItem.children" :key="item.path" :index="item.path">
{{ (item.meta as any).title }}
{{ item.meta?.title }}
</el-menu-item>
</el-sub-menu>
<el-menu-item v-else :key="`${menusItem.path}-menuitem`" :index="menusItem.path">
<el-icon>
<component :is="(menusItem.meta as any).icon"></component>
<component :is="menusItem.meta?.icon"></component>
</el-icon>
{{ (menusItem.meta as any).title }}
{{ menusItem.meta?.title }}
</el-menu-item>
</template>
</el-menu>
+30
View File
@@ -0,0 +1,30 @@
/*
* Copyright 2016-present the IoT DC3 original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Augment vue-router's RouteMeta so route definitions under src/config/router/**
// can use `meta: { title, icon }` with full type-checking.
import 'vue-router';
declare module 'vue-router' {
interface RouteMeta {
/** Page title used in document.title and menu labels */
title?: string;
/** Global Element Plus icon name (e.g. 'Promotion', 'List') used in the nav menu */
icon?: string;
}
}
export {};
-5
View File
@@ -14,11 +14,6 @@
* limitations under the License.
*/
import moment from 'moment';
import 'moment/locale/zh-cn';
moment.locale('zh-cn');
/**
* Format timestamp to date string
*
+4 -7
View File
@@ -14,10 +14,7 @@
* limitations under the License.
*/
import moment from 'moment';
import 'moment/locale/zh-cn';
moment.locale('zh-cn');
import dayjs from 'dayjs';
/**
* Log utility with timestamp and color-coded levels
@@ -29,7 +26,7 @@ export const log = {
* @param message Message to log
*/
info(message: string) {
const now = moment().format('YYYY-MM-DD HH:mm:ss.SSS');
const now = dayjs().format('YYYY-MM-DD HH:mm:ss.SSS');
console.log(now, '%cINFO%c --- :', 'color:#67C23A', message);
},
@@ -39,7 +36,7 @@ export const log = {
* @param message Message to log
*/
warn(message: string) {
const now = moment().format('YYYY-MM-DD HH:mm:ss.SSS');
const now = dayjs().format('YYYY-MM-DD HH:mm:ss.SSS');
console.log(now, '%cWARN%c --- :', 'color:#E6A23C', message);
},
@@ -49,7 +46,7 @@ export const log = {
* @param message Message to log
*/
error(message: string) {
const now = moment().format('YYYY-MM-DD HH:mm:ss.SSS');
const now = dayjs().format('YYYY-MM-DD HH:mm:ss.SSS');
console.log(now, '%cERROR%c --- :', 'color:#F56C6C', message);
},
};
+33 -59
View File
@@ -16,7 +16,7 @@
import { defineComponent, onMounted, reactive, ref } from 'vue';
import * as echarts from 'echarts';
import { Chart } from '@antv/g2';
import TitleCard from '@/components/card/title/TitleCard.vue';
import ApplicationCard from '@/views/application/card/ApplicationCard.vue';
@@ -238,64 +238,38 @@ export default defineComponent({
});
onMounted(() => {
const chart = echarts.init(countDataChartRef.value as HTMLElement);
reactiveData.data = reactiveData.data.map((item) => [item[1], item[0], item[2]]);
const option = {
legend: {
data: ['日/时数据量统计'],
left: 'right',
},
tooltip: {
position: 'top',
formatter: (params) => {
return (
params.value[2] +
' commits in ' +
reactiveData.hours[params.value[0]] +
' of ' +
reactiveData.days[params.value[1]]
);
},
},
grid: {
left: 2,
bottom: 10,
right: 10,
containLabel: true,
},
xAxis: {
type: 'category',
data: reactiveData.hours,
boundaryGap: false,
splitLine: {
show: true,
},
axisLine: {
show: false,
},
},
yAxis: {
type: 'category',
data: reactiveData.days,
axisLine: {
show: false,
},
},
series: [
{
name: '日/时数据量统计',
type: 'scatter',
symbolSize: (val) => {
return val[2] * 2;
},
data: reactiveData.data,
animationDelay: (idx) => {
return idx * 5;
},
},
],
};
chart.setOption(option);
const el = countDataChartRef.value as HTMLElement | null;
if (!el) return;
// Original data is [dayIndex, hourIndex, count]; turn it into labeled objects
const points = reactiveData.data
.filter(([dayIdx, hourIdx]: number[]) => dayIdx !== undefined && hourIdx !== undefined)
.map(([dayIdx, hourIdx, count]: number[]) => ({
hour: reactiveData.hours[hourIdx!],
day: reactiveData.days[dayIdx!],
count,
}));
const chart = new Chart({ container: el, autoFit: true });
chart
.point()
.data(points)
.encode('x', 'hour')
.encode('y', 'day')
.encode('size', 'count')
.scale('size', { type: 'sqrt', range: [4, 24] })
.scale('x', { padding: 0.5 })
.scale('y', { padding: 0.5 })
.style('fill', '#409eff')
.style('fillOpacity', 0.65)
.axis({ x: { title: false }, y: { title: false } })
.tooltip({
title: (d: { hour: string; day: string }) => `${d.day} ${d.hour}`,
items: [{ field: 'count', name: '数据量' }],
});
chart.render();
});
return {
-131
View File
@@ -1,131 +0,0 @@
/*
* Copyright 2016-present the IoT DC3 original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { defineComponent, onMounted, reactive } from 'vue';
import { CircleClose, Edit, Management, Sunrise, Sunset, Timer, ZoomIn } from '@element-plus/icons-vue';
import { TinyArea } from '@antv/g2plot';
import { copy } from '@/utils/CommonUtil';
import { timestamp } from '@/utils/DateUtil';
export default defineComponent({
name: 'PointValueCard',
components: {
Edit,
Sunset,
Timer,
Management,
Sunrise,
ZoomIn,
},
props: {
embedded: {
type: String,
default: () => {
return '';
},
},
data: {
type: Object,
default: () => {
return {};
},
},
device: {
type: Object,
default: () => {
return {};
},
},
point: {
type: Object,
default: () => {
return {};
},
},
unit: {
type: String,
default: '',
},
historyData: {
type: Array<number>,
default: () => {
return [];
},
},
icon: {
type: String,
default: 'images/common/point.png',
},
},
emits: ['show-edit', 'show-detail'],
setup(props, { emit }) {
// 定义响应式数据
const reactiveData = reactive({
spRefLineStyles: {
stroke: '#54a5ff',
strokeOpacity: 0.5,
strokeDasharray: '2, 2',
},
spCurveStyles: {
stroke: '#54a5ff',
},
});
// 图标
const Icon = {
CircleClose,
};
const showEdit = (pointValue) => {
emit('show-edit', pointValue);
};
const copyValue = (data) => {
const content = {
deviceId: data.deviceId,
pointId: data.pointId,
value: data.value,
};
copy(JSON.stringify(content, null, 2), '位号值');
};
onMounted(() => {
if (props.embedded == '') {
return;
}
const tinyArea = new TinyArea(props.data.pointId, {
height: 60,
data: props.historyData,
autoFit: true,
smooth: true,
});
tinyArea.render();
});
return {
reactiveData,
showEdit,
copyId: copy,
copyValue,
timestamp,
...Icon,
};
},
});
+1 -2
View File
@@ -13,9 +13,8 @@
"noUncheckedIndexedAccess": true,
"noImplicitOverride": true,
"moduleResolution": "bundler",
"baseUrl": "./",
"paths": {
"@/*": ["src/*"]
"@/*": ["./src/*"]
},
"types": ["vite/client", "element-plus/global"],
"allowSyntheticDefaultImports": true,
+4 -15
View File
@@ -14,7 +14,6 @@
* limitations under the License.
*/
import legacy from '@vitejs/plugin-legacy';
import vue from '@vitejs/plugin-vue';
import { resolve } from 'path';
import AutoImport from 'unplugin-auto-import/vite';
@@ -42,7 +41,6 @@ export default (configEnv: ConfigEnv) => {
entryFileNames: `assets/dc3.[name].[hash].js`,
chunkFileNames: `assets/dc3.[name].[hash].js`,
assetFileNames: `assets/dc3.[name].[hash].[ext]`,
compact: true,
manualChunks: (id: string) => {
if (id.includes('node_modules')) {
// Merge vue and element-plus to avoid circular dependency
@@ -52,11 +50,8 @@ export default (configEnv: ConfigEnv) => {
if (id.includes('vue-router')) {
return 'router-vendor';
}
if (id.includes('echarts')) {
return 'echarts-vendor';
}
if (id.includes('lodash')) {
return 'lodash-vendor';
if (id.includes('@antv')) {
return 'g2-vendor';
}
return 'vendor';
}
@@ -85,7 +80,7 @@ export default (configEnv: ConfigEnv) => {
build: {
outDir: 'dist',
chunkSizeWarningLimit: 1500,
minify: 'esbuild',
// minify defaults to rolldown in Vite 8
sourcemap: configEnv.mode === 'production' ? false : true,
reportCompressedSize: false,
cssCodeSplit: true,
@@ -93,12 +88,6 @@ export default (configEnv: ConfigEnv) => {
},
plugins: [
vue(),
legacy({
targets: 'defaults, not ie 11, not op_mini all',
additionalLegacyPolyfills: ['regenerator-runtime/runtime'],
renderLegacyChunks: true,
modernPolyfills: true,
}),
AutoImport({
resolvers: [ElementPlusResolver()],
imports: [
@@ -119,7 +108,7 @@ export default (configEnv: ConfigEnv) => {
}),
],
optimizeDeps: {
include: ['vue', 'vue-router', 'element-plus', '@element-plus/icons-vue', 'echarts'],
include: ['vue', 'vue-router', 'element-plus', '@element-plus/icons-vue', '@antv/g2'],
exclude: ['@vitejs/plugin-vue'],
},
css: {