Files
energy_storage/bin/Release/assets/html/main.html

682 lines
20 KiB
HTML
Raw Normal View History

2025-05-19 09:54:33 +08:00
<!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>
<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>
<script src="./libs/echarts/echarts.min.js"></script>
<script src="./js/qwebchannel.js"></script>
<script src="./js/myecharts.js"></script>
<style>
body {
background-image: url('../ui/bkg01.png');
background-size: 100% 100%;
background-attachment: fixed;
}
a {
display: inline-block;
/* 添加间距,使链接之间不会紧贴 */
padding-right: 8px;
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;
}
table thead {
background-color: #125c70;
}
table thead tr {
height: 32px;
/* border: solid 2px red; */
}
table thead 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 */
}
</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>
</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>
</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>
</body>
</html>