实现系统总览、统计分析的图标数据接口

This commit is contained in:
lixiaoyuan
2025-07-31 17:56:08 +08:00
parent 0958fcc224
commit 697193a7aa
19 changed files with 984 additions and 640 deletions

View File

@@ -453,3 +453,8 @@ tr.shown td.details-control {
.btn-default:hover {
background-color: #858585;
}
/* 隐藏所有输入框的清除按钮 */
input[type="date"]::-webkit-clear-button {
display: none;
}

View File

@@ -219,20 +219,43 @@ var G = {
getRandDataDay: function (a, b, n) {
var data = []
var t0 = Date.parse('2025-03-01 00:00:00')
var t0 = Date.parse('2025-07-01 00:00:00')
if (!n) { n = 24 }
var step = 86400 / n
var y = a;
for (var i = 0; i < n; ++i) {
// data[i] = { x: t0 + i * step * 1000, y: Math.sin(i * 0.1) * (n - m) }
var x = t0 + i * step * 1000
y = Math.floor((y + RAND(0, 50) - 25) * 100) / 100
data[i] = { x: t0 + i * step * 1000, y: y }
data[i] = { name: x, value: [x, y] }
}
return data
}
}
},
// 格式化日期为YYYY-MM-DD
formatDateMD: function (date) {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
//return `${year}-${month}-${day}`;
return `${month}-${day}`;
},
alertMessage: function (type, message) {
const wrapper = document.createElement('div')
wrapper.innerHTML = [
`<div class="alert alert-${type} alert-dismissible" role="alert">`,
` <div>${message}</div>`,
' <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>',
'</div>'
].join('')
const elemtParent = document.getElementById('alertBox')
if (elemtParent) { elemtParent.append(wrapper); }
}
}
function RAND(a, b) {
return a + Math.random() * (b - a)
}

View File

