逆变器综合监控

This commit is contained in:
tcy
2025-08-27 14:59:18 +08:00
parent 46bfa429d3
commit e6c92a3b51
19 changed files with 894 additions and 2 deletions

View File

@ -6,9 +6,9 @@ VITE_APP_ENV = 'development'
# 开发环境
# 李陈杰 209
VITE_APP_BASE_API = 'http://192.168.110.209:8899'
# VITE_APP_BASE_API = 'http://192.168.110.209:8899'
# 曾涛
# VITE_APP_BASE_API = 'http://192.168.110.180:8899'
VITE_APP_BASE_API = 'http://192.168.110.180:8899'
# 罗成
# VITE_APP_BASE_API = 'http://192.168.110.213:8899'
# 朱银

View File

@ -31,6 +31,7 @@
"await-to-js": "3.0.0",
"axios": "1.7.8",
"crypto-js": "4.2.0",
"date-fns": "^4.1.0",
"diagram-js": "12.3.0",
"didi": "9.0.2",
"echarts": "5.5.0",

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
public/assets/demo/back.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 419 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 344 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 428 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
public/assets/demo/rain.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
public/assets/demo/yin.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
src/assets/demo/back.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

View File

@ -0,0 +1,128 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- 引入图标(这里用的是阿里图标库示例,实际可替换成自己的图标资源) -->
<link rel="stylesheet" href="https://at.alicdn.com/t/c/font_4245527_xxxxxx.css">
<!-- <link rel="stylesheet" href="style.css"> -->
<style>
/* 初始化样式 */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background: #eef5ff;
font-family: sans-serif;
}
/* 时间轴容器 */
.weather-timeline {
display: flex;
align-items: center;
background: #fff;
border-radius: 12px;
padding: 20px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
overflow-x: auto;
/* 适配小屏幕横向滚动 */
}
/* 每个时间项 */
.time-item {
display: flex;
flex-direction: column;
align-items: center;
margin: 0 12px;
min-width: 80px;
/* 保证 item 最小宽度 */
}
/* 当前时间项特殊样式 */
.time-item.current {
background: #e3f0ff;
border-radius: 8px;
padding: 10px;
transform: scale(1.1);
/* 稍微放大突出 */
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
}
/* 时间文本 */
.time {
font-size: 14px;
color: #333;
margin-bottom: 4px;
}
/* 温度文本 */
.temp {
font-size: 16px;
color: #666;
margin-bottom: 8px;
}
/* 图标样式(基于阿里图标库,可替换成自己的图标字体或图片) */
.iconfont {
font-size: 24px;
color: #f9b115;
/* 太阳/主色调 */
}
.icon-rain {
color: #9ec8f2;
/* 雨/蓝色系 */
}
.icon-cloud-moon {
color: #c9d6e5;
/* 多云 moon/浅灰蓝 */
}
</style>
<title>天气时间轴</title>
</head>
<body>
<div class="weather-timeline">
<div class="time-item">
<div class="time">16:00</div>
<div class="temp">30°C</div>
<i class="iconfont icon-sun"></i> <!-- 太阳图标 -->
</div>
<div class="time-item">
<div class="time">17:00</div>
<div class="temp">29°C</div>
<i class="iconfont icon-sun"></i>
</div>
<div class="time-item">
<div class="time">18:00</div>
<div class="temp">25°C</div>
<i class="iconfont icon-rain"></i> <!-- 小雨图标 -->
</div>
<div class="time-item current">
<div class="time">现在</div>
<div class="temp">25°C</div>
<i class="iconfont icon-rain"></i>
</div>
<div class="time-item">
<div class="time">20:00</div>
<div class="temp">25°C</div>
<i class="iconfont icon-cloud-moon"></i> <!-- 多云 moon 图标 -->
</div>
<div class="time-item">
<div class="time">21:00</div>
<div class="temp">20°C</div>
<i class="iconfont icon-cloud-moon"></i>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,311 @@
<template>
<div class="chart-container">
<!-- 图表标题和时间范围选择器 -->
<div class="chart-header">
<h2>功率与效率趋势</h2>
<div class="chart-actions">
<button @click="timeRange = 'day'" :class="{ active: timeRange === 'day' }">今日</button>
<button @click="timeRange = 'week'" :class="{ active: timeRange === 'week' }">本周</button>
<button @click="timeRange = 'month'" :class="{ active: timeRange === 'month' }">本月</button>
</div>
</div>
<!-- 图表内容区域 -->
<div ref="chartRef" class="chart-content"></div>
</div>
</template>
<script setup>
import { ref, onMounted, watch } from 'vue';
import * as echarts from 'echarts';
// 图表DOM引用
const chartRef = ref(null);
// 时间范围状态
const timeRange = ref('day');
// 图表实例
let chartInstance = null;
// 定义颜色常量
const POWER_COLOR = 'rgba(42, 130, 228, 1)';
const EFFICIENCY_COLOR = 'rgba(67, 207, 124, 1)';
// 生成指定范围内的随机数(用于模拟数据)
const getRandomValue = (min, max) => {
return Math.floor(Math.random() * (max - min + 1)) + min;
};
// 生成指定范围内的随机浮点数(用于效率数据)
const getRandomFloat = (min, max, decimalPlaces = 1) => {
const value = Math.random() * (max - min) + min;
return parseFloat(value.toFixed(decimalPlaces));
};
// 获取当前月份的天数
const getDaysInCurrentMonth = () => {
const now = new Date();
const year = now.getFullYear();
const month = now.getMonth() + 1; // 月份从0开始所以+1
return new Date(year, month, 0).getDate();
};
// 根据时间范围返回对应的数据
const getChartData = () => {
if (timeRange.value === 'day') {
return {
xAxis: ['00:00', '03:00', '06:00', '09:00', '12:00', '15:00', '18:00', '21:00'],
powerData: [320, 380, 350, 420, 580, 630, 550, 480],
efficiencyData: [85.2, 86.5, 87.1, 88.3, 89.5, 89.2, 88.7, 88.1]
};
} else if (timeRange.value === 'week') {
return {
xAxis: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
powerData: [4200, 4800, 5100, 4900, 5300, 3800, 3200],
efficiencyData: [86.2, 87.5, 88.1, 87.8, 89.0, 88.5, 87.9]
};
} else {
// 本月数据 - 按天显示
const daysInMonth = getDaysInCurrentMonth();
const xAxis = [];
const powerData = [];
const efficiencyData = [];
// 生成每天的数据
for (let i = 1; i <= daysInMonth; i++) {
xAxis.push(`${i}`);
// 生成合理范围内的功率数据10000-25000之间
powerData.push(getRandomValue(10000, 25000));
// 生成合理范围内的效率数据85-90之间保留1位小数
efficiencyData.push(getRandomFloat(85, 90));
}
return {
xAxis,
powerData,
efficiencyData
};
}
};
// 初始化图表
const initChart = () => {
if (chartRef.value && !chartInstance) {
chartInstance = echarts.init(chartRef.value);
}
const data = getChartData();
const option = {
tooltip: {
trigger: 'axis',
axisPointer: { type: 'cross' }
},
legend: {
data: ['总功率(kW)', '平均效率(%)'],
top: 0
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: {
type: 'category',
boundaryGap: false,
data: data.xAxis,
// 当月天数较多时优化X轴标签显示
axisLabel: {
interval: timeRange.value === 'month' ? 'auto' : 0,
rotate: timeRange.value === 'month' ? 45 : 0
}
},
yAxis: [
{
type: 'value',
name: '总功率(kW)',
axisLabel: {
formatter: '{value}'
}
},
{
type: 'value',
name: '平均效率(%)',
min: 80,
max: 95,
axisLabel: {
formatter: '{value}%'
}
}
],
series: [
{
name: '总功率(kW)',
type: 'line',
data: data.powerData,
smooth: true,
lineStyle: {
width: 3,
color: POWER_COLOR
},
symbol: 'circle',
symbolSize: 8,
itemStyle: {
color: POWER_COLOR
},
markPoint: {
data: [
{ type: 'max', name: '最大值' },
{ type: 'min', name: '最小值' }
],
itemStyle: {
color: POWER_COLOR
}
}
},
{
name: '平均效率(%)',
type: 'line',
yAxisIndex: 1,
data: data.efficiencyData,
smooth: true,
lineStyle: {
width: 3,
type: 'dashed',
color: EFFICIENCY_COLOR
},
symbol: 'diamond',
symbolSize: 8,
itemStyle: {
color: EFFICIENCY_COLOR
},
markPoint: {
data: [
{ type: 'max', name: '最大值' },
{ type: 'min', name: '最小值' }
],
itemStyle: {
color: EFFICIENCY_COLOR
}
}
}
]
};
chartInstance.setOption(option);
};
// 响应窗口大小变化
const handleResize = () => {
if (chartInstance) {
chartInstance.resize();
}
};
// 生命周期钩子
onMounted(() => {
initChart();
window.addEventListener('resize', handleResize);
// 清理函数
return () => {
window.removeEventListener('resize', handleResize);
if (chartInstance) {
chartInstance.dispose();
chartInstance = null;
}
};
});
// 监听时间范围变化,更新图表
watch(timeRange, () => {
initChart();
});
</script>
<style scoped>
.chart-container {
background-color: #fff;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
overflow: hidden;
height: 400px;
width: 100%;
}
.chart-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px 20px;
border-bottom: 1px solid #f0f0f0;
}
.chart-header h2 {
font-size: 16px;
font-weight: 600;
color: #333;
margin: 0;
}
.chart-actions button {
background: none;
border: 1px solid #e0e0e0;
padding: 5px 12px;
border-radius: 4px;
margin-left: 8px;
cursor: pointer;
font-size: 12px;
transition: all 0.2s ease;
}
.chart-actions button.active {
background-color: #1890ff;
color: white;
border-color: #1890ff;
}
.chart-content {
width: 100%;
height: calc(100% - 54px);
padding: 10px;
}
@media (max-width: 768px) {
.chart-container {
height: 350px;
}
}
@media (max-width: 480px) {
.chart-container {
height: 300px;
}
.chart-header {
flex-direction: column;
align-items: flex-start;
gap: 10px;
}
.chart-actions {
width: 100%;
display: flex;
justify-content: space-between;
}
.chart-actions button {
margin: 0;
flex: 1;
margin-right: 5px;
}
.chart-actions button:last-child {
margin-right: 0;
}
}
.model {
padding: 20px;
background-color: rgba(242, 248, 252, 1);
}
</style>

