提交系统管理web端代码

This commit is contained in:
lixiaoyuan
2025-07-18 09:09:30 +08:00
parent 7b3f32f334
commit 387237c81c
74 changed files with 1997 additions and 918 deletions

Binary file not shown.

Binary file not shown.

BIN
bin/Release/EES.pdb Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,9 @@
{
"database": {
"host": "localhost",
"port": 3306,
"user": "root",
"passwd": "123456",
"dbname": "ees"
}
}

View File

@@ -0,0 +1,454 @@
/* 自定义滚动条样式 */
div::-webkit-scrollbar {
width: 12px;
}
div::-webkit-scrollbar-thumb {
background-color: #08536e60;
border-radius: 4px;
}
div::-webkit-scrollbar-track {
background-color: #60606060;
}
/******************************************************************************************************/
.dt-container {
color: white;
font-size: 14px;
padding-left: 0px;
}
/* div.dt-container .dt-paging {
margin-top: 10px;
} */
.dt-paging {
color: white;
margin-left: 0px;
}
div.dt-container .dt-paging .dt-paging-button {
line-height: 28px;
/* width: 32px; */
padding: 0 0px 0 0;
border: 1px solid white;
margin-right: 5px;
padding: 0 10px 0 10px;
}
div.dt-container .dt-paging .dt-paging-button.disabled,
div.dt-container .dt-paging .dt-paging-button.disabled:hover,
div.dt-container .dt-paging .dt-paging-button.disabled:active {
color: white !important;
border: 1px solid gray;
}
div.dt-container .dt-paging .dt-paging-button.current {
background: linear-gradient(to bottom, #1c797a 0%, #1c797a 100%);
}
div.dt-container .dt-paging .dt-paging-button.current:hover {
background: linear-gradient(to bottom, #1c797a 0%, #1c797a 100%);
}
div.dt-container .dt-paging .dt-paging-button:hover {
color: white !important;
border: 1px solid #111;
background-color: #111;
/* Chrome,Safari4+ */
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #585858), color-stop(100%, #111));
/* Chrome10+,Safari5.1+ */
background: -webkit-linear-gradient(top, #585858 0%, #111 100%);
/* FF3.6+ */
background: -moz-linear-gradient(top, #585858 0%, #111 100%);
/* IE10+ */
background: -ms-linear-gradient(top, #585858 0%, #111 100%);
/* Opera 11.10+ */
background: -o-linear-gradient(top, #585858 0%, #111 100%);
/* W3C */
background: linear-gradient(to bottom, #1c797a 0%, #1c797a 100%);
}
.mydt-ext {
display: flex;
flex-direction: row;
align-items: center;
margin-top: 10px;
/* justify-content: flex-start; */
}
.mydt-ext .item {
margin-right: 30px;
}
/******************************************************************************************************/
/* table {
border: solid 2px #1c797a;
font-weight: bold;
color: white;
width: 100%;
text-align: center;
border-collapse: separate;
border-spacing: 0;
}
tr,
th {
height: 60px;
border-right: solid 1px gray;
border-bottom: solid 1px gray;
}
table thead {
background-color: #125c70;
height: 20px;
}
table thead tr {
font-size: 14px;
height: 20px;
}
table thead tr th {
height: 20px;
border-right: solid 1px gray;
border-bottom: solid 1px gray;
}
table tbody tr {
height: 24px;
font-size: 13px;
font-weight: bold;
}
table tbody tr td {
height: 24px;
border-right: solid 1px gray;
border-bottom: solid 1px gray;
} */
/*
td:last-child,
th:last-child {
border-right-color: transparent;
}
td.details-control {
background: url('../assets/details_open.png') no-repeat center center;
cursor: pointer;
}
tr.shown td.details-control {
background: url('../assets/details_close.png') no-repeat center center;
}
*/
#flex-sample {
display: flex;
/* 排列方向 flex-direction: row | row-reverse | column | column-reverse */
flex-direction: column;
/* 换行方式 flex-wrap: nowrap(不换行) | wrap换行第一行在上面 | wrap-reverse换行第一行在下面 */
flex-wrap: nowrap;
/* 是flex-direction属性和flex-wrap属性的简写形式默认值为row nowrap */
flex-flow: column nowrap;
/* 主轴上的对齐方式 justify-content: flex-start | flex-end | center | space-between | space-around */
justify-content: center;
align-items: stretch;
/* flex-start | flex-end | center | baseline | stretch */
align-content: flex-start;
/* flex-start | flex-end | center | space-between | space-around | stretch */
}
.mypanelstat {
/* width: 100%; */
height: calc(90vh - 130px);
background-color: #052f4d;
/* margin-top: 10px; */
/* padding: 10px 10px 10px 10px; */
border-radius: 12px;
}
.mask {
position: fixed;
left: 0px;
top: 0px;
width: 100%;
height: 100%;
font-size: 16px;
/* IE9以下不支持rgba模式 */
background-color: rgba(0, 0, 0, 0.3);
/* 兼容IE8及以下 */
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#7f000000, endColorstr=#7f000000);
/* 显示: block 不显示none overlay.style.display = 'block' */
display: none;
}
/* 弹出框主体 */
.pop {
background-color: #e0e0e0;
min-width: 200px;
max-width: 600px;
height: 300px;
border-radius: 10px;
margin: 200px auto;
text-align: center;
/* overflow: hidden; */
}
/* 弹出框的标题 */
.pop_title {
font-size: 28px;
font-weight: 1000;
height: 50px;
line-height: 50px;
background-color: #909090;
border-radius: 10px 10px 0 0;
/* border-bottom: solid 2px #8080ff; */
}
/* 弹出框的内容 */
.pop_content {
height: 50px;
line-height: 50px;
padding: 15px 20px;
color: #198754;
}
/* 弹出框的按钮栏 */
.pop_btn {
padding-bottom: 10px;
}
/* 弹出框的按钮 */
.pop_btn button {
color: #778899;
width: 40%;
height: 40px;
cursor: pointer;
border: solid 1px #cccccc;
border-radius: 5px;
margin: 5px 10px;
color: #ffffff;
background-color: #337ab7;
}
.myrow {
color: white;
display: flex;
flex-direction: row;
align-content: flex-start;
}
.mycol {
color: white;
display: flex;
flex-direction: column;
}
.myblock {
background-color: chocolate;
width: 50px;
height: 50px;
margin: 10px 0px 0px 10px;
}
.mycardbtn {
background-color: #07486f;
border-radius: 10px;
margin: 0 10px 10px 10px;
padding: 10px 10px 10px 10px;
}
.mycardbtn-active {
background-color: #1d6466;
border-radius: 10px;
margin: 0 10px 10px 10px;
padding: 10px 10px 10px 10px;
border: 2px solid #01b7d1;
}
.mycardbtn:hover {
background-color: #1d6466;
cursor: pointer;
}
.mycard {
background-color: #08365b;
width: 220px;
height: 340px;
border-radius: 10px;
margin: 10px 0px 0px 10px;
padding: 10px;
position: relative;
}
.mycard-param {
display: flex;
margin-top: 3px;
font-size: 14px;
margin-left: 10px;
}
.mycard-param-key {
font-weight: bold;
color: #a6b8dd;
width: 70px;
}
.mycard-param-text {
font-weight: bold;
color: white;
}
.status-ok {
background-color: green;
width: 14px;
height: 14px;
border-radius: 7px;
}
.status-err {
background-color: red;
width: 14px;
height: 14px;
border-radius: 7px;
}
.text-ok {
color: green;
}
.text-err {
color: red;
}
.mychart {
background-color: #30303030;
}
.mypanel {
width: 100%;
height: 200px;
background-color: #052f4d;
border-radius: 8px;
padding: 10px 10px 10px 10px;
margin: 0px 0px 10px 0px;
overflow: hidden;
}
.mypanel-title {
height: 30px;
font-size: 16px;
font-weight: 1000;
color: #63c4d8;
}
.myline-l {
/* 前 5px 红色, 5px 后剩余部分透明 */
background: linear-gradient(#21ffd2, #21ffd2) left 2px / 5px 100% no-repeat;
padding-left: 16px;
height: 20px;
}
.myline-b {
background: linear-gradient(to right, #09c8d3ff, transparent) bottom / 100% 3px no-repeat;
padding-bottom: 5px;
}
.myline-lb {
/* 左侧 5px + 底部 3px 渐变透明 */
background:
linear-gradient(#21ffd2, #21ffd2) left 3px / 5px calc(100% - 12px) no-repeat,
linear-gradient(to right, #09c8d3ff, transparent) bottom / 100% 3px no-repeat;
padding-bottom: 5px;
padding-left: 16px;
padding-top: 0px;
}
.label-bkg {
border-radius: 5px;
background-color: #a0a0a010;
float: left;
/* margin-right: 10px; */
}
.label-key {
/* border: solid 1px white; */
width: 100%;
height: 50%;
font-size: 14px;
font-weight: 1000;
color: white;
text-align: center;
display: flex;
justify-content: center;
align-items: center;
}
.label-val-lg {
/* border: solid 1px white; */
width: 65%;
height: 50%;
font-size: 36px;
color: #4dd7f0;
float: left;
display: flex;
justify-content: flex-end;
align-items: flex-end;
text-align: right;
}
.label-val {
/* border: solid 1px white; */
width: 65%;
height: 50%;
font-size: 20px;
color: #4dd7f0;
float: left;
display: flex;
justify-content: flex-end;
align-items: flex-end;
}
.label-tail {
/* border: solid 1px white; */
padding-left: 10px;
width: 35%;
height: 45%;
font-size: 16px;
font-weight: 1000;
color: white;
display: flex;
justify-content: left;
align-items: flex-end;
}
#maskTest {
position: absolute;
z-index: 1;
left: 0px;
top: 0px;
width: 100%;
height: 100%;
}
.page {
padding: 5px 8px 5px 8px;
}
.btn-default {
background-color: #a5a5a5;
}
.btn-default:hover {
background-color: #858585;
}

Binary file not shown.

View File

@@ -0,0 +1,238 @@
var G = {
user: { username: '' },
loadPage: function (pagename) {
while (1) {
var script = document.querySelector("script[id='mytempfile']")
if (!script) break
script.remove()
}
var file = 'assets/html/pages/' + pagename + '.html'
G.cppNative.readFile(file).then(function (text) {
// 加载 html 页面内容文件
document.getElementById('mypage').innerHTML = text
// 加载 js 脚本文件
var jsUrl = './pages/' + pagename + '.js'
var element = document.createElement('script')
element.src = jsUrl + '?t=' + new Date().getTime()
element.async = false // 脚本按照加载先后顺序处理
element.setAttribute('id', 'mytempfile')
document.body.appendChild(element)
})
},
switchSetStatus: function (id1, id2, checked, callback) {
document.getElementById(id2).checked = !(document.getElementById(id1).checked = checked)
if (callback) callback(checked)
},
switchGetStatus: function (id) { return document.getElementById(id).checked },
initTable: function (id, info) {
if (info.table) {
info.table.ajax.reload()
return;
}
var tableOption = G.tableGetOption()
tableOption.columns = info.columns
tableOption.ajax = function (req, callback, settings) {
G.cppNative.log('lxy=== table ajax start')
if (info.query) {
info.query(1, 10).then(res => {
var result = []
res.data.forEach(function (item, index) {
var rowData = []
info.header.forEach(function (key, index) { rowData.push(item[key]) })
result.push(rowData)
})
G.cppNative.log("table ajax: " + JSON.stringify(result))
callback({ draw: req.draw, recordsTotal: result.length, recordsFiltered: result.length, data: result })
})
} else {
callback({ draw: req.draw, recordsTotal: 0, recordsFiltered: 0, data: [] })
}
}
// 初始化表格
info.table = $('#' + id + 'Table').DataTable(tableOption)
G.cppNative.log('lxy=== table init end')
//$('div.gotopage').html('<b style="color:#7f8fa4">跳转至 </b><input id="searchNumber" style="width:80px"/><b style="color:#7f8fa4;"> 页</b>')
},
updateTableData: function (queryFunc, params) {
if (queryFunc) {
}
},
cppCall: function (id) {
var cppfunc = G.cppNative[id]
if (cppfunc) {
G.cppNative.log('call cpp function [' + id + ']')
cppfunc()
} else {
G.cppNative.log('call cpp function [' + id + '] error: not exist')
}
},
cppSignal: function (id, callback) {
var signal = G.cppNative[id]
if (signal) {
G.cppNative.log('cpp signal [' + id + '] ')
signal.connect(callback)
} else {
G.cppNative.log('cpp signal [' + id + '] error: not exist')
}
},
initForm: function (id, funcPopConfirm) {
var form = document.getElementById(id + 'Form')
var formBtnOk = document.getElementById(id + 'FormOk')
if (form && formBtnOk) {
// 监听表单的输入事件,检查表单的必填项是否完成输入,如果未完成,则确认按钮不可用
form.addEventListener('input', function () { formBtnOk.disabled = !form.checkValidity() })
// 编辑弹窗的确定按钮监听点击事件
formBtnOk.addEventListener('click', function () { if (funcPopConfirm) { funcPopConfirm(id) } })
}
},
showElement: function (id, visible) {
var elemt = document.getElementById(id)
if (elemt) { elemt.style.display = visible ? 'block' : 'none' }
},
popSetParams: function (id, keys, rowdata, callback) {
keys.forEach(function (key, index) {
var val = ''
if (rowdata && rowdata.length > index) { val = rowdata[index] }
if (key == 'is_open') {
G.switchSetStatus(id + 'Form_on', id + 'Form_off', parseInt(val))
} else {
var myval = (callback) ? callback(id, key, val) : val
// 回调函数返回 undefined 时, 不需要设置参数值
if (myval != undefined) {
val = myval
var element = $('#' + id + 'Form_' + key)
if (element) {
if (element.prop("tagName") == "SELECT" && val == '') {
element.get(0).selectedIndex = 0;
} else {
element.val(val)
}
}
}
}
})
},
popGetParams: function (id, keys, rowdata, callback) {
var params = {}
keys.forEach(function (key, index) {
var val
if (key == 'is_open') {
val = G.switchGetStatus(id + 'Form_on') ? '1' : '0'
} else {
var myval = callback ? callback(id, key) : undefined
val = myval != undefined ? myval : $('#' + id + 'Form_' + key).val()
}
if (rowdata) {
if (rowdata.length > index && val != rowdata[index]) { params[key] = val }
} else {
if (val != '') { params[key] = val }
}
})
G.cppNative.log('POP get params id=' + id + ', params=' + JSON.stringify(params))
return params
},
popSetParamReadonly: function (id, key, isReadonly) {
$('#' + id + 'Form_' + key).attr('readonly', isReadonly)
},
tableGetOption: function () {
return {
data: [],
columns: [],
bSort: false,
scollY: "600px",
//aLengthMenu: [10, 20, 50, 100], //设置每页显示数据条数的下拉选项
//displayLength: 5, //每页初始显示最大记录数量
// 设置表格t、分页数据条数l、搜索框f、表格信息i、分页p、加载信息r
dom: 'rt<"mydt-ext"p<"item"<"gotopage">><"item"i><"item"f>>',
language: {
emptyTable: '无数据',
lengthMenu: '每页显示 _MENU_ 条记录',
zeroRecords: '对不起,查询不到任何相关数据',
info: '共有 _TOTAL_ 条记录', // '当前显示 _START_ 到 _END_ 条,共 _TOTAL_ 条记录',
infoEmpty: '共 0 页',
infoFiltered: '数据表中共为 _MAX_ 条记录)',
processing: '正在加载中...',
search: '结果中搜索',
paginate: {
previous: '上一页', next: '下一页', first: '首页', last: '尾页'
},
},
columnDefs: [{ targets: '_all', className: 'dt-head-left' }, { targets: '_all', className: 'dt-body-left' }],
//serverSide: true,
processing: false,
ajax: function (req, callback, settings) {
// 查询服务器获取数据, 同时获取总数据条数
callback({ draw: req.draw, recordsTotal: 0, recordsFiltered: 0, data: [] })
},
createdRow: function (row, data, dataIndex) {
if (dataIndex % 2 === 0) {
//$(row).css('background-color', '#ff000010')
} else {
//$(row).css('background-color', '#00ff0010')
}
$(row).on('mouseenter', function () {
//if (curEditRow && myTableApi.row(curEditRow).index() == myTableApi.row($(this)).index()) return
$(this).css('background-color', '#ff808050') // 高亮颜色
})
$(row).on('mouseleave', function () {
//if (curEditRow && myTableApi.row(curEditRow).index() == myTableApi.row($(this)).index()) return
$(this).css('background-color', '') // 恢复默认
})
},
}
},
clickSubpageBtn: function (id) {
if (G.curSubpageId == id) return
if (G.curSubpageId) {
var oldBtn = document.getElementById(G.curSubpageId + 'Btn')
if (oldBtn) { oldBtn.className = 'btn btn-primary' }
var oldSubpage = $('#' + G.curSubpageId)
if (oldSubpage) { oldSubpage.hide() }
}
if (id) {
var curBtn = document.getElementById(id + 'Btn')
if (curBtn) { curBtn.className = 'btn btn-success btn-lg' }
var curSubpage = $('#' + id)
if (curSubpage) { curSubpage.show() }
}
G.curSubpageId = id
},
getRandDataDay: function (a, b, n) {
var data = []
var t0 = Date.parse('2025-03-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) }
y = Math.floor((y + RAND(0, 50) - 25) * 100) / 100
data[i] = { x: t0 + i * step * 1000, y: y }
}
return data
}
}
function RAND(a, b) {
return a + Math.random() * (b - a)
}

View File

@@ -204,7 +204,7 @@ function initEchartCurve(id, seriesItems) {
option.legend.data = seriesItems
option.series = []
seriesItems.forEach(item => {
option.series.push({ name: item, type: 'line', smooth: true, symbolSize: 0, data: [] })
option.series.push({ name: item, type: 'line', smooth: false, symbolSize: 0, data: [] })
})
echart.setOption(option)
return echart

View File

@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>光储充站控系统</title>
</head>
<body>
</body>
</html>

View File

@@ -3,680 +3,232 @@
<head>
<meta charset="UTF-8" />
<title>光储充站控系统</title>
<script src="./libs/jquery/jquery-3.7.1.min.js"></script>
<link rel="stylesheet" href="./libs/DataTables-2.1.8/css/dataTables.dataTables.css" />
<script src="./libs/DataTables-2.1.8/js/dataTables.js"></script>
<link rel="stylesheet" href="./libs/bootstrap-5.3.3-dist/css/bootstrap.min.css" />
<script src="./libs/bootstrap-5.3.3-dist/js/bootstrap.min.js"></script>
<script src="./libs/bootstrap-5.3.3-dist/js/bootstrap.bundle.min.js"></script>
<link rel="stylesheet" href="./libs/DataTables-2.1.8/css/dataTables.dataTables.css" />
<script src="./libs/DataTables-2.1.8/js/dataTables.js"></script>
<script src="./libs/echarts/echarts.min.js"></script>
<script src="./js/qwebchannel.js"></script>
<script src="./js/myecharts.js"></script>
<script src="./js/common.js"></script>
<link rel="stylesheet" href="./css/mystyle.css" />
<style>
@font-face {
font-family: 优设标题黑;
src: url(./font/优设标题黑.ttf);
}
body {
background-image: url('../ui/bkg01.png');
background-size: 100% 100%;
background-attachment: fixed;
}
div {
user-select: none;
}
a {
display: inline-block;
/* 添加间距,使链接之间不会紧贴 */
padding-right: 8px;
color: #ffffff;
/* color: #ffffff; */
}
table {
font-size: 16px;
font-weight: bold;
color: white;
width: 100%;
text-align: center;
border-collapse: separate;
border-spacing: 0;
border: solid 2px #1c797a;
font-size: 14px;
color: white;
/* font-weight: bold; */
/* width: 100%; */
/* text-align: center; */
/* border-collapse: separate; */
/* border-spacing: 0; */
}
table thead {
background-color: #125c70;
}
table thead tr {
height: 32px;
/* border: solid 2px red; */
table tbody {
/* font-size: 13px; */
}
table thead tr th {
tr th {
border-right: solid 1px gray;
border-bottom: solid 1px gray;
}
table tbody tr {
height: 32px;
font-size: 13px;
font-weight: bold;
}
table tbody tr td {
border-right: solid 1px gray;
border-bottom: solid 1px gray;
}
td:last-child,
th:last-child {
border-right-color: transparent;
}
.dt-container {
color: white;
}
.dt-paging {
color: white;
}
td.details-control {
background: url('../assets/details_open.png') no-repeat center center;
cursor: pointer;
}
tr.shown td.details-control {
background: url('../assets/details_close.png') no-repeat center center;
}
.table-ext {
display: flex;
flex-direction: row;
justify-content: flex-end;
align-items: center;
margin-top: 10px;
}
.table-ext .item {
margin: 0px 20px 0px 10px;
}
#flex-sample {
display: flex;
/* 排列方向 flex-direction: row | row-reverse | column | column-reverse */
flex-direction: column;
/* 换行方式 flex-wrap: nowrap(不换行) | wrap换行第一行在上面 | wrap-reverse换行第一行在下面 */
flex-wrap: nowrap;
/* 是flex-direction属性和flex-wrap属性的简写形式默认值为row nowrap */
flex-flow: column nowrap;
/* 主轴上的对齐方式 justify-content: flex-start | flex-end | center | space-between | space-around */
justify-content: center;
align-items: stretch;
/* flex-start | flex-end | center | baseline | stretch */
align-content: flex-start;
/* flex-start | flex-end | center | space-between | space-around | stretch */
}
.mypanelstat {
width: 100%;
height: calc(90vh - 130px);
background-color: #052f4d;
/* margin-top: 10px; */
/* padding: 10px 10px 10px 10px; */
border-radius: 12px;
}
.mask {
position: fixed;
left: 0px;
top: 0px;
width: 100%;
height: 100%;
font-size: 16px;
/* IE9以下不支持rgba模式 */
background-color: rgba(0, 0, 0, 0.3);
/* 兼容IE8及以下 */
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#7f000000, endColorstr=#7f000000);
/* 显示: block 不显示none overlay.style.display = 'block' */
display: none;
}
/* 弹出框主体 */
.pop {
background-color: #e0e0e0;
min-width: 200px;
max-width: 600px;
height: 300px;
border-radius: 10px;
margin: 200px auto;
text-align: center;
/* overflow: hidden; */
}
/* 弹出框的标题 */
.pop_title {
font-size: 28px;
font-weight: 1000;
height: 50px;
line-height: 50px;
background-color: #909090;
border-radius: 10px 10px 0 0;
/* border-bottom: solid 2px #8080ff; */
}
/* 弹出框的内容 */
.pop_content {
height: 50px;
line-height: 50px;
padding: 15px 20px;
color: #198754;
}
/* 弹出框的按钮栏 */
.pop_btn {
padding-bottom: 10px;
}
/* 弹出框的按钮 */
.pop_btn button {
color: #778899;
width: 40%;
height: 40px;
cursor: pointer;
border: solid 1px #cccccc;
border-radius: 5px;
margin: 5px 10px;
color: #ffffff;
background-color: #337ab7;
}
myrow {
color: white;
display: flex;
flex-direction: row;
align-content: flex-start;
}
mycolumn {
color: white;
display: flex;
flex-direction: column;
}
.myrow {
color: white;
display: flex;
flex-direction: row;
align-content: flex-start;
}
.mycolumn {
color: white;
display: flex;
flex-direction: column;
width: 100%;
}
.myblock {
background-color: chocolate;
width: 50px;
height: 50px;
margin: 10px 0px 0px 10px;
}
.mycardbtn {
background-color: #07486f;
border-radius: 10px;
margin: 0 10px 10px 10px;
padding: 10px 10px 10px 10px;
}
.mycardbtn-active {
background-color: #1d6466;
border-radius: 10px;
margin: 0 10px 10px 10px;
padding: 10px 10px 10px 10px;
border: 2px solid #01b7d1;
}
.mycardbtn:hover {
background-color: #1d6466;
cursor: pointer;
}
.mycard {
background-color: #08365b;
width: 300px;
height: 280px;
border-radius: 10px;
margin: 10px 0px 0px 10px;
padding: 10px;
}
.mycard-param {
display: flex;
font-size: 16px;
margin-left: 20px;
}
.mycard-param-title {
font-weight: 200;
color: #a6b8dd;
width: 70px;
}
.mycard-param-text {
font-weight: 500;
margin-left: 10px;
color: white;
}
.mychart {
background-color: #30303030;
}
.mypanel {
width: 100%;
height: 200px;
background-color: #07253f;
border-radius: 8px;
padding: 10px 10px 10px 10px;
margin: 0px 0px 10px 0px;
overflow: hidden;
}
.mypanel .mypanel-icon {
width: 5px;
height: 24px;
background-color: #21ffd2;
float: left;
}
.mypanel .mypanel-title {
height: 24px;
margin-left: 15px;
font-size: 16px;
font-weight: 1000;
color: #63c4d8;
}
.mypanel-title {
height: 24px;
margin-left: 15px;
font-size: 16px;
font-weight: 1000;
color: #63c4d8;
}
.mypanel .mypanel-line {
margin-top: 5px;
margin-bottom: 0px;
width: 100%;
height: 2px;
background: linear-gradient(to right, #21ffd2ff, #21ffd200);
}
.label-bkg {
border-radius: 5px;
background-color: #a0a0a010;
float: left;
/* margin-right: 10px; */
}
.label-key {
/* border: solid 1px white; */
width: 100%;
height: 50%;
font-size: 16px;
font-weight: 1000;
color: white;
text-align: center;
display: flex;
justify-content: center;
align-items: center;
}
.label-val-lg {
/* border: solid 1px white; */
width: 65%;
height: 50%;
font-size: 36px;
color: #4dd7f0;
float: left;
display: flex;
justify-content: flex-end;
align-items: flex-end;
text-align: right;
}
.label-val {
/* border: solid 1px white; */
width: 65%;
height: 50%;
font-size: 20px;
color: #4dd7f0;
float: left;
display: flex;
justify-content: flex-end;
align-items: flex-end;
}
.label-tail {
/* border: solid 1px white; */
padding-left: 10px;
width: 35%;
height: 45%;
font-size: 16px;
font-weight: 1000;
color: white;
display: flex;
justify-content: left;
align-items: flex-end;
}
#maskTest {
position: absolute;
z-index: 1;
left: 0px;
top: 0px;
width: 100%;
height: 100%;
}
.page {
padding: 5px 8px 5px 8px;
}
.dt-container {
color: white;
}
div.dt-container .dt-paging .dt-paging-button {
line-height: 32px;
width: 32px;
padding: 0 0px 0 0;
border: 1px solid white;
margin-right: 10px;
}
div.dt-container .dt-paging .dt-paging-button.disabled,
div.dt-container .dt-paging .dt-paging-button.disabled:hover,
div.dt-container .dt-paging .dt-paging-button.disabled:active {
color: white !important;
border: 1px solid gray;
}
div.dt-container .dt-paging .dt-paging-button.current {
background: linear-gradient(to bottom, #1c797a 0%, #1c797a 100%);
}
div.dt-container .dt-paging .dt-paging-button.current:hover {
background: linear-gradient(to bottom, #1c797a 0%, #1c797a 100%);
}
div.dt-container .dt-paging .dt-paging-button:hover {
color: white !important;
border: 1px solid #111;
background-color: #111;
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #585858), color-stop(100%, #111));
/* Chrome,Safari4+ */
background: -webkit-linear-gradient(top, #585858 0%, #111 100%);
/* Chrome10+,Safari5.1+ */
background: -moz-linear-gradient(top, #585858 0%, #111 100%);
/* FF3.6+ */
background: -ms-linear-gradient(top, #585858 0%, #111 100%);
/* IE10+ */
background: -o-linear-gradient(top, #585858 0%, #111 100%);
/* Opera 11.10+ */
background: linear-gradient(to bottom, #1c797a 0%, #1c797a 100%);
/* W3C */
/* min-height: 20px; */
/* line-height: 20px; */
/* height: 30px; */
/* border-right: solid 1px gray; */
/* border-bottom: solid 1px gray; */
border: solid 1px gray;
}
</style>
<script>
var G = {
loadPage: function (pagename) {
while (1) {
var script = document.querySelector("script[id='mytempfile']")
if (!script) break
script.remove()
}
var file = 'assets/html/pages/' + pagename + '.html'
G.cppNative.readFile(file).then(function (text) {
// 加载 html 页面内容文件
document.getElementById('mypage').innerHTML = text
// 加载 js 脚本文件
var jsUrl = './pages/' + pagename + '.js'
var element = document.createElement('script')
element.src = jsUrl + '?t=' + new Date().getTime()
element.async = false // 脚本按照加载先后顺序处理
element.setAttribute('id', 'mytempfile')
document.body.appendChild(element)
})
},
switchSetStatus: function (id1, id2, isOn, callback) {
var switch1 = document.getElementById(id1)
var switch2 = document.getElementById(id2)
switch2.checked = !(switch1.checked = isOn)
if (callback) callback(isOn)
},
switchGetStatus: function (id) { return document.getElementById(id).checked },
initTable: function (id, info) {
if (info.table) {
info.table.ajax.reload()
return;
}
var tableOption = G.tableGetOption()
tableOption.columns = info.columns
tableOption.ajax = function (req, callback, settings) {
if (info.query) {
info.query(1, 10).then(res => {
var result = []
res.data.forEach(function (item, index) {
var rowData = []
info.header.forEach(function (key, index) { rowData.push(item[key]) })
result.push(rowData)
})
G.cppNative.log("table ajax: " + JSON.stringify(result))
callback({ draw: req.draw, recordsTotal: result.length, recordsFiltered: result.length, data: result })
})
} else {
callback({ draw: req.draw, recordsTotal: 0, recordsFiltered: 0, data: [] })
}
}
// 初始化表格
info.table = $('#' + id + 'Table').DataTable(tableOption)
$('div.gotopage').html(
'<b style="color:#7f8fa4">跳转至 </b><input id="searchNumber" style="width:80px"/><b style="color:#7f8fa4;"> 页</b>'
)
},
initForm: function (id, funcPopConfirm) {
var form = document.getElementById(id + 'Form')
var formBtnOk = document.getElementById(id + 'FormOk')
if (form && formBtnOk) {
// 监听表单的输入事件,检查表单的必填项是否完成输入,如果未完成,则确认按钮不可用
form.addEventListener('input', function () { formBtnOk.disabled = !form.checkValidity() })
// 编辑弹窗的确定按钮监听点击事件
formBtnOk.addEventListener('click', function () { if (funcPopConfirm) { funcPopConfirm(id) } })
}
},
showElement: function (id, visible) {
var elemt = document.getElementById(id)
if (elemt) { elemt.style.display = visible ? 'block' : 'none' }
},
popSetParams: function (id, keys, rowdata, callback) {
keys.forEach(function (key, index) {
var val = ''
if (rowdata && rowdata.length > index) { val = rowdata[index] }
if (key == 'is_open') {
G.switchSetStatus(id + 'Form_on', id + 'Form_off', parseInt(val))
} else {
var myval = (callback) ? callback(id, key, val) : val
// 回调函数返回 undefined 时, 不需要设置参数值
if (myval != undefined) {
val = myval
var element = $('#' + id + 'Form_' + key)
if (element) {
if (element.prop("tagName") == "SELECT" && val == '') {
element.get(0).selectedIndex = 0;
} else {
element.val(val)
}
}
}
}
})
},
popGetParams: function (id, keys, rowdata, callback) {
var params = {}
keys.forEach(function (key, index) {
var val
if (key == 'is_open') {
val = G.switchGetStatus(id + 'Form_on') ? '1' : '0'
} else {
var myval = callback ? callback(id, key) : undefined
val = myval != undefined ? myval : $('#' + id + 'Form_' + key).val()
}
if (rowdata) {
if (rowdata.length > index && val != rowdata[index]) { params[key] = val }
} else {
if (val != '') { params[key] = val }
}
})
G.cppNative.log('POP get params id=' + id + ', params=' + JSON.stringify(params))
return params
},
popSetParamReadonly: function (id, key, isReadonly) {
$('#' + id + 'Form_' + key).attr('readonly', isReadonly)
},
tableGetOption: function () {
return {
data: [],
columns: [],
bSort: false,
aLengthMenu: [10, 20, 50, 100], //设置每页显示数据条数的下拉选项
displayLength: 10, //每页初始显示最大记录数量
// 设置表格t、分页数据条数l、搜索框f、表格信息i、分页p、加载信息r
dom: 'rt<"table-ext"<"item">p<"item"<"gotopage">><"item"i>>',
language: {
emptyTable: '无数据',
lengthMenu: '每页显示 _MENU_ 条记录',
zeroRecords: '对不起,查询不到任何相关数据',
info: '共 _TOTAL_ 条记录', // '当前显示 _START_ 到 _END_ 条,共 _TOTAL_ 条记录',
infoEmpty: '共 0 页',
infoFiltered: '数据表中共为 _MAX_ 条记录)',
processing: '正在加载中...',
search: '结果中搜索',
paginate: { previous: '<', next: '>' }, // first: '首页', last: '尾页'
},
columnDefs: [{ targets: '_all', className: 'dt-head-left' }, { targets: '_all', className: 'dt-body-left' }],
serverSide: true,
processing: false,
ajax: function (req, callback, settings) {
// 查询服务器获取数据, 同时获取总数据条数
callback({ draw: req.draw, recordsTotal: 0, recordsFiltered: 0, data: [] })
},
createdRow: function (row, data, dataIndex) {
if (dataIndex % 2 === 0) {
//$(row).css('background-color', '#ff000010')
} else {
//$(row).css('background-color', '#00ff0010')
}
$(row).on('mouseenter', function () {
//if (curEditRow && myTableApi.row(curEditRow).index() == myTableApi.row($(this)).index()) return
$(this).css('background-color', '#ff808050') // 高亮颜色
})
$(row).on('mouseleave', function () {
//if (curEditRow && myTableApi.row(curEditRow).index() == myTableApi.row($(this)).index()) return
$(this).css('background-color', '') // 恢复默认
})
},
}
},
clickSubpageBtn: function (id) {
if (G.curSubpageId == id) return
if (G.curSubpageId) {
var oldBtn = document.getElementById(G.curSubpageId + 'Btn')
if (oldBtn) { oldBtn.className = 'btn btn-primary' }
var oldSubpage = $('#' + G.curSubpageId)
if (oldSubpage) { oldSubpage.hide() }
}
if (id) {
var curBtn = document.getElementById(id + 'Btn')
if (curBtn) { curBtn.className = 'btn btn-success btn-lg' }
var curSubpage = $('#' + id)
if (curSubpage) { curSubpage.show() }
}
G.curSubpageId = id
}
}
</script>
</head>
<body>
<div style="height: calc(8vh); line-height: 100px; display: flex;">
<!-- <button style="height:50px; line-height: 50px;" onclick='window.location.reload()'>重新加载</button> -->
<div id="currentTime"
style="color:white; font-family: Cascadia Mono; font-size: 20px; font-weight: 1000; margin-left: 20px; float: left">
<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">
<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>
<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;"
onclick="loginOut()"></button>
</div>
</div>
<div id="mypage" style="height: calc(92vh - 60px); overflow: hidden;">
</div>
<div id="mypage" style="height: calc(92vh - 60px);display: flex;flex-direction: row;"> </div>
<div style="background-color: #00496e; display: flex; justify-content: center;">
<button class="btn btn-primary" style="margin: 10px" onclick="G.loadPage('系统总览')">系统总览</button>
<button class="btn btn-primary" style="margin: 10px" onclick="G.loadPage('运行监控')">运行监控</button>
<button class="btn btn-primary" style="margin: 10px" onclick="G.loadPage('预测管理')">预测管理</button>
<button class="btn btn-primary" style="margin: 10px" onclick="G.loadPage('统计分析')">统计分析</button>
<button class="btn btn-primary" style="margin: 10px" onclick="G.loadPage('系统管理')">系统管理</button>
<button class="btn btn-primary" style="margin: 10px" onclick="G.loadPage('安全管理')">安全管理</button>
<button id="homePageBtn" class="btn btn-success" style="margin: 10px"
onclick="onClickMenuBtn(this, '系统总览')">系统总览</button>
<button class="btn btn-primary" style="margin: 10px" onclick="onClickMenuBtn(this, '运行监控')">运行监控</button>
<button class="btn btn-primary" style="margin: 10px" onclick="onClickMenuBtn(this, '预测管理')">预测管理</button>
<button class="btn btn-primary" style="margin: 10px" onclick="onClickMenuBtn(this, '统计分析')">统计分析</button>
<button class="btn btn-primary" style="margin: 10px" onclick="onClickMenuBtn(this, '系统管理')">系统管理</button>
<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>
<script>
//第一个参数是QtWebEngine 挂载到前端全局环境中的 window.qt.webChannelTransport
new QWebChannel(qt.webChannelTransport, function (channel) {
// 在C++侧注册的对象名称为cppNative所以channel.objects后面的名字是cppNative
G.cppNative = channel.objects.cppNative
// 连接WebObject类的signalNativeTextChanged信号
G.cppNative.signalNativeTextChanged.connect(function (text) { alert('signal: ' + text) })
})
document.addEventListener("keydown", function (e) {
if (e.keyCode == 116) { window.location.reload() }
});
// 查询用户权限,确定页面显示内容
$(document).ready(function () {
setInterval(() => {
var now = new Date()
var year = now.getFullYear();
var month = ('0' + (now.getMonth() + 1)).slice(-2);
var day = ('0' + now.getDate()).slice(-2);
var hours = ('0' + now.getHours()).slice(-2);
var minutes = ('0' + now.getMinutes()).slice(-2);
var seconds = ('0' + now.getSeconds()).slice(-2);
var currentT = year + '-' + month + '-' + day + ' ' + hours + ':' + minutes + ':' + seconds;
document.getElementById('currentTime').innerHTML = currentT;
}, 1000);
//G.loadPage('系统总览')
})
</script>
<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"
style="position: fixed; top:41.0%; left:43.6%; width:17.6%; height: 13%; ">
<input id="loginForm_name" type="text" class="form-control" required
style="height: 33%; background-color: #163b7d; color: white" />
<input id="loginForm_pwd" type="password" class="form-control" required
style="margin-top: 4.5%;height: 33%; background-color: #163b7d; color: white" />
</form>
<div id="loginMsg" style="position:fixed;top:52%;left:43.7%;width:17.5%;height:30px;color:crimson"></div>
<button id="loginFormOK"
style="position: fixed; top:54.7%; left:43.7%; width: 17.5%; height: 4%; background-color: #2a82e4; border-radius:5px; border: none; color: white; font-weight: 600;"
onclick="login()"> 登 录</button>
</div>
</body>
<script>
// 第一个参数是QtWebEngine 挂载到前端全局环境中的 window.qt.webChannelTransport
new QWebChannel(qt.webChannelTransport, function (channel) {
// 在C++侧注册的对象名称为cppNative所以channel.objects后面的名字是cppNative
G.cppNative = channel.objects.cppNative
// 连接QWeb的信号signalNativeTextChanged是qt侧定义的signal
G.cppNative.signalNativeTextChanged.connect(function (text) { alert('signal: ' + text) })
// 连接信号:登录完成
G.cppNative.signalLongin.connect(onSignalLogin)
})
document.addEventListener("keydown", function (e) {
if (e.keyCode == 116) { window.location.reload() }
});
var activeMenuBtn = document.getElementById('homePageBtn')
function onClickMenuBtn(btn, id) {
if (activeMenuBtn) activeMenuBtn.className = 'btn btn-primary'
activeMenuBtn = btn
activeMenuBtn.className = 'btn btn-success'
G.loadPage(id)
}
function login() {
var username = $("#loginForm_name").val()
var passwd = $("#loginForm_pwd").val()
if (!username) {
$('#loginMsg').text('请输入用户名!')
return
}
if (!passwd) {
$('#loginMsg').text('请输入密码!')
return
}
$('#loginMsg').text('')
// 调用CPP接口
G.cppNative.login(username, passwd);
}
function loginOut() {
$("#loginPage").show()
}
var form = document.getElementById('loginForm')
var formBtnOk = document.getElementById('loginFormOK')
if (form && formBtnOk) {
// 监听表单的输入事件,检查表单的必填项是否完成输入,如果未完成,则确认按钮不可用
form.addEventListener('input', function () {
formBtnOk.disabled = !form.checkValidity()
if (!$("#loginForm_name").val()) {
$('#loginMsg').text('请输入用户名!')
} else if (!$("#loginForm_pwd").val()) {
$('#loginMsg').text('请输入密码!')
} else {
$('#loginMsg').text('')
}
})
}
function onSignalLogin(username, ecode) {
if (ecode != 0) {
const ErrCode = {
101: '数据库连接错误',
102: '数据库查询SQL错误',
103: '用户不存在',
104: '密码不正确'
}
var errmsg = ErrCode[ecode]
if (!errmsg) { errmsg = '错误码:' + ecode }
$('#loginMsg').text('登入失败,' + errmsg)
// $("#loginForm_name").val('')
// $("#loginForm_pwd").val('')
} else {
G.user.username = username
$('#username').text(username)
$("#loginPage").hide()
onClickMenuBtn(document.getElementById('homePageBtn'), '系统总览')
}
}
// 查询用户权限,确定页面显示内容
$(document).ready(function () {
setInterval(() => {
var now = new Date()
var year = now.getFullYear();
var month = ('0' + (now.getMonth() + 1)).slice(-2);
var day = ('0' + now.getDate()).slice(-2);
var hours = ('0' + now.getHours()).slice(-2);
var minutes = ('0' + now.getMinutes()).slice(-2);
var seconds = ('0' + now.getSeconds()).slice(-2);
var weekday = now.toLocaleDateString('zh-CN', { weekday: "long" });
var time = year + '-' + month + '-' + day + ' ' + hours + ':' + minutes + ':' + seconds;
document.getElementById('currentTime').innerHTML = time;
document.getElementById('currentWeekday').innerHTML = weekday
}, 1000);
// 测试: 不显示登录页,正式版本需要删除
$("#loginPage").hide()
onClickMenuBtn(document.getElementById('homePageBtn'), '系统总览')
})
</script>
</html>

View File

@@ -1,34 +1,110 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<div style="width: 100%; height: 100%; ;">
<script src="../libs/jquery/jquery-3.7.1.min.js"></script>
<div id="workspace" class="myrow">
<div class="mycard" style="width:320px">
<div class="myrow" style="margin-bottom: 20px; border: solid 1px salmon;">
<div style="width: 65px;height: 65px; background-color: #2991b6;border-radius: 10px;"></div>
<div class="mycol" style="margin-left: 10px; font-size:15px;">
<div> 编号111 </div>
<div style="font-size:15px;"> 名称 </div>
<div style="color: #08afff; font-size:14px; font-weight: bold;"> 设备类型 </div>
</div>
</div>
<link rel="stylesheet" href="../libs/DataTables-2.1.8/css/dataTables.dataTables.css" />
<script src="../libs/DataTables-2.1.8/js/dataTables.js"></script>
<div class="mycard-param">
<div class="mycard-param-key">工作状态: </div>
<div id="id" class="mycard-param-text">运行/空闲</div>
</div>
</div>
<link rel="stylesheet" href="../libs/bootstrap-5.3.3-dist/css/bootstrap.min.css" />
<script src="../libs/bootstrap-5.3.3-dist/js/bootstrap.min.js"></script>
<script src="../libs/bootstrap-5.3.3-dist/js/bootstrap.bundle.min.js"></script>
<div class="mycard" style="width:320px">
<div class="myrow" style="margin-bottom: 20px; ">
<div style="width: 65px;height: 65px; background-color: #2991b6;border-radius: 10px;"></div>
<div class="mycol" style="margin-left: 10px; font-size:15px;">
<div> 编号222 </div>
<div style="font-size:15px;"> 名称 </div>
<div style="color: #08afff; font-size:14px; font-weight: bold;"> 设备类型 </div>
</div>
</div>
<div class="myrow">
<div style="width: calc(50% - 10px); border: solid gray; border-width: 0 1px 0 0;">
<div class="myrow" style="font-size:14px; margin-left: 10px;">
<div style="background-color:#00dbd7; width: 5px; height:18px; "></div>
<div style="margin-left: 10px;">枪: #1</div>
<div class="status-ok" style="margin: 3px 0 0 30px; ">
</div>
</div>
<script type="text/javascript" src="../js/qwebchannel.js"></script>
<div class=" mycard-param">
<div class="mycard-param-key">状态: </div>
<div id="id" class="mycard-param-text">运行</div>
</div>
<div class="mycard-param">
<div class="mycard-param-key">电压: </div>
<div id="id" class="mycard-param-text">220 V</div>
</div>
<div class="mycard-param">
<div class="mycard-param-key">电流: </div>
<div id="id" class="mycard-param-text">10 A</div>
</div>
<div class="mycard-param">
<div class="mycard-param-key">功率: </div>
<div id="id" class="mycard-param-text">2.2 kW</div>
</div>
<div class="mycard-param">
<div class="mycard-param-key">温度: </div>
<div id="id" class="mycard-param-text">2.2 kW</div>
</div>
<div class="mycard-param">
<div class="mycard-param-key">SOC: </div>
<div id="id" class="mycard-param-text">20.6%</div>
</div>
<div class="mycard-param">
<div class="mycard-param-key">SOH: </div>
<div id="id" class="mycard-param-text">89.7%</div>
</div>
</div>
<link rel="stylesheet" type="text/css" href="../css/mystyle.css" />
<div style="width: calc(50% - 10px); margin-left: 10px;">
<div class="myrow" style="font-size:14px; margin-left: 10px;">
<div style="background-color:#00dbd7; width: 5px; height:18px; "></div>
<div style="margin-left: 10px;">枪: #2</div>
<div class="status-err" style="margin: 3px 0 0 30px; "></div>
</div>
<style>
.tablebox {
width: 100%;
height: 600px;
background-color: #052f4d;
margin-top: 20px;
padding: 20px 20px 20px 20px;
}
</style>
</head>
<body>
<iframe src="./index.html"></iframe>
<script src="./index.js"></script>
<>
</body>
</html>
<div class="mycard-param">
<div class="mycard-param-key">状态: </div>
<div id="id" class="mycard-param-text">运行</div>
</div>
<div class="mycard-param">
<div class="mycard-param-key">电压: </div>
<div id="id" class="mycard-param-text">220 V</div>
</div>
<div class="mycard-param">
<div class="mycard-param-key">电流: </div>
<div id="id" class="mycard-param-text">10 A</div>
</div>
<div class="mycard-param">
<div class="mycard-param-key">功率: </div>
<div id="id" class="mycard-param-text">2.2 kW</div>
</div>
<div class="mycard-param">
<div class="mycard-param-key">温度: </div>
<div id="id" class="mycard-param-text">2.2 kW</div>
</div>
<div class="mycard-param">
<div class="mycard-param-key">SOC: </div>
<div id="id" class="mycard-param-text">57.3%</div>
</div>
<div class="mycard-param">
<div class="mycard-param-key">SOH: </div>
<div id="id" class="mycard-param-text">93.2%</div>
</div>
</div>
</div>
</div>
</div>
<table id="myTable"></table>
</div>

View File

@@ -0,0 +1,149 @@
function addCardPanel(code, name, type, subList) {
var root = document.getElementById('workspace')
var card = document.createElement('div')
card.className = 'mycard'
card.setAttribute('id', code);
card.innerHTML =
`<div class="myrow" style="margin-bottom: 20px">
<div style="width: 65px;height: 65px; background-color: #2991b6;border-radius: 10px;"></div>
<div class="mycol" style="margin-left: 10px; font-size:15px;">
<div> ${code} </div>
<div style="font-size:15px;"> ${name} </div>
<div style="color: #08afff; font-size:14px; font-weight: bold;"> ${type} </div>
</div>
</div>`
// '<div class="mycard-param">'
// '<div class="mycard-param-key">工作状态: </div>'
// '<div id="id" class="mycard-param-text">运行/空闲</div>'
// '</div>'
if (subList && subList.length > 1) {
card.innerHTML +=
`<div class="myrow">
<div id="${code}_${subList[0]}" style="width: calc(50% - 10px); border: solid gray; border-width: 0 1px 0 0;">
<div class="myrow" style="font-size:14px; margin-left: 10px;">
<div style="background-color:#00dbd7; width: 5px; height:18px; "></div>
<div style="margin-left: 10px;">#${subList[0]}</div>
<div class="status-ok" style="margin: 3px 0 0 30px; "></div>
</div>
</div>
<div id="${code}_${subList[1]}" style="width: calc(50% - 10px); margin-left: 10px;">
<div class="myrow" style="font-size:14px; margin-left: 10px;">
<div style="background-color:#00dbd7; width: 5px; height:18px; "></div>
<div style="margin-left: 10px;">#${subList[1]}</div>
<div class="status-err" style="margin: 3px 0 0 30px; "></div>
</div>
</div>
</div>`
}
root.appendChild(card)
return card
}
function addCardParam(cardid, subid, key, text) {
var paramid = cardid + (subid ? ("_" + subid) : "") + "_" + key
param = document.createElement('div')
param.className = 'mycard-param'
param.innerHTML = `<div class="mycard-param-key">${key}: </div>
<div id="${paramid}" class="mycard-param-text">${text}</div>`
if (subid) {
$('#' + cardid + '_' + subid).append(param)
} else {
$('#' + cardid).append(param)
}
}
function setCardParam(cardid, subid, key, text) {
var paramid = cardid + (subid ? ("_" + subid) : "") + "_" + key
$("#" + paramid).text(text);
}
addCardPanel('编号1', '名称', '设备类型')
addCardParam('编号1', null, "电压", "220 V");
setCardParam('编号1', null, "电压", "290 V");
addCardPanel('编号2', '名称', '设备类型', ['1', '2'])
addCardParam('编号2', '1', "电压", "200 V");
addCardParam('编号2', '1', "电流", "10 V");
addCardParam('编号2', '2', "电压", "220 V");
setCardParam('编号2', '1', "电压", "210 V");
// var dataTablesOption = {
// data: [],
// columns: [],
// scrollY: "800px",
// bSort: false,
// aLengthMenu: [10, 20, 50, 100], //设置每页显示数据条数的下拉选项
// displayLength: 20, //每页初始显示最大记录数量
// // 设置表格t、分页数据条数l、搜索框f、表格信息i、分页p、加载信息r
// //dom: '<"table-ext"<"item"f><"item"l><"item"i><"item"p>>rt',
// language: {
// lengthMenu: '每页显示 _MENU_ 条记录',
// sZeroRecords: '对不起,查询不到任何相关数据',
// sInfo: '当前显示 _START_ 到 _END_ 条,共 _TOTAL_ 条记录',
// sInfoEmtpy: '找不到相关数据',
// sInfoFiltered: '数据表中共为 _MAX_ 条记录)',
// processing: '正在加载中...',
// search: '结果中搜索: ',
// paginate: { sPrevious: ' 上一页 ', sNext: ' 下一页 ', },
// },
// }
// var htmlOptEdit = '<button class="btn btn-outline-primary btn-sm" style="width:80px; height: 28px;" id="btnRowEdit">编辑</button>'
// var htmlOptHref = '<a href="javascript:void(0);" class="table-btn-edit">编辑</a>' +
// // '<a href="javascript:void(0);" class="table-btn-del">删除</a>' +
// '<a href="javascript:void(0);" class="">采购</a>' +
// '<a href="javascript:void(0);" class="">入库</a>' +
// '<a href="javascript:void(0);" class="">销售</a>' +
// '<a href="javascript:void(0);" class="">出库</a>'
// dataTablesOption.columns = [
// { title: '编号', width: '50px' },
// { title: '产品名称', width: '150px' },
// { title: '规格型号', width: '150px' },
// { title: '类别', width: '150px' },
// { title: '库存量', width: '80px' },
// { title: '采购总量', width: '80px' },
// { title: '入库总量', width: '80px' },
// { title: '销售总量', width: '80px' },
// { title: '出库总量', width: '80px' },
// { title: '异常总量', width: '80px' },
// { title: '异常说明' },
// {
// title: '操作',
// width: '300px',
// render: function (data, type, row) { return htmlOptEdit },
// },
// ]
// var table = $('#myTable').DataTable(dataTablesOption)
// var rowid = 0;
// table.row.add([++rowid, '产品名称', '产品型号', '五金类库/五金制品', '', '', '', '', '', '', ''])
// table.row.add([++rowid, '产品名称', '产品型号', '五金类库/五金制品', '', '', '', '', '', '', ''])
// table.row.add([++rowid, '产品名称', '产品型号', '五金类库/五金制品', '', '', '', '', '', '', ''])
// table.row.add([++rowid, '产品名称', '产品型号', '五金类库/五金制品', '', '', '', '', '', '', ''])
// table.row.add([++rowid, '产品名称', '产品型号', '五金类库/五金制品', '', '', '', '', '', '', ''])
// table.row.add([++rowid, '产品名称', '产品型号', '五金类库/五金制品', '', '', '', '', '', '', ''])
// table.row.add([++rowid, '产品名称', '产品型号', '五金类库/五金制品', '', '', '', '', '', '', ''])
// table.row.add([++rowid, '产品名称', '产品型号', '五金类库/五金制品', '', '', '', '', '', '', ''])
// table.row.add([++rowid, '产品名称', '产品型号', '五金类库/五金制品', '', '', '', '', '', '', ''])
// table.row.add([++rowid, '产品名称', '产品型号', '五金类库/五金制品', '', '', '', '', '', '', ''])
// table.row.add([++rowid, '产品名称', '产品型号', '五金类库/五金制品', '', '', '', '', '', '', ''])
// table.row.add([++rowid, '产品名称', '产品型号', '五金类库/五金制品', '', '', '', '', '', '', ''])
// table.row.add([++rowid, '产品名称', '产品型号', '五金类库/五金制品', '', '', '', '', '', '', ''])
// table.row.add([++rowid, '产品名称', '产品型号', '五金类库/五金制品', '', '', '', '', '', '', ''])
// table.row.add([++rowid, '产品名称', '产品型号', '五金类库/五金制品', '', '', '', '', '', '', ''])
// table.row.add([++rowid, '产品名称', '产品型号', '五金类库/五金制品', '', '', '', '', '', '', ''])
// table.row.add([++rowid, '产品名称', '产品型号', '五金类库/五金制品', '', '', '', '', '', '', ''])
// table.row.add([++rowid, '产品名称', '产品型号', '五金类库/五金制品', '', '', '', '', '', '', ''])
// table.row.add([++rowid, '产品名称', '产品型号', '五金类库/五金制品', '', '', '', '', '', '', ''])
// table.row.add([++rowid, '产品名称', '产品型号', '五金类库/五金制品', '', '', '', '', '', '', ''])
// table.row.add([++rowid, '产品名称', '产品型号', '五金类库/五金制品', '', '', '', '', '', '', ''])
// table.row.add([++rowid, '产品名称', '产品型号', '五金类库/五金制品', '', '', '', '', '', '', ''])
// table.row.add([++rowid, '产品名称', '产品型号', '五金类库/五金制品', '', '', '', '', '', '', ''])
// table.draw()

View File

@@ -1,4 +1,4 @@
<div class="mycolumn" style="padding: 10px">
<div class="mycol" style="width:100%;padding: 10px">
<div class="myrow" style="height: 40px">
<button id="secpolicyBtn" class="btn btn-success btn-lg" style="width: 120px"
onclick="initSubpage('secpolicy')">安全策略</button>

View File

@@ -1,177 +1,174 @@
<div class="myrow" style="width:100%; height:100%; padding: 10px; ">
<div class="myrow" style="height:100%; padding: 10px; ">
<div style="width: 25%; height: 100%; overflow: hidden">
<div class="mypanel" style="height: calc(30% - 10px)">
<div class="mypanel-icon"></div>
<div class="mypanel-title">运行状况</div>
<div class="mypanel-line"></div>
<div class="mypanel " style="height: calc(30% - 10px)">
<myrow style="width: 100%; height: calc(100% - 40px); margin-top: 10px">
<div class="mypanel-title myline-lb">运行状况</div>
<div class="myrow" style="width: 100%; height: calc(100% - 40px); margin-top: 10px">
<div class="label-bkg" style="width: 30%">
<div class="label-val-lg">123</div>
<div class="label-val-lg">0</div>
<div class="label-tail"></div>
<div class="label-key">安全运行</div>
</div>
<mycolumn style="width: 70%; margin-left: 5px">
<myrow style="width: 100%; height: 33%">
<div class="mycol" style="width: 70%; margin-left: 5px">
<div class="myrow" style="width: 100%; height: 33%">
<div class="label-bkg" style="width: 50%; height: 100%">
<div class="label-key">风机设备</div>
<div class="label-val">100</div>
<div id="windTurbineNum" class="label-val">0</div>
<div class="label-tail"></div>
</div>
<div class="label-bkg" style="width: 50%; height: 100%; margin-left: 5px">
<div class="label-key">光伏设备</div>
<div class="label-val">100</div>
<div id="solarNum" class="label-val">0</div>
<div class="label-tail"></div>
</div>
</myrow>
<myrow style="width: 100%; height: 33%; margin-top: 5px">
</div>
<div class="myrow" style="width: 100%; height: 33%; margin-top: 5px">
<div class="label-bkg" style="width: 50%; height: 100%">
<div class="label-key">累计发电电量</div>
<div class="label-val">100</div>
<div id="electricTotal" class="label-val">0</div>
<div class="label-tail">kWh</div>
</div>
<div class="label-bkg" style="width: 50%; height: 100%; margin-left: 5px">
<div class="label-key">累计入网电量</div>
<div class="label-val">100</div>
<div id="electricInTotal" class="label-val">0</div>
<div class="label-tail">kWh</div>
</div>
</myrow>
<myrow style="width: 100%; height: 33%; margin-top: 5px">
</div>
<div class="myrow" style="width: 100%; height: 33%; margin-top: 5px">
<div class="label-bkg" style="width: 50%; height: 100%">
<div class="label-key">累计收益</div>
<div class="label-val">100</div>
<div id="incomeTotal" class="label-val">0</div>
<div class="label-tail"></div>
</div>
<div class="label-bkg" style="width: 50%; height: 100%; margin-left: 5px">
<div class="label-key">碳减排量</div>
<div class="label-val">100</div>
<div id="carbonReduction" class="label-val">0</div>
<div class="label-tail"></div>
</div>
</myrow>
</mycolumn>
</myrow>
</div>
</div>
</div>
</div>
<div class="mypanel" style="height: calc(35% - 10px)">
<div class="mypanel-icon"></div>
<div class="mypanel-title">光伏设备</div>
<div class="mypanel-line"></div>
<myrow style="margin-top: 10px">
<div class="mypanel-title myline-lb">光伏设备</div>
<div class="myrow" style="margin-top: 10px">
<div class="label-bkg" style="width: 33%; height: 100%; margin-left: 0px">
<div class="label-key">日发电电量</div>
<div class="label-val">100</div>
<div class="label-val">0</div>
<div class="label-tail">kWh</div>
</div>
<div class="label-bkg" style="width: 33%; height: 100%; margin-left: 5px">
<div class="label-key">日入网电量</div>
<div class="label-val">100</div>
<div class="label-val">0</div>
<div class="label-tail">kWh</div>
</div>
<div class="label-bkg" style="width: 33%; height: 100%; margin-left: 5px">
<div class="label-key">日收益金额</div>
<div class="label-val">100</div>
<div class="label-val">0</div>
<div class="label-tail"></div>
</div>
</myrow>
</div>
<div id="mychartSolar" style="width: 100%; height: calc(100% - 90px)"></div>
</div>
<div class="mypanel" style="height: calc(35% - 10px)">
<div class="mypanel-icon"></div>
<div class="mypanel-title">储能设备</div>
<div class="mypanel-line"></div>
<myrow style="margin-top: 10px">
<div class="mypanel-title myline-lb">储能设备</div>
<div class="myrow" style="margin-top: 10px">
<div class="label-bkg" style="width: 50%; height: 100%; margin-left: 0px">
<div class="label-key">日充电电量</div>
<div class="label-val">100</div>
<div class="label-val">0</div>
<div class="label-tail">kWh</div>
</div>
<div class="label-bkg" style="width: 50%; height: 100%; margin-left: 5px">
<div class="label-key">日放电电量</div>
<div class="label-val">100</div>
<div class="label-val">0</div>
<div class="label-tail">kWh</div>
</div>
</myrow>
</div>
<div id="mychartStorage" style="width: 100%; height: calc(100% - 90px)"></div>
</div>
</div>
<div style="margin-left: 10px; width: 50%; height: 100%; overflow: hidden">
<div class="mypanel" style="height: calc(70% - 10px); ">
<myrow style="justify-content: center ; ">
<div style="margin-left: 10px; width: 50%; height: 100%; overflow: hidden; font-size: 14px;">
<div class="mypanel" style="height: calc(70% - 10px); background-color: #012036;">
<div class="myrow" style="justify-content: center ; ">
<div style="display: flex; width: 20%;">
<div style="width:5px; height: 50px; background-color: #f69b52;"></div>
<div style="width:50px; height: 50px; background-color: #f69b5250;"></div>
<mycolumn style="margin-left: 10px;">
<img src="./res/icon-brightness.png"
style="width:50px; height: 50px; object-fit: fill; background-color: #f69b5250;">
<!-- <div style="width:50px; height: 50px; background-color: #f69b5250;"></div> -->
<div class="mycol" style="margin-left: 10px; margin-top: 5px;">
<div>光照</div>
<div id="envIllumination">--</div>
</mycolumn>
</div>
</div>
<div style="display: flex;width: 20%;">
<div style="float: left;width:5px; height: 50px; background-color: #9bd801;"></div>
<div style="width:50px; height: 50px; background-color: #9bd80150;"></div>
<mycolumn style="margin-left: 10px;">
<img src="./res/icon-windspeed.png"
style="width:50px; height: 50px; object-fit: fill; background-color: #9bd80150;">
<!-- <div style="width:50px; height: 50px; background-color: #9bd80150;"></div> -->
<div class="mycol" style="margin-left: 10px; margin-top: 5px;">
<div>风速</div>
<div id="envWindspeed">--</div>
</mycolumn>
</div>
</div>
<div style="display: flex;width: 20%;">
<div style="float: left;width:5px; height: 50px; background-color: #3dfefa;"></div>
<div style="width:50px; height: 50px; background-color: #3dfefa50;"></div>
<mycolumn style="margin-left: 10px;">
<img src="./res/icon-temperature.png"
style="width:50px; height: 50px; object-fit: fill; background-color: #3dfefa50;">
<!-- <div style="width:50px; height: 50px; background-color: #3dfefa50;"></div> -->
<div class="mycol" style="margin-left: 10px; margin-top: 5px;">
<div>环境温度</div>
<div id="envTemperture">--</div>
</mycolumn>
</div>
</div>
<div style="display: flex;width: 20%;">
<div style="float: left;width:5px; height: 50px; background-color: #d83d6c;"></div>
<div style="width:50px; height: 50px; background-color: #d83d6c50;"></div>
<mycolumn style="margin-left: 10px;">
<img src="./res/icon-humidity.png"
style="width:50px; height: 50px; object-fit: fill; background-color: #d83d6c50;">
<!-- <div style="width:50px; height: 50px; background-color: #d83d6c50;"></div> -->
<div class="mycol" style="margin-left: 10px; margin-top: 5px;">
<div>环境湿度</div>
<div id="envHumidity">--</div>
</mycolumn>
</div>
</div>
</myrow>
<img src="./res/overview.png" style="width: 100%; height: calc(100% - 50px); object-fit: fill;"> </img>
</div>
<img src="./res/overview.png" style="width: 100%; height: calc(100% - 60px); object-fit: fill; margin-top: 20px;">
</img>
</div>
<div class="mypanel" style="height: calc(30% - 10px)">
<div class="mypanel-icon"></div>
<div class="mypanel-title">发电功率和辐照度</div>
<div class="mypanel-line"></div>
<div class="mypanel-title myline-lb">发电功率和辐照度</div>
<div id="mychartRunning" style="width: 100%; height: 90%"></div>
</div>
</div>
<div style="margin-left: 10px; width: 25%; height: 100%; overflow: hidden">
<div class="mypanel" style="height: calc(30% - 10px)">
<div class="mypanel-icon"></div>
<div class="mypanel-title">负荷设备</div>
<div class="mypanel-line"></div>
<myrow style="margin-top: 10px">
<div class="mypanel-title myline-lb">负荷设备</div>
<div class="myrow" style="margin-top: 10px">
<div class="label-bkg" style="width: 50%; height: 100%; margin-left: 0px">
<div class="label-key">日用电电量</div>
<div class="label-val">100</div>
<div class="label-val">0</div>
<div class="label-tail">kWh</div>
</div>
<div class="label-bkg" style="width: 50%; height: 100%; margin-left: 5px">
<div class="label-key">日最大功率</div>
<div class="label-val">100</div>
<div class="label-val">0</div>
<div class="label-tail">kW</div>
</div>
</myrow>
</div>
<div id="mychartLoad" style="width: 100%; height: calc(100% - 90px)"></div>
</div>
<div class="mypanel" style="height: calc(35% - 10px)">
<div class="mypanel-icon"></div>
<div class="mypanel-title">充电设备</div>
<div class="mypanel-line"></div>
<myrow style="margin-top: 10px">
<div class="mypanel-title myline-lb">充电设备</div>
<div class="myrow" style="margin-top: 10px">
<div class="label-bkg" style="width: 33%; height: 100%; margin-left: 0px">
<div class="label-key">日充电电量</div>
<div class="label-val">100</div>
<div class="label-val">0</div>
<div class="label-tail">kWh</div>
</div>
<div class="label-bkg" style="width: 33%; height: 100%; margin-left: 5px">
@@ -181,18 +178,16 @@
</div>
<div class="label-bkg" style="width: 33%; height: 100%; margin-left: 5px">
<div class="label-key">日充电收益</div>
<div class="label-val">100</div>
<div class="label-val">0</div>
<div class="label-tail"></div>
</div>
</myrow>
</div>
<div id="mychartCharge" style="width: 100%; height: calc(100% - 90px)"></div>
</div>
<div class="mypanel" style="height: calc(35% - 10px)">
<div class="mypanel-icon"></div>
<div class="mypanel-title">告警信息</div>
<div class="mypanel-line"></div>
<myrow style="margin-top: 10px">
<div class="mypanel-title myline-lb">告警信息</div>
<div class="myrow" style="margin-top: 10px">
<div class="label-bkg" style="width: 33%; height: 100%; margin-left: 0px">
<div class="label-key">日光伏设备告警</div>
<div class="label-val">1</div>
@@ -208,7 +203,7 @@
<div class="label-val">3</div>
<div class="label-tail"></div>
</div>
</myrow>
</div>
<div id="mychartAlert" style="width: 100%; height: calc(100% - 90px)"></div>
</div>
</div>

View File

@@ -1,4 +1,4 @@
optionBar.xAxis.data = ['2025/3/1', '2025/3/2', '2025/3/3', '2025/3/4', '2025/3/5', '2025/3/6', '2025/3/7']
optionBar.xAxis.data = ['03/01', '03/02', '03/03', '03/04', '03/05', '03/06', '03/07']
optionBar.legend.data = ['发电电量', '入网电量']
optionBar.series = [
{ name: '发电电量', type: 'bar', data: [50, 28, 35, 18, 36, 27, 19] },
@@ -47,9 +47,12 @@ function getRandomCurveData(m, n) {
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
data[i] = { name: t, value: [t, Math.sin(i * 0.1) * (n - m) + m] }
//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
}
@@ -78,6 +81,13 @@ function updatePageData() {
$('#envWindspeed').text('1.5 m/s')
$('#envTemperture').text('27.8 ℃')
$('#envHumidity').text('37.6 %')
// 查询获取统计信息
$('#windTurbineNum').text('8')
$('#solarNum').text('207')
$('#electricTotal').text('153.21')
$('#electricInTotal').text('120.35')
$('#carbonReduction').text('36.17')
}
var timerId = null

View File

@@ -1,4 +1,5 @@
<div class="mycolumn" style="padding: 10px">
<div class="mycol" style="width:100%;padding: 10px">
<div class="myrow" style="height: 40px">
<button id="userBtn" class="btn btn-success btn-lg" style="width: 120px" onclick="initSubpage('user')">人员管理</button>
<button id="roleBtn" class="btn btn-primary" style="width: 120px; margin-left: 10px"
@@ -16,6 +17,7 @@
<button id="syslogBtn" class="btn btn-primary" style="width: 120px; margin-left: 10px"
onclick="initSubpage('syslog')">系统日志</button>
</div>
<hr style="margin: 10px 0 10px 0;" />
<div id="user" style="display: block">
@@ -35,26 +37,31 @@
<div id="role" style="display: none">
<button class="btn btn-success" style="width: 90px" onclick="showPop('role')">新增</button>
<button class="btn btn-success" style="width: 90px; margin-left: 20px" onclick="">查询</button>
<table id="roleTable" class="stripe" style="width: 100%; margin-top: 10px"></table>
</div>
<div id="permission" style="display: none">
<button class="btn btn-success" style="width: 90px" onclick="showPop('permission')">新增</button>
<button class="btn btn-success" style="width: 90px; margin-left: 20px" onclick="">查询</button>
<table id="permissionTable" class="stripe" style="width: 100%; margin-top: 10px"></table>
</div>
<div id="device" style="display: none">
<button class="btn btn-success" style="width: 90px" onclick="showPop('device')">新增</button>
<button class="btn btn-success" style="width: 90px; margin-left: 20px" onclick="">查询</button>
<table id="deviceTable" class="stripe" style="width: 100%; margin-top: 10px"></table>
</div>
<div id="price" style="display: none">
<button class="btn btn-success" style="width: 90px" onclick="showPop('price')">新增</button>
<button class="btn btn-success" style="width: 90px; margin-left: 20px" onclick="">查询</button>
<table id="priceTable" class="stripe" style="width: 100%; margin-top: 10px"></table>
</div>
<div id="policy" style="display: none">
<button class="btn btn-success" style="width: 90px" onclick="showPop('policy')">新增</button>
<button class="btn btn-success" style="width: 90px; margin-left: 20px" onclick="">查询</button>
<table id="policyTable" class="stripe" style="width: 100%; margin-top: 10px"></table>
</div>
@@ -196,7 +203,18 @@
<form id="deviceForm" class="was-validated" style="margin: 0 80px 0 80px; padding-top: 30px">
<div class="input-group mb-3">
<span class="input-group-text" style="width: 90px; background-color: #a6c0da">类型*</span>
<input id="deviceForm_type" type="text" class="form-control" required />
<select id="deviceForm_type" class="form-select" required>
<option value="101">逆变器</option>
<option value="102">汇流箱</option>
<option value="103">光伏板</option>
<option value="104">风力发电机</option>
<option value="105">储能变流器</option>
<option value="106">储能电池</option>
<option value="107">BMS</option>
<option value="108">充电桩</option>
<option value="109">充电枪</option>
<option value="110">集中器</option>
</select>
</div>
<div class="input-group mb-3">
<span class="input-group-text" style="width: 90px; background-color: #a6c0da">名称*</span>
@@ -229,7 +247,23 @@
<div style="display: flex; justify-content: center; padding: 20px 20px 20px 20px">
<button id="deviceFormOk" class="btn btn-success" style="width: 90px; margin-right: 20px" disabled>确定</button>
<button class="btn btn-danger" style="width: 90px; margin-left: 20px"
onclick="G.showElement('device', false)">取消</button>
onclick="G.showElement('devicePop', false)">取消</button>
</div>
</div>
</div>
<div id="deviceAttrPop" class="mask">
<div 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 class="btn btn-danger" style="width: 90px; margin-left: 20px"
onclick="G.showElement('deviceAttrPop', false)">取消</button>
</div>
</div>
</div>
@@ -313,6 +347,8 @@
</div>
</div>
<div id="promptPop" class="mask">
<div class="pop" style="height: 240px">
<p id="promptTitle" class="pop_title"></p>

View File

@@ -19,20 +19,29 @@ function renderPolicy(data, type, row) {
}
var deviceTypeDef = {
101: "光伏设备",
102: "充电设备",
103: "储能设备",
104: "汇流箱",
105: "逆变器",
106: "储能变流器",
1: "变压器",
2: "配电柜",
3: "电表",
4: "门禁",
5: "空调",
6: "照明",
7: "消防",
8: "光照监测设备",
9: "风速监测设备",
10: "温湿度监测设备",
11: "烟感监测设备",
12: "水浸传感器",
13: "视频监控",
101: "逆变器",
102: "汇流箱",
103: "光伏板",
104: "风力发电机",
105: "储能变流器",
106: "储能电池",
107: "BMS",
108: "配电柜",
109: "电表",
201: "光照监测设备",
202: "风速监测设备",
203: "温湿度监测设备",
204: "视频监控",
205: "照明设备"
108: "充电桩",
109: "充电枪",
110: "集中器",
}
function renderDeviceType(data, type, row) {
var text = deviceTypeDef[data]
@@ -146,14 +155,13 @@ var tableDef = {
{ title: '是否启用', width: '120px', render: renderIsOpen },
{ title: '创建时间', width: '180px' },
{ title: '更新时间', width: '180px' },
{ title: '更新人', width: '180px' },
{
title: '操作',
width: '200px',
render: function (data, type, row) { return htmlOptEdit + htmlOptDel },
render: function (data, type, row) { return htmlOptEdit + htmlOptAttrs },
},
],
header: ['device_id', 'type', 'name', 'code', 'model', 'factory', 'is_open', 'create_time', 'update_time', 'update_by'],
header: ['device_id', 'type', 'name', 'code', 'model', 'factory', 'is_open', 'create_time', 'update_time', 'attrs'],
query: G.cppNative.queryDeviceList,
update: G.cppNative.updateDevice,
insert: G.cppNative.insertDevice,
@@ -225,9 +233,9 @@ var tableDef = {
}
}
var htmlOptEdit = '<button class="btn btn-outline-primary btn-sm" style="width:80px" id="btnRowEdit">编辑</button>'
var htmlOptEdit = '<button class="btn btn-primary btn-sm" style="width:80px; height:28px;" id="btnRowEdit">编辑</button>'
var htmlOptDel = '' //'<button class="btn btn-outline-danger btn-sm" style="width:80px; margin-left:8px;" id="btnRowDel">删除</button>'
var htmlOptAttrs = '<button class="btn btn-outline-warning btn-sm" style="width:80px; margin-left:8px;" id="btnRowAttrs">属性设置</button>'
var htmlOptAttrs = '<button class="btn btn-primary btn-sm" style="width:80px; height:28px; margin-left:8px;" id="btnRowAttrs">属性设置</button>'
var popRowdata = null
@@ -280,6 +288,11 @@ async function initSubpage(id) {
var row = tableInfo.table.row($(this).closest('tr'))
showPop(id, row.data())
})
tableInfo.table.on('click', '#btnRowAttrs', function () {
var row = tableInfo.table.row($(this).closest('tr'))
showPopDeviceAttr(row.data())
})
}
@@ -302,6 +315,46 @@ function showPop(id, rowData) {
}
}
var deviceAttrKeyDef = {
commType: "通讯方式",
ip: "通讯地址",
port: "通讯端口",
isclient: "客户端",
}
// 显示设备的属性编辑弹窗属性字段格式为JSON: attrs="{}"
function showPopDeviceAttr(rowData) {
G.showElement('deviceAttrPop', true)
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 elemtForm = document.getElementById('deviceAttrForm')
elemtForm.innerHTML =
`<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='${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>`
for (k in attrs) {
var title = deviceAttrKeyDef[k]
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>`
}
}
function showPrompt(text, status) {
G.showElement('promptPop', true)
var promptText = $('#promptText')
@@ -358,6 +411,17 @@ function callbackPopGetParams(id, key) {
return val
}
function updateTableData(id) {
var info = tableDef[id]
var queryFunc = info.query
if (!queryFunc) return
queryFunc(1, 10).then((res) => {
})
}
// 用户弹窗确认
function popConfirm(id) {
// 获取数据表格操作对象
@@ -398,6 +462,15 @@ function popConfirm(id) {
}
}
// 设置设备类型下拉列表
var elementSelectDeviceType = document.getElementById('deviceForm_type')
elementSelectDeviceType.innerHTML = ''
for (k in deviceTypeDef) {
elementSelectDeviceType.options.add(new Option(deviceTypeDef[k], k))
}
$(document).ready(function () {
initSubpage('user')
//G.initTable('user', tableDef['user'])
})

View File

@@ -1,4 +1,4 @@
<div class="mycolumn" style="padding: 10px; overflow: hidden">
<div class="mycol" style="width:100%; height:100%; padding: 10px; overflow: hidden">
<div class="myrow" style="height: 40px">
<button id="solarBtn" class="btn btn-success btn-lg" style="width: 200px"
onclick="initSubPage('solar')">光伏设备运行分析</button>
@@ -22,97 +22,75 @@
</div> -->
<div id="solar" class="mypanelstat" style="height: 100%; display: block;">
<!-- <mycolumn style="width:100%; height: 100%;"> -->
<myrow style="height: 50%; ">
<!-- <div class="mycol" style="width:100%; height: 100%;"> -->
<div class="myrow" style="height: 50%; ">
<div class="mypanel" style="width: 50%; height: calc(100% - 20px); margin: 10px; ">
<div class="mypanel-icon"></div>
<div class="mypanel-title">电量与收益分析</div>
<!-- <div class="mypanel-line"></div> -->
<div class="mypanel-title myline-l">电量与收益分析</div>
<div id="solarEchart1" style="width: 100%; height:calc(100% - 30px)"></div>
</div>
<div class="mypanel" style="width: 50%; height: calc(100% - 20px); margin: 10px; ">
<div class="mypanel-icon"></div>
<div class="mypanel-title">运行状态分析</div>
<!-- <div class="mypanel-line"></div> -->
<div class="mypanel-title myline-l">运行状态分析</div>
<div id="solarEchart2" style="width: 100%; height:calc(100% - 30px)"></div>
</div>
</myrow>
<myrow style="height: 50%; ">
</div>
<div class="myrow" style="height: 50%; ">
<div class="mypanel" style="width: 50%; height: calc(100% - 20px); margin: 10px; ">
<div class="mypanel-icon"></div>
<div class="mypanel-title">日电压/电流分析</div>
<!-- <div class="mypanel-line"></div> -->
<div class="mypanel-title myline-l">日电压/电流分析</div>
<div id="solarEchart3" style="width: 100%; height:calc(100% - 30px)"></div>
</div>
<div class="mypanel" style="width: 50%; height: calc(100% - 20px); margin: 10px; ">
<div class="mypanel-icon"></div>
<div class="mypanel-title">日功率分析</div>
<!-- <div class="mypanel-line"></div> -->
<div class="mypanel-title myline-l">日功率分析</div>
<div id="solarEchart4" style="width: 100%; height:calc(100% - 30px)"></div>
</div>
</myrow>
</div>
</div>
<div id="storage" class="mypanelstat" style="height: 100%; display: none;">
<myrow style="height: 50%; ">
<div class="myrow" style="height: 50%; ">
<div class="mypanel" style="width: 50%; height: calc(100% - 20px); margin: 10px; ">
<div class="mypanel-icon"></div>
<div class="mypanel-title">储能放电分析</div>
<!-- <div class="mypanel-line"></div> -->
<div class="mypanel-title myline-l">储能放电分析</div>
<div id="storageEchart1" style="width: 100%; height:calc(100% - 30px)"></div>
</div>
<div class="mypanel" style="width: 50%; height: calc(100% - 20px); margin: 10px; ">
<div class="mypanel-icon"></div>
<div class="mypanel-title">运行状态分析</div>
<!-- <div class="mypanel-line"></div> -->
<div class="mypanel-title myline-l">运行状态分析</div>
<div id="storageEchart2" style="width: 100%; height:calc(100% - 30px)"></div>
</div>
</myrow>
<myrow style="height: 50%; ">
</div>
<div class="myrow" style="height: 50%; ">
<div class="mypanel" style="width: 50%; height: calc(100% - 20px); margin: 10px; ">
<div class="mypanel-icon"></div>
<div class="mypanel-title">日电压电流分析</div>
<!-- <div class="mypanel-line"></div> -->
<div class="mypanel-title myline-l">日电压电流分析</div>
<div id="storageEchart3" style="width: 100%; height:calc(100% - 30px)"></div>
</div>
<div class="mypanel" style="width: 50%; height: calc(100% - 20px); margin: 10px; ">
<div class="mypanel-icon"></div>
<div class="mypanel-title">日功率分析</div>
<!-- <div class="mypanel-line"></div> -->
<div class="mypanel-title myline-l">日功率分析</div>
<div id="storageEchart4" style="width: 100%; height:calc(100% - 30px)"></div>
</div>
</myrow>
</div>
</div>
<div id="charge" class="mypanelstat" style="height: 100%; display: none;">
<myrow style="height: 50%; ">
<div class="myrow" style="height: 50%; ">
<div class="mypanel" style="width: 50%; height: calc(100% - 20px); margin: 10px; ">
<div class="mypanel-icon"></div>
<div class="mypanel-title">充电与收益分析</div>
<!-- <div class="mypanel-line"></div> -->
<div class="mypanel-title myline-l">充电与收益分析</div>
<div id="chargeEchart1" style="width: 100%; height:calc(100% - 30px)"></div>
</div>
<div class="mypanel" style="width: 50%; height: calc(100% - 20px); margin: 10px; ">
<div class="mypanel-icon"></div>
<div class="mypanel-title">运行状态分析</div>
<!-- <div class="mypanel-line"></div> -->
<div class="mypanel-title myline-l">运行状态分析</div>
<div id="chargeEchart2" style="width: 100%; height:calc(100% - 30px)"></div>
</div>
</myrow>
<myrow style="height: 50%; ">
</div>
<div class="myrow" style="height: 50%; ">
<div class="mypanel" style="width: 50%; height: calc(100% - 20px); margin: 10px; ">
<div class="mypanel-icon"></div>
<div class="mypanel-title">日电压电流分析</div>
<!-- <div class="mypanel-line"></div> -->
<div class="mypanel-title myline-l">日电压电流分析</div>
<div id="chargeEchart3" style="width: 100%; height:calc(100% - 30px)"></div>
</div>
<div class="mypanel" style="width: 50%; height: calc(100% - 20px); margin: 10px; ">
<div class="mypanel-icon"></div>
<div class="mypanel-title">日功率分析</div>
<!-- <div class="mypanel-line"></div> -->
<div class="mypanel-title myline-l">日功率分析</div>
<div id="chargeEchart4" style="width: 100%; height:calc(100% - 30px)"></div>
</div>
</myrow>
</div>
</div>
</div>

View File

@@ -39,8 +39,11 @@ function getRandomCurveData(m, n) {
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) }
// 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
}
@@ -56,7 +59,7 @@ function getCurveData(a, b, n) {
}
function RAND(a, b) {
return (Math.random() * (b - a) + a).toFixed(2)
return a + Math.random() * (b - a)
}
// 点击子页面菜单按钮,切换子页面
@@ -89,7 +92,7 @@ function initSubPage(id) {
} else if (item.type == 'line') {
item.echart = initEchartCurve(item.id, item.series)
for (var i = 0; i < item.series.length; ++i) {
updateEchartCurve(item.echart, i, getRandomCurveData(100 * (i + 1), 200 * (i + 1)))
updateEchartCurve(item.echart, i, G.getRandDataDay(100 * (i + 1), 200 * (i + 1)))
}
}

View File

@@ -1,65 +1,157 @@
<div class="mypanelstat" style="height: calc(100% - 20px); margin: 10px">
<myrow style="height: 100%">
<div class="mycolumn" style="width: 18%; height: 100%; padding-top: 10px; ">
<div id="solarCardBtn" class="mycardbtn" style="height: 15%;" onclick="clickCardBtn(this, 'solar')">
<div class="mypanelstat" style="width:100%; height: calc(100% - 20px); margin: 10px">
<div class="myrow" style="height: 100%">
<div class="mycol" style="width: 300px; height: 100%; padding-top: 10px; ">
<div id="solarCardBtn" class="mycardbtn" style="height: 15%;" onclick="onClickCardBtn(this, 'solar')">
<div class="mypanel-title">光伏系统</div>
<mycolumn style="margin-top: 20px; height:60%">
<div>光伏板数量: 100 个</div>
<myrow style="font-size: 14px; margin-top: 10px;">
<div>空闲: 0 个</div>
<div style="margin-left: 30px;">离线: 0 个</div>
<div style="margin-left: 30px;">故障: 0 个</div>
</myrow>
</mycolumn>
<div class="mycol" style="margin-top: 20px; height:60%">
<div id="solarDeviceNum">光伏板数量: 100 个</div>
<div class="myrow" style="font-size: 14px; margin-top: 10px;">
<div id="solarIdleNum">空闲: 0 个</div>
<div id="solarOfflineNum" style="margin-left: 30px;">离线: 0 个</div>
<div id="solarFaultNum" style="margin-left: 30px;">故障: 0 个</div>
</div>
</div>
</div>
<div class="mycardbtn" style="height: 15%;" onclick="clickCardBtn(this, 'storage')">
<div class="mycardbtn" style="height: 15%;" onclick="onClickCardBtn(this, 'storage')">
<div class="mypanel-title">储能系统</div>
<mycolumn style="margin-top: 20px; height:60%">
<div>储能电池数量: 10 个</div>
<myrow style="font-size: 14px; margin-top: 10px;">
<div>空闲: 0 个</div>
<div style="margin-left: 30px;">离线: 0 个</div>
<div style="margin-left: 30px;">故障: 0 个</div>
</myrow>
</mycolumn>
<div class="mycol" style="margin-top: 20px; height:60%">
<div id="storageDeviceNum">储能电池数量: 0 个</div>
<div class="myrow" style="font-size: 14px; margin-top: 10px;">
<div id="storageIdleNum">空闲: 0 个</div>
<div id="storageOfflineNum" style="margin-left: 30px;">离线: 0 个</div>
<div id="storageFaultNum" style="margin-left: 30px;">故障: 0 个</div>
</div>
</div>
</div>
<div class="mycardbtn" style="height: 15%;" onclick="clickCardBtn(this, 'charge')">
<div class="mycardbtn" style="height: 15%;" onclick="onClickCardBtn(this, 'charge')">
<div class="mypanel-title">充电系统</div>
<mycolumn style="margin-top: 20px; height:60%">
<div>充电桩数量: 50 个</div>
<myrow style="font-size: 14px; margin-top: 10px;">
<div>空闲: 0 个</div>
<div style="margin-left: 30px;">离线: 0 个</div>
<div style="margin-left: 30px;">故障: 0 个</div>
</myrow>
</mycolumn>
<div class="mycol" style="margin-top: 20px; height:60%">
<div id="chargeDeviceNum">充电桩数量: 0 个</div>
<div class="myrow" style="font-size: 14px; margin-top: 10px;">
<div id="chargeIdleNum">空闲: 0 个</div>
<div id="chargeOfflineNum" style="margin-left: 30px;">离线: 0 个</div>
<div id="chargeFaultNum" style="margin-left: 30px;">故障: 0 个</div>
</div>
</div>
</div>
<div class="mycardbtn" style="height: 15%;" onclick="clickCardBtn(this, 'load')">
<div class="mycardbtn" style="height: 15%;" onclick="onClickCardBtn(this, 'load')">
<div class="mypanel-title">负荷系统</div>
<mycolumn style="margin-top: 20px; height:60%">
<div>照明设备数量: 100 个</div>
<myrow style="font-size: 14px; margin-top: 10px;">
<div>空闲: 0 个</div>
<div style="margin-left: 30px;">离线: 0 个</div>
<div style="margin-left: 30px;">故障: 0 个</div>
</myrow>
</mycolumn>
<div class="mycol" style="margin-top: 20px; height:60%">
<div id="loadDeviceNum">照明设备数量: 0 个</div>
<div class="myrow" style="font-size: 14px; margin-top: 10px;">
<div id="loadIdleNum">空闲: 0 个</div>
<div id="loadOfflineNum" style="margin-left: 30px;">离线: 0 个</div>
<div id="loadFaultNum" style="margin-left: 30px;">故障: 0 个</div>
</div>
</div>
</div>
<div class="mycardbtn" style="height: 15%;" onclick="clickCardBtn(this, 'security')">
<div class="mycardbtn" style="height: 15%;" onclick="onClickCardBtn(this, 'security')">
<div class="mypanel-title">安防系统</div>
<mycolumn style="margin-top: 20px; height:60%">
<div>摄像头数量: 50 个</div>
<myrow style="font-size: 14px; margin-top: 10px;">
<div class="mycol" style="margin-top: 20px; height:60%">
<div id="securityDeviceNum">摄像头数量: 0 个</div>
<div class="myrow" style="font-size: 14px; margin-top: 10px;">
<div>空闲: 0 个</div>
<div style="margin-left: 30px;">离线: 0 个</div>
<div style="margin-left: 30px;">故障: 0 个</div>
</myrow>
</mycolumn>
</div>
</div>
</div>
</div>
<div style="width: 82%; height: 100%; overflow: auto">
<div id="deviceList" class="myrow" style="width: 100%; height: 100%; flex-wrap: wrap;"> </div>
<div class="myrow" style="width: calc(100% - 300px); height: 100%; ">
<div id="deviceList" class="myrow" style="width: 100%; height: 100%; flex-wrap: wrap; overflow-y: auto;">
<!-- <div class="mycard">
<div class='btn-group' style="width: 80px; position: absolute; left: 100px; top: 30px;">
<input id="_off" type="checkbox" class="btn-check" //
onclick="G.switchSetStatus('_on', '_off', !this.checked)" checked />
<label class="btn btn-outline-danger" for="_off" style="padding: 0;">关</label>
<input id="_on" type="checkbox" class="btn-check" //
onclick="G.switchSetStatus('_on', '_off', this.checked)" />
<label class="btn btn-outline-success" for="_on" style="padding: 0;">开</label>
</div>
</div> -->
</div>
<div id="envpanel" style="width: 300px; height: 100%; display: block">
<div class="mycol" style="width: 250px; height: 100%; padding: 12px;">
<div style="font-size: 16px; font-weight: 600;">环境温湿度信息</div>
<div class="mypanel-line"></div>
<div style="margin-top: 12px;">
<div class="myrow"
style="font-size: 14px; font-weight: 600; justify-content: space-between; border: solid #00fffb; border-radius: 8px 8px 0 0; border-width: 1px 1px 0 1px; background-color: #115d73; height: 40px;line-height: 40px;">
<div style="width: 33%; text-align: center;">点位</div>
<div style="width: 33%; text-align: center;">温度</div>
<div style="width: 33%; text-align: center;">湿度</div>
</div>
<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>
</div>
<div style="font-size: 16px; font-weight: 600; margin-top: 30px;">消防信息</div>
<div class="mypanel-line"></div>
<div style="margin-top: 12px; border: 1px solid #00fffb; border-radius: 8px; ">
<div class="myrow"
style="font-size: 14px; font-weight: 600; justify-content: space-between; border-radius: 8px 8px 0 0; background-color: #115d73; height: 40px;line-height: 40px;">
<div style="width: 50%; text-align: center;">点位</div>
<div style="width: 50%; text-align: center;">烟感状态</div>
</div>
<div class="myrow"
style="font-size: 14px; font-weight: 600; justify-content: space-between; height: 40px; line-height: 40px;">
<div style="width: 50%; text-align: center;">#1</div>
<div style="width: 50%; text-align: center;">正常</div>
</div>
<div class="myrow"
style="font-size: 14px; font-weight: 600; justify-content: space-between; height: 40px; line-height: 40px;">
<div style="width: 50%; text-align: center;">#1</div>
<div style="width: 50%; text-align: center;">正常</div>
</div>
<div class="myrow"
style="font-size: 14px; font-weight: 600; justify-content: space-between; height: 40px; line-height: 40px;">
<div style="width: 50%; text-align: center;">#1</div>
<div style="width: 50%; text-align: center;">正常</div>
</div>
<div class="myrow"
style="font-size: 14px; font-weight: 600; justify-content: space-between; height: 40px; line-height: 40px;">
<div style="width: 50%; text-align: center;">#1</div>
<div style="width: 50%; text-align: center;">正常</div>
</div>
<div class="myrow"
style="font-size: 14px; font-weight: 600; justify-content: space-between; height: 40px; line-height: 40px;">
<div style="width: 50%; text-align: center;">#1</div>
<div style="width: 50%; text-align: center;">正常</div>
</div>
<div class="myrow"
style="font-size: 14px; font-weight: 600; justify-content: space-between; height: 40px; line-height: 40px;">
<div style="width: 50%; text-align: center;">#1</div>
<div style="width: 50%; text-align: center;">正常</div>
</div>
<div class="myrow"
style="font-size: 14px; font-weight: 600; justify-content: space-between; height: 40px; line-height: 40px;">
<div style="width: 50%; text-align: center;">#1</div>
<div style="width: 50%; text-align: center;">正常</div>
</div>
</div>
</div>
</div>
</div>
</myrow>
<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; ">
<div class="myline-b" style="color:white;">控制功能</div>
<div style="display: flex; justify-content: center; width: 100%; margin-top: 100px;">
<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;"
onclick="G.showElement('deviceSettingPop', false)">取消</button>
</div>
</div>
</div>
</div>
</div>

View File

@@ -1,64 +1,244 @@
var mapDeviceTypeDef = new Map([
['1', '变压器'],
['2', '配电柜'],
['3', '电表'],
['4', '门禁'],
['5', '空调'],
['6', '照明'],
['7', '消防'],
['8', '光照监测设备'],
['9', '风速监测设备'],
['10', '温湿度监测设备'],
['11', '烟感监测设备'],
['12', '水浸传感器'],
['13', '视频监控'],
['101', '逆变器'],
['102', '汇流箱'],
['103', '光伏板'],
['104', '风力发电机'],
['105', '储能变流器'],
['106', '储能电池'],
['107', 'BMS'],
['108', '充电桩'],
['109', '充电枪'],
['110', '集中器'],
])
function getDeviceTypeId(name) {
var res = ''
mapDeviceTypeDef.forEach((v, k) => { if (v == name) { res = k } })
return res;
}
function getDeviceTypeName(id) {
var res = ''
mapDeviceTypeDef.forEach((v, k) => { if (k == id) { res = v } })
return res;
}
function addCard(deviceId, type, name, code) {
var a = '<div class="myrow">' +
'< div style = "width: 100px;height: 70px; background-color: #2991b6;border-radius: 10px;" > </div>' +
'< div class="mycolumn" style = "margin-left: 10px;" > ' +
'<div>3201001234567890</div>' +
'<div>逆变器1 </div>' +
'<div style="color: #08afff; font-size:14px; font-weight: bold;">逆变器 </div>' +
'</div >' +
'</div >'
var elementDeviceList = document.getElementById('deviceList')
// <div class="mycard" ></div>
function addDeviceCardPanel(root, deviceid, name, type, subList) {
var card = document.createElement('div')
card.className = 'mycard'
card.innerHTML = '<div class="myrow" style="margin-bottom: 20px">' +
'<div style="width: 100px;height: 70px; background-color: #2991b6;border-radius: 10px;"></div>' +
'<div class="mycolumn" style="margin-left: 10px;">' +
'<div>' + code + '</div><div>' + name + '</div>' +
'<div style="color: #08afff; font-size:14px; font-weight: bold;">' + type + '</div>' +
'</div></div>'
card.setAttribute('id', deviceid) // 设置id
if (type == "充电桩") { card.style.width = '320px' }
card.innerHTML =
`<div class="myrow" style="margin-bottom: 20px">
<div style="width:64px; height:64px; background-color: #2991b6;border-radius: 10px;"></div>
<div class="mycol" style="margin-left: 10px; font-size:15px;">
<div> ${deviceid} </div>
<div style="font-size:15px;"> ${name} </div>
<div style="color: #08afff; font-size:14px; font-weight: bold;"> ${type} </div>
</div>
</div>`
var params = {
工作状态: '运行',
在线状态: '运行',
故障状态: '运行',
额定功率: '20 kW',
电压: '220 V',
电流: '30 A',
功率: '11 kW',
// 充电桩区分1号枪和2号枪
if (subList && subList.length > 1) {
card.innerHTML +=
`<div class="myrow">
<div id="${deviceid}_${subList[0]}" style="width: calc(50% - 10px); border: solid gray; border-width: 0 1px 0 0;">
<div class="myrow" style="font-size:14px; margin-left: 10px;">
<div style="background-color:#00dbd7; width: 5px; height:18px; "></div>
<div style="margin-left: 10px;">#${subList[0]}</div>
</div>
</div>
<div id="${deviceid}_${subList[1]}" style="width: calc(50% - 10px); margin-left: 10px;">
<div class="myrow" style="font-size:14px; margin-left: 10px;">
<div style="background-color:#00dbd7; width: 5px; height:18px; "></div>
<div style="margin-left: 10px;">#${subList[1]}</div>
</div>
</div>
</div>`
}
Object.keys(params).forEach((k) => {
var id = deviceId + '_' + k
card.innerHTML += ('<div class="mycard-param">' +
'<div class="mycard-param-title">' + k + '</div>' + '<div id="' + id + '" class="mycard-param-text">' + params[k] + '</div>' +
'</div>')
});
elementDeviceList.appendChild(card)
root.appendChild(card)
return card
}
function updateParam(deviceId, k, v) {
var id = deviceId + '_' + k
document.getElementById(id).innerHTML = v
/// ===========================================================
// 创建设备卡片的参数信息
// @param deviceid: 设备 ID
// @param subid: 参数子分类 ID如充电桩的充电枪的编号1号枪2号枪
// @param key: 参数名称
// @param key: 参数值
// 说明: 每个参数值的 element 的 id 设置为:{deviceid}_{subid}_{key}
function addDeviceCardParam(deviceid, subid, key, text) {
var elemtid = deviceid + (subid ? ("_" + subid) : "") + "_" + key
param = document.createElement('div')
param.className = 'mycard-param'
param.innerHTML = `<div class="mycard-param-key">${key}: </div>
<div id="${elemtid}" class="mycard-param-text">${text}</div>`
if (subid) {
$('#' + deviceid + '_' + subid).append(param)
} else {
$('#' + deviceid).append(param)
}
if (text == '离线' | text == '故障') {
$("#" + elemtid).css("color", "red")
}
}
/// ===========================================================
// 设置设备卡片的参数值
// @param deviceid: 设备ID
// @param subid: 参数子分类ID如充电桩的充电枪的编号1号枪2号枪
// @param key: 参数名称
// @param key: 参数值
// 说明: 每个参数值的 element 的 id 设置为:{deviceid}_{subid}_{key}
function setDeviceCardParam(deviceid, subid, key, text) {
var elemtid = deviceid + (subid ? ("_" + subid) : "") + "_" + key
$("#" + elemtid).text(text);
// 特殊状态设置颜色区分显示
if (text == '离线' | text == '故障') {
$("#" + elemtid).css("color", "red")
}
}
var activeCardBtn = null
function clickCardBtn(btn, id) {
function onClickCardBtn(btn, id) {
if (activeCardBtn) activeCardBtn.className = 'mycardbtn'
activeCardBtn = btn
activeCardBtn.className = 'mycardbtn-active'
var deviceType = id
initDeviceList(deviceType)
}
function initDeviceList() {
function creatElementSwitch(id, x, y) {
var eswitch = document.createElement('div')
eswitch.className = 'btn-group'
eswitch.setAttribute('style', `margin-left: 5px; width: 60px; height: 26px; position:absolute; left: ${x}px; top: ${y}px`);
eswitch.innerHTML = `
<input id="${id}_off" type="checkbox" class="btn-check"
onclick="G.switchSetStatus('${id}_on', '${id}_off', !this.checked)" checked />
<label class="btn btn-outline-danger" for="${id}_off" style="padding: 0;">关</label>
<input id="${id}_on" type="checkbox" class="btn-check"
onclick="G.switchSetStatus('${id}_on', '${id}_off', this.checked)" />
<label class="btn btn-outline-success" for="${id}_on" style="padding: 0;">开</label>`
return eswitch;
}
function creatElementCard() {
var card = document.createElement('div')
card.className = 'mycard'
return card;
}
function createCardVideo(name) {
var elemt = document.createElement('div')
elemt.className = 'mycard'
elemt.style.width = '320px'
elemt.innerHTML = `
<div>${name}</div>
<div style='width=90%; height:84%; margin-top:10px; border: 5px solid black;'>
<div style='width:100%; height:100%; line-height:200px; text-align: center; background-color: gray'> 无信号</div>
</div>`
return elemt;
}
function initDeviceList(deviceType) {
var elemtDeviceList = document.getElementById('deviceList')
elemtDeviceList.innerHTML = ''
var subList = [null]
if (deviceType === 'security') {
document.getElementById('envpanel').style.display = 'block'
elemtDeviceList.appendChild(createCardVideo('监控点1'))
elemtDeviceList.appendChild(createCardVideo('监控点2'))
elemtDeviceList.appendChild(createCardVideo('监控点3'))
elemtDeviceList.appendChild(createCardVideo('监控点4'))
elemtDeviceList.appendChild(createCardVideo('监控点5'))
elemtDeviceList.appendChild(createCardVideo('监控点6'))
elemtDeviceList.appendChild(createCardVideo('监控点7'))
elemtDeviceList.appendChild(createCardVideo('监控点8'))
elemtDeviceList.appendChild(createCardVideo('监控点9'))
elemtDeviceList.appendChild(createCardVideo('监控点1'))
elemtDeviceList.appendChild(createCardVideo('监控点2'))
elemtDeviceList.appendChild(createCardVideo('监控点3'))
elemtDeviceList.appendChild(createCardVideo('监控点4'))
elemtDeviceList.appendChild(createCardVideo('监控点5'))
elemtDeviceList.appendChild(createCardVideo('监控点6'))
elemtDeviceList.appendChild(createCardVideo('监控点7'))
elemtDeviceList.appendChild(createCardVideo('监控点8'))
elemtDeviceList.appendChild(createCardVideo('监控点9'))
return
}
var reqDeviceType = ['101', '102', '103']
if (deviceType === 'storage') {
reqDeviceType = ['101', '102', '106']
}
else if (deviceType === 'charge') {
subList = ['1', '2']
reqDeviceType = ['108']
}
else {
document.getElementById('envpanel').style.display = 'none'
}
// 查询数据库,获取设备信息
//G.cppNative.queryDevice({ type: reqDeviceType }).then((res) => {
G.cppNative.getDeviceInfo(reqDeviceType).then((res) => {
res.forEach(function (item, index) {
var deviceType = getDeviceTypeName(item.type)
addDeviceCardPanel(elemtDeviceList, item.device_id, item.name, deviceType, subList)
var params = {
在线状态: (item.online == 0) ? '离线' : '在线',
工作状态: (item.status == 0) ? '空闲' : '运行',
故障状态: (item.err == 0) ? '正常' : '故障',
额定功率: '-- kW',
电压: '-- V',
电流: '-- A',
功率: '-- kW',
}
if (subList) {
subList.forEach((subid) => {
Object.keys(params).forEach((k) => {
addDeviceCardParam(item.device_id, subid, k, params[k]);
});
})
}
var elemtPanel = document.getElementById(item.device_id)
elemtPanel.innerHTML += `<button
class="btn btn-outline-primary btn-sm"
style="height:30px; margin: 5px 0 0 10px"
onclick="onDeviceSetting(${item.device_id})">
参数设置
</button>`
})
})
}
function onDeviceSetting(deviceid) {
G.showElement('deviceSettingPop', true)
}
// ====================================================================================================
// 【注意】 DOM 元素的移除不会自动清理 JavaScript 运行时创建的资源(如定时器、事件监听器等),这些都需要手动管理
// 开启定时器更新页面数据
var timerId = null
@@ -69,27 +249,43 @@ document.currentScript.addEventListener('DOMNodeRemoved', () => {
clearInterval(timerId);
});
$(document).ready(function () {
addCard('1', '逆变器', '逆变器1', '1111')
addCard('2', '汇流箱', '汇流箱', '2222')
addCard('3', '光伏板', '光伏板1', '3333')
addCard('4', '光伏板', '光伏板2', '4444')
addCard('5', '光伏板', '光伏板3', '5555')
addCard('5', '光伏板', '光伏板3', '5555')
addCard('5', '光伏板', '光伏板3', '5555')
addCard('5', '光伏板', '光伏板3', '5555')
addCard('5', '光伏板', '光伏板3', '5555')
addCard('5', '光伏板', '光伏板3', '5555')
addCard('5', '光伏板', '光伏板3', '5555')
addCard('5', '光伏板', '光伏板3', '5555')
addCard('5', '光伏板', '光伏板3', '5555')
addCard('5', '光伏板', '光伏板3', '5555')
addCard('5', '光伏板', '光伏板3', '5555')
addCard('5', '光伏板', '光伏板3', '5555')
onClickCardBtn(document.getElementById('solarCardBtn'), 'solar')
// timerId = setInterval(() => {
// updateParam('1', '电压', Math.floor(Math.random() * 220) + ' V')
// }, 2000);
clickCardBtn(document.getElementById('solarCardBtn'), 'solar')
G.cppNative.getDeviceInfo([0]).then((res) => {
var nums = {
'103': { num: 0, numIdle: 0, numOffline: 0, numFault: 0 },
'106': { num: 0, numIdle: 0, numOffline: 0, numFault: 0 },
'108': { num: 0, numIdle: 0, numOffline: 0, numFault: 0 },
}
res.forEach(function (item, index) {
var deviceType = item.type + ''
if (nums[deviceType]) {
nums[deviceType].num += 1
if (item.status == 0) nums[deviceType].numIdle += 1
if (item.online == 0) nums[deviceType].numOffline += 1
if (item.err != 0) nums[deviceType].numFault += 1
}
})
$('#solarDeviceNum').text('光伏板数量: ' + nums['103'].num + ' 个')
$('#solarIdleNum').text('空闲: ' + nums['103'].numIdle + ' 个')
$('#solarOfflineNum').text('离线: ' + nums['103'].numOffline + ' 个')
$('#solarFaultNum').text('故障: ' + nums['103'].numFault + ' 个')
$('#storageDeviceNum').text('储能电池数量: ' + nums['106'].num + ' 个')
$('#storageIdleNum').text('空闲: ' + nums['106'].numIdle + ' 个')
$('#storageOfflineNum').text('离线: ' + nums['106'].numOffline + ' 个')
$('#storageFaultNum').text('故障: ' + nums['106'].numFault + ' 个')
$('#chargeDeviceNum').text('充电桩数量: ' + nums['108'].num + ' 个')
$('#chargeIdleNum').text('空闲: ' + nums['108'].numIdle + ' 个')
$('#chargeOfflineNum').text('离线: ' + nums['108'].numOffline + ' 个')
$('#chargeFaultNum').text('故障: ' + nums['108'].numFault + ' 个')
})
timerId = setInterval(() => {
updateParam('1', '电压', Math.floor(Math.random() * 220) + ' V')
}, 2000);
})

View File

@@ -0,0 +1,30 @@
<div class="mycol" style="width:100%; height:100%; padding: 10px; overflow: hidden">
<div class="myrow" style="height: 50%; ">
<div class="mypanel" style="width: 100%; height: calc(100% - 20px); margin: 10px; position:relative">
<div class="myrow">
<div class="mypanel-title myline-l">光伏发电预测</div>
<div style="margin: 0px 0 0 50px; font-size: 12px; font-weight:bold; color:#a6a6a6; ">
当天累计发电量 <span style="font-size: 16px; font-weight:bold; color:white"> 1520 kW/h</span>
</div>
</div>
<div id="solarEchart" style="width: 100%; height:calc(100% - 30px); "></div>
</div>
</div>
<div class="myrow" style="height: 50%; ">
<div class="mypanel" style="width: 50%; height: calc(100% - 20px); margin: 10px; ">
<div class="mypanel-title myline-l">充电负荷预测</div>
<!-- <div class="mypanel-line"></div> -->
<div id="chargeEchart" style="width: 100%; height:calc(100% - 30px)"></div>
</div>
<div class="mypanel" style="width: 50%; height: calc(100% - 20px); margin: 10px; ">
<div class="mypanel-title myline-l">用电负荷预测</div>
<!-- <div class="mypanel-line"></div> -->
<div id="loadEchart" style="width: 100%; height:calc(100% - 30px)"></div>
</div>
</div>
<table id="myTable" class="stripe" style="width: 100%; margin-top: 10px"></table>
</div>

View File

@@ -0,0 +1,45 @@
var chartDef = [
{ id: 'solarEchart', echart: null, type: 'bar', series: ['预测功率', '实时功率', '预测发电量', '实时发电量'] },
{ id: 'chargeEchart', echart: null, type: 'bar', series: ['预测功率', '实时功率'] },
{ 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 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
}
chartDef.forEach((item) => {
item.echart = initEchartCurve(item.id, item.series)
updateEchartCurve(item.echart, 1, getRandomData1(100, 200))
for (var i = 0; i < item.series.length; ++i) {
updateEchartCurve(item.echart, i, getRandomData1(300 * (i + 1), 400 * (i + 1)))
}
})

Binary file not shown.

After

Width:  |  Height:  |  Size: 879 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 726 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 749 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 679 B

View File

@@ -0,0 +1,128 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>光储充站控系统</title>
<script src="./libs/jquery/jquery-3.7.1.min.js"></script>
<link rel="stylesheet" href="./libs/DataTables-2.1.8/css/dataTables.dataTables.css" />
<script src="./libs/DataTables-2.1.8/js/dataTables.js"></script>
<style>
body {
/* background-color: #012036; */
/* background-image: url('../ui/bkg01.png'); */
background-size: 100% 100%;
background-attachment: fixed;
}
button {
color: #f0f0f0;
background-color: #44aaec;
border: 1px solid #0a87da;
border-radius: 5px;
margin: 5px;
height: 40px;
font-size: 16px;
}
</style>
</head>
<body>
<table id="myTable" class="cell-border compact hover order-column stripe">
<thead>
<tr></tr>
</thead>
<tbody></tbody>
</table>
</body>
<script>
const dataTablesOption = {
data: [],
columns: [],
bSort: false,
aLengthMenu: [10, 20, 50, 100], //设置每页显示数据条数的下拉选项
displayLength: 20, //每页初始显示最大记录数量
// 设置表格t、分页数据条数l、搜索框f、表格信息i、分页p、加载信息r
//dom: '<"table-ext"<"item"f><"item"l><"item"i><"item"p>>rt',
language: {
sLengthMenu: '每页显示 _MENU_ 条记录',
sZeroRecords: '对不起,查询不到任何相关数据',
sInfo: '当前显示 _START_ 到 _END_ 条,共 _TOTAL_ 条记录',
sInfoEmtpy: '找不到相关数据',
sInfoFiltered: '数据表中共为 _MAX_ 条记录)',
sProcessing: '正在加载中...',
sSearch: '结果中搜索',
paginate: { sPrevious: ' 上一页 ', sNext: ' 下一页 ', },
},
}
$(document).ready(function () {
dataTablesOption.columns = [
{ title: '编号1', width: '50px' },
{ title: '产品名称', width: '150px' },
{ title: '规格型号', width: '150px' },
{ title: '类别', width: '150px' },
{ title: '库存量', width: '80px' },
{ title: '采购总量', width: '80px' },
{ title: '入库总量', width: '80px' },
{ title: '销售总量', width: '80px' },
{ title: '出库总量', width: '80px' },
{ title: '异常总量', width: '80px' },
{ title: '异常说明' },
{
title: '操作',
width: '160px',
render: function (data, type, row) {
return (
'<a href="javascript:void(0);" class="table-btn-edit">编辑</a>' +
// '<a href="javascript:void(0);" class="table-btn-del">删除</a>' +
'<a href="javascript:void(0);" class="">采购</a>' +
'<a href="javascript:void(0);" class="">入库</a>' +
'<a href="javascript:void(0);" class="">销售</a>' +
'<a href="javascript:void(0);" class="">出库</a>'
)
},
},
]
var table = $('#myTable').DataTable(dataTablesOption)
table.row.add(['1', '产品名称', '产品型号', '五金类库/五金制品', '', '', '', '', '', '', ''])
table.row.add(['1', '产品名称', '产品型号', '五金类库/五金制品', '', '', '', '', '', '', ''])
table.row.add(['1', '产品名称', '产品型号', '五金类库/五金制品', '', '', '', '', '', '', ''])
table.row.add(['1', '产品名称', '产品型号', '五金类库/五金制品', '', '', '', '', '', '', ''])
table.row.add(['1', '产品名称', '产品型号', '五金类库/五金制品', '', '', '', '', '', '', ''])
table.row.add(['1', '产品名称', '产品型号', '五金类库/五金制品', '', '', '', '', '', '', ''])
table.row.add(['1', '产品名称', '产品型号', '五金类库/五金制品', '', '', '', '', '', '', ''])
table.row.add(['1', '产品名称', '产品型号', '五金类库/五金制品', '', '', '', '', '', '', ''])
table.row.add(['1', '产品名称', '产品型号', '五金类库/五金制品', '', '', '', '', '', '', ''])
table.row.add(['1', '产品名称', '产品型号', '五金类库/五金制品', '', '', '', '', '', '', ''])
table.row.add(['1', '产品名称', '产品型号', '五金类库/五金制品', '', '', '', '', '', '', ''])
table.row.add(['1', '产品名称', '产品型号', '五金类库/五金制品', '', '', '', '', '', '', ''])
table.row.add(['1', '产品名称', '产品型号', '五金类库/五金制品', '', '', '', '', '', '', ''])
table.row.add(['1', '产品名称', '产品型号', '五金类库/五金制品', '', '', '', '', '', '', ''])
table.row.add(['1', '产品名称', '产品型号', '五金类库/五金制品', '', '', '', '', '', '', ''])
table.row.add(['1', '产品名称', '产品型号', '五金类库/五金制品', '', '', '', '', '', '', ''])
table.row.add(['1', '产品名称', '产品型号', '五金类库/五金制品', '', '', '', '', '', '', ''])
table.row.add(['1', '产品名称', '产品型号', '五金类库/五金制品', '', '', '', '', '', '', ''])
table.row.add(['1', '产品名称', '产品型号', '五金类库/五金制品', '', '', '', '', '', '', ''])
table.row.add(['1', '产品名称', '产品型号', '五金类库/五金制品', '', '', '', '', '', '', ''])
table.row.add(['1', '产品名称', '产品型号', '五金类库/五金制品', '', '', '', '', '', '', ''])
table.row.add(['1', '产品名称', '产品型号', '五金类库/五金制品', '', '', '', '', '', '', ''])
table.row.add(['1', '产品名称', '产品型号', '五金类库/五金制品', '', '', '', '', '', '', ''])
table.draw()
})
</script>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

View File

Before

Width:  |  Height:  |  Size: 770 B

After

Width:  |  Height:  |  Size: 770 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 388 B

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,2 @@
cd %~dp0
D:\Programs\Qt5\5.15.2\msvc2019\bin\windeployqt.exe EES.exe