@@ -1,8 +1,4 @@
var optionBar = {
animation: false,
tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } },
grid: { left: '2%', right: '2%', bottom: '2%', containLabel: true },
legend: {
var optionLegend = {
show: true, //是否显示
orient: 'horizontal',
x: 'center', //可设定图例在左、右、居中
@@ -35,46 +31,66 @@ var optionBar = {
// textShadowOffsetX: 0, // 文字本身的阴影 X 偏移。
// textShadowOffsetY: 0, // 文字本身的阴影 Y 偏移。
},
},
}
xAxis: {
type: 'category',
//data: ['2025/3/1', '2025/3/2', '2025/3/3', '2025/3/4', '2025/3/5', '2025/3/6', '2025/3/7'],
data: ['1', '2', '3', '4', '5', '6', '7'],
axisTick: { alignWithLabel: true },
axisLabel: { color: 'white', fontSize: 12, margin: 8, interval: 'auto' },
},
var axisLabel = { color: 'white', fontSize: 12, margin: 8, interval: 'auto' };
var splitLine = { show: true, interval: 2, lineStyle: { type: 'dashed', color: 'gray' } }; //网格线
function echartGetOptionBar(yAxisLeft, yAxisRight) {
var option = {
animation: false,
tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } },
grid: { left: '2%', right: '2%', bottom: '2%', containLabel: true },
legend: optionLegend,
xAxis: { type: 'category', axisTick: { alignWithLabel: true }, axisLabel: axisLabel, data: [] },
yAxis: [
{
type: 'value',
show: true,
name: yAxisLeft,
nameTextStyle: { color: 'white', fontSize: 15, width: 300 },
axisTick: { show: true },
axisLine: { show: true },
axisLabel: { color: 'white', fontSize: 12, margin: 8, interval: 'auto' },
//网格线
splitLine: { show: true, interval: 2, lineStyle: { type: 'dashed', color: 'gray' } },
axisLabel: axisLabel,
splitLine: splitLine,
//boundaryGap: [0, '100%'],
},
{
position: 'right',
type: 'value',
show: true,
name: yAxisRight,
nameTextStyle: { color: 'white', fontSize: 15, width: '160px' },
axisTick: { show: true },
axisLine: { show: true },
axisLabel: axisLabel,
splitLine: splitLine,
//boundaryGap: [0, '100%'],
}
],
series: [
// { name: '日发电电量', type: 'bar', data: [30, 28, 35, 18, 36, 27, 19], color: '#2a82e4' },
],
}
function echartGetOptionBar() {
return JSON.parse(JSON.stringify(optionBar))
//if (yAxisLeft) { option.yAxis[0].name = yAxisLeft; }
//if (yAxisRight) { option.yAxis[1].name = yAxisRight; }
// yaxis.forEach(item => { })
//return JSON.parse(JSON.stringify(optionBar))
return option;
}
var optionAxisX_category = {
type: 'category',
//data: ['2025/3/1', '2025/3/2', '2025/3/3', '2025/3/4', '2025/3/5', '2025/3/6', '2025/3/7'],
data: ['1'],
axisTick: { alignWithLabel: true },
axisLabel: { color: 'white', fontSize: 12, margin: 8, interval: 'auto' },
data: [],
}
var optionAxisX_time = {
type: 'time',
splitLine: { show: false },
splitNumber: 8,
axisTick: { alignWithLabel: true },
axisLine: { lineStyle: { color: 'white' } },
@@ -84,54 +100,29 @@ var optionAxisX_time = {
var date = new Date(value)
var hour = date.getHours()
var minutes = date.getMinutes()
if (hour < 10) {
hour = '0' + hour
}
if (minutes < 10) {
minutes = '0' + minutes
}
if (hour < 10) { hour = '0' + hour }
if (minutes < 10) { minutes = '0' + minutes }
return hour + ':' + minutes
},
},
}
function echartGetOptionCurve(yAxisLeft, yAxisRight) {
var optionCurve = {
animation: false,
title: [], //
grid: { left: '2%', right: '2%', bottom: '2%', containLabel: true },
legend: { show: true, orient: 'horizontal', x: 'center', y: 'top', padding: [20, 10, 10, 50], textStyle: { color: '#ffffff' }, data: [], },
tooltip: {
trigger: 'axis',
// formatter: function (params) {
// params = params[0]
// var date = new Date(params.name)
// var hour = date.getHours()
// var minutes = date.getMinutes()
// if (hour < 10) { hour = '0' + hour }
// if (minutes < 10) { minutes = '0' + minutes }
// var dateStr = hour + ':' + minutes
// return dateStr + ' ' + params.value[1]
// },
axisPointer: { animation: false },
},
legend: optionLegend,
tooltip: { trigger: 'axis', axisPointer: { animation: false } },
xAxis: {
type: 'time',
splitLine: { show: false },
splitNumber: 8,
axisTick: { alignWithLabel: true },
axisLine: { lineStyle: { color: 'white' } },
//axisLine: { lineStyle: { color: 'white' } },
//interval: 3600, // 设置x轴时间间隔
axisLabel: {
color: 'white',
// formatter: function (value, index) {
// var date = new Date(value)
// var hour = date.getHours()
// var minutes = date.getMinutes()
// if (hour < 10) { hour = '0' + hour }
// if (minutes < 10) { minutes = '0' + minutes }
// //return hour + ':' + minutes
// return "value"
// },
fontSize: 12,
// 格式化x轴显示
formatter: function (value, index) {
var date = new Date(value)
@@ -140,32 +131,36 @@ var optionCurve = {
if (hour < 10) { hour = '0' + hour }
if (minutes < 10) { minutes = '0' + minutes }
return hour + ':' + minutes
// alert(new Date().toLocaleDateString())
// // 如果时间是 23:59:59 , 格式化为 24:00
// if (value === new Date(moment().endOf('day').format('YYYY-MM-DD HH:mm:ss')).getTime()) {
// return moment(value).format("24:00");
// } else {
// // 其他的时间返回格式化 00:00
// return moment(value).format("HH:mm");
// }
}
},
},
yAxis: {
yAxis: [
{
type: 'value',
axisTick: { show: true },
axisLine: { show: true, lineStyle: { color: 'white' } },
axisLabel: { color: 'white' },
splitLine: { show: true, lineStyle: { type: 'dashed', color: 'gray' } },
show: true,
name: yAxisLeft,
nameTextStyle: { color: 'white', fontSize: 15 },
boundaryGap: [0, '100%'],
axisTick: { show: true },
axisLine: { show: true },
axisLabel: axisLabel,
splitLine: splitLine,
//boundaryGap: [0, '100%'],
},
{
position: 'right',
type: 'value',
show: true,
name: yAxisRight,
nameTextStyle: { color: 'white', fontSize: 15 },
axisTick: { show: true },
axisLine: { show: true },
axisLabel: axisLabel,
splitLine: splitLine,
//boundaryGap: [0, '100%'],
}
],
// series: [{ name: '数据', type: 'line', hoverAnimation: false, smooth: false, symbolSize: 4, data: [] }],
}
function echartGetOptionCurve() {
optionCurve.legend.data = []
optionCurve.series = []
return optionCurve
}
@@ -177,11 +172,17 @@ function echartUpdateData(chart, index, data) {
}
}
function initEchartBar(id, seriesItems) {
function initEchartBar(id, seriesItems, xdata, yAxisLeft, yAxisRight) {
var echart = echarts.init(document.getElementById(id))
var option = echartGetOptionBar()
var option = echartGetOptionBar(yAxisLeft, yAxisRight)
option.legend.data = seriesItems
option.series = []
option.xAxis = {
type: 'category',
axisTick: { alignWithLabel: true },
axisLabel: { color: 'white', fontSize: 12, margin: 8, interval: 'auto' },
data: xdata
}
seriesItems.forEach(item => {
option.series.push({ name: item, type: 'bar', data: [] })
});
@@ -189,18 +190,18 @@ function initEchartBar(id, seriesItems) {
return echart
}
function updateEchartBar(chart, index, xdata, ydata) {
function updateEchartBar(chart, xdata, series) {
var option = chart.getOption()
option.xAxis.data = xdata
if (index < option.series.length) {
option.series[index].data = ydata
option.xAxis = { data: xdata }
//var series = [];
//ydataArray.forEach((d => { series.push({ data: d }) }))
option.series = series
chart.setOption(option)
}
}
function initEchartCurve(id, seriesItems) {
function initEchartCurve(id, seriesItems, yAxisLeft, yAxisRight) {
var echart = echarts.init(document.getElementById(id))
var option = echartGetOptionCurve()
var option = echartGetOptionCurve(yAxisLeft, yAxisRight)
option.legend.data = seriesItems
option.series = []
seriesItems.forEach(item => {
@@ -213,9 +214,10 @@ function initEchartCurve(id, seriesItems) {
function updateEchartCurve(chart, index, data) {
var option = chart.getOption()
if (index < option.series.length) {
for (var i = 0; i < data.length; ++i) {
option.series[index].data[i] = { name: data[i].x, value: [data[i].x, data[i].y] }
}
option.series[index].data = data
// for (var i = 0; i < data.length; ++i) {
// option.series[index].data[i] = { name: data[i].x, value: [data[i].x, data[i].y] }
// }
chart.setOption(option)
}
}

View File

@@ -82,16 +82,21 @@
</head>
<body>
<div style="width:100%; height:100%;">
<div
style="width:100%; height: calc(8vh); display: flex; justify-content: space-between; padding-top: 1.4%; font-family: 优设标题黑;">
<div class="myrow" style="height: 30px; color:white; font-size: 20px; float: left">
<button type="button" class="btn btn-danger btn-sm" id="liveAlertBtn" style="font-size: 20px;">显示警告框</button>
<div id="currentTime" style="width:250px; margin-left: 20px; "></div>
<div id="currentWeekday"></div>
</div>
<div style=" width:500px; height: 30px; display: flex;justify-content: flex-end;">
<div style=" width: 28px; height: 28px; background-color: #01b7d1; border-radius: 14px;"></div>
<div id='username' style="line-height:28px;color: white; font-size: 20px; font-weight: 500; margin-left: 10px; ">
<div id='username'
style="line-height:28px;color: white; font-size: 20px; font-weight: 500; margin-left: 10px; ">
</div>
<button
style="width:30px; height: 30px; background-color: transparent; border: none; background-image: url('../ui/exit.png'); background-size: cover; background-repeat: no-repeat;margin-left: 10px; margin-right: 10px;"
@@ -110,7 +115,12 @@
<button class="btn btn-primary" style="margin: 10px" onclick="onClickMenuBtn(this, '安全管理')">安全管理</button>
<button class="btn btn-primary" style="margin: 10px" onclick="onClickMenuBtn(this, 'test')">测试页面</button>
</div>
<!-- 浮动在右下角的子元素 -->
<div id="alertBox"
style="position: absolute; right: 0; top: 120px; width: 600px; height: 0px; background: red; z-index: 10;">
</div>
</div>
<div id="loginPage" style="position: fixed; top:0px; left:0px; width: 100%; height: 100%; background-color: #07486f; background-image: url('../ui/bkgLogin.png'); background-size: 100% 100%;
background-attachment: fixed;">
<form id="loginForm" class="was-validated"
@@ -229,6 +239,14 @@
$("#loginPage").hide()
onClickMenuBtn(document.getElementById('homePageBtn'), '系统总览')
})
const alertTrigger = document.getElementById('liveAlertBtn')
if (alertTrigger) {
alertTrigger.addEventListener('click', () => {
G.alertMessage('danger', '这是一个错误提示信息!')
})
}
</script>
</html>

View File

@@ -33,7 +33,7 @@
<option value="3">储能设备</option>
<option value="4">充电设备</option>
<option value="5">负荷设备</option>
<option value="0">其它</option>0
<option value="0">其它</option>
</select>
</div>
<div class="input-group mb-3">

View File

@@ -38,27 +38,6 @@ $(document).ready(function () {
$('div.gotopage').html('<b style="color:#7f8fa4">跳转至 </b><input id="searchNumber" style="width:80px"/><b style="color:#7f8fa4;"> 页</b>')
// myTable.row.add(['5214875222', 'C018', 'XH150', '', '', '2025-03-03', 'TCP', '', '', '', '', ''])
// myTable.row.add(['5214875222', 'C018', 'XH150', '', '', '2025-03-03', 'TCP', '', '', '', '', ''])
// myTable.row.add(['5214875222', 'C018', 'XH150', '', '', '2025-03-03', 'TCP', '', '', '', '', ''])
// myTable.row.add(['5214875222', 'C018', 'XH150', '', '', '2025-03-03', 'TCP', '', '', '', '', ''])
// myTable.row.add(['5214875222', 'C018', 'XH150', '', '', '2025-03-03', 'TCP', '', '', '', '', ''])
// myTable.row.add(['5214875222', 'C018', 'XH150', '', '', '2025-03-03', 'TCP', '', '', '', '', ''])
// myTable.row.add(['5214875222', 'C018', 'XH150', '', '', '2025-03-03', 'TCP', '', '', '', '', ''])
// myTable.row.add(['5214875222', 'C018', 'XH150', '', '', '2025-03-03', 'TCP', '', '', '', '', ''])
// myTable.row.add(['5214875222', 'C018', 'XH150', '', '', '2025-03-03', 'TCP', '', '', '', '', ''])
// myTable.row.add(['5214875222', 'C018', 'XH150', '', '', '2025-03-03', 'TCP', '', '', '', '', ''])
// myTable.row.add(['5214875222', 'C018', 'XH150', '', '', '2025-03-03', 'TCP', '', '', '', '', ''])
// myTable.row.add(['5214875222', 'C018', 'XH150', '', '', '2025-03-03', 'TCP', '', '', '', '', ''])
// myTable.row.add(['5214875222', 'C018', 'XH150', '', '', '2025-03-03', 'TCP', '', '', '', '', ''])
// myTable.row.add(['5214875222', 'C018', 'XH150', '', '', '2025-03-03', 'TCP', '', '', '', '', ''])
// myTable.row.add(['5214875222', 'C018', 'XH150', '', '', '2025-03-03', 'TCP', '', '', '', '', ''])
// myTable.row.add(['5214875222', 'C018', 'XH150', '', '', '2025-03-03', 'TCP', '', '', '', '', ''])
// myTable.row.add(['5214875222', 'C018', 'XH150', '', '', '2025-03-03', 'TCP', '', '', '', '', ''])
// myTable.row.add(['5214875222', 'C018', 'XH150', '', '', '2025-03-03', 'TCP', '', '', '', '', ''])
// myTable.row.add(['5214875222', 'C018', 'XH150', '', '', '2025-03-03', 'TCP', '', '', '', '', ''])
// myTable.row.add(['5214875222', 'C018', 'XH150', '', '', '2025-03-03', 'TCP', '', '', '', '', ''])
// myTable.row.add(['5214875222', 'C018', 'XH150', '', '', '2025-03-03', 'TCP', '', '', '', '', ''])
// myTable.row.add(['1', '2', '3', '', '', '', '', '', '', '', '', ''])
// myTable.row.add(['1', '2', '3', '', '', '', '', '', '', '', '', ''])
// myTable.row.add(['1', '2', '3', '', '', '', '', '', '', '', '', ''])

View File

@@ -1,67 +1,65 @@
optionBar.xAxis.data = ['03/01', '03/02', '03/03', '03/04', '03/05', '03/06', '03/07']
var optionBar = echartGetOptionBar()
optionBar.xAxis.data = []
optionBar.legend.data = ['发电电量', '入网电量']
optionBar.series = [
{ name: '发电电量', type: 'bar', data: [50, 28, 35, 18, 36, 27, 19] },
{ name: '入网电量', type: 'bar', data: [10, 32, 20, 33, 39, 13, 22] },
{ name: '发电电量', type: 'bar', data: [] },
{ name: '入网电量', type: 'bar', data: [] },
]
optionBar.yAxis[0].name = '电量'
optionBar.yAxis[1].name = ''
var mychartSolar = echarts.init(document.getElementById('mychartSolar'))
mychartSolar.setOption(optionBar)
optionBar.legend.data = ['充电电量', '放电电量']
optionBar.series = [
{ name: '充电电量', type: 'bar', data: [50, 28, 35, 18, 36, 27, 19] },
{ name: '放电电量', type: 'bar', data: [10, 32, 20, 33, 39, 13, 22] },
{ name: '充电电量', type: 'bar', data: [] },
{ name: '放电电量', type: 'bar', data: [] },
]
optionBar.yAxis[0].name = '电量'
optionBar.yAxis[1].name = ''
var mychartStorage = echarts.init(document.getElementById('mychartStorage'))
mychartStorage.setOption(optionBar)
optionBar.legend.data = ['用电电量', '最大功率']
optionBar.series = [
{ name: '用电电量', type: 'bar', data: [50, 28, 35, 18, 36, 27, 19] },
{ name: '最大功率', type: 'bar', data: [10, 32, 20, 33, 39, 13, 22] },
{ name: '用电电量', type: 'bar', data: [] },
{ name: '最大功率', type: 'bar', data: [] },
]
optionBar.yAxis[0].name = '电量'
optionBar.yAxis[1].name = '功率'
var mychartLoad = echarts.init(document.getElementById('mychartLoad'))
mychartLoad.setOption(optionBar)
optionBar.legend.data = ['充电电量', '充电次数', '充电收益']
optionBar.series = [
{ name: '充电电量', type: 'bar', data: [50, 28, 35, 18, 36, 27, 19] },
{ name: '充电次数', type: 'bar', data: [10, 32, 20, 33, 39, 13, 22] },
{ name: '充电收益', type: 'bar', data: [10, 32, 20, 33, 39, 13, 22] },
{ name: '充电电量', type: 'bar', data: [] },
{ name: '充电次数', type: 'bar', data: [] },
{ name: '充电收益', type: 'bar', data: [] },
]
optionBar.yAxis[0].name = '电量'
optionBar.yAxis[1].name = '收益'
var mychartCharge = echarts.init(document.getElementById('mychartCharge'))
mychartCharge.setOption(optionBar)
optionBar.legend.data = ['光伏设备', '储能设备', '负荷设备']
optionBar.series = [
{ name: '光伏设备', type: 'bar', data: [50, 28, 35, 18, 36, 27, 19] },
{ name: '储能设备', type: 'bar', data: [10, 32, 20, 33, 39, 13, 22] },
{ name: '负荷设备', type: 'bar', data: [10, 32, 20, 33, 39, 13, 22] },
{ name: '光伏设备', type: 'bar', data: [] },
{ name: '储能设备', type: 'bar', data: [] },
{ name: '负荷设备', type: 'bar', data: [] },
]
optionBar.yAxis[0].name = '次数'
optionBar.yAxis[1].name = ''
var mychartAlert = echarts.init(document.getElementById('mychartAlert'))
mychartAlert.setOption(optionBar)
function getRandomCurveData(m, n) {
var data = []
var t0 = Date.parse('2025-03-01 00:00:00')
var step = 600
var N = 86400 / step
var y = 500
for (var i = 0; i <= N; ++i) {
var t = t0 + i * step * 1000
//var y = Math.sin(i * 0.1) * (n - m) + m
y = Math.floor((y + RAND(0, 50) - 25) * 100) / 100
data[i] = { name: t, value: [t, y] }
}
return data
}
var optionCurve = echartGetOptionCurve()
optionCurve.legend.data = ['发电功率', '辐照度']
optionCurve.series = [
{ name: '发电功率', type: 'line', hoverAnimation: false, smooth: false, symbolSize: 0, data: getRandomCurveData(100, 200) },
{ name: '辐照度', type: 'line', hoverAnimation: false, smooth: false, symbolSize: 0, data: getRandomCurveData(100, 200) },
{ name: '发电功率', type: 'line', hoverAnimation: false, smooth: false, symbolSize: 0, data: [] },
{ name: '辐照度', type: 'line', hoverAnimation: false, smooth: false, symbolSize: 0, data: [] },
]
optionCurve.yAxis[0].name = '功率kw'
optionCurve.yAxis[1].name = '光照Lux'
var mychartRunning = echarts.init(document.getElementById('mychartRunning'))
mychartRunning.setOption(optionCurve)
@@ -95,8 +93,8 @@ function updatePageData() {
var charge = { d1: [], d2: [], d3: [] }
res.forEach(item => {
solar.d1.push(item['elect_gen_solar'])
solar.d2.push(item['elect_in_solar'])
solar.d1.push(item['elect_gen'])
solar.d2.push(item['elect_in'])
storage.d1.push(item['elect_store'])
storage.d2.push(item['elect_discharge'])
@@ -113,21 +111,32 @@ function updatePageData() {
// var data2 = [1, 2, 3, 4, 3, 2, 1]
// var data3 = [1, 2, 3, 4, 3, 2, 1]
mychartSolar.setOption({ series: [{ data: solar.d1 }, { data: solar.d2 }, { data: solar.d3 }] });
mychartStorage.setOption({ series: [{ data: storage.d1 }, { data: storage.d2 }, { data: storage.d3 }] });
mychartLoad.setOption({ series: [{ data: load.d1 }, { data: load.d2 }, { data: load.d3 }] });
mychartCharge.setOption({ series: [{ data: charge.d1 }, { data: charge.d2 }, { data: charge.d3 }] });
mychartAlert.setOption({ series: [{ data: solar.d1 }, { data: solar.d2 }, { data: solar.d3 }] });
var xdata = []
for (let i = 6; i >= 0; i--) {
const date = new Date();
date.setDate(date.getDate() - i);
xdata.push(G.formatDateMD(date));
}
updateEchartBar(mychartSolar, xdata, [{ data: solar.d1 }, { data: solar.d2 }, { data: solar.d3 }])
updateEchartBar(mychartStorage, xdata, [{ data: storage.d1 }, { data: storage.d2 }, { data: storage.d3 }])
updateEchartBar(mychartLoad, xdata, [{ data: load.d1 }, { data: load.d2 }, { data: load.d3 }])
updateEchartBar(mychartCharge, xdata, [{ data: charge.d1 }, { data: charge.d2 }, { data: charge.d3 }])
updateEchartBar(mychartAlert, xdata, [{ data: solar.d1 }, { data: solar.d2 }, { data: solar.d3 }])
}))
G.cppNative.getStatisticPowerDay().then(res => {
mychartRunning.setOption({ series: [{ data: res }] })
})
G.cppNative.getStatisticIrradianceDay().then(res => {
mychartRunning.setOption({ series: [{}, { data: res, yAxisIndex: 1 }] })
})
// 查询数据获取环境信息:光照、风速、环境温度、湿度
G.cppNative.getEnvironmentInfo().then(res => {
$('#envIllumination').text(res['illumination'] + ' Lux')
$('#envWindspeed').text(res['windspeed'] + ' m/s')
$('#envTemperture').text(res['temperature'] + ' ℃')
$('#envHumidity').text(res['humidity'] + ' %')
})
}
@@ -139,6 +148,8 @@ document.currentScript.addEventListener('DOMNodeRemoved', () => {
});
$(document).ready(function () {
updatePageData()
// 定时器更新页面数据

View File

@@ -253,15 +253,14 @@
</div>
<div id="deviceAttrPop" class="mask">
<div class="pop" style="height: 500px">
<div id="deviceAttrPopPanel" class="pop" style="height: 500px">
<p id="devicePopTitle" class="pop_title">设备属性设置</p>
<form id="deviceAttrForm" class="was-validated" style="margin: 0 80px 0 80px; padding-top: 30px">
<div class="input-group mb-3"></div>
<div class="input-group mb-3"></div>
</form>
<div style="display: flex; justify-content: center; padding: 20px 20px 20px 20px">
<button id="deviceAttrFormOk" class="btn btn-success" style="width: 90px; margin-right: 20px"
disabled>确定</button>
<button id="deviceAttrFormOk" class="btn btn-success" style="width: 90px; margin-right: 20px">确定</button>
<button class="btn btn-danger" style="width: 90px; margin-left: 20px"
onclick="G.showElement('deviceAttrPop', false)">取消</button>
</div>
@@ -298,7 +297,7 @@
</div>
</form>
<div style="display: flex; justify-content: center; padding: 20px 20px 20px 20px">
<button id="priceFormOk" class="btn btn-success" style="width: 90px; margin-right: 20px" disabled>确定</button>
<button id="priceFormOk" class="btn btn-success" style="width: 90px; margin-right: 20px">确定</button>
<button class="btn btn-danger" style="width: 90px; margin-left: 20px"
onclick="G.showElement('pricePop', false)">取消</button>
</div>

View File

@@ -254,23 +254,18 @@ async function initSubpage(id) {
})
})
}
else if (id == 'role') {
}
else if (id == 'role') { }
else if (id == 'price') {
var elementSelectPriceType = document.getElementById('priceForm_type')
elementSelectPriceType.innerHTML = ''
await G.cppNative.queryPriceTypeList().then(res => {
res.forEach(item => {
elementSelectPriceType.options.add(new Option(item.name, item.id))
})
G.cppNative.queryPriceTypeList().then(res => {
res.forEach(item => { elementSelectPriceType.options.add(new Option(item.name, item.id)) })
})
}
else if (id == 'policy') {
var elementSelectPolicyType = document.getElementById('policyForm_type')
elementSelectPolicyType.innerHTML = ''
for (var k in policyTypeDef) {
elementSelectPolicyType.options.add(new Option(policyTypeDef[k], k))
}
for (var k in policyTypeDef) { elementSelectPolicyType.options.add(new Option(policyTypeDef[k], k)) }
}
var tableInfo = tableDef[id]
@@ -280,8 +275,11 @@ async function initSubpage(id) {
return
}
// 初始化表格
G.initTable(id, tableInfo)
// 初始化弹窗Form
G.initForm(id, popConfirm)
if (id == 'device') { G.initForm("deviceAttr", popConfirm) }
// 绑定行编辑
tableInfo.table.on('click', '#btnRowEdit', function () {
@@ -310,50 +308,67 @@ function showPop(id, rowData) {
// 设置弹框的参数信息
G.popSetParams(id, tableInfo.popkeys, popRowdata, callbackPopSetParams)
if (id == 'user') {
G.popSetParamReadonly('user', 'account', isEdit)
}
if (id == 'user') { G.popSetParamReadonly('user', 'account', isEdit) }
}
var deviceAttrKeyDef = {
commType: "通讯方式",
ip: "通讯地址",
port: "通讯端口",
isclient: "客户端",
}
var deviceAttrKeyDef = { commType: "通讯方式", ip: "通讯地址", port: "通讯端口", isclient: "客户端" }
// 显示设备的属性编辑弹窗属性字段格式为JSON: attrs="{}"
function showPopDeviceAttr(rowData) {
G.showElement('deviceAttrPop', true)
popRowdata = (rowData && rowData.length > 0) ? rowData : null
var device_id = rowData[0]
var deviceType = rowData[1]
var deviceTypeStr = deviceTypeDef[deviceType]
var attrsStr = rowData[9]
var attrs = { commType: "", ip: "", port: 0, isclient: 1 }
try {
attrs = JSON.parse(attrsStr);
} catch (error) {
}
var attrs = {}
try { attrs = JSON.parse(attrsStr); } catch (error) { attrs = {} }
if (Object.keys(attrs).length == 0) { attrs = { commType: "", ip: "", port: 0, isclient: 1 } }
var elemtForm = document.getElementById('deviceAttrForm')
elemtForm.innerHTML =
`<div class="input-group mb-3">
<span class="input-group-text" style="width: 90px; background-color: #a6c0da">编号</span>
<span class="input-group-text" style="width: 90px; background-color: #a6c0da">ID</span>
<input type="text" class="form-control" value='${device_id}' disabled />
</div>
<div class="input-group mb-3">
<span class="input-group-text" style="width: 90px; background-color: #a6c0da">设备类型</span>
<input type="text" class="form-control" value='${deviceTypeStr}' disabled />
</div>`
</div>
`
for (k in attrs) {
var title = deviceAttrKeyDef[k]
elemtForm.innerHTML += `<div class="input-group mb-3">
var v = attrs[k]
if (k == "commType") {
var optionStr = ('<option ' + (v == "TCP" ? 'selected ' : '') + 'value="TCP">TCP</option>')
+ ('<option ' + (v == "MODBUS" ? 'selected ' : '') + 'value="MODBUS">MODBUS</option>')
+ ('<option ' + (v == "SDK" ? 'selected ' : '') + 'value="SDK">SDK</option>')
+ ('<option ' + (v == "ACTIVEX" ? 'selected ' : '') + 'value="ACTIVEX">ACTIVEX</option>')
elemtForm.innerHTML +=
`<div class="input-group mb-3">
<span class="input-group-text" style="width: 90px; background-color: #a6c0da">${title}</span>
<input type="text" class="form-control" value='${attrs[k]}' />
</div>`
<select id="${k}" class="form-select" required>
${optionStr}
</select>
</div>
`
} else {
elemtForm.innerHTML +=
`<div class="input-group mb-3">
<span class="input-group-text" style="width: 90px; background-color: #a6c0da">${title}</span>
<input id="${k}" type="text" class="form-control" value='${v}' />
</div>
`
}
}
G.cppNative.log(elemtForm.innerHTML);
}
function showPrompt(text, status) {
G.showElement('promptPop', true)
@@ -404,9 +419,7 @@ function callbackPopGetParams(id, key) {
val = []
var elemtFormPermission = document.getElementById('roleForm_permission')
var elemtPermissionList = elemtFormPermission.querySelectorAll('input')
elemtPermissionList.forEach((elemt => {
val.push({ permission_id: elemt.value, is_open: (elemt.checked ? 1 : 0) })
}))
elemtPermissionList.forEach((elemt => { val.push({ permission_id: elemt.value, is_open: (elemt.checked ? 1 : 0) }) }))
}
return val
}
@@ -417,13 +430,36 @@ function updateTableData(id) {
if (!queryFunc) return
queryFunc(1, 10).then((res) => {
})
}
// 用户弹窗确认
function popConfirm(id) {
// 设备属性弹窗: 读取属性配置
if (id == "deviceAttr") {
/// 选择所有表单元素(input, select, textarea) $('#parentElement :input')
/// :input 是jQuery特有的选择器可以匹配所有input、select、textarea和button元素。
/// 同时选择input和select元素 $('#parentElement input, #parentElement select')
var param = {}
$("#deviceAttrForm :input").each(function () {
var id = $(this).attr('id'); // 获取id属性
var val = $(this).val(); // 获取value值
if ((id == "port" || id == "isclient")) { param[id] = parseInt(val) }
else if (id == "commType") { }
else if (id) { param[id] = val }
});
G.cppNative.log(JSON.stringify(param))
// 存储更新数据
G.cppNative.log("rowdata: " + JSON.stringify(popRowdata))
var dataId = popRowdata[0]
G.cppNative.updateDevice(dataId, { attrs: JSON.stringify(param) }).then(ret => {
G.showElement('deviceAttrPop', false)
showPrompt((ret == 0 ? '操作成功!' : '操作失败!'), ret)
})
return;
}
// 获取数据表格操作对象
var mytable = $('#' + id + 'Table').DataTable()
// 获取弹框的参数信息
@@ -471,6 +507,5 @@ for (k in deviceTypeDef) {
$(document).ready(function () {
initSubpage('user')
//G.initTable('user', tableDef['user'])
})

View File

@@ -6,6 +6,8 @@
onclick="initSubPage('storage')">储能设备运行分析</button>
<button id="chargeBtn" class="btn btn-primary" style="width: 200px;margin-left: 10px"
onclick="initSubPage('charge')">充电设备运行分析</button>
<input id="statisticDate" type="date" class="form-control" style="width: 240px; margin-left: 30px;">
</div>
<hr style="margin: 10px 0 10px 0;" />
<!-- <div

View File

@@ -2,80 +2,48 @@
var pageDef = {
solar: {
charts: [
{ id: 'solarEchart1', echart: null, type: 'bar', series: ['发电电量', '入网电量'] },
{ id: 'solarEchart2', echart: null, type: 'bar', series: ['发电时长', '故障次数'] },
{ id: 'solarEchart3', echart: null, type: 'line', series: ['日电压', '日电流'] },
{ id: 'solarEchart4', echart: null, type: 'line', series: ['日功率'] }
{ id: 'solarEchart1', echart: null, type: 'bar', series: ['发电电量', '入网电量'], yAxisLeft: "电量kWh", yAxisRight: "" },
{ id: 'solarEchart2', echart: null, type: 'bar', series: ['发电时长', '故障次数'], yAxisLeft: "时长s", yAxisRight: "次数" },
{ id: 'solarEchart3', echart: null, type: 'line', series: ['日电压', '日电流'], yAxisLeft: "电压V", yAxisRight: "电流A" },
{ id: 'solarEchart4', echart: null, type: 'line', series: ['日功率'], yAxisLeft: "功率kw" },
],
},
storage: {
charts: [
{ id: 'storageEchart1', echart: null, type: 'bar', series: ['储能电量', '放电电量'] },
{ id: 'storageEchart2', echart: null, type: 'bar', series: ['储能时长', '放电时长', '故障次数'] },
{ id: 'storageEchart3', echart: null, type: 'line', series: ['日电压', '日电流'] },
{ id: 'storageEchart4', echart: null, type: 'line', series: ['日功率'] }
{ id: 'storageEchart1', echart: null, type: 'bar', series: ['储能电量', '放电电量'], yAxisLeft: "电量kWh" },
{ id: 'storageEchart2', echart: null, type: 'bar', series: ['储能时长', '放电时长', '故障次数'], yAxisLeft: "时长s" },
{ id: 'storageEchart3', echart: null, type: 'line', series: ['日电压', '日电流'], yAxisLeft: "电压V" },
{ id: 'storageEchart4', echart: null, type: 'line', series: ['日功率'], yAxisLeft: "功率kw" }
],
},
charge: {
charts: [
{ id: 'chargeEchart1', echart: null, type: 'bar', series: ['充电电量', '充电收益'] },
{ id: 'chargeEchart2', echart: null, type: 'bar', series: ['充电次数', '充电时长', '故障次数'] },
{ id: 'chargeEchart3', echart: null, type: 'line', series: ['日电压', '日电流'] },
{ id: 'chargeEchart4', echart: null, type: 'line', series: ['日功率'] }
{ id: 'chargeEchart1', echart: null, type: 'bar', series: ['充电电量', '充电收益'], yAxisLeft: "电量kWh" },
{ id: 'chargeEchart2', echart: null, type: 'bar', series: ['充电次数', '充电时长', '故障次数'], yAxisLeft: '次数' },
{ id: 'chargeEchart3', echart: null, type: 'line', series: ['日电压', '日电流'], yAxisLeft: "电压V" },
{ id: 'chargeEchart4', echart: null, type: 'line', series: ['日功率'], yAxisLeft: "功率kw" }
],
}
}
var xdataBar = ['2025/3/1', '2025/3/2', '2025/3/3', '2025/3/4', '2025/3/5', '2025/3/6', '2025/3/7']
var ydataBar = [
[30, 28, 35, 18, 36, 27, 19],
[10, 32, 20, 33, 39, 13, 22],
]
var curActiveId = 'solar'
function getRandomCurveData(m, n) {
var data = []
var t0 = Date.parse('2025-03-01 00:00:00')
var step = 600
var N = 86400 / step
var y = 500;
for (var i = 0; i < N; ++i) {
// data[i] = { x: t0 + i * step * 1000, y: Math.sin(i * 0.1) * (n - m) }
y = Math.floor((y + RAND(0, 50) - 25) * 100) / 100
data[i] = { x: t0 + i * step * 1000, y: y }
}
return data
}
function getCurveData(a, b, n) {
var d = [[], []]
for (var i = 0; i < n; ++i) {
var v = RAND(a, b)
d[0].push(v)
d[1].push(v - RAND(50, 200))
}
return d
}
function RAND(a, b) {
return a + Math.random() * (b - a)
}
var activeModuleId = ''
// 点击子页面菜单按钮,切换子页面
function initSubPage(id) {
//if (curActiveId == id) return
//if (activeModuleId == id) return
// 切换子菜单按钮样式,旧选择按钮恢复样式
if (curActiveId && curActiveId != '') {
document.getElementById(curActiveId + 'Btn').className = 'btn btn-primary'
if (activeModuleId && activeModuleId != '') {
document.getElementById(activeModuleId + 'Btn').className = 'btn btn-primary'
// 隐藏旧菜单对应的表格子页面
$('#' + curActiveId).hide()
$('#' + activeModuleId).hide()
}
curActiveId = id
activeModuleId = id
// 切换子菜单按钮样式,新选择按钮设置样式
document.getElementById(curActiveId + 'Btn').className = 'btn btn-success btn-lg'
document.getElementById(activeModuleId + 'Btn').className = 'btn btn-success btn-lg'
// 显示新菜单对应的表格子页面
$('#' + curActiveId).show()
$('#' + activeModuleId).show()
var page = pageDef[id]
if (!page) {
@@ -83,46 +51,131 @@ function initSubPage(id) {
return
}
// 更新曲线数据
G.cppNative.getCurveDataDay(200, 300).then(res => {
updateEchartCurve(pageDef[activeModuleId].charts[2].echart, 0, res)
})
G.cppNative.getCurveDataDay(100, 300).then(res => {
updateEchartCurve(pageDef[activeModuleId].charts[2].echart, 1, res)
})
G.cppNative.getCurveDataDay(300, 400).then(res => {
updateEchartCurve(pageDef[activeModuleId].charts[3].echart, 0, res)
})
// 柱状图的 x 轴, 7天的时间的日期
var dateStr = $('#statisticDate').val()
var xdata = []
for (let i = 6; i >= 0; i--) {
const date = new Date(dateStr);
date.setDate(date.getDate() - i);
xdata.push(G.formatDateMD(date));
}
page.charts.forEach(item => {
if (item.type == 'bar') {
item.echart = initEchartBar(item.id, item.series)
item.echart = initEchartBar(item.id, item.series, xdata, item.yAxisLeft, item.yAxisRight)
for (var i = 0; i < item.series.length; ++i) {
//updateEchartBar(item.echart, i, xdataBar, ydataBar[i])
}
} else if (item.type == 'line') {
item.echart = initEchartCurve(item.id, item.series)
item.echart = initEchartCurve(item.id, item.series, item.yAxisLeft, item.yAxisRight)
for (var i = 0; i < item.series.length; ++i) {
updateEchartCurve(item.echart, i, G.getRandDataDay(100 * (i + 1), 200 * (i + 1)))
}
}
if (id == 'solar') {
if (item.id == 'solarEchart1') {
var d = getCurveData(400, 500, 7)
updateEchartBar(item.echart, 0, xdataBar, d[0])
updateEchartBar(item.echart, 1, xdataBar, d[1])
} else if (item.id == 'solarEchart2') {
var d = getCurveData(480, 780, 7)
updateEchartBar(item.echart, 0, xdataBar, d[0])
updateEchartBar(item.echart, 1, xdataBar, [0, 2, 0, 0, 3, 0, 1])
}
} else if (id == 'storage') {
} else if (id == 'charge') {
}
});
}
window.onresize = () => {
var page = pageDef[curActiveId]
charts.charts.forEach(item => {
if (item.echart) { item.echart.resize() }
// 更新页面数据
function updatePageData() {
// 柱状图的 x 轴, 7天的时间的日期
var dateStr = $('#statisticDate').val()
var xdata = []
for (let i = 6; i >= 0; i--) {
const date = new Date(dateStr);
date.setDate(date.getDate() - i);
xdata.push(G.formatDateMD(date));
}
// 光伏统计
if (activeModuleId == "solar") {
G.cppNative.getStatisticDay(7).then(res => {
var d1 = [], d2 = [], d3 = [], d4 = [], d5 = []
res.forEach(item => {
d1.push(item['elect_gen'])
d2.push(item['elect_in'])
d3.push(item['elect_gen_t'])
d4.push(item['num_fault_solar'])
})
// 发电电量、入网电量
updateEchartBar(pageDef.solar.charts[0].echart, xdata, [{ data: d1 }, { data: d2 }]);
// 发电时长、故障次数
updateEchartBar(pageDef.solar.charts[1].echart, xdata, [{ data: d3 }, { data: d4 }]);
})
}
// 储能统计
else if (activeModuleId == "storage") {
G.cppNative.getStatisticDay(7).then(res => {
var d1 = [], d2 = [], d3 = [], d4 = [], d5 = []
res.forEach(item => {
d1.push(item['elect_store'])
d2.push(item['elect_discharge'])
d3.push(item['elect_store_t'])
d4.push(item['elect_discharge_t'])
d5.push(item['num_fault_store'])
})
// 储能电量、放电电量
updateEchartBar(pageDef.storage.charts[0].echart, xdata, [{ data: d1 }, { data: d2 }]);
// 储能时长、放电时长、故障次数
updateEchartBar(pageDef.storage.charts[1].echart, xdata, [{ data: d3 }, { data: d4 }, { data: d5 }]);
})
}
// 充电统计
else if (activeModuleId == "charge") {
G.cppNative.getStatisticDay(7).then(res => {
var d1 = [], d2 = [], d3 = [], d4 = [], d5 = []
res.forEach(item => {
d1.push(item['elect_charge'])
d2.push(item['income_charge'])
d3.push(item['num_charge'])
d4.push(item['elect_charge_t'])
d5.push(item['num_fault_charge'])
})
// 充电电量、充电收益
updateEchartBar(pageDef.charge.charts[0].echart, xdata, [{ data: d1 }, { data: d2 }]);
// 充电次数、充电时长、故障次数
updateEchartBar(pageDef.charge.charts[1].echart, xdata, [{ data: d3 }, { data: d4 }, { data: d5 }]);
})
}
}
window.onresize = () => {
var page = pageDef[activeModuleId]
page.charts.forEach(item => { if (item.echart) { item.echart.resize() } })
}
/// 清理资源
var timerId = null
document.currentScript.addEventListener('DOMNodeRemoved', () => {
G.cppNative.log('DOMNodeRemoved: 统计分析')
clearInterval(timerId);
});
$(document).ready(function () {
var dateStr = new Date().toLocaleString('zh', { year: 'numeric', month: '2-digit', day: '2-digit' }).replace(/\//g, '-')
$('#statisticDate').val(dateStr)
document.getElementById('statisticDate').addEventListener('input', function (e) {
// updatePageData()
});
initSubPage("solar")
updatePageData()
// 定时器更新页面数据
timerId = setInterval(updatePageData, 1000)
})

View File

@@ -86,8 +86,8 @@
<div class="myrow"
style="font-size: 14px; font-weight: 600; justify-content: space-between; border: solid #00fffb; border-radius: 0 0 8px 8px; border-width: 0 1px 1px 1px; height: 40px; line-height: 40px;">
<div style="width: 33%; text-align: center;">#1</div>
<div style="width: 33%; text-align: center;">20℃</div>
<div style="width: 33%; text-align: center;">20%</div>
<div id="envTemperture" style="width: 33%; text-align: center;">20℃</div>
<div id="envHumidity" style="width: 33%; text-align: center;">20%</div>
</div>
</div>
@@ -142,12 +142,69 @@
<div id="deviceSettingPop" class="mask" style="display: none;">
<div
style="margin: 200px auto;width:800px; padding: 20px; height: 500px; background-color: #012036f0; border:4px solid #14dcfb; ">
style="margin: 200px auto; padding: 20px; width:550px; height: 380px; background-color: #012036f0; border:4px solid #14dcfb; ">
<div id="popDeviceInfo" style="height: 30px;"></div>
<div class="myline-b" style="color:white;">控制功能</div>
<div style="display: flex; justify-content: center; width: 100%; margin-top: 100px;">
<div class="myrow" style="height: 26px; margin-top:30px;">
<div style="width: 120px;">开关机控制</div>
<div class="btn-group" style="width:80px;">
<input id="deviceSwitch_on" type="checkbox" class="btn-check" autocomplete="off"
onclick="G.switchSetStatus('deviceSwitch_on', 'deviceSwitch_off', this.checked)" />
<label class="btn btn-outline-primary" for="deviceSwitch_on" style="padding: 0;"></label>
<input id="deviceSwitch_off" type="checkbox" class="btn-check" autocomplete="off"
onclick="G.switchSetStatus('deviceSwitch_on', 'deviceSwitch_off', !this.checked)" checked />
<label class="btn btn-outline-danger" for="deviceSwitch_off" style="padding: 0;"></label>
</div>
</div>
<div class="myrow" style="height: 26px; margin-top:16px;">
<div style="width: 120px;">功率调控</div>
<div class="btn-group" style="width:80px;">
<input id="powerCtrl_on" type="checkbox" class="btn-check" autocomplete="off"
onclick="G.switchSetStatus('powerCtrl_on', 'powerCtrl_off', this.checked)" />
<label class="btn btn-outline-primary" for="powerCtrl_on" style="padding: 0;"></label>
<input id="powerCtrl_off" type="checkbox" class="btn-check" autocomplete="off"
onclick="G.switchSetStatus('powerCtrl_on', 'powerCtrl_off', !this.checked)" checked />
<label class="btn btn-outline-danger" for="powerCtrl_off" style="padding: 0;"></label>
</div>
<div style="margin-left:60px; width: 90px;">调控策略</div>
<select class="form-select" aria-label="选择策略"
style="width: 100px; padding: 0 0 0 10px; background-color: #0c283b; color: white;">
<option value="0">策略1</option>
<option value="1">策略2</option>
<option value="2">策略3</option>
<option value="3">策略4</option>
</select>
</div>
<div class="myrow" style="height: 26px; margin-top:16px;">
<div style="width: 120px;">充放电模式控制</div>
<div class="btn-group" style="width:80px;">
<input id="chargeMode_on" type="checkbox" class="btn-check" autocomplete="off"
onclick="G.switchSetStatus('chargeMode_on', 'chargeMode_off', this.checked)" />
<label class="btn btn-outline-primary" for="chargeMode_on" style="padding: 0;"></label>
<input id="chargeMode_off" type="checkbox" class="btn-check" autocomplete="off"
onclick="G.switchSetStatus('chargeMode_on', 'chargeMode_off', !this.checked)" checked />
<label class="btn btn-outline-danger" for="chargeMode_off" style="padding: 0;"></label>
</div>
</div>
<div class="myrow" style="height: 26px; margin-top:16px;">
<div style="width: 120px;">并离网模式控制</div>
<div class="btn-group" style="width:80px;">
<input id="workMode_on" type="checkbox" class="btn-check" autocomplete="off"
onclick="G.switchSetStatus('workMode_on', 'workMode_off', this.checked)" />
<label class="btn btn-outline-primary" for="workMode_on" style="padding: 0;"></label>
<input id="workMode_off" type="checkbox" class="btn-check" autocomplete="off"
onclick="G.switchSetStatus('workMode_on', 'workMode_off', !this.checked)" checked />
<label class="btn btn-outline-danger" for="workMode_off" style="padding: 0;"></label>
</div>
</div>
<div style="display: flex; justify-content: flex-end; width: 100%; margin-top: 50px; ">
<button class="btn btn-success" style="width:80px; color: white;"
onclick="G.showElement('deviceSettingPop', false)">确定</button>
<button class="btn btn-default" style="width:80px; color: white; margin-left: 50px;"
<button class="btn btn-default" style="width:80px; color: white; margin-left: 20px;"
onclick="G.showElement('deviceSettingPop', false)">取消</button>
</div>
</div>

View File

@@ -113,14 +113,14 @@ function setDeviceCardParam(deviceid, subid, key, text) {
}
var activeCardBtn = null
var activeModuleId = null
function onClickCardBtn(btn, id) {
if (activeCardBtn) activeCardBtn.className = 'mycardbtn'
activeCardBtn = btn
activeCardBtn.className = 'mycardbtn-active'
var deviceType = id
initDeviceList(deviceType)
activeModuleId = id
initDeviceList(activeModuleId)
}
function creatElementSwitch(id, x, y) {
@@ -223,19 +223,46 @@ function initDeviceList(deviceType) {
})
}
var elemtPanel = document.getElementById(item.device_id)
//JSON.stringify(item)
var paramStr = JSON.stringify(item).replace(/"/g, '"')
elemtPanel.innerHTML += `<button
class="btn btn-outline-primary btn-sm"
style="height:30px; margin: 5px 0 0 10px"
onclick="onDeviceSetting(${item.device_id})">
onclick='onDeviceSetting(${paramStr})'>
参数设置
</button>`
})
})
}
function onDeviceSetting(deviceid) {
function onDeviceSetting(param) {
var deviceType = getDeviceTypeName(param.type)
$('#popDeviceInfo').text(param.device_id + ":" + deviceType + ":" + param.name)
G.showElement('deviceSettingPop', true)
if (deviceType == "逆变器") {
}
}
function updatePageData() {
if (activeModuleId == "security") {
// 查询数据获取环境信息:光照、风速、环境温度、湿度
G.cppNative.getEnvironmentInfo().then(res => {
// $('#envIllumination').text(res['illumination'] + ' Lux')
// $('#envWindspeed').text(res['windspeed'] + ' m/s')
$('#envTemperture').text(res['temperature'] + '℃')
$('#envHumidity').text(res['humidity'] + '%')
})
// 消防信息
G.cppNative.getFireInfo().then(res => {
//res.data.forEach(item => { })
})
}
}
// ====================================================================================================
@@ -252,9 +279,6 @@ document.currentScript.addEventListener('DOMNodeRemoved', () => {
$(document).ready(function () {
onClickCardBtn(document.getElementById('solarCardBtn'), 'solar')
// timerId = setInterval(() => {
// updateParam('1', '电压', Math.floor(Math.random() * 220) + ' V')
// }, 2000);
G.cppNative.getDeviceInfo([0]).then((res) => {
var nums = {
@@ -271,6 +295,7 @@ $(document).ready(function () {
if (item.err != 0) nums[deviceType].numFault += 1
}
})
$('#solarDeviceNum').text('光伏板数量: ' + nums['103'].num + ' 个')
$('#solarIdleNum').text('空闲: ' + nums['103'].numIdle + ' 个')
$('#solarOfflineNum').text('离线: ' + nums['103'].numOffline + ' 个')
@@ -285,7 +310,8 @@ $(document).ready(function () {
$('#chargeIdleNum').text('空闲: ' + nums['108'].numIdle + ' 个')
$('#chargeOfflineNum').text('离线: ' + nums['108'].numOffline + ' 个')
$('#chargeFaultNum').text('故障: ' + nums['108'].numFault + ' 个')
})
// 定时更新页面数据
timerId = setInterval(updatePageData, 1000);
})

View File

@@ -4,42 +4,25 @@ var chartDef = [
{ id: 'loadEchart', echart: null, type: 'line', series: ['预测功率', '实时功率'] },
]
function RAND(a, b) {
return (a + Math.random() * (b - a))
}
function getRandomCurveData(m, n) {
var data = []
var t0 = Date.parse('2025-03-01 00:00:00')
var step = 600
var N = 86400 / step
for (var i = 0; i < N; ++i) {
//data[i] = { x: t0 + i * step * 1000, y: Math.sin(i * 0.1) * (n - m) }
data[i] = { x: t0 + i * step * 1000, y: RAND(m, n) }
}
return data
}
function getRandomData1(m, n) {
var data = []
var t0 = Date.parse('2025-03-01 00:00:00')
var t0 = Date.parse('2025-07-01 00:00:00')
var step = 600
var N = 86400 / step
var y = 500;
for (var i = 0; i < N; ++i) {
//data[i] = { x: t0 + i * step * 1000, y: Math.sin(i * 0.1) * (n - m) }
y = Math.floor((y + RAND(0, 50) - 25) * 100) / 100
data[i] = { x: t0 + i * step * 1000, y: y }
var x = t0 + i * step * 1000
y = Math.floor((y + RAND(0, 20) - 10) * 100) / 100
data[i] = { name: x, value: [x, y] }
}
return data
}
chartDef.forEach((item) => {
item.echart = initEchartCurve(item.id, item.series)
updateEchartCurve(item.echart, 1, getRandomData1(100, 200))
item.echart = initEchartCurve(item.id, item.series, item.yAxisLeft, item.yAxisRight)
updateEchartCurve(item.echart, 1, getRandomCurveData(100, 200))
for (var i = 0; i < item.series.length; ++i) {
updateEchartCurve(item.echart, i, getRandomData1(300 * (i + 1), 400 * (i + 1)))
updateEchartCurve(item.echart, i, getRandomCurveData(300 * (i + 1), 400 * (i + 1)))
}
})

View File

@@ -5,6 +5,82 @@
#include "Operator.h"
struct AppData
{
/////////////////////////////////////////////
/// === 系统 ===
int64_t sysActivationTime {};
/////////////////////////////////////////////
/// === 数据库 ===
struct {
std::string host;
int port;
std::string user;
std::string passwd;
} db;
/////////////////////////////////////////////
/// === 系统统计 ===
// 累计发电量单位kWh
double electGenTatal {};
// 累计入网电量单位kWh
double electInTotal {};
// 累计收益,单位:元
double incomeTotal {};
// 碳减排量, 单位:吨
double ccers {};
/////////////////////////////////////////////
/// === 环境 ===
// 光照度
double illuminance {};
// 辐照度
double irradiance {};
// 风速
double windspeed {};
// 温度
double temperature {};
// 湿度
double humidity {};
/////////////////////////////////////////////
/// === 日统计 ===
struct {
// 发电量
double electGen {};
// 入网电量
double electIn {};
// 发电收益金额
double incomeElect {};
// 储能电量
double electStorage {};
// 储能次数
int numStore {};
// 放电电量
double electDischarge {};
// 放电次数
int numDischarge {};
// 用电电量
double electLoad {};
// 充电电量
double electCharge {};
// 充电次数
int numCharge {};
// 充电收益
double incomeCharge {};
// 故障次数
int numFault {};
// 故障次数:光伏设备
int numFaultSolar {};
// 故障次数:储能设备
int numFaultStorage {};
// 故障次数:负荷设备
int numFaultLoad {};
} statDay;
};
class Application
{
public:
@@ -22,7 +98,6 @@ public:
void runThreadMain();
void runThreadDevice();
private:

View File

@@ -205,6 +205,23 @@ int64_t Utils::timeNowMS()
return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
//return std::chrono::time_point_cast<std::chrono::microseconds>(std::chrono::system_clock::now()).time_since_epoch().count();
}
int64_t Utils::timeNowDate()
{
// 获取当前时间
auto now = std::chrono::system_clock::now();
time_t t = std::chrono::system_clock::to_time_t(now);
// 转换为本地时间结构体
struct tm* tmlocal = localtime(&t);
// 设置时分秒为0
tmlocal->tm_hour = 0;
tmlocal->tm_min = 0;
tmlocal->tm_sec = 0;
// 转换回time_t
return mktime(tmlocal);
}
string Utils::timeNowStr(std::string fmt /*= "%Y-%m-%dT%H:%M:%S"*/)
{
auto t = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());

View File

@@ -41,6 +41,7 @@ public:
static int64_t timeNow();
static int64_t timeNowMS();
static int64_t timeNowDate();
static string timeNowStr(std::string fmt = "%Y-%m-%d %H:%M:%S");
static string timeNowStrMS(std::string fmt = "%Y-%m-%d %H:%M:%S");
static string timeStr(int64_t ts, std::string fmt = "%Y-%m-%d %H:%M:%S");

View File

@@ -438,6 +438,7 @@ int MyWebHandler::updateDevice(const QString& deviceId, QVariantMap params)
JSgetReqParam("model", params, fields);
JSgetReqParam("factory", params, fields);
JSgetReqParam("is_open", params, fields);
JSgetReqParam("attrs", params, fields);
if (fields.size() == 0)
{
return 0;
@@ -783,16 +784,70 @@ QVariantList MyWebHandler::getStatisticDay(const QString& startDate, int nday)
{
QVariantMap row;
row["dt"] = "";
row["elect_gen_solar"] = float(i);
row["elect_in_solar"] = float(i);
row["income_solar"] = float(i);
// 光伏:发电量、入网电量、发电时长、故障次数
row["elect_gen"] = float(i);
row["elect_in"] = float(i);
row["elect_gen_t"] = float(i);
row["income_elect"] = float(i); // 发电收益
row["num_fault_solar"] = float(i);
// 储能:储能电量、放电电量、储能时长、放电时长、故障次数
row["elect_store"] = float(i);
row["elect_discharge"] = float(i);
row["elect_load"] = float(i);
row["elect_store_t"] = float(i);
row["elect_discharge_t"] = float(i);
row["num_fault_store"] = float(i);
// 充电:充电电量、充电收益、充电次数、充电时长、故障次数
row["elect_charge"] = float(i);
row["num_charge"] = float(i);
row["elect_charge_t"] = float(i);
row["income_charge"] = float(i);
row["num_charge"] = float(i);
row["num_fault_charge"] = float(i);
// 负载:
row["elect_load"] = float(i);
row["num_fault_load"] = float(i);
result << row;
}
return result;
}
static QVariantList RandCurveDataDay(int a, int b)
{
QVariantList d;
int64_t t0 = Utils::timeNowDate();
int step = 600;
int N = 86400 / step;
int y = a;
for (int i = 0; i <= N; ++i) {
int t = t0 + i * step * 1000;
y = std::floor((y + Utils::random(0, 20) - 10) * 100) / 100;
QVariantMap item;
item["name"] = t;
item["value"] = QVariantList {t, y};
d << item;
}
return d;
}
// 获取一天的发电功率
QVariantList MyWebHandler::getStatisticPowerDay()
{
static auto tempData = RandCurveDataDay(500, 600);
return tempData;
}
// 获取一天的辐照度
QVariantList MyWebHandler::getStatisticIrradianceDay()
{
static auto tempData = RandCurveDataDay(500, 600);
return tempData;
}
QVariantList MyWebHandler::getCurveDataDay(int a, int b)
{
return RandCurveDataDay(a, b);
}

View File

@@ -129,9 +129,12 @@ public slots:
QVariantMap getStatisticTotal();
// 获取按天统计数据
QVariantList getStatisticDay(const QString& startDate, int nday=7);
// 获取一天的
// 获取一天的发电功率
QVariantList getStatisticPowerDay();
// 获取一天的辐照度
QVariantList getStatisticIrradianceDay();
QVariantList getCurveDataDay(int a, int b);
public:
QString nativeText_;