View File

@ -0,0 +1,23 @@
<template>
<div style="color: rgba(0, 30, 59, 1);;font-family: 'Alibaba-PuHuiTi-Bold';margin: 10px 0 0 0;"
:style="{ fontSize: fontLevelMap[props.fontLevel] }">
{{ props.title }}
</div>
<p style="color: rgba(154, 154, 154, 1);font-size: 14px;">
{{ props.subtitle }}
</p>
</template>
<script setup>
const props = defineProps({
title: String,
subtitle: String,
fontLevel: {
type: Number,
default: 1
}
})
const fontLevelMap = {
1: "24px",
2: "18px"
}
</script>

View File

@ -0,0 +1,222 @@
<template>
<div class="cardItem">
<el-card>
<div class="tianqi"
style="display: flex;flex-direction: column;align-items: center;background-color: #FAFAFA;border-radius: 10px;padding-bottom: 40px;">
<div>
<img src="/assets/demo/Sunny.png" style="display: block; width: 100px;height: 100px;" alt="">
</div>
<div style="font-family: 'Alibaba-PuHuiTi-Bold';font-size: 24px;">
31
</div>
<div>晴朗</div>
<div style="color: rgba(154, 154, 154, 1);font-size: 14px;">
紫外线强度<span></span>
</div>
<div class="tianqi2">
<div class="item">
<div>
<img src="/assets/demo/shidu.png" alt="">
</div>
<div class="text">相对湿度 <span>45%</span></div>
</div>
<div class="item">
<div>
<img src="/assets/demo/qiangdu.png" alt="">
</div>
<div class="text">光照强度 <span>45%</span></div>
</div>
<div class="item">
<div>
<img src="/assets/demo/fengshu.png" alt="">
</div>
<div class="text">风速 <span>2.3m/s</span></div>
</div>
<div class="item">
<div>
<img src="/assets/demo/riluo.png" alt="">
</div>
<div class="text">日落时间 <span>19.45</span></div>
</div>
</div>
</div>
<div class="weather-timeline">
<div class="time-box">
<div class="time-item">
<div class="time">16:00</div>
<div class="temp">30°C</div>
<div class="img-box">
<img src="/assets/demo/Sunny.png" alt="">
</div>
</div>
<div class="time-item">
<div class="time">17:00</div>
<div class="temp">29°C</div>
<div class="img-box">
<img src="/assets/demo/Sunny.png" alt="">
</div>
</div>
<div class="time-item">
<div class="child">
<div class="time">18:00</div>
<div class="temp">25°C</div>
<div class="img-box">
<img src="/assets/demo/rain.png" alt="">
</div>
</div>
</div>
<div class="time-item show">
<div class="time">现在</div>
<div class="temp">25°C</div>
<div class="img-box">
<img src="/assets/demo/rain.png" alt="">
</div>
</div>
<div class="time-item ">
<div class="time">20:00</div>
<div class="temp">25°C</div>
<div class="img-box">
<img src="/assets/demo/yin.png" alt="">
</div>
</div>
<div class="time-item">
<div class="time">21:00</div>
<div class="temp">20°C</div>
<div class="img-box">
<img src="/assets/demo/yin.png" alt="">
</div>
</div>
</div>
</div>
</el-card>
</div>
</template>
<style scoped lang="scss">
.cardItem {
padding: -20px !important;
}
.tianqi2 {
width: 100%;
display: flex;
justify-content: space-around;
margin-top: 50px;
img {
width: 40px;
height: 40x;
display: block;
}
.item {
display: flex;
flex-direction: column;
align-items: center;
font-size: 14px;
.text {
margin-top: 10px;
}
}
}
.weather-timeline {
text-align: center;
color: #fff;
font-size: 14px;
margin: 15px 0;
.time {
margin: 10px 0;
}
.img-box {
width: 50px;
height: 50px;
}
img {
width: 100%;
height: 100%;
display: block;
}
// img[src*='Sunny'] {
// width: 50px;
// height: 50px;
// }
// img[src*='rain'] {
// width: 60px;
// height: 60px;
// }
padding: 15px;
background: linear-gradient(to right, #D6E2FF, #DEEBFF);
border-radius: 15px;
.time-box {
background: linear-gradient(to right, #447BFF, #67A3FD);
display: flex;
justify-content: space-between;
border-radius: 10px;
padding: 10px 20px;
align-items: center;
}
.time-item.show {
color: rgba(24, 109, 245, 1);
position: relative;
// z-index: 888;
background-color: #fff;
}
.show::after {
// color: rgba(24, 109, 245, 1);
// position: relative;
// z-index: 888;
// background-color: #fff;
content: '';
position: absolute;
width: 100%;
height: 25px;
// background-color: red;
background-color: #fff;
left: 0;
border-radius: 0 0 25px 25px;
}
.show::before {
// color: rgba(24, 109, 245, 1);
// position: relative;
// z-index: 888;
// background-color: #fff;
content: '';
position: absolute;
width: 100%;
height: 25px;
// background-color: red;
background-color: #fff;
left: 0;
top: -25px;
border-radius: 25px 25px 0 0;
}
// .show::after {
// content: '';
// position: absolute;
// height: 155px;
// background-color: #fff;
// z-index: 999;
// width: 100%;
// top: -25px;
// left: 0;
// border-radius: 20px;
// }
}
</style>
<script setup>
</script>

207
src/views/demo/index.vue Normal file

File diff suppressed because one or more lines are too long