feat: 解决各模块的警告和报错

dev
donghao 3 weeks ago
parent d0a2edeb6e
commit abbab281af

@ -2,7 +2,7 @@
* @Author: donghao donghao@supervision.ltd * @Author: donghao donghao@supervision.ltd
* @Date: 2025-08-14 10:33:46 * @Date: 2025-08-14 10:33:46
* @LastEditors: donghao donghao@supervision.ltd * @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2025-08-18 17:03:28 * @LastEditTime: 2025-08-20 14:35:52
* @FilePath: \5G-Web\src\components\Charts\appearanceDailyAlertChart.vue * @FilePath: \5G-Web\src\components\Charts\appearanceDailyAlertChart.vue
* @Description: 外观日告警统计 * @Description: 外观日告警统计
--> -->
@ -37,7 +37,7 @@ function initChart() {
data: [ data: [
80, 30, 120, 80, 100, 60, 70, 50, 40, 60, 110, 30, 80, 100, 120, 150, 80, 30, 120, 80, 100, 60, 70, 50, 40, 60, 110, 30, 80, 100, 120, 150,
], ],
color: "rgba(212, 145, 20, 1)", color: "rgba(212, 145, 20, 0.9)",
color1: "rgba(212, 145, 20, 0.3)", color1: "rgba(212, 145, 20, 0.3)",
}, },
{ {
@ -46,7 +46,7 @@ function initChart() {
100, 20, 220, 180, 120, 180, 100, 120, 100, 140, 160, 20, 180, 140, 80, 100, 20, 220, 180, 120, 180, 100, 120, 100, 140, 160, 20, 180, 140, 80,
170, 170,
], ],
color: "rgba(0, 157, 255, 1)", color: "rgba(0, 157, 255, 0.9)",
color1: "rgba(0, 157, 255, 0.3)", color1: "rgba(0, 157, 255, 0.3)",
}, },
{ {
@ -55,7 +55,7 @@ function initChart() {
150, 180, 200, 190, 180, 50, 80, 100, 80, 140, 120, 190, 150, 60, 100, 150, 180, 200, 190, 180, 50, 80, 100, 80, 140, 120, 190, 150, 60, 100,
120, 120,
], ],
color: "rgba(44, 188, 204, 1)", color: "rgba(44, 188, 204, 0.9)",
color1: "rgba(44, 188, 204, 0.3)", color1: "rgba(44, 188, 204, 0.3)",
}, },
{ {
@ -64,7 +64,7 @@ function initChart() {
120, 140, 180, 170, 80, 140, 130, 110, 140, 100, 100, 140, 120, 80, 140, 120, 140, 180, 170, 80, 140, 130, 110, 140, 100, 100, 140, 120, 80, 140,
140, 140,
], ],
color: "rgba(13, 233, 138, 1)", color: "rgba(13, 233, 138, 0.9)",
color1: "rgba(13, 233, 138, 0.3)", color1: "rgba(13, 233, 138, 0.3)",
}, },
{ {
@ -73,7 +73,7 @@ function initChart() {
100, 120, 80, 100, 50, 70, 150, 120, 100, 140, 60, 100, 60, 150, 120, 100, 120, 80, 100, 50, 70, 150, 120, 100, 140, 60, 100, 60, 150, 120,
170, 170,
], ],
color: "rgba(198, 81, 14, 1)", color: "rgba(198, 81, 14, 0.9)",
color1: "rgba(198, 81, 14, 0.3)", color1: "rgba(198, 81, 14, 0.3)",
}, },
{ {
@ -82,7 +82,7 @@ function initChart() {
150, 160, 180, 170, 150, 80, 100, 140, 120, 80, 140, 80, 120, 80, 100, 150, 160, 180, 170, 150, 80, 100, 140, 120, 80, 140, 80, 120, 80, 100,
150, 150,
], ],
color: "rgba(255, 209, 92, 1)", color: "rgba(255, 209, 92, 0.9)",
color1: "rgba(255, 209, 92, 0.3)", color1: "rgba(255, 209, 92, 0.3)",
}, },
]; ];
@ -95,7 +95,7 @@ function initChart() {
seriesOptions.push({ seriesOptions.push({
name: item.name, name: item.name,
type: "line", type: "line",
color: item.color1, color: item.color,
symbolSize: 9, symbolSize: 9,
symbol: "none", symbol: "none",
areaStyle: { areaStyle: {
@ -132,9 +132,6 @@ function initChart() {
right: 0, right: 0,
top: "5%", top: "5%",
icon: "rect", icon: "rect",
// itemWidth: 16,
// itemHeight: 16,
// itemGap: 32,
textStyle: { textStyle: {
fontFamily: "PingFangSC-Semibold", fontFamily: "PingFangSC-Semibold",
fontSize: 14, fontSize: 14,
@ -144,10 +141,10 @@ function initChart() {
data: legendData, data: legendData,
}, },
grid: { grid: {
top: "25%", left: "1%",
left: "2%", right: "1%",
right: "2%",
bottom: "5%", bottom: "5%",
top: "25%",
containLabel: true, containLabel: true,
}, },
xAxis: { xAxis: {

@ -2,7 +2,7 @@
* @Author: donghao donghao@supervision.ltd * @Author: donghao donghao@supervision.ltd
* @Date: 2025-08-14 10:33:22 * @Date: 2025-08-14 10:33:22
* @LastEditors: donghao donghao@supervision.ltd * @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2025-08-18 17:00:57 * @LastEditTime: 2025-08-20 16:03:07
* @FilePath: \5G-Web\src\components\Charts\appearanceDailyDetectionChart.vue * @FilePath: \5G-Web\src\components\Charts\appearanceDailyDetectionChart.vue
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
--> -->
@ -18,7 +18,7 @@ const props = defineProps({
function initChart() { function initChart() {
const chartDom = document.getElementById("appearanceDailyDetectionChart"); const chartDom = document.getElementById("appearanceDailyDetectionChart");
const mainChart = echarts.init(chartDom); const mainChart = echarts.init(chartDom);
const data1 = [ const data1 = [
{ {
name: "1日", name: "1日",
value: 175, value: 175,
@ -117,23 +117,25 @@ function initChart() {
const barWidth = 16; const barWidth = 16;
const DOMURL = window.URL || window.webkitURL || window; const DOMURL = window.URL || window.webkitURL || window;
const insetShadowUrl = DOMURL.createObjectURL(svg); const insetShadowUrl = DOMURL.createObjectURL(svg);
let xAxisData = []; let xAxisData = [];
let seriesData1 = []; let seriesData1 = [];
data1.forEach((item) => { data1.forEach((item) => {
xAxisData.push(item.name); xAxisData.push(item.name);
seriesData1.push(item.value); seriesData1.push(item.value);
}); });
const option = { const option = {
backgroundColor: "", backgroundColor: "",
grid: { tooltip: {
left: "1%", trigger: "axis",
right: "1%", },
bottom: "2%", grid: {
top: "15%", left: "1%",
containLabel: true, right: "1%",
}, bottom: "5%",
top: "15%",
containLabel: true,
},
xAxis: { xAxis: {
type: "category", type: "category",
axisLine: { axisLine: {
@ -166,7 +168,7 @@ function initChart() {
lineStyle: { lineStyle: {
type: "dashed", type: "dashed",
color: "rgba(255,255,255,0.1)", color: "rgba(255,255,255,0.1)",
width: 2, width: 1,
}, },
}, },
}, },
@ -176,14 +178,18 @@ function initChart() {
type: "pictorialBar", type: "pictorialBar",
symbol: "image://" + insetShadowUrl, symbol: "image://" + insetShadowUrl,
barWidth: barWidth, barWidth: barWidth,
legendHoverLink: false,
}, },
{ {
tooltip: {
show: false,
},
data: seriesData1, data: seriesData1,
type: "bar", type: "bar",
barWidth: barWidth, barWidth: barWidth,
itemStyle: { itemStyle: {
color: "transparent", color: "transparent",
borderWidth: 3, borderWidth: 1,
borderColor: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ borderColor: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ {
offset: 0, offset: 0,

@ -89,9 +89,10 @@ function initChart() {
borderWidth: 1, borderWidth: 1,
}, },
grid: { grid: {
left: "2%", left: "1%",
right: "0%", right: "1%",
bottom: "5%", bottom: "5%",
top: "15%",
containLabel: true, containLabel: true,
}, },
toolbox: { toolbox: {
@ -172,42 +173,12 @@ function initChart() {
shadowOffsetY: 10, shadowOffsetY: 10,
}, },
itemStyle: { itemStyle: {
normal: { color: "rgba(255, 209, 92, 1)",
color: "rgba(255, 209, 92, 1)",
borderColor: "", borderColor: "",
borderWidth: 3, borderWidth: 3,
shadowColor: "rgba(255, 209, 92, 01)", shadowColor: "rgba(255, 209, 92, 01)",
shadowBlur: 5, shadowBlur: 5,
},
}, },
// areaStyle: {
// //
// normal: {
// //线4x0,y0,x2,y2(0~1);true
// color: new echarts.graphic.LinearGradient(
// 0,
// 0,
// 0,
// 1,
// [
// {
// offset: 0,
// color: "rgba(165, 170, 247, 1)",
// },
// {
// offset: 0.5,
// color: "rgba(165, 170, 247, 0.2)",
// },
// {
// offset: 1,
// color: "rgba(165, 170, 247, 0)",
// },
// ],
// false
// ),
// shadowBlur: 0, //shadowBlurshadowColor,shadowOffsetX/Y,
// },
// },
}, },
], ],
}; };

@ -8,10 +8,8 @@ function generateData(totalNum, bigvalue, smallvalue, color) {
name: (i + 1).toString(), name: (i + 1).toString(),
value: bigvalue, value: bigvalue,
itemStyle: { itemStyle: {
normal: { color: color,
color: color, borderWidth: 0,
borderWidth: 0,
},
}, },
}); });
} else { } else {
@ -19,10 +17,8 @@ function generateData(totalNum, bigvalue, smallvalue, color) {
name: (i + 1).toString(), name: (i + 1).toString(),
value: smallvalue, value: smallvalue,
itemStyle: { itemStyle: {
normal: { color: "rgba(0,0,0,0)",
color: "rgba(0,0,0,0)", borderWidth: 0,
borderWidth: 0,
},
}, },
}); });
} }
@ -220,8 +216,8 @@ function initChart() {
/**区域位置*/ /**区域位置*/
grid: { grid: {
// Adjust grid for spacing // Adjust grid for spacing
left: "5%", left: "1%",
right: "0%", right: "1%",
bottom: "5%", bottom: "5%",
top: "15%", top: "15%",
containLabel: true, containLabel: true,
@ -239,13 +235,14 @@ function initChart() {
barWidth: barWidth, barWidth: barWidth,
symbolOffset: ["10%", "50%"], symbolOffset: ["10%", "50%"],
itemStyle: { itemStyle: {
normal: { color: function (params) {
color: function (params) { return colors[0];
return colors[0];
},
}, },
}, },
data: seriesData1, data: seriesData1,
tooltip: {
show: false,
},
}, },
{ {
@ -257,12 +254,13 @@ function initChart() {
symbolOffset: ["0%", "0%"], symbolOffset: ["0%", "0%"],
symbolSize: [barWidth, barWidth * 0.3], symbolSize: [barWidth, barWidth * 0.3],
itemStyle: { itemStyle: {
normal: { color: function (params) {
color: function (params) { return "rgba(0,255,252,0.1)";
return "rgba(0,255,252,0.1)";
},
}, },
}, },
tooltip: {
show: false,
},
}, },
{ {
// //
@ -273,11 +271,9 @@ function initChart() {
symbolOffset: ["0%", "-50%"], symbolOffset: ["0%", "-50%"],
symbolSize: [barWidth, barWidth * 0.3], symbolSize: [barWidth, barWidth * 0.3],
itemStyle: { itemStyle: {
normal: { borderWidth: 0,
borderWidth: 0, color: function (params) {
color: function (params) { return colors1[0];
return colors1[0];
},
}, },
}, },
}, },

@ -29,7 +29,7 @@ const propsData = {
legendData: ["撑杆断裂", "撑杆锈蚀", "撑杆穿孔"], legendData: ["撑杆断裂", "撑杆锈蚀", "撑杆穿孔"],
seriesData: { seriesData: {
撑杆断裂: [ 撑杆断裂: [
60, 80, 120, 100, 90, 120, 110, 140, 130, 120, 120, 125, 130, 160, 150, 210, 80, 120, 100, 90, 120, 110, 140, 130, 120, 120, 125, 130, 160, 150,
100, 100,
], ],
撑杆锈蚀: [ 撑杆锈蚀: [
@ -51,10 +51,11 @@ const option = {
y: 0, y: 0,
x2: 0, x2: 0,
y2: 0, y2: 0,
left: "1%",
right: "1%",
bottom: "5%",
top: "25%", top: "25%",
left: "16px",
right: "0%",
bottom: "0%",
containLabel: true, containLabel: true,
}, },
tooltip: { tooltip: {
@ -128,13 +129,11 @@ const option = {
smooth: true, //true线; false线 smooth: true, //true线; false线
symbol: "none", symbol: "none",
itemStyle: { itemStyle: {
normal: { color: "#ffc600", //线
color: "#ffc600", //线
lineStyle: { lineStyle: {
color: "#ffc600", //线 color: "#ffc600", //线
type: "solid", type: "solid",
}, },
},
}, },
areaStyle: { areaStyle: {
//线 //线
@ -166,13 +165,11 @@ const option = {
symbol: "none", symbol: "none",
itemStyle: { itemStyle: {
normal: { color: "#24adfe", //线
color: "#24adfe", //线
lineStyle: { lineStyle: {
color: "#24adfe", //线 color: "#24adfe", //线
type: "solid", type: "solid",
}, },
},
}, },
areaStyle: { areaStyle: {
//线 //线
@ -204,13 +201,11 @@ const option = {
symbol: "none", symbol: "none",
itemStyle: { itemStyle: {
normal: { color: "#0DE98A", //线
color: "#0DE98A", //线
lineStyle: { lineStyle: {
color: "#0DE98A", //线 color: "#0DE98A", //线
type: "solid", type: "solid",
}, },
},
}, },
areaStyle: { areaStyle: {
//线 //线

@ -9,7 +9,7 @@ const props = defineProps({
const data1 = [ const data1 = [
{ {
name: "1日", name: "1日",
value: 175, value: 220,
}, },
{ {
name: "2日", name: "2日",
@ -21,7 +21,7 @@ const data1 = [
}, },
{ {
name: "4日", name: "4日",
value: 115, value: 245,
}, },
{ {
name: "5日", name: "5日",
@ -41,7 +41,7 @@ const data1 = [
}, },
{ {
name: "9日", name: "9日",
value: 15, value: 250,
}, },
{ {
name: "10日", name: "10日",
@ -78,8 +78,8 @@ data1.forEach((item) => {
xAxisData.push(item.name); xAxisData.push(item.name);
seriesData1.push(item.value); seriesData1.push(item.value);
}); });
var barWidth = 32; var barWidth = 16;
var barWidthBg = 45; var barWidthBg = 25;
const color = [ const color = [
{ {
type: "linear", type: "linear",
@ -113,7 +113,7 @@ const option = {
grid: { grid: {
left: "1%", left: "1%",
right: "1%", right: "1%",
bottom: "2%", bottom: "5%",
top: "15%", top: "15%",
containLabel: true, containLabel: true,
}, },

@ -1,5 +1,4 @@
<script setup lang="ts"> <script setup lang="ts">
import { defineComponent, onMounted, ref, watchEffect } from "vue";
import * as echarts from "echarts"; import * as echarts from "echarts";
interface ChartItem { interface ChartItem {
percent: number; percent: number;
@ -8,35 +7,10 @@ interface ChartItem {
pieData: number[]; // [65, 35] pieData: number[]; // [65, 35]
pieColors: string[]; // pieColors: string[]; //
} }
// //
const mainChartRef = ref<HTMLDivElement | null>(null); const mainChartRef = ref<HTMLDivElement | null>(null);
const miniChartRef = ref<HTMLDivElement | null>(null);
// //
let mainChart: echarts.ECharts | null = null; let mainChart: echarts.ECharts | null = null;
let miniChart: echarts.ECharts | null = null;
// ECharts ref
const chartRefs = ref<Ref<HTMLDivElement | null>[]>([]);
// const chartData = [
// {
// percent: 65,
// desc: "",
// color: "#488AFE",
// pieData: [65, 35],
// pieColors: ["#488AFE", "#ffffff44"],
// },
// {
// percent: 35,
// desc: "",
// color: "#F7D36D",
// pieData: [35, 65],
// pieColors: ["#F7D36D", "#ffffff44"],
// },
// ];
// //
const colors = [ const colors = [
[ [
@ -73,11 +47,9 @@ function Pie() {
name: (i + 1).toString(), name: (i + 1).toString(),
value: 10, value: 10,
itemStyle: { itemStyle: {
normal: { color: "#fff",
color: "#fff", borderWidth: 0,
borderWidth: 0, borderColor: "rgba(0,0,0,0)",
borderColor: "rgba(0,0,0,0)",
},
}, },
}); });
} else { } else {
@ -85,11 +57,9 @@ function Pie() {
name: (i + 1).toString(), name: (i + 1).toString(),
value: 25, value: 25,
itemStyle: { itemStyle: {
normal: { color: "rgba(0,0,0,0)",
color: "rgba(0,0,0,0)", borderWidth: 0,
borderWidth: 0, borderColor: "rgba(0,0,0,0)",
borderColor: "rgba(0,0,0,0)",
},
}, },
}); });
} }
@ -107,10 +77,8 @@ const initMainChart = () => {
trigger: "item", trigger: "item",
formatter: " {b} : {d}% <br/> {c}", formatter: " {b} : {d}% <br/> {c}",
}, },
legend: { legend: {
orient: "horizontal", orient: "horizontal",
// icon: "circle",
bottom: 20, bottom: 20,
x: "center", x: "center",
textStyle: { textStyle: {
@ -125,21 +93,19 @@ const initMainChart = () => {
center: centerPoint, center: centerPoint,
color: colors, color: colors,
itemStyle: { itemStyle: {
normal: { borderColor: "#031845",
borderColor: "#031845", borderWidth: 10,
borderWidth: 10, //
// color: function (params) {
color: function (params) { return {
return { //type: 'linear',
//type: 'linear', x: 0,
x: 0, y: 1,
y: 1, x2: 1,
x2: 1, y2: 0,
y2: 0, colorStops: colors[params.dataIndex], // 100%
colorStops: colors[params.dataIndex], // 100% //globalCoord: false // false
//globalCoord: false // false };
};
},
}, },
}, },
data: [ data: [
@ -153,14 +119,10 @@ const initMainChart = () => {
}, },
], ],
labelLine: { labelLine: {
normal: { show: false,
show: false,
},
}, },
label: { label: {
normal: { show: false,
show: false,
},
}, },
}, },
{ {
@ -175,11 +137,9 @@ const initMainChart = () => {
value: 270, value: 270,
name: "1", name: "1",
itemStyle: { itemStyle: {
normal: { color: "transparent",
color: "transparent", borderWidth: 2,
borderWidth: 2, borderColor: "#ffffff",
borderColor: "#ffffff",
},
}, },
}, },
@ -187,21 +147,15 @@ const initMainChart = () => {
value: 90, value: 90,
name: "2", name: "2",
itemStyle: { itemStyle: {
normal: { color: "transparent",
color: "transparent",
},
}, },
}, },
], ],
labelLine: { labelLine: {
normal: { show: false,
show: false,
},
}, },
label: { label: {
normal: { show: false,
show: false,
},
}, },
}, },
{ {
@ -215,11 +169,9 @@ const initMainChart = () => {
value: 25, value: 25,
name: "1", name: "1",
itemStyle: { itemStyle: {
normal: { color: "transparent",
color: "transparent", borderWidth: 2,
borderWidth: 2, borderColor: "#ffffff",
borderColor: "#ffffff",
},
}, },
}, },
@ -227,23 +179,17 @@ const initMainChart = () => {
value: 75, value: 75,
name: "2", name: "2",
itemStyle: { itemStyle: {
normal: { color: "transparent",
color: "transparent",
},
}, },
}, },
], ],
// selectedOffset: 10, // selectedOffset: 10,
labelLine: { labelLine: {
normal: { show: false,
show: false,
},
}, },
label: { label: {
normal: { show: false,
show: false,
},
}, },
}, },
{ {
@ -286,14 +232,10 @@ const initMainChart = () => {
], ],
labelLine: { labelLine: {
normal: { show: false,
show: false,
},
}, },
label: { label: {
normal: { show: false,
show: false,
},
}, },
}, },
{ {
@ -304,14 +246,10 @@ const initMainChart = () => {
center: centerPoint, center: centerPoint,
z: 10, z: 10,
label: { label: {
normal: { show: false,
show: false,
},
}, },
labelLine: { labelLine: {
normal: { show: false,
show: false,
},
}, },
data: Pie(), data: Pie(),
}, },
@ -324,89 +262,75 @@ const initMainChart = () => {
z: 10, z: 10,
startAngle: 90, startAngle: 90,
label: { label: {
normal: { show: false,
show: false,
},
}, },
color: ["red", "blue", "red", "blue"], color: ["red", "blue", "red", "blue"],
labelLine: { labelLine: {
normal: { show: false,
show: false,
},
}, },
data: [ data: [
{ {
name: "r1", name: "r1",
value: 25, value: 25,
itemStyle: { itemStyle: {
normal: { color: new echarts.graphic.LinearGradient(0, 1, 0, 0, [
color: new echarts.graphic.LinearGradient(0, 1, 0, 0, [ {
{ offset: 0,
offset: 0, color: "rgba(51,149,191,0.5)",
color: "rgba(51,149,191,0.5)", },
}, {
{ offset: 1,
offset: 1, color: "rgba(51,149,191,0)",
color: "rgba(51,149,191,0)", },
}, ]),
]),
},
}, },
}, },
{ {
name: "r2", name: "r2",
value: 25, value: 25,
itemStyle: { itemStyle: {
normal: { color: new echarts.graphic.LinearGradient(0, 1, 0, 0, [
color: new echarts.graphic.LinearGradient(0, 1, 0, 0, [ {
{ offset: 0,
offset: 0, color: "rgba(0,0,0,0)",
color: "rgba(0,0,0,0)", },
}, {
{ offset: 1,
offset: 1, color: "rgba(51,149,191,0.5)",
color: "rgba(51,149,191,0.5)", },
}, ]),
]),
},
}, },
}, },
{ {
name: "r3", name: "r3",
value: 25, value: 25,
itemStyle: { itemStyle: {
normal: { color: new echarts.graphic.LinearGradient(0, 1, 0, 0, [
color: new echarts.graphic.LinearGradient(0, 1, 0, 0, [ {
{ offset: 0,
offset: 0, color: "rgba(51,149,191,0)",
color: "rgba(51,149,191,0)", },
}, {
{ offset: 1,
offset: 1, color: "rgba(51,149,191,0.5)",
color: "rgba(51,149,191,0.5)", },
}, ]),
]),
},
}, },
}, },
{ {
name: "r4", name: "r4",
value: 25, value: 25,
itemStyle: { itemStyle: {
normal: { color: new echarts.graphic.LinearGradient(0, 1, 0, 0, [
color: new echarts.graphic.LinearGradient(0, 1, 0, 0, [ {
{ offset: 0,
offset: 0, color: "rgba(51,149,191,0.5)",
color: "rgba(51,149,191,0.5)", },
}, {
{ offset: 1,
offset: 1, color: "rgba(0,0,0,0)",
color: "rgba(0,0,0,0)", },
}, ]),
]),
},
}, },
}, },
], ],
@ -420,7 +344,6 @@ const initMainChart = () => {
// //
const handleResize = () => { const handleResize = () => {
mainChart?.resize(); mainChart?.resize();
// miniChart?.resize();
}; };
onMounted(() => { onMounted(() => {
@ -432,7 +355,6 @@ onMounted(() => {
const cleanup = () => { const cleanup = () => {
window.removeEventListener("resize", handleResize); window.removeEventListener("resize", handleResize);
mainChart?.dispose(); mainChart?.dispose();
miniChart?.dispose();
}; };
// //

@ -186,13 +186,11 @@ const updateChart = () => {
name: props.legendArr[index], name: props.legendArr[index],
barWidth: 25, barWidth: 25,
// label: { // label: {
// normal: {
// show: true, // show: true,
// position: "top", // position: "top",
// fontSize: 16, // fontSize: 16,
// color: "#fff", // color: "#fff",
// offset: [0, -10], // offset: [0, -10],
// },
// }, // },
itemStyle: { color: "transparent" }, itemStyle: { color: "transparent" },
data: item, data: item,
@ -238,13 +236,13 @@ const updateChart = () => {
grid: { grid: {
left: "5%", left: "5%",
right: "5%", right: "5%",
top: "5%", top: "15%",
bottom: "10%", bottom: "20%",
containLabel: true, containLabel: true,
}, },
legend: { legend: {
left: "center", left: "center",
top: "90%", top: "85%",
itemWidth: 12, // itemWidth: 12, //
itemHeight: 8, itemHeight: 8,
textStyle: { color: "#fff", fontSize: 12 }, textStyle: { color: "#fff", fontSize: 12 },
@ -267,7 +265,7 @@ const updateChart = () => {
splitLine: { splitLine: {
lineStyle: { type: "dashed", color: "rgba(80,112,242,0.3)" }, lineStyle: { type: "dashed", color: "rgba(80,112,242,0.3)" },
}, },
axisLabel: { textStyle: { color: "#8C8C8C" }, fontSize: 12 }, axisLabel: { color: "#8C8C8C", fontSize: 12 },
// axisLine: { lineStyle: { color: "#8C8C8C" } }, // axisLine: { lineStyle: { color: "#8C8C8C" } },
// scale: true, // // scale: true, //
}, },
@ -275,7 +273,7 @@ const updateChart = () => {
// name: "kWh", // name: "kWh",
// nameTextStyle: { color: "#fff", fontSize: 12 }, // nameTextStyle: { color: "#fff", fontSize: 12 },
splitLine: { lineStyle: { color: "transparent" } }, splitLine: { lineStyle: { color: "transparent" } },
axisLabel: { textStyle: { color: "#8C8C8C" }, fontSize: 12 }, axisLabel: { color: "#8C8C8C", fontSize: 12 },
// axisLine: { lineStyle: { color: "#8C8C8C" } }, // axisLine: { lineStyle: { color: "#8C8C8C" } },
position: "right", position: "right",
// scale: true, // // scale: true, //

@ -8,10 +8,8 @@ function generateData(totalNum, bigvalue, smallvalue, color) {
name: (i + 1).toString(), name: (i + 1).toString(),
value: bigvalue, value: bigvalue,
itemStyle: { itemStyle: {
normal: { color: color,
color: color, borderWidth: 0,
borderWidth: 0,
},
}, },
}); });
} else { } else {
@ -19,10 +17,8 @@ function generateData(totalNum, bigvalue, smallvalue, color) {
name: (i + 1).toString(), name: (i + 1).toString(),
value: smallvalue, value: smallvalue,
itemStyle: { itemStyle: {
normal: { color: "rgba(0,0,0,0)",
color: "rgba(0,0,0,0)", borderWidth: 0,
borderWidth: 0,
},
}, },
}); });
} }
@ -38,7 +34,7 @@ function initChart() {
let color = [ let color = [
"#3862d8", "#3862d8",
"#219CF9", "#219CF9",
"#6efbbf", "#2DE6FF",
"#40c057", "#40c057",
"#ffd351", "#ffd351",
"#ff8e43", "#ff8e43",
@ -57,7 +53,7 @@ function initChart() {
value: "2200", value: "2200",
}, },
{ {
name: "搭扣未搭", name: "小门外胀",
value: "1420", value: "1420",
}, },
{ {
@ -78,23 +74,21 @@ function initChart() {
}, 0); }, 0);
const option = { const option = {
backgroundColor: "transparent", backgroundColor: "transparent",
color: color, color: color, // color
tooltip: { tooltip: {
trigger: "item", trigger: "item",
}, },
title: [ title: {
{ text: "",
text: "", top: 20,
top: 20, left: 20,
left: 20, textStyle: {
textStyle: { fontSize: 14,
fontSize: 14, color: "#666666",
color: "#666666", fontWeight: 400,
fontWeight: 400,
},
show: false,
}, },
], show: false,
},
series: [ series: [
{ {
type: "pie", type: "pie",
@ -103,21 +97,11 @@ function initChart() {
radius: ["10%", "65%"], radius: ["10%", "65%"],
center: ["50%", "50%"], center: ["50%", "50%"],
data: echartData, data: echartData,
hoverAnimation: false, itemStyle: {}, // normal
itemStyle: {
normal: {
// borderColor: bgColor,
// borderWidth: 2,
},
},
labelLine: { labelLine: {
normal: { length: 18,
length: 18, length2: 32,
length2: 32, lineStyle: {}, // normal
lineStyle: {
// color: '#e6e6e6'
},
},
}, },
label: { label: {
show: true, show: true,
@ -132,49 +116,37 @@ function initChart() {
padding: [3, 3, 0, -12], padding: [3, 3, 0, -12],
}, },
name: { name: {
fontSize: "10", fontSize: 10, //
padding: [-12, 5, -20, 2], padding: [-12, 5, -20, 2],
color: "#fff", color: "#fff",
}, },
rate: { rate: {
fontSize: "10", fontSize: 10, //
align: 'left', align: "left",
padding: [-12, 5, -50, 2], padding: [-12, 5, -40, 2], //
color: "#fff", color: "#fff",
}, },
}, },
}, },
}, },
{ {
//
type: "pie", type: "pie",
zlevel: 1, zlevel: 1,
silent: true, // silent: true,
radius: ["0%", "75%"], radius: ["0%", "75%"],
center: ["50%", "50%"], center: ["50%", "50%"],
itemStyle: { itemStyle: {
normal: { color: "#0E4E89", //
show: false,
color: "#0E4E89",
},
}, },
labelLine: { labelLine: {
show: false, show: false,
normal: {
length: 10,
length2: 0,
lineStyle: {
color: "transparent",
},
},
}, },
label: { label: {
show: false, show: false,
}, },
data: [100], data: [{ value: 100, name: "" }], //
}, },
{ {
name: "不动外圆",
type: "pie", type: "pie",
zlevel: 1, zlevel: 1,
silent: true, silent: true,
@ -182,7 +154,10 @@ function initChart() {
label: { label: {
show: false, show: false,
}, },
data: generateData(300, 2, 1, "#3F7D97"), itemStyle: {
color: "#3F7D97", //
},
data: [{ value: 100, name: "" }], //
}, },
], ],
}; };

@ -6,7 +6,7 @@ import {
defineComponent, defineComponent,
nextTick, nextTick,
reactive, reactive,
type PropType type PropType,
} from "vue"; } from "vue";
import "./baseTable.scss"; import "./baseTable.scss";
@ -17,7 +17,7 @@ function getDefaultSort(attrs: Record<string, any>): any {
export default defineComponent({ export default defineComponent({
name: "XTable", name: "XTable",
directives: { directives: {
loading: ElLoading.directive loading: ElLoading.directive,
}, },
inheritAttrs: false, inheritAttrs: false,
props: { props: {
@ -26,7 +26,7 @@ export default defineComponent({
*/ */
columns: { columns: {
type: Array as PropType<XTableColumn[]>, type: Array as PropType<XTableColumn[]>,
required: true required: true,
}, },
/** /**
@ -34,7 +34,7 @@ export default defineComponent({
*/ */
dataSource: { dataSource: {
type: Array as PropType<XTableData[]>, type: Array as PropType<XTableData[]>,
required: true required: true,
}, },
/** /**
@ -42,7 +42,7 @@ export default defineComponent({
*/ */
loading: { loading: {
type: Boolean, type: Boolean,
default: false default: false,
}, },
/** /**
@ -50,7 +50,7 @@ export default defineComponent({
*/ */
maxHeight: { maxHeight: {
type: [Number, String] as PropType<number | "auto">, type: [Number, String] as PropType<number | "auto">,
default: "auto" default: "auto",
}, },
/** /**
@ -64,7 +64,7 @@ export default defineComponent({
default: true, default: true,
validator(value: boolean | "always") { validator(value: boolean | "always") {
return ["always", true, false].includes(value); return ["always", true, false].includes(value);
} },
}, },
/** /**
@ -76,11 +76,11 @@ export default defineComponent({
validator(value: string) { validator(value: string) {
return value return value
.split(",") .split(",")
.map(item => item.trim()) .map((item) => item.trim())
.every(item => .every((item) =>
["total", "sizes", "prev", "pager", "next", "jumper"].includes(item) ["total", "sizes", "prev", "pager", "next", "jumper"].includes(item)
); );
} },
}, },
/** /**
@ -88,7 +88,7 @@ export default defineComponent({
*/ */
total: { total: {
type: Number, type: Number,
default: 0 default: 0,
}, },
/** /**
@ -96,7 +96,7 @@ export default defineComponent({
*/ */
pageSize: { pageSize: {
type: Number, type: Number,
default: 10 default: 10,
}, },
/** /**
@ -104,7 +104,7 @@ export default defineComponent({
*/ */
page: { page: {
type: Number, type: Number,
default: 1 default: 1,
}, },
/** /**
@ -114,7 +114,7 @@ export default defineComponent({
type: Array as PropType<number[]>, type: Array as PropType<number[]>,
default() { default() {
return [10, 20, 30, 50]; return [10, 20, 30, 50];
} },
}, },
/** /**
@ -124,7 +124,7 @@ export default defineComponent({
type: [Function, String] as PropType< type: [Function, String] as PropType<
(row: XTableData) => string | string (row: XTableData) => string | string
>, >,
default: "id" default: "id",
}, },
/** /**
@ -132,7 +132,7 @@ export default defineComponent({
*/ */
visibleColumn: { visibleColumn: {
type: Boolean, type: Boolean,
default: undefined default: undefined,
}, },
/** /**
@ -140,17 +140,8 @@ export default defineComponent({
*/ */
isFixedPagination: { isFixedPagination: {
type: Boolean, type: Boolean,
default: true default: true,
} },
// handleDel: {
// type: Function,
// default: () => {}
// }
// customActions: {
// type: Function,
// default: () => {}
// }
}, },
emits: ["change", "columnChange", "update:visibleColumn", "actions"], emits: ["change", "columnChange", "update:visibleColumn", "actions"],
setup(props, { slots, attrs, emit }) { setup(props, { slots, attrs, emit }) {
@ -159,7 +150,7 @@ export default defineComponent({
const tableState = reactive<XTableState>({ const tableState = reactive<XTableState>({
tid: 0, tid: 0,
sortBy, sortBy,
sortOrder sortOrder,
}); });
const showPagination = computed(() => { const showPagination = computed(() => {
@ -203,7 +194,7 @@ export default defineComponent({
pageSize, pageSize,
prop: sortBy, prop: sortBy,
order: sortOrder, order: sortOrder,
type: "number" type: "number",
}); });
} }
@ -220,7 +211,7 @@ export default defineComponent({
pageSize, pageSize,
prop: sortBy, prop: sortBy,
order: sortOrder, order: sortOrder,
type: "size" type: "size",
}); });
}); });
} }
@ -261,6 +252,30 @@ export default defineComponent({
return col; return col;
} }
/**
*
*/
function renderBaseColumn(column: XTableColumn) {
const columnSlots: {
default?: (scope: Record<string, any>) => any;
header?: (scope: Record<string, any>) => any;
} = {};
const slot = getSlot(column);
const headerSlot = getSlot(column, "header");
if (slot) {
columnSlots.default = (scope) => slot(scope);
}
if (headerSlot) {
columnSlots.header = (scope) => headerSlot(scope);
}
return (
<ElTableColumn {...getColumnProps(column)}>{columnSlots}</ElTableColumn>
);
}
/** /**
* *
*/ */
@ -272,7 +287,7 @@ export default defineComponent({
default: (scope: Record<string, any>) => { default: (scope: Record<string, any>) => {
const slot = getSlot(column); const slot = getSlot(column);
return slot?.(scope); return slot?.(scope);
} },
}} }}
</ElTableColumn> </ElTableColumn>
); );
@ -285,74 +300,21 @@ export default defineComponent({
return ( return (
<div> <div>
{slots.actionBar && <div>{slots.actionBar({ row })}</div>} {slots.actionBar && <div>{slots.actionBar({ row })}</div>}
{/* <ul>
<li
class="flex items-center"
style={{ fontSize: "14px", color: "#E80D0D" }}
onClick={() => handleDel(row)}
>
<i class="iconfont icon-shanchu pr-[8px]"></i>
<el-button type="text">
<span
style={{
fontSize: "14px",
color: "#E80D0D"
}}
>
</span>
</el-button>
</li>
</ul> */}
</div> </div>
); );
} },
}} }}
</ElTableColumn> </ElTableColumn>
); );
} }
return <ElTableColumn {...getColumnProps(column)} />; return renderBaseColumn(column);
}
/**操作按钮事件 */
// function handleDel(row) {
// console.log(row, "handleDel");
// emit("actions", {
// type: "delete",
// data: { ...row }
// });
// }
/**
*
*/
function renderBaseColumn(column: XTableColumn) {
const columnSlots: {
default?: (scope: Record<string, any>) => any;
header?: (scope: Record<string, any>) => any;
} = {};
const slot = getSlot(column);
const headerSlot = getSlot(column, "header");
if (slot) {
columnSlots.default = scope => slot(scope);
}
if (headerSlot) {
columnSlots.header = scope => headerSlot(scope);
}
return (
<ElTableColumn {...getColumnProps(column)}>{columnSlots}</ElTableColumn>
);
} }
/** /**
* *
*/ */
function renderTableColumn(column: XTableColumn) { function renderTableColumn(column: XTableColumn) {
if (column.hidden) return; if (column.hidden) return null;
if (column.type) { if (column.type) {
return renderTypeColumn(column); return renderTypeColumn(column);
} }
@ -369,7 +331,7 @@ export default defineComponent({
if (column.hidden) return; if (column.hidden) return;
return ( return (
<ElTableColumn {...getColumnProps(column)}> <ElTableColumn {...getColumnProps(column)}>
{children.map(column => renderTableColumn(column))} {children.map((column) => renderTableColumn(column))}
</ElTableColumn> </ElTableColumn>
); );
} }
@ -387,7 +349,7 @@ export default defineComponent({
pageSizes: props.pageSizes, pageSizes: props.pageSizes,
currentPage: props.page, currentPage: props.page,
onSizeChange: handlePageSizeChange, onSizeChange: handlePageSizeChange,
onCurrentChange: handlePageNumChange onCurrentChange: handlePageNumChange,
}; };
return ( return (
@ -396,7 +358,7 @@ export default defineComponent({
"x-table-pagination pagination_wrap", "x-table-pagination pagination_wrap",
props.isFixedPagination props.isFixedPagination
? "fixed_pagination" ? "fixed_pagination"
: "noneFixed_pagination" : "noneFixed_pagination",
]} ]}
> >
<ElPagination {...paginationProps} /> <ElPagination {...paginationProps} />
@ -412,7 +374,7 @@ export default defineComponent({
columns: props.columns, columns: props.columns,
visible: props.visibleColumn, visible: props.visibleColumn,
onChange: handleColumnChange, onChange: handleColumnChange,
onVisibleChange: handleVisibleChange onVisibleChange: handleVisibleChange,
}; };
return <BaseColumn {...customColumnProps} />; return <BaseColumn {...customColumnProps} />;
@ -425,14 +387,13 @@ export default defineComponent({
maxHeight: mHeight.value, maxHeight: mHeight.value,
data: props.dataSource, data: props.dataSource,
rowKey: props.rowKey, rowKey: props.rowKey,
onSortChange: handleTableSortChange onSortChange: handleTableSortChange,
}; };
const extraSlots: { const extraSlots: {
append?: () => any; append?: () => any;
empty?: () => any; empty?: () => any;
} = {}; } = {};
if (slots.append) { if (slots.append) {
extraSlots.append = () => slots.append?.(); extraSlots.append = () => slots.append?.();
} }
@ -449,40 +410,20 @@ export default defineComponent({
v-loading={props.loading} v-loading={props.loading}
v-slots={extraSlots} v-slots={extraSlots}
> >
{props.columns.map(column => { {{
if (Array.isArray(column.children)) { default: () => {
return renderColumnChildren(column, column.children); return props.columns.map((column) =>
} Array.isArray(column.children)
return renderTableColumn(column); ? renderColumnChildren(column, column.children)
})} : renderTableColumn(column)
{/* 使用插槽引入操作栏的内容 */} );
{/* <ElTableColumn label=""> },
{{ }}
default: ({ row }: { row: Record<string, any> }) => {
return extraSlots.customActions?.({
row
});
}
}}
</ElTableColumn> */}
{/* <ElTableColumn label="">
<template #default="scope">
<el-button size="small" @click="handleEdit(scope.$index, scope.row)"
>Edit</el-button
>
<el-button
size="small"
type="danger"
@click="handleDelete(scope.$index, scope.row)"
>Delete</el-button>
>
</template>
</ElTableColumn> */}
</ElTable> </ElTable>
{showPagination.value && renderPagination()} {showPagination.value && renderPagination()}
{!isUndefined(props.visibleColumn) && renderCustomColumn()} {!isUndefined(props.visibleColumn) && renderCustomColumn()}
</div> </div>
); );
}; };
} },
}); });

@ -2,14 +2,14 @@
* @Author: donghao donghao@supervision.ltd * @Author: donghao donghao@supervision.ltd
* @Date: 2025-08-14 13:38:30 * @Date: 2025-08-14 13:38:30
* @LastEditors: donghao donghao@supervision.ltd * @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2025-08-19 14:21:29 * @LastEditTime: 2025-08-20 09:46:29
* @FilePath: \5G-Web\src\views\dashboard\components\SwpierMonitor.vue * @FilePath: \5G-Web\src\views\dashboard\components\SwpierMonitor.vue
* @Description: 外观撑杆统一封装轮播图&视频组件 * @Description: 外观撑杆统一封装轮播图&视频组件
--> -->
<script lang="ts" setup> <script lang="ts" setup>
import Player from "@/components/videoPlayer/Player.vue"; import Player from "@/components/videoPlayer/Player.vue";
import SwiperPlayer from "./SwiperPlayer.vue"; import SwiperPlayer from "./swiperPlayer.vue";
import { Swiper, SwiperSlide } from "swiper/vue"; import { Swiper, SwiperSlide } from "swiper/vue";
import { Navigation, Scrollbar, Mousewheel, Pagination } from "swiper/modules"; import { Navigation, Scrollbar, Mousewheel, Pagination } from "swiper/modules";
import "swiper/css"; import "swiper/css";
@ -81,7 +81,6 @@ watch(
<!-- 缩略图区域 --> <!-- 缩略图区域 -->
<div class="flex" v-if="fileList?.length > 0"> <div class="flex" v-if="fileList?.length > 0">
<div class="thumbnail-container"> <div class="thumbnail-container">
<!-- //TODO -->
<swiper <swiper
ref="swiperRef" ref="swiperRef"
:modules="modules" :modules="modules"

@ -2,9 +2,9 @@
* @Author: donghao donghao@supervision.ltd * @Author: donghao donghao@supervision.ltd
* @Date: 2025-08-19 11:04:59 * @Date: 2025-08-19 11:04:59
* @LastEditors: donghao donghao@supervision.ltd * @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2025-08-19 11:26:43 * @LastEditTime: 2025-08-20 09:46:44
* @FilePath: \5G-Web\src\components\Swiper\SwiperPlayer.vue * @FilePath: \5G-Web\src\components\Swiper\swiperPlayer.vue
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE * @Description: 作为轮播文件中的视频块
--> -->
<template> <template>
<div class="flex items-center justify-center w-full h-full position-relative"> <div class="flex items-center justify-center w-full h-full position-relative">
@ -14,7 +14,7 @@
muted muted
:src="videoUrl" :src="videoUrl"
width="100%" width="100%"
height="148" height="100%"
style="object-fit: cover" style="object-fit: cover"
@error="handleVideoError" @error="handleVideoError"
v-if="!isVideoError" v-if="!isVideoError"

@ -7,203 +7,207 @@
* @Description: 视频播放器 * @Description: 视频播放器
--> -->
<template> <template>
<!-- 视频播放器 --> <!-- 视频播放器 -->
<div class="video-player-box"> <div class="video-player-box">
<video ref="videoRef" class="video-element" controls @timeupdate="handleTimeUpdate" <video
@loadedmetadata="handleLoadedMetadata" @play="handlePlay" @pause="handlePause" @waiting="handleWaiting" ref="videoRef"
@canplay="handleCanPlay" style="object-fit: cover;" @error="handleVideoError"> class="video-element"
<source :src="src" type="video/mp4"> controls
您的浏览器不支持视频播放 @timeupdate="handleTimeUpdate"
</video> @loadedmetadata="handleLoadedMetadata"
<!-- 加载状态提示 --> @play="handlePlay"
<div v-if="loading" class="loading-overlay"> @pause="handlePause"
<el-icon class="is-loading"> @waiting="handleWaiting"
<Loading /> @canplay="handleCanPlay"
</el-icon> style="object-fit: cover"
</div> @error="handleVideoError"
<div class="bg_error_img" v-if="isVideoError"> >
<source :src="src" type="video/mp4" />
</div> 您的浏览器不支持视频播放
</video>
<!-- 加载状态提示 -->
<div v-if="loading" class="loading-overlay">
<el-icon class="is-loading">
<Loading />
</el-icon>
</div> </div>
<div class="bg_error_img" v-if="isVideoError"></div>
</div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ElIcon } from 'element-plus' import { ElIcon } from "element-plus";
import { Loading } from '@element-plus/icons-vue' import { Loading } from "@element-plus/icons-vue";
type ProgressData = { type ProgressData = {
currentTime: number currentTime: number;
duration: number duration: number;
progress: number progress: number;
} };
const props = defineProps({ const props = defineProps({
src: { src: {
type: String, type: String,
required: true },
}, isPlaying: {
isPlaying: { type: Boolean,
type: Boolean, default: false,
default: false },
} });
})
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'update:progress', data: ProgressData): void (e: "update:progress", data: ProgressData): void;
(e: 'update:duration', duration: number): void (e: "update:duration", duration: number): void;
(e: 'play'): void (e: "play"): void;
(e: 'pause'): void (e: "pause"): void;
}>() }>();
const videoRef = ref<HTMLVideoElement | null>(null) const videoRef = ref<HTMLVideoElement | null>(null);
const loading = ref<boolean>(false) const loading = ref<boolean>(false);
const isVideoError = ref<boolean>(false); const isVideoError = ref<boolean>(false);
let currentDuration = 0 let currentDuration = 0;
// //
watch(() => props.isPlaying, (newVal) => { watch(
if (!videoRef.value) return () => props.isPlaying,
newVal ? videoRef.value.play() : videoRef.value.pause() (newVal) => {
}) if (!videoRef.value) return;
newVal ? videoRef.value.play() : videoRef.value.pause();
}
);
// //
watch(() => props.src, (newVal) => { watch(
if (!videoRef.value) return () => props.src,
isVideoError.value = false (newVal) => {
videoRef.value.pause() if (!videoRef.value) return;
videoRef.value.src = newVal isVideoError.value = false;
videoRef.value.load() videoRef.value.pause();
videoRef.value.src = newVal;
videoRef.value.load();
if (props.isPlaying) { if (props.isPlaying) {
videoRef.value.play() videoRef.value.play();
} }
}) }
);
// //
const handleTimeUpdate = () => { const handleTimeUpdate = () => {
if (!videoRef.value) return if (!videoRef.value) return;
const currentTime = videoRef.value.currentTime const currentTime = videoRef.value.currentTime;
const progress = currentDuration > 0 const progress =
? (currentTime / currentDuration) * 100 currentDuration > 0 ? (currentTime / currentDuration) * 100 : 0;
: 0
emit("update:progress", {
emit('update:progress', { currentTime,
currentTime, duration: currentDuration,
duration: currentDuration, progress,
progress });
}) };
}
// //
const handleLoadedMetadata = () => { const handleLoadedMetadata = () => {
if (!videoRef.value) return if (!videoRef.value) return;
currentDuration = videoRef.value.duration currentDuration = videoRef.value.duration;
emit('update:duration', currentDuration) emit("update:duration", currentDuration);
} };
const handleVideoError = () => { const handleVideoError = () => {
console.log('handleVideoError') console.log("handleVideoError");
isVideoError.value = true; isVideoError.value = true;
}; };
// //
const handlePlay = () => emit('play') const handlePlay = () => emit("play");
const handlePause = () => emit('pause') const handlePause = () => emit("pause");
// //
const handleWaiting = () => loading.value = true const handleWaiting = () => (loading.value = true);
const handleCanPlay = () => loading.value = false const handleCanPlay = () => (loading.value = false);
onMounted(() => { onMounted(() => {
console.log('onMounted', props.src) console.log("onMounted", props.src);
if (videoRef.value) { if (videoRef.value) {
videoRef.value.src = props.src videoRef.value.src = props.src;
} }
}) });
onUnmounted(() => { onUnmounted(() => {
if (videoRef.value) { if (videoRef.value) {
videoRef.value.pause() videoRef.value.pause();
videoRef.value.removeAttribute('src') videoRef.value.removeAttribute("src");
videoRef.value.load() videoRef.value.load();
} }
}) });
// //
defineExpose({ defineExpose({
play: () => videoRef.value?.play(), play: () => videoRef.value?.play(),
pause: () => videoRef.value?.pause(), pause: () => videoRef.value?.pause(),
seek: (time: number) => { seek: (time: number) => {
if (videoRef.value) { if (videoRef.value) {
videoRef.value.currentTime = time videoRef.value.currentTime = time;
}
} }
}) },
});
</script> </script>
<style lang="scss"> <style lang="scss">
.video-player-box { .video-player-box {
position: relative; position: relative;
width: 100%;
height: 100%;
margin: 0 auto;
.bg_error_img {
position: absolute;
top: 0;
left: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
margin: 0 auto; z-index: 99999999;
background-color: #090f48;
.bg_error_img { background-image: url("@/assets/common/load_file_error.png");
position: absolute; background-position: center;
top: 0; background-repeat: no-repeat;
left: 0; background-size: 25%;
width: 100%; border: 1px dashed red;
height: 100%; }
z-index: 99999999;
background-color: #090F48; .video-element {
background-image: url("@/assets/common/load_file_error.png"); width: 100%;
background-position: center; height: auto;
background-repeat: no-repeat; border-radius: 8px;
background-size: 25%; }
border: 1px dashed red;
} .loading-overlay {
position: absolute;
.video-element { top: 0;
width: 100%; left: 0;
height: auto; right: 0;
border-radius: 8px; bottom: 0;
} background: rgba(0, 0, 0, 0.5);
display: flex;
.loading-overlay { align-items: center;
position: absolute; justify-content: center;
top: 0; color: white;
left: 0; }
right: 0;
bottom: 0; .el-icon.is-loading {
background: rgba(0, 0, 0, 0.5); font-size: 32px;
display: flex; animation: rotating 2s linear infinite;
align-items: center; }
justify-content: center;
color: white; @keyframes rotating {
} from {
transform: rotate(0deg);
.el-icon.is-loading {
font-size: 32px;
animation: rotating 2s linear infinite;
} }
@keyframes rotating { to {
from { transform: rotate(360deg);
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
} }
}
} }
</style> </style>

@ -0,0 +1,52 @@
export const dataViewConfig = {
monthArr: [
{
name: "1月",
value: "1",
},
{
name: "2月",
value: "2",
},
{
name: "3月",
value: "3",
},
{
name: "4月",
value: "4",
},
{
name: "5月",
value: "5",
},
{
name: "6月",
value: "6",
},
{
name: "7月",
value: "7",
},
{
name: "8月",
value: "8",
},
{
name: "9月",
value: "9",
},
{
name: "10月",
value: "10",
},
{
name: "11月",
value: "11",
},
{
name: "12月",
value: "12",
},
],
};

@ -94,7 +94,7 @@
color: white; color: white;
margin-left: 0; margin-left: 0;
height: 32px; height: 32px;
.icon { .icon {
width: 14px; width: 14px;
height: 14px; height: 14px;
background-image: url("@/assets/common/search_icon.png"); background-image: url("@/assets/common/search_icon.png");
@ -213,30 +213,30 @@
width: 100%; width: 100%;
& > li { & > li {
height: 230px; // height: 230px;
background: url("@/assets/common/long_chart_bg.png") no-repeat center center; background: url("@/assets/common/long_chart_bg.png") no-repeat center center;
background-size: 100% 100%; background-size: 100% 100%;
&:nth-child(1) { &:nth-child(1) {
width: calc(50% - 50px); width: calc(50% - 50px - 16px);
// background-color: red; // overflow: hidden;
} }
&:nth-child(2) { &:nth-child(2) {
width: calc(50% + 50px); width: calc(50% + 50px - 16px);
overflow: hidden; // overflow: hidden;
} }
.fg-footer-charts-title { .fg-footer-charts-title {
@apply fg-title; @apply fg-title;
font-size: 18px; font-size: 18px;
padding-left: 16px; padding-left: 16px;
padding-top: 8px; padding-top: 7px;
padding-bottom: 1px;
} }
.fg-footer-charts-content { .fg-footer-charts-content {
max-width: 950px; overflow: hidden;
max-width: 100%;
height: 195px;
// background-color: red; // background-color: red;
// overflow-x: auto;
// overflow-y: hidden;
height: calc(230px - 40px);
} }
} }
} }

@ -112,6 +112,11 @@
width: 150px; width: 150px;
background-color: #032b5c; /* 自定义背景色 */ background-color: #032b5c; /* 自定义背景色 */
border: none; /* 可选:去掉边框 */ border: none; /* 可选:去掉边框 */
--fg-select-height: 32px; // *
&.mini-size {
--fg-select-height: 28px; // *
width: 78px;
}
.el-select__selected-item { .el-select__selected-item {
color: white; /* 文字颜色 */ color: white; /* 文字颜色 */
} }
@ -120,7 +125,7 @@
background: rgba(74, 126, 191, 0.1); /* 下拉框背景色 */ background: rgba(74, 126, 191, 0.1); /* 下拉框背景色 */
border: none !important; /* 边框 */ border: none !important; /* 边框 */
color: white; /* 文字颜色 */ color: white; /* 文字颜色 */
height: 32px; height: var(--fg-select-height); /* 高度 */
box-shadow: none; box-shadow: none;
&::placeholder { &::placeholder {
@ -128,8 +133,8 @@
} }
} }
.el-select__wrapper { .el-select__wrapper {
min-height: 32px; min-height: var(--fg-select-height);
line-height: 32px; line-height: var(--fg-select-height);
box-shadow: 0 0 0 0 !important; box-shadow: 0 0 0 0 !important;
} }
.el-select__arrow { .el-select__arrow {
@ -159,8 +164,8 @@
height: 32px; height: 32px;
} }
} }
.el-progress-bar__outer{ .el-progress-bar__outer {
background: rgba(255,255,255,0.3); background: rgba(255, 255, 255, 0.3);
} }
/* 修改下拉菜单背景色 */ /* 修改下拉菜单背景色 */
@ -207,4 +212,3 @@
background-color: transparent; background-color: transparent;
} }
} }

@ -44,14 +44,15 @@
flex-direction: column; flex-direction: column;
margin: 0 24px; margin: 0 24px;
background: url("@/assets/home/realTime_monitor_bg.png") no-repeat center; background: url("@/assets/home/realTime_monitor_bg.png") no-repeat center;
background-size: contain; background-size: 100% 100%;
} }
.monitor-images { .monitor-images {
width: 948px; width: 100%;
display: flex; display: flex;
gap: 16px; gap: 16px;
padding: 20px 16px; padding: 32px 16px 15px;
flex-wrap: wrap; flex-wrap: wrap;
.monitor-images-item { .monitor-images-item {
width: calc(50% - 8px); width: calc(50% - 8px);

@ -1,13 +1,9 @@
// TODO
<script lang="ts" setup> <script lang="ts" setup>
import * as echarts from "echarts"; import * as echarts from "echarts";
import TotalChart from "@/components/Charts/totalChart.vue"; import TotalChart from "@/components/Charts/totalChart.vue";
import PoleMonitorChart from "@/components/Charts/poleMonitorChart.vue"; import PoleMonitorChart from "@/components/Charts/poleMonitorChart.vue";
import VehicleMonitorChart from "@/components/Charts/vehicleMonitorChart.vue"; import VehicleMonitorChart from "@/components/Charts/vehicleMonitorChart.vue";
import HomeSubTitle from "@/components/HeaderBar/homeSubTitle.vue"; import HomeSubTitle from "@/components/HeaderBar/homeSubTitle.vue";
import BarChart from "./components/BarChart.vue";
import PieChart from "./components/PieChart.vue";
import PieChartSmall from "./components/PieChartSmall.vue";
import DeviceStatus from "./components/DeviceStatus.vue"; import DeviceStatus from "./components/DeviceStatus.vue";
import car_device_icon from "@/assets/home/car_device_icon.png"; import car_device_icon from "@/assets/home/car_device_icon.png";
import pole_device_icon from "@/assets/home/pole_device_icon.png"; import pole_device_icon from "@/assets/home/pole_device_icon.png";
@ -19,13 +15,15 @@ import {
getRealTimeApi, getRealTimeApi,
} from "@/api/dashboard"; } from "@/api/dashboard";
import { isSuccessApi } from "@/utils/forApi"; import { isSuccessApi } from "@/utils/forApi";
import { isArray } from "@/utils/is";
import AlarmModal from "./components/AlarmModal.vue"; import AlarmModal from "./components/AlarmModal.vue";
import { dataViewConfig } from "@/config/dataView";
import { useWebSocketStore } from "@/stores/websocketStore"; import { useWebSocketStore } from "@/stores/websocketStore";
import { onBeforeRouteLeave } from "vue-router"; import { onBeforeRouteLeave } from "vue-router";
defineOptions({ defineOptions({
name: "DataOverviewWrap", name: "DataOverviewWrap",
}); });
// TODO mock
const xData = ref(["1月", "2月", "3月", "4月", "5月"]); const xData = ref(["1月", "2月", "3月", "4月", "5月"]);
const legendArr = ["车体检测", "撑杆检测"]; const legendArr = ["车体检测", "撑杆检测"];
const datas = ref([ const datas = ref([
@ -141,7 +139,7 @@ const getDeviceInfo = async () => {
console.error("获取设备信息出错:", error); console.error("获取设备信息出错:", error);
} }
}; };
const getPoleFault = async () => { const fetchPoleMonitorData = async () => {
try { try {
const res = await getRecordFaultApi({ const res = await getRecordFaultApi({
dateType: "month", dateType: "month",
@ -158,7 +156,8 @@ const getPoleFault = async () => {
console.error("获取设备信息出错:", error); console.error("获取设备信息出错:", error);
} }
}; };
const getCarFault = async () => { //
const fetchTrainMonitorData = async () => {
try { try {
const res = await getRecordFaultApi({ const res = await getRecordFaultApi({
dateType: "month", dateType: "month",
@ -181,7 +180,10 @@ const getRealTime = async () => {
const res = await getRealTimeApi({ deviceType: "" }); const res = await getRealTimeApi({ deviceType: "" });
if (isSuccessApi(res)) { if (isSuccessApi(res)) {
const { data } = res; const { data } = res;
imageFault.value = data; if (isArray(data)) {
// TODO 使
imageFault.value = data.concat(data).concat(data).splice(0, 4);
}
// deviceStatus.value = data // deviceStatus.value = data
console.log(data); console.log(data);
} }
@ -197,8 +199,8 @@ onBeforeRouteLeave(() => {
onMounted(() => { onMounted(() => {
getList(); getList();
getDeviceInfo(); getDeviceInfo();
getCarFault(); fetchTrainMonitorData();
getPoleFault(); fetchPoleMonitorData();
getRealTime(); getRealTime();
}); });
</script> </script>
@ -243,25 +245,22 @@ onMounted(() => {
<div class="module-header"> <div class="module-header">
<HomeSubTitle title="车体监测"> <HomeSubTitle title="车体监测">
<template #extra> <template #extra>
<el-select <div class="flex items-center text-[14px] px-[16px]">
v-model="searchForm.car" <span>时间</span>
placeholder="时间" <el-select
class="custom-select" v-model="searchForm.pole"
@change="getCarFault()" placeholder="时间"
> class="custom-select mini-size"
<el-option label="1月" value="1"></el-option> @change="fetchPoleMonitorData()"
<el-option label="2月" value="2"></el-option> >
<el-option label="3月" value="3"></el-option> <el-option
<el-option label="4月" value="4"></el-option> v-for="v in dataViewConfig.monthArr"
<el-option label="5月" value="5"></el-option> :key="v?.value"
<el-option label="6月" value="6"></el-option> :label="v?.name"
<el-option label="7月" value="7"></el-option> :value="v?.value"
<el-option label="8月" value="8"></el-option> ></el-option>
<el-option label="9月" value="9"></el-option> </el-select>
<el-option label="10月" value="10"></el-option> </div>
<el-option label="11月" value="11"></el-option>
<el-option label="12月" value="12"></el-option>
</el-select>
</template> </template>
</HomeSubTitle> </HomeSubTitle>
</div> </div>
@ -281,25 +280,22 @@ onMounted(() => {
<div class="module-header"> <div class="module-header">
<HomeSubTitle title="撑杆监测"> <HomeSubTitle title="撑杆监测">
<template #extra> <template #extra>
<el-select <div class="flex items-center text-[14px] px-[16px]">
v-model="searchForm.pole" <span>时间</span>
placeholder="时间" <el-select
class="custom-select" v-model="searchForm.pole"
@change="getPoleFault()" placeholder="时间"
> class="custom-select mini-size"
<el-option label="1月" value="1"></el-option> @change="fetchPoleMonitorData()"
<el-option label="2月" value="2"></el-option> >
<el-option label="3月" value="3"></el-option> <el-option
<el-option label="4月" value="4"></el-option> v-for="v in dataViewConfig.monthArr"
<el-option label="5月" value="5"></el-option> :key="v?.value"
<el-option label="6月" value="6"></el-option> :label="v?.name"
<el-option label="7月" value="7"></el-option> :value="v?.value"
<el-option label="8月" value="8"></el-option> ></el-option>
<el-option label="9月" value="9"></el-option> </el-select>
<el-option label="10月" value="10"></el-option> </div>
<el-option label="11月" value="11"></el-option>
<el-option label="12月" value="12"></el-option>
</el-select>
</template> </template>
</HomeSubTitle> </HomeSubTitle>
</div> </div>
@ -311,26 +307,15 @@ onMounted(() => {
</div> </div>
<!-- 中部检测模块 --> <!-- 中部检测模块 -->
<div class="realTime-monitor-box"> <div class="realTime-monitor-box">
<div class="monitor-images"> <div class="w-full h-[35px] fg-title px-[16px] py-[20px]">
<div class="w-full h-[35px] fg-title ">实时监测画面</div> 实时监测画面
<div class="monitor-images-left monitor-images-item">
<img :src="imageFault[0]?.url" />
<div class="fault-info">{{ imageFault[0]?.fault_type }}</div>
</div>
<div class="monitor-images-right monitor-images-item">
<img :src="imageFault[1]?.url" />
<div class="fault-info">{{ imageFault[1]?.fault_type }}</div>
</div>
<div class="monitor-images-left monitor-images-item">
<img :src="imageFault[0]?.url" />
<div class="fault-info">{{ imageFault[0]?.fault_type }}</div>
</div>
<div class="monitor-images-right monitor-images-item">
<img :src="imageFault[1]?.url" />
<div class="fault-info">{{ imageFault[1]?.fault_type }}</div>
</div>
</div> </div>
<ul class="flex monitor-images">
<li class="monitor-images-item" v-for="(v, i) in imageFault" :key="i">
<img :src="v?.url" />
<div class="fault-info">{{ v?.fault_type }}</div>
</li>
</ul>
</div> </div>
<!-- 设备信息 --> <!-- 设备信息 -->
<div class="device-info-box"> <div class="device-info-box">

@ -1,50 +1,3 @@
<template>
<el-dialog class="alarmModal-wrap fg-dialog" v-model="show" @close="handleClose" align-center :show-close="false">
<!-- 自定义标题栏 -->
<template #header="{ close, titleId, titleClass }">
<div class="flex items-center justify-between alarm-dialog-header fg-dialog-header">
<div class="flex items-center justify-center header-left">
<div class="header-icon mr-[12px]"></div>
<p class="overflow-hidden whitespace-nowrap text-ellipsis max-w-[650px]">故障提示</p>
</div>
<div class="fg-dialog-header-close" @click="close">
</div>
</div>
</template>
<!-- 图片区域 -->
<div class="alarm-content">
<div class="alarm-content-top">
<div class="flex flex-wrap alarm-content-file" v-if="image?.length">
<template v-for="(item,index) in image" :key="index">
<img :src="item.image_url" alt="" v-if="item.image_url && index < 4"></img>
</template>
</div>
<div class="fg-empty-image" v-else>
</div>
</div>
<div class="alarm-content-bottom">
<span class="alarm-content-bottom-title">列车信息:</span>
<div class="alarm-content-bottom-info">
<span class="mr-8">列车编号: <i>{{ info.train_number }}</i></span>
<span class="mr-8">车型: <i>{{ info.train_model }}</i></span>
<span>发生时间: <i>{{ info.created_at }}</i></span>
</div>
<div class="alarm-content-bottom-info">
<span class="mr-8">告警类型: <i>{{ info.alarm_type }}</i></span>
<span>故障类型: <i>{{ info.fault_type }}</i></span>
</div>
<div class="alarm-content-bottom-btn">
<el-button type="primary" @click="exportToExcel" class="alarm-btn">
<span class="icon"></span> 导出
</el-button>
</div>
</div>
</div>
</el-dialog>
</template>
<script lang="ts" setup> <script lang="ts" setup>
// TODO // TODO
import ExcelJS from 'exceljs'; import ExcelJS from 'exceljs';
@ -66,11 +19,6 @@ const props = withDefaults(defineProps<Props>(), {
const emit = defineEmits<Emits>(); const emit = defineEmits<Emits>();
//
const handleClose = () => {
// emits('close');
};
const show = computed({ const show = computed({
get() { get() {
return props.value; return props.value;
@ -136,6 +84,54 @@ const exportToExcel = async () => {
} }
}; };
</script> </script>
<template>
<el-dialog class="alarmModal-wrap fg-dialog" v-model="show" align-center :show-close="false">
<!-- 自定义标题栏 -->
<template #header="{ close, titleId, titleClass }">
<div class="flex items-center justify-between alarm-dialog-header fg-dialog-header">
<div class="flex items-center justify-center header-left">
<div class="header-icon mr-[12px]"></div>
<p class="overflow-hidden whitespace-nowrap text-ellipsis max-w-[650px]">故障提示</p>
</div>
<div class="fg-dialog-header-close" @click="close">
</div>
</div>
</template>
<!-- 图片区域 -->
<div class="alarm-content">
<div class="alarm-content-top">
<div class="flex flex-wrap alarm-content-file" v-if="image?.length">
<template v-for="(item,index) in image" :key="index">
<img :src="item.image_url" alt="" v-if="item.image_url && index < 4"></img>
</template>
</div>
<div class="fg-empty-image" v-else>
</div>
</div>
<div class="alarm-content-bottom">
<span class="alarm-content-bottom-title">列车信息:</span>
<div class="alarm-content-bottom-info">
<span class="mr-8">列车编号: <i>{{ info.train_number }}</i></span>
<span class="mr-8">车型: <i>{{ info.train_model }}</i></span>
<span>发生时间: <i>{{ info.created_at }}</i></span>
</div>
<div class="alarm-content-bottom-info">
<span class="mr-8">告警类型: <i>{{ info.alarm_type }}</i></span>
<span>故障类型: <i>{{ info.fault_type }}</i></span>
</div>
<div class="alarm-content-bottom-btn">
<el-button type="primary" @click="exportToExcel" class="alarm-btn">
<span class="icon"></span> 导出
</el-button>
</div>
</div>
</div>
</el-dialog>
</template>
<style lang="scss"> <style lang="scss">

@ -1,83 +1,3 @@
<template>
<el-dialog class="appearanceAlarmModal fg-dialog" v-model="show" @close="handleClose" align-center :show-close="false" >
<!-- 自定义标题栏 -->
<template #header="{ close, titleId, titleClass }">
<div class="flex items-center justify-between appearanceAlarm-dialog-header fg-dialog-header">
<div class="flex items-center justify-center header-left">
<div class="header-icon mr-[12px]"></div>
<p class="overflow-hidden whitespace-nowrap text-ellipsis max-w-[650px]">故障提示</p>
</div>
<div class="fg-dialog-header-close" @click="close">
</div>
</div>
</template>
<!-- 图片区域 -->
<div class="appearanceAlarm-content">
<div class="appearanceAlarm-content-top">
<!-- <template v-for="(item,index) in image" :key="index">
<img :src="item.image_url" alt="" v-if="index < 4"></img>
</template> -->
<div class="appearanceAlarm-content-top-left">
<div class="appearanceAlarm-error-title-before appearanceAlarm-error-title">故障前</div>
<div class="appearanceAlarm-content-top-left-img">
<div class="appearanceAlarm-content-top-img">
<img :src="imageBefore" alt="" />
</div>
<div class="appearanceAlarm-content-top-img-slider">
<swiper ref="swiperModalRef" :modules="modules" :slides-per-view="3" :space-between="10" navigation
:scrollbar="{ draggable: false }" :centered-slides="false" :observer="true" :observeParents="true"
@swiper="onSwiper" @slideChange="onSlideChange">
<swiper-slide v-for="(file, index) in beforeImage" :key="index" @click="handleSlideClick(index, 'before')"
:class="{ 'active-slide': activeBeforeIndex === index }">
<img :src="file.image_url" class="cursor-pointer" v-if="file.image_url" />
</swiper-slide>
</swiper>
</div>
</div>
</div>
<div class="appearanceAlarm-content-top-right">
<div class="appearanceAlarm-error-title-after appearanceAlarm-error-title">故障后</div>
<div class="appearanceAlarm-content-top-right-img">
<div class="appearanceAlarm-content-top-img">
<img :src="imageAfter" alt=""></img>
</div>
<div class="appearanceAlarm-content-top-img-slider">
<swiper ref="swiperModalRef" :modules="modules" :slides-per-view="3" :space-between="10" navigation
:scrollbar="{ draggable: false }" :centered-slides="false" :observer="true" :observeParents="true"
@swiper="onSwiper" @slideChange="onSlideChange">
<swiper-slide v-for="(file, index) in image" :key="index" @click="handleSlideClick(index, 'after')"
:class="{ 'active-slide': activeAfterIndex === index }">
<img :src="file.image_url" class="cursor-pointer" v-if="file.image_url" />
</swiper-slide>
</swiper>
</div>
</div>
</div>
</div>
<div class="appearanceAlarm-content-info mt-[16px]">
<div class="font-bold appearanceAlarm-content-info-title mb-[12px]">列车信息:</div>
<ul class="appearanceAlarm-content-info-list">
<li>
<span class="mr-8">列车编号: <i>{{ info.train_number }}</i></span>
<span class="mr-8">车型: <i>{{ info.train_model }}</i></span>
<span>发生时间: <i>{{ info.created_at }}</i></span>
</li>
<li>
<span class="mr-8">告警类型: <i>{{ info.alarm_type }}</i></span>
<span>故障类型: <i>{{ info.fault_type }}</i></span>
</li>
</ul>
<div class="appearanceAlarm-content-info-btn">
<el-button type="primary" @click="exportToExcel" class="appearanceAlarm-btn">
<span class="icon"></span> 导出
</el-button>
</div>
</div>
</div>
</el-dialog>
</template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref } from 'vue'; import { ref } from 'vue';
import ExcelJS from 'exceljs'; import ExcelJS from 'exceljs';
@ -216,6 +136,87 @@ onMounted(() => {
}); });
</script> </script>
<template>
<el-dialog class="appearanceAlarmModal fg-dialog" v-model="show" @close="handleClose" align-center :show-close="false" >
<!-- 自定义标题栏 -->
<template #header="{ close, titleId, titleClass }">
<div class="flex items-center justify-between appearanceAlarm-dialog-header fg-dialog-header">
<div class="flex items-center justify-center header-left">
<div class="header-icon mr-[12px]"></div>
<p class="overflow-hidden whitespace-nowrap text-ellipsis max-w-[650px]">故障提示</p>
</div>
<div class="fg-dialog-header-close" @click="close">
</div>
</div>
</template>
<!-- 图片区域 -->
<div class="appearanceAlarm-content">
<div class="appearanceAlarm-content-top">
<!-- <template v-for="(item,index) in image" :key="index">
<img :src="item.image_url" alt="" v-if="index < 4"></img>
</template> -->
<div class="appearanceAlarm-content-top-left">
<div class="appearanceAlarm-error-title-before appearanceAlarm-error-title">故障前</div>
<div class="appearanceAlarm-content-top-left-img">
<div class="appearanceAlarm-content-top-img">
<img :src="imageBefore" alt="" />
</div>
<div class="appearanceAlarm-content-top-img-slider">
<swiper ref="swiperModalRef" :modules="modules" :slides-per-view="3" :space-between="10" navigation
:scrollbar="{ draggable: false }" :centered-slides="false" :observer="true" :observeParents="true"
@swiper="onSwiper" @slideChange="onSlideChange">
<swiper-slide v-for="(file, index) in beforeImage" :key="index" @click="handleSlideClick(index, 'before')"
:class="{ 'active-slide': activeBeforeIndex === index }">
<img :src="file.image_url" class="cursor-pointer" v-if="file.image_url" />
</swiper-slide>
</swiper>
</div>
</div>
</div>
<div class="appearanceAlarm-content-top-right">
<div class="appearanceAlarm-error-title-after appearanceAlarm-error-title">故障后</div>
<div class="appearanceAlarm-content-top-right-img">
<div class="appearanceAlarm-content-top-img">
<img :src="imageAfter" alt=""></img>
</div>
<div class="appearanceAlarm-content-top-img-slider">
<swiper ref="swiperModalRef" :modules="modules" :slides-per-view="3" :space-between="10" navigation
:scrollbar="{ draggable: false }" :centered-slides="false" :observer="true" :observeParents="true"
@swiper="onSwiper" @slideChange="onSlideChange">
<swiper-slide v-for="(file, index) in image" :key="index" @click="handleSlideClick(index, 'after')"
:class="{ 'active-slide': activeAfterIndex === index }">
<img :src="file.image_url" class="cursor-pointer" v-if="file.image_url" />
</swiper-slide>
</swiper>
</div>
</div>
</div>
</div>
<div class="appearanceAlarm-content-info mt-[16px]">
<div class="font-bold appearanceAlarm-content-info-title mb-[12px]">列车信息:</div>
<ul class="appearanceAlarm-content-info-list">
<li>
<span class="mr-8">列车编号: <i>{{ info.train_number }}</i></span>
<span class="mr-8">车型: <i>{{ info.train_model }}</i></span>
<span>发生时间: <i>{{ info.created_at }}</i></span>
</li>
<li>
<span class="mr-8">告警类型: <i>{{ info.alarm_type }}</i></span>
<span>故障类型: <i>{{ info.fault_type }}</i></span>
</li>
</ul>
<div class="appearanceAlarm-content-info-btn">
<el-button type="primary" @click="exportToExcel" class="appearanceAlarm-btn">
<span class="icon"></span> 导出
</el-button>
</div>
</div>
</div>
</el-dialog>
</template>
<style lang="scss"> <style lang="scss">
.appearanceAlarmModal.el-dialog { .appearanceAlarmModal.el-dialog {

@ -1,320 +0,0 @@
<script setup lang="ts">
import { onMounted, onUnmounted, ref, watch, nextTick } from "vue";
import * as echarts from "echarts";
// props
const props = defineProps({
xData: {
type: Array as PropType<Array<string>>,
default: () => [],
},
legendArr: {
type: Array as PropType<Array<string>>,
default: () => [],
},
datas: {
type: Array as PropType<Array<Array<number>>>,
default: () => [],
},
colorArr: {
type: Array as PropType<Array<Array<string>>>,
default: () => [],
},
});
const chartContainer = ref<HTMLDivElement | null>(null);
let chartInstance: echarts.ECharts | null = null;
// 3D
const CubeLeft = echarts.graphic.extendShape({
shape: { x: 0, y: 0 },
buildPath: (ctx, shape) => {
const { xAxisPoint } = shape;
const [c0, c1, c2, c3] = [
[shape.x, shape.y],
[shape.x - 12, shape.y - 6],
[xAxisPoint[0] - 12, xAxisPoint[1] - 6],
[xAxisPoint[0], xAxisPoint[1]],
];
ctx
.moveTo(c0[0], c0[1])
.lineTo(c1[0], c1[1])
.lineTo(c2[0], c2[1])
.lineTo(c3[0], c3[1])
.closePath();
},
});
const CubeRight = echarts.graphic.extendShape({
shape: { x: 0, y: 0 },
buildPath: (ctx, shape) => {
const { xAxisPoint } = shape;
const [c1, c2, c3, c4] = [
[shape.x, shape.y],
[xAxisPoint[0], xAxisPoint[1]],
[xAxisPoint[0] + 12, xAxisPoint[1] - 6],
[shape.x + 12, shape.y - 6],
];
ctx
.moveTo(c1[0], c1[1])
.lineTo(c2[0], c2[1])
.lineTo(c3[0], c3[1])
.lineTo(c4[0], c4[1])
.closePath();
},
});
const CubeTop = echarts.graphic.extendShape({
shape: { x: 0, y: 0 },
buildPath: (ctx, shape) => {
const [c1, c2, c3, c4] = [
[shape.x, shape.y],
[shape.x + 12, shape.y - 6],
[shape.x, shape.y - 12],
[shape.x - 12, shape.y - 6],
];
ctx
.moveTo(c1[0], c1[1])
.lineTo(c2[0], c2[1])
.lineTo(c3[0], c3[1])
.lineTo(c4[0], c4[1])
.closePath();
},
});
//
echarts.graphic.registerShape("CubeLeft", CubeLeft);
echarts.graphic.registerShape("CubeRight", CubeRight);
echarts.graphic.registerShape("CubeTop", CubeTop);
//
const initChart = () => {
if (!chartContainer.value) return;
chartInstance = echarts.init(chartContainer.value);
setTimeout(() => {
chartInstance?.resize();
updateChart();
}, 500);
};
//
const updateChart = () => {
if (!chartInstance) return;
const series = props.datas
.map((item, index) => [
{
type: "custom",
name: props.legendArr[index],
renderItem: (params, api) => ({
type: "group",
x: (index - props.datas.length / 2) * 30 + 15,
children: [
{
type: "CubeLeft",
shape: {
api,
xValue: api.value(0),
yValue: api.value(1),
x: api.coord([api.value(0), api.value(1)])[0],
y: api.coord([api.value(0), api.value(1)])[1],
xAxisPoint: api.coord([api.value(0), 0]),
},
style: {
fill: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: props.colorArr[index % props.colorArr.length][1],
},
{
offset: 1,
color: props.colorArr[index % props.colorArr.length][0],
},
]),
},
},
{
type: "CubeRight",
shape: {
api,
xValue: api.value(0),
yValue: api.value(1),
x: api.coord([api.value(0), api.value(1)])[0],
y: api.coord([api.value(0), api.value(1)])[1],
xAxisPoint: api.coord([api.value(0), 0]),
},
style: {
fill: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: props.colorArr[index % props.colorArr.length][1],
},
{
offset: 1,
color: props.colorArr[index % props.colorArr.length][0],
},
]),
},
},
{
type: "CubeTop",
shape: {
api,
xValue: api.value(0),
yValue: api.value(1),
x: api.coord([api.value(0), api.value(1)])[0],
y: api.coord([api.value(0), api.value(1)])[1],
xAxisPoint: api.coord([api.value(0), 0]),
},
style: {
fill: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: props.colorArr[index % props.colorArr.length][1],
},
{
offset: 1,
color: props.colorArr[index % props.colorArr.length][1],
},
]),
},
},
],
}),
data: item,
},
{
type: "bar",
name: props.legendArr[index],
barWidth: 25,
// label: {
// normal: {
// show: true,
// position: "top",
// fontSize: 16,
// color: "#fff",
// offset: [0, -10],
// },
// },
itemStyle: { color: "transparent" },
data: item,
yAxisIndex: 0, // 使y
},
{
type: "bar",
name: props.legendArr[index],
barWidth: 25,
itemStyle: { color: "transparent" },
data: item,
yAxisIndex: 1, // 使y
},
])
.flat();
chartInstance.setOption({
tooltip: {
trigger: "axis",
borderWidth: 0,
backgroundColor: "rgba(8,36,68,.9)",
color: "#fff",
textStyle: { color: "#fff" },
formatter: (params) => {
let str = params[0].name + "</br>";
params.forEach((item, index) => {
if (item.seriesType === "custom") {
str += `
<div style='display:flex;justify-content:space-between;align-items:center'>
<div style='margin-right:20px;'>
<span style="display:inline-block;width:10px;height:10px;border-radius:5px;background-color:${
props.colorArr[index % props.colorArr.length][0]
}"></span>
&nbsp;${item.seriesName}
</div>
<span>&nbsp;${item.value ? item.value : "-"}</span>
</div>`;
}
});
return str;
},
},
grid: {
left: "5%",
right: "5%",
top: "5%",
bottom: "10%",
containLabel: true,
},
legend: {
left: "center",
top: "90%",
itemWidth: 12, //
itemHeight: 8,
textStyle: { color: "#fff", fontSize: 12 },
data: props.legendArr.map((name, index) => ({
name,
textStyle: { color: "#fff", fontSize: 12 },
itemStyle: { color: props.colorArr[index % props.colorArr.length][1] },
})),
},
xAxis: {
type: "category",
data: props.xData,
axisLine: { lineStyle: { color: "rgba(239, 247, 253, .1)" } },
axisLabel: { fontSize: 12, color: "#fff", margin: 12 },
},
yAxis: [
{
// name: "kWh",
// nameTextStyle: { color: "#fff", fontSize: 12 },
splitLine: {
lineStyle: { type: "dashed", color: "rgba(80,112,242,0.3)" },
},
axisLabel: { textStyle: { color: "#8C8C8C" }, fontSize: 12 },
// axisLine: { lineStyle: { color: "#8C8C8C" } },
// scale: true, //
},
{
// name: "kWh",
// nameTextStyle: { color: "#fff", fontSize: 12 },
splitLine: { lineStyle: { color: "transparent" } },
axisLabel: { textStyle: { color: "#8C8C8C" }, fontSize: 12 },
// axisLine: { lineStyle: { color: "#8C8C8C" } },
position: "right",
// scale: true, //
},
],
series,
});
};
const handleResize = () => {
chartInstance?.resize();
};
//
onMounted(async () => {
await nextTick();
initChart();
});
onUnmounted(() => {
if (chartInstance) {
chartInstance.dispose();
chartInstance = null;
chartInstance?.resize();
}
});
//
watch(
() => props,
async () => {
await nextTick();
updateChart();
// delay(600).then(() => resize());
},
{
deep: true,
immediate: true,
}
);
</script>
<template>
<div ref="chartContainer" style="width: 100%; height: 100%" />
</template>

@ -2,7 +2,7 @@
* @Author: donghao donghao@supervision.ltd * @Author: donghao donghao@supervision.ltd
* @Date: 2025-03-10 18:00:44 * @Date: 2025-03-10 18:00:44
* @LastEditors: donghao donghao@supervision.ltd * @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2025-08-13 15:58:03 * @LastEditTime: 2025-08-20 09:19:06
* @FilePath: \5G-Loading-Bay-Web\src\views\dashboard\components\DeviceStatus.vue * @FilePath: \5G-Loading-Bay-Web\src\views\dashboard\components\DeviceStatus.vue
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
--> -->
@ -57,14 +57,15 @@ const deviceStatusOptions = ref<Record<string, any>[]>([
<el-progress <el-progress
:show-text="false" :show-text="false"
:stroke-width="4" :stroke-width="4"
:percentage=" :percentage="100"
Math.floor(
(deviceStatus?.[v.valueKey] / deviceStatus?.total) * 100
)
"
:color="v.bgColor" :color="v.bgColor"
/> />
</div> </div>
<!-- :percentage="
Math.floor(
(deviceStatus?.[v.valueKey] / deviceStatus?.total) * 100
)
" -->
</div> </div>
</li> </li>
</ul> </ul>

@ -1,8 +1,39 @@
<script lang="ts" setup>
import { ref } from "vue";
import { Navigation, Scrollbar } from "swiper/modules";
interface Props {
/** 弹窗显隐 */
value: boolean;
info: Record<string, any>;
fileList: any[];
}
interface Emits {
(e: "update:value", val: boolean): void;
(e: "close"): void;
}
const props = withDefaults(defineProps<Props>(), {
value: false,
info: {},
fileList: [],
});
const emit = defineEmits<Emits>();
const show = computed({
get() {
return props.value;
},
set(val: boolean) {
emit("update:value", val);
},
});
</script>
<template> <template>
<el-dialog <el-dialog
class="digger-alarm-modal fg-dialog" class="digger-alarm-modal fg-dialog"
v-model="show" v-model="show"
@close="handleClose"
align-center align-center
:show-close="false" :show-close="false"
> >
@ -35,41 +66,7 @@
</el-dialog> </el-dialog>
</template> </template>
<script lang="ts" setup>
import { ref } from "vue";
import { Navigation, Scrollbar } from "swiper/modules";
interface Props {
/** 弹窗显隐 */
value: boolean;
info: Record<string, any>;
fileList: any[];
}
interface Emits {
(e: "update:value", val: boolean): void;
(e: "close"): void;
}
const props = withDefaults(defineProps<Props>(), {
value: false,
info: {},
fileList: [],
});
const emit = defineEmits<Emits>();
//
const handleClose = () => {
emits("close");
};
const show = computed({
get() {
return props.value;
},
set(val: boolean) {
emit("update:value", val);
},
});
</script>
<style lang="scss"> <style lang="scss">
.digger-alarm-modal.el-dialog { .digger-alarm-modal.el-dialog {

@ -29,16 +29,7 @@ const togglePlay = () => {
isPlaying.value = !isPlaying.value; isPlaying.value = !isPlaying.value;
}; };
// TODO 使
const handleProgress = (data: { currentTime: number; duration: number }) => {
console.log((data.currentTime / data.duration) * 100, "handleProgress");
const progressVal = (data.currentTime / data.duration) * 100;
};
// TODO 使
const handleDuration = (newDuration: number) => {
// duration.value = newDuration
};
// //
const loadData = () => { const loadData = () => {
recordList.value = props.historyVideos; recordList.value = props.historyVideos;
@ -76,11 +67,6 @@ const formatTime = (timeStr) => {
return timeStr.split(" ")[1].substring(0, 5); // return timeStr.split(" ")[1].substring(0, 5); //
}; };
//
const handleClose = () => {
emits("close");
};
const show = computed({ const show = computed({
get() { get() {
return props.value; return props.value;
@ -96,7 +82,6 @@ defineExpose({ loadData });
<el-dialog <el-dialog
class="historyVideoModal-wrap fg-dialog fg-dialog2" class="historyVideoModal-wrap fg-dialog fg-dialog2"
v-model="show" v-model="show"
@close="handleClose"
align-center align-center
:show-close="false" :show-close="false"
> >
@ -119,10 +104,8 @@ defineExpose({ loadData });
<div class="flex main-content"> <div class="flex main-content">
<!-- 播放器 --> <!-- 播放器 -->
<Player <Player
:src="currentVideo.video_url" :src="currentVideo?.video_url"
:is-playing="isPlaying" :is-playing="isPlaying"
@update:progress="handleProgress"
@update:duration="handleDuration"
@play="isPlaying = true" @play="isPlaying = true"
@pause="isPlaying = false" @pause="isPlaying = false"
/> />
@ -136,7 +119,6 @@ defineExpose({ loadData });
class="custom-select record_date_select" class="custom-select record_date_select"
clearable clearable
@change="handleDateChange" @change="handleDateChange"
@clear="handleClear"
> >
<el-option <el-option
v-for="(item, index) in dateList" v-for="(item, index) in dateList"

@ -1,92 +0,0 @@
<script setup lang="ts">
import { onMounted, onUnmounted, ref, watch } from "vue";
import * as echarts from "echarts";
const props = defineProps({
data: {
type: Array as PropType<Array<{ value: number; name: string }>>,
required: true,
},
colors: { type: Array as PropType<Array<string>>, default: () => [] },
});
const chartContainer = ref<HTMLDivElement | null>(null);
let chartInstance: echarts.ECharts | null = null;
const colorsArr = ['#FFCC4A','#028FF5','#06EA7C','#8500FF','#FF7D05','#00D1FF']
//
const initChart = () => {
if (!chartContainer.value) return;
chartInstance = echarts.init(chartContainer.value);
setTimeout(() => {
chartInstance?.resize();
updateChart();
}, 500);
};
//
const updateChart = () => {
if (!chartInstance) return;
chartInstance.setOption({
legend: {
type: "scroll",
orient: "vertical",
left: "70%",
align: "left",
top: "middle",
itemWidth: 16, //
itemHeight: 8,
textStyle: { color: "#FFF" },
},
series: [
{
type: "pie",
radius: ["30%", "80%"],
center: ["35%", "50%"],
label: { show: false },
itemStyle: {
color: (params) =>
new echarts.graphic.LinearGradient(0, 0, 1, 0, [
{ offset: 0, color: props.colors[params.dataIndex] },
{ offset: 1, color: colorsArr[params.dataIndex] },
]),
},
data: props.data,
},
],
});
};
//
onMounted(() => {
initChart();
});
onUnmounted(() => {
if (chartInstance) {
chartInstance.dispose();
chartInstance = null;
}
});
//
watch(
() => props.data,
async () => {
await nextTick();
updateChart();
}
);
//
// onMounted(() => {
// window.addEventListener("resize", () => chartInstance?.resize());
// });
// onUnmounted(() => {
// window.removeEventListener("resize", () => chartInstance?.resize());
// });
</script>
<template>
<div ref="chartContainer" style="width: 100%; height: 100%" />
</template>

@ -1,92 +0,0 @@
<script setup lang="ts">
import { onMounted, onUnmounted, ref, watch } from "vue";
import * as echarts from "echarts";
const props = defineProps({
data: {
type: Array as PropType<Array<{ value: number; name: string }>>,
required: true,
},
colors: { type: Array as PropType<Array<string>>, default: () => [] },
});
const chartContainer = ref<HTMLDivElement | null>(null);
let chartInstance: echarts.ECharts | null = null;
const colorsArr = ['#3FE3FA','#FF4D00']
//
const initChart = () => {
if (!chartContainer.value) return;
chartInstance = echarts.init(chartContainer.value);
setTimeout(() => {
chartInstance?.resize();
updateChart();
}, 500);
};
//
const updateChart = () => {
if (!chartInstance) return;
chartInstance.setOption({
legend: {
type: "scroll",
orient: "vertical",
left: "70%",
align: "left",
top: "middle",
itemWidth: 16, //
itemHeight: 8,
textStyle: { color: "#FFF" },
},
series: [
{
type: "pie",
radius: ["40%", "80%"],
center: ["35%", "50%"],
label: { show: false },
itemStyle: {
color: (params) =>
new echarts.graphic.LinearGradient(0, 0, 1, 0, [
{ offset: 0, color: props.colors[params.dataIndex] },
{ offset: 1, color: colorsArr[params.dataIndex] },
]),
},
data: props.data,
},
],
});
};
//
onMounted(() => {
initChart();
});
onUnmounted(() => {
if (chartInstance) {
chartInstance.dispose();
chartInstance = null;
}
});
//
watch(
() => props.data,
async () => {
await nextTick();
updateChart();
}
);
//
// onMounted(() => {
// window.addEventListener("resize", () => chartInstance?.resize());
// });
// onUnmounted(() => {
// window.removeEventListener("resize", () => chartInstance?.resize());
// });
</script>
<template>
<div ref="chartContainer" style="width: 100%; height: 100%" />
</template>

@ -9,7 +9,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import Player from "@/components/videoPlayer/Player.vue"; import Player from "@/components/videoPlayer/Player.vue";
import SwiperPlayer from "./SwiperPlayer.vue"; import SwiperPlayer from "@/components/Swiper/swiperPlayer.vue";
import { Swiper, SwiperSlide } from "swiper/vue"; import { Swiper, SwiperSlide } from "swiper/vue";
import { Navigation, Scrollbar, Mousewheel, Pagination } from "swiper/modules"; import { Navigation, Scrollbar, Mousewheel, Pagination } from "swiper/modules";
import "swiper/css"; import "swiper/css";

@ -1,49 +0,0 @@
<template>
<div class="flex items-center justify-center w-full h-full position-relative">
<video ref="videoRef" :controls="false" muted :src="videoUrl" width="100%" height="144"
style="object-fit: cover;" @error="handleVideoError" v-if="!isVideoError"></video>
<div class="bg_error_img" v-if="isVideoError">
</div>
<div :class="{ 'bg_icon': true, 'playing': isPlaying }" v-if="!isVideoError">
<!-- {{ isPlaying }} -->
</div>
</div>
</template>
<script lang="ts" setup>
const props = defineProps<{
videoUrl: string;
isPlaying: boolean;
}>();
const videoRef = ref<HTMLVideoElement | null>(null);
const isVideoError = ref<boolean>(false);
const handleVideoError = () => {
console.log('handleVideoError')
isVideoError.value = true;
};
</script>
<style lang="scss" scoped>
.bg_error_img {
width: 100%;
height: 100%;
background: url("@/assets/common/load_file_error.png") no-repeat center center;
background-size: 50%;
border: 1px dashed red;
}
.bg_icon {
position: absolute;
width: 100%;
height: 100%;
background: url("@/assets/common/player_icon_1.png") no-repeat center center;
background-size: 40px;
&.playing {
background: url("@/assets/common/player_icon_2.png") no-repeat center center;
background-size: 40px;
}
}
</style>

@ -18,10 +18,6 @@ const props = withDefaults(defineProps<Props>(), {
const emit = defineEmits<Emits>(); const emit = defineEmits<Emits>();
//
const handleClose = () => {
// emits('close');
};
const show = computed({ const show = computed({
get() { get() {
@ -36,7 +32,7 @@ const show = computed({
const itemCount = 16; // const itemCount = 16; //
</script> </script>
<template> <template>
<el-dialog class="vehiclModal-wrap fg-dialog fg-dialog2" v-model="show" @close="handleClose" align-center :show-close="false" > <el-dialog class="vehiclModal-wrap fg-dialog fg-dialog2" v-model="show" align-center :show-close="false" >
<!-- 自定义标题栏 --> <!-- 自定义标题栏 -->
<template #header="{ close, titleId, titleClass }"> <template #header="{ close, titleId, titleClass }">
<div class="flex items-center justify-between vehicl-dialog-header fg-dialog-header"> <div class="flex items-center justify-between vehicl-dialog-header fg-dialog-header">
@ -51,7 +47,6 @@ const itemCount = 16; // 这里可以根据实际需求动态设置
</template> </template>
<!-- 图片区域 --> <!-- 图片区域 -->
<div class="vehicl-content"> <div class="vehicl-content">
<!-- //TODO -->
<div class="vehicl-content-top"> <div class="vehicl-content-top">
<span class="vehicl-content-bottom-title">列车ID:</span> <span class="vehicl-content-bottom-title">列车ID:</span>
<div class="vehicl-content-top-img"> <div class="vehicl-content-top-img">
@ -64,7 +59,6 @@ const itemCount = 16; // 这里可以根据实际需求动态设置
</div> </div>
</div> </div>
<div class="vehicl-content-bottom"> <div class="vehicl-content-bottom">
<!-- //TODO -->
<span class="vehicl-content-bottom-title">列车与车厢号</span> <span class="vehicl-content-bottom-title">列车与车厢号</span>
<div class="flex items-center vehicl-content-bottom-vehicl"> <div class="flex items-center vehicl-content-bottom-vehicl">
<div class="train-card-item mb-[8px] mr-[8px] flex items-center justify-center "> <div class="train-card-item mb-[8px] mr-[8px] flex items-center justify-center ">

@ -4,6 +4,9 @@ import SwiperPlayer from "@/components/Swiper/swiperPlayer.vue";
import SwiperFile from "@/components/Swiper/swiperFile.vue"; import SwiperFile from "@/components/Swiper/swiperFile.vue";
import { isSuccessApi } from "@/utils/forApi"; import { isSuccessApi } from "@/utils/forApi";
// TODO // TODO
/**
* @使用数据结构 {"infer_result": [{"log": "一段文本", "pic_url": "图片路径"}, {"log": "", "pic_url": ""}]}
*/
// //
const longText = ` const longText = `
const xData = ref(["1月", "2月", "3月", "4月", "5月"]); const xData = ref(["1月", "2月", "3月", "4月", "5月"]);
@ -401,7 +404,7 @@ const handleExport = () => {
// //
const textGenerationSpeed = computed(() => { const textGenerationSpeed = computed(() => {
// //
return 10; return 2;
// return 100; // return 100;
}); });

Loading…
Cancel
Save