New function: data management

This commit is contained in:
Eason010212
2022-07-15 23:36:48 +08:00
parent 5de5fa0da5
commit 33d5482bde
16 changed files with 648 additions and 2 deletions

View File

@@ -74,6 +74,11 @@
<i class="fa fa-fw fa-tachometer"></i>
<span class="lang" key="PROJECTSMANAGE"></span></a>
</li>
<li class="nav-item">
<a class="nav-link" href="mqttdata" id="manage_data">
<i class="fa fa-fw fa-table"></i>
<span class="lang" key="DATAMANAGE"></span></a>
</li>
<li class="nav-item active">
<a class="nav-link" href="webapps" id="share_app">
<i class="fa fa-fw fa-share"></i>

210
src/ejs/data.ejs Normal file
View File

@@ -0,0 +1,210 @@
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<title>MixIO</title>
<link rel="shortcut icon" href="img/shortcut.png"/>
<!-- Custom fonts for this template-->
<link rel="stylesheet" href="css/farbtastic.css">
<link href="css/font-awesome.min.css" rel="stylesheet">
<link href="css/nunito.css" rel="stylesheet">
<!-- Custom styles for this template-->
<link href="css/sb-admin-2.min.css" rel="stylesheet">
<link rel="stylesheet" href="css/muuri.css?v=2">
<link rel="stylesheet" href="css/widgets.css?v=1">
<!-- Bootstrap core JavaScript-->
<script src="js/jquery.min.js"></script>
<script src="js/lang.js"></script>
<script src="js/lang2.js?v=5"></script>
<script src="js/farbtastic.js"></script>
<script src="js/bootstrap.bundle.min.js"></script>
<!-- Core plugin JavaScript-->
<script src="js/jquery.easing.min.js"></script>
<!-- Custom scripts for all pages-->
<script src="js/echarts.min.js"></script>
<script src="js/jquery.easyui.min.js"></script>
<script src="js/mqtt.min.js"></script>
<script src="js/gauge.min.js"></script>
<link rel="stylesheet" href="css/dataTables.bootstrap4.min.css">
<script src="js/jquery.dataTables.min.js"></script>
<script src="js/dataTables.bootstrap4.min.js"></script>
<script src="js/tools.js"></script>
<script src="js/data.js?v=6"></script>
</head>
<body id="page-top" class="sidebar-toggled">
<!-- Page Wrapper -->
<div id="wrapper">
<!-- Sidebar -->
<ul class="navbar-nav bg-gradient-primary sidebar sidebar-dark accordion" id="accordionSidebar">
<!-- Sidebar - Brand -->
<a class="sidebar-brand d-flex align-items-center justify-content-center" href="/">
<div class="sidebar-brand-icon">
<img src="img/logo.png" style="width:35px" alt="">
</div>
<div class="sidebar-brand-text mx-3" >MixIO</div>
</a>
<!-- Divider -->
<hr class="sidebar-divider my-0">
<!-- Nav Item - Dashboard -->
<!-- Divider -->
<hr class="sidebar-divider">
<!-- Heading -->
<div class="sidebar-heading lang" key="MANAGE">
</div>
<li class="nav-item">
<a class="nav-link" href="projects" id="manage_prj">
<i class="fa fa-fw fa-tachometer"></i>
<span class="lang" key="PROJECTSMANAGE"></span></a>
</li>
<li class="nav-item active">
<a class="nav-link" href="mqttdata" id="manage_data">
<i class="fa fa-fw fa-table"></i>
<span class="lang" key="DATAMANAGE"></span></a>
</li>
<li class="nav-item">
<a class="nav-link" href="webapps" id="share_app">
<i class="fa fa-fw fa-share"></i>
<span class="lang" key="SHAREMANAGE"></span></a>
</li>
<hr class="sidebar-divider">
<div class="sidebar-heading lang" key="SETTINGS">
</div>
<li class="nav-item">
<a class="nav-link" href="logout">
<i class="fa fa-fw fa-arrow-circle-left"></i>
<span class="lang" key="LOGOUT"></span></a>
</li>
<!-- Divider -->
<hr class="sidebar-divider d-none d-md-block">
<!-- Sidebar Toggler (Sidebar) -->
<div class="text-center d-none d-md-inline">
<button class="rounded-circle border-0" id="sidebarToggle"></button>
</div>
</ul>
<!-- End of Sidebar -->
<!-- Content Wrapper -->
<div id="content-wrapper" class="d-flex flex-column">
<!-- Main Content -->
<div id="content">
<!-- Topbar -->
<nav class="navbar navbar-expand navbar-light bg-white topbar mb-4 static-top shadow" style="display:flex;justify-content:space-between">
<div style="display:flex;align-items:center;justify-content:center">
<button id="sidebarToggleTop" class="btn btn-link d-md-none rounded-circle mr-3">
<i class="fa fa-bars"></i>
</button>
<h1 class="d-sm-inline-block h3 mb-0 text-gray-800 lang" key="DATAMANAGE" style="margin-left:10px;font-size:1.25rem;display:inline-block;cursor:pointer"></h1>
</div>
</nav>
<div class="container-fluid" id="project_list">
<div class="row" style="display:flex;align-items:center;justify-content:center">
<div class="col-xl-4">
<div class="card shadow mb-4" style="border-radius:0px 0px 30px 30px;min-height:85px;margin-top:-1.5rem;box-shadow: 0 .75rem 1.75rem 0 rgba(58,59,69,.15)!important;border:0">
<div class="card-body" style="padding:0;display:flex;align-items:center;justify-content: center;">
<a id="play" class="btn btn-success" style="margin:5px;font-size:0.8rem;cursor:pointer" onclick = "play()">
<i class="fa fa-play" style="font-size:1.2rem"></i><br>
</a>
<a id="stop" class="btn btn-warning" style="margin:5px;font-size:0.8rem;cursor:pointer" onclick = "stop()">
<i class="fa fa-stop" style="font-size:1.2rem"></i><br>
</a>
<a class="btn btn-info" style="margin:5px;font-size:0.8rem;cursor:pointer" onclick = "refresh()">
<i class="fa fa-refresh" style="font-size:1.2rem"></i><br>
</a>
<a class="btn btn-primary" style="margin:5px;font-size:0.8rem;cursor:pointer" onclick = "output()">
<i class="fa fa-upload" style="font-size:1.2rem"></i><br>
</a>
<a class="btn btn-danger" style="margin:5px;font-size:0.8rem;cursor:pointer" onclick = "clearAll()">
<i class="fa fa-trash" style="font-size:1.2rem"></i><br>
</a>
</div>
<div class="card-body" style="padding-bottom:0;padding-top:0">
<div class="">
<h4 class="small font-weight-bold"><span class="lang" key="OFFLINECOUNT"></span><span class="float-right" id="prj_num"></span></h4>
<div class="progress mb-4" style="margin-bottom:1rem!important">
<div class="progress-bar bg-info" role="progressbar" id="prj_num_bar" style="width: 20%" aria-valuenow="0" aria-valuemin="0" aria-valuemax="1000"></div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row" >
<div class="col-xl-6">
<div class="card shadow mb-4" style="border-radius:10px;min-height:660px">
<div class="card-body" style="overflow:auto;">
<table id="apps_table" class="table table-striped table-bordered" style="width:100%">
<thead>
<tr>
<th class="lang" key="TOPIC"></th>
<th class="lang" key="MESSAGE"></th>
<th class="lang" key="TIME"></th>
</tr>
</thead>
<tbody id="mqttdata">
</tbody>
</table>
</div>
</div>
</div>
<div class="col-xl-6">
<div class="card shadow mb-4" style="border-radius:10px">
<div class="card-body" style="overflow:auto;height:660px">
<div id="chart" style="width:100%;height:100%">
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<footer class="sticky-footer bg-white">
<div class="container my-auto">
<div class="copyright text-center my-auto">
<span>Copyright &copy; mixio.mixly.org 2021</span>
</div>
</div>
</footer>
</div>
<!-- End of Page Wrapper -->
<!-- Page level custom scripts -->
<script src="js/sb-admin-2.min.js?v=2"></script>
</body>
</html>

View File

@@ -70,6 +70,11 @@
<i class="fa fa-fw fa-tachometer"></i>
<span class="lang" key="PROJECTSMANAGE"></span></a>
</li>
<li class="nav-item">
<a class="nav-link" href="mqttdata" id="manage_data">
<i class="fa fa-fw fa-table"></i>
<span class="lang" key="DATAMANAGE"></span></a>
</li>
<li class="nav-item">
<a class="nav-link" href="webapps" id="share_app">
<i class="fa fa-fw fa-share"></i>
@@ -148,7 +153,7 @@
<div class="col-xl-12 col-md-12">
<h4 class="small font-weight-bold"><span class="lang" key="MANAGECOUNT"></span><span class="float-right" id="prj_num"></span></h4>
<div class="progress mb-4">
<div class="progress-bar bg-warning" role="progressbar" id="prj_num_bar" style="width: 20%" aria-valuenow="0" aria-valuemin="0" aria-valuemax="20"></div>
<div class="progress-bar bg-info" role="progressbar" id="prj_num_bar" style="width: 20%" aria-valuenow="0" aria-valuemin="0" aria-valuemax="20"></div>
</div>
</div>
</div>

225
src/js/data.js Normal file
View File

@@ -0,0 +1,225 @@
function get_data(){
$.get('queryHook',function(res){
if(res == 1)
{
$("#play").addClass("disabled")
}
else{
$("#stop").addClass("disabled")
}
$.getJSON('getData',{
},function(res){
$("#prj_num").html(res['count']+" / "+1000)
$("#prj_num_bar").attr("aria-valuenow",res['count'])
$("#prj_num_bar").css("width",(res['count']*100/1000)+"%")
init_table(res["rows"])
sync_chart()
})
})
}
function init_table(rows){
for (i in rows)
{
let row = rows[i]
$("#mqttdata").append("<tr><td>"+row["topic"]+"</td><td>"+row["message"]+"</td><td>"+row["time"]+"</td></tr>")
}
if(lang=='zh')
datatable = $("#apps_table").DataTable({
"order": [[ 2, "asc" ]],
language: {
"sProcessing": "处理中...",
"sLengthMenu": "每页 _MENU_ 项",
"sZeroRecords": "没有匹配结果",
"sInfo": "显示第 _START_ 项至 第 _END_ 项结果,共 _TOTAL_ 项",
"sInfoEmpty": "显示第 0 项至 0 项结果,共 0 项",
"sInfoFiltered": "(由 _MAX_ 项结果过滤)",
"sInfoPostFix": "",
"sSearch": "搜索:",
"sUrl": "",
"sEmptyTable": "表中数据为空",
"sLoadingRecords": "载入中...",
"sInfoThousands": ",",
"oPaginate": {
"sFirst": "首页",
"sPrevious": "上页",
"sNext": "下页",
"sLast": "末页"
},
"oAria": {
"sSortAscending": ": 以升序排列此列",
"sSortDescending": ": 以降序排列此列"
}
}
});
else if(lang=='tw')
datatable = $("#apps_table").DataTable({
"order": [[ 2, "asc" ]],
language: {
"sProcessing": "處理中...",
"sLengthMenu": "每頁 _MENU_ 項",
"sZeroRecords": "沒有匹配結果",
"sInfo": "顯示第 _START_ 項至 第 _END_ 項結果,共 _TOTAL_ 項",
"sInfoEmpty": "顯示第 0 項至 0 項結果,共 0 項",
"sInfoFiltered": "(由 _MAX_ 項結果過濾)",
"sInfoPostFix": "",
"sSearch": "搜索:",
"sUrl": "",
"sEmptyTable": "表中數據為空",
"sLoadingRecords": "載入中...",
"sInfoThousands": ",",
"oPaginate": {
"sFirst": "首頁",
"sPrevious": "上頁",
"sNext": "下頁",
"sLast": "末頁"
},
"oAria": {
"sSortAscending": ": 以升序排列此列",
"sSortDescending": ": 以降序排列此列"
}
}
});
else
datatable = $("#apps_table").DataTable({
"order": [[ 2, "asc" ]]
});
datatable.on("page",sync_chart)
datatable.on("length",sync_chart)
datatable.on("search",sync_chart)
}
var sync_chart = function(){
var rows = datatable.rows({
order:'current',
page:'current',
search:'applied'
}).data()
console.log(rows)
var xis = []
var srs = []
for (var i = 0;i<=rows.length - 1;i = i+1)
{
if(xis.length==0 || xis[xis.length-1] != rows[i][2])
xis.push(rows[i][2])
var have = false
for(j in srs)
{
if(srs[j]["name"] == rows[i][0])
have = true
}
if(!have)
{
srs.push({
name:rows[i][0],
data:[],
type:"line"
})
}
}
for(i in xis)
{
var time = xis[i]
for(j in srs)
{
var name = srs[j]["name"]
var have = false
for(var k = 0;k<=rows.length - 1;k = k+1)
{
if(rows[k][0] == name && rows[k][2] == time)
{
srs[j]["data"].push(rows[k][1])
have = true
break
}
}
if(!have)
srs[j]["data"].push(NaN)
}
}
option = {
tooltip: {
trigger: 'axis'
},
xAxis: {
type: 'category',
data: xis
},
yAxis: {
type: 'value'
},
series: srs
};
option && myChart.setOption(option, true);
}
$(function(){
var chartDom = document.getElementById('chart');
myChart = echarts.init(chartDom);
option = {
tooltip: {
trigger: 'axis'
},
xAxis: {
type: 'category',
data: []
},
yAxis: {
type: 'value'
},
series: [
{
}
]
};
option && myChart.setOption(option);
get_data()
})
var play = function(){
var modald = showmodaltext("<div style='text-align:center'><i class='fa fa-spin fa-cog' style='font-size:2rem;color:#4e73df'></i><p style='margin-top:6px;margin-bottom:0;color:#4e73df;font-size:1rem;font-weight:bold'>"+JSLang[lang].loading+"</p></div>")
$.get('startHook',function(res){
modald.close()
if(res == 1)
refresh()
else
showtext("unknown error")
})
}
var stop = function(){
var modald = showmodaltext("<div style='text-align:center'><i class='fa fa-spin fa-cog' style='font-size:2rem;color:#4e73df'></i><p style='margin-top:6px;margin-bottom:0;color:#4e73df;font-size:1rem;font-weight:bold'>"+JSLang[lang].loading+"</p></div>")
$.get('stopHook',function(res){
modald.close()
if(res == 1)
refresh()
else
showtext("unknown error")
})
}
var refresh = function(){
window.location.href = window.location.href
}
var output = function(){
}
var clearAll = function(){
console.log(111)
var modald = showmodaltext("<div style='text-align:center'><i class='fa fa-spin fa-cog' style='font-size:2rem;color:#4e73df'></i><p style='margin-top:6px;margin-bottom:0;color:#4e73df;font-size:1rem;font-weight:bold'>"+JSLang[lang].loading+"</p></div>")
$.get('clearHook',function(res){
modald.close()
if(res == 1)
refresh()
else
showtext("unknown error")
})
}

View File

@@ -486,6 +486,10 @@ var JSLang = {
var arrLang = {
"en": {
"TOPIC": "Topic",
"MESSAGE": "Message",
"TIME":"Time",
"DATAMANAGE": "Data",
"ADMIN":"Admin",
"BASICADMIN": "Basic",
"USERADMIN": "Users",
@@ -547,6 +551,10 @@ var JSLang = {
"CFMSET":"Confirm"
},
"zh": {
"TOPIC": "主题",
"MESSAGE": "消息",
"TIME":"时间",
"DATAMANAGE": "数据管理",
"ADMIN":"管理",
"BASICADMIN": "基础设置",
"USERADMIN": "批量注册",
@@ -608,6 +616,10 @@ var JSLang = {
"CFMSET":"确定设置"
},
"tw": {
"TOPIC": "主題",
"MESSAGE": "消息",
"TIME":"時間",
"DATAMANAGE": "數據管理",
"ADMIN":"管理",
"BASICADMIN": "基礎設置",
"USERADMIN": "批量註冊",

View File

@@ -20,6 +20,7 @@ const path = require('path');
var VERSION = JSON.parse(fs.readFileSync("../version.json","utf-8"))["version"]
var configs = fs.readFileSync('./config.json');
configs = JSON.parse(configs.toString());
const MAX_MESSAGE_PER_USER = 1000
var serverStatus = true
@@ -363,6 +364,64 @@ var mixioServer = function(){
} else if (topic[2] == '9d634e1a156dc0c1611eb4c3cff57276') {
db.run("delete from devices where userName = ? and clientid = ?", [topic[0], payload])
}
else if(reserveJSON[topic[0]]){
var userName = topic[0]
var reserveTopic = topic[1] + "/" + topic[2]
var hash = 0, i, chr;
if (this.length === 0) return hash;
for (i = 0; i < userName.length; i++) {
chr = userName.charCodeAt(i);
hash = ((hash << 5) - hash) + chr;
hash |= 0;
}
var targetDB = reserveDBs[hash%8]
targetDB.get("select count(*) from 'reserve' where userName = ?", [userName,], function(err, row){
if(err){
console.log(err.message)
}
else{
if(row && row["count(*)"] < MAX_MESSAGE_PER_USER)
{
targetDB.run("insert into 'reserve' (userName, topic, message) values (?,?,?)", [userName, reserveTopic, payload], function(err){
if(err)
{
console.log(err.message)
}
})
}
else if(row["count(*)"] >= MAX_MESSAGE_PER_USER)
{
targetDB.get("select id from 'reserve' where userName = ? order by id asc limit 1", [userName,],function(err,row){
if(err)
{
console.log(err.message)
}
else
{
if(row&&row["id"])
{
targetDB.run("delete from 'reserve' where id = ?",[row["id"],],function(err){
if(err)
{
console.log(err.message)
}
else
{
targetDB.run("insert into 'reserve' (userName, topic, message) values (?,?,?)", [userName, reserveTopic, payload], function(err){
if(err)
{
console.log(err.message)
}
})
}
})
}
}
})
}
}
})
}
}
})
@@ -601,6 +660,19 @@ var mixioServer = function(){
res.redirect('/')
})
app.get('/mqttdata', function(req, res){
if(req.session.userName){
ejs.renderFile(__dirname +'/ejs/data.ejs', {
userName: req.session.userName,
projectPass: req.session.projectPass,
'configs': configs
}, function (err, data) {
res.send(data)
})
}else
res.redirect('/')
})
app.get('/projects-mixly', function (req, res) {
ejs.renderFile(__dirname +'/ejs/projects.ejs', {
isMixly: 1,
@@ -651,6 +723,37 @@ var mixioServer = function(){
}
})
app.get('/getData', function (req, res) {
if(req.session.userName)
{
var userName = req.session.userName
var hash = 0, i, chr;
if (this.length === 0) return hash;
for (i = 0; i < userName.length; i++) {
chr = userName.charCodeAt(i);
hash = ((hash << 5) - hash) + chr;
hash |= 0;
}
reserveDBs[hash%8].all("select * from `reserve` where userName=?", [req.session.userName], function (err, rows) {
if(err)
{
console.log(err)
}
else
{
if(rows)
{
res.send({
"count":rows.length,
"rows":rows
})
}
}
})
}
})
app.get('/getProjects', function (req, res) {
if (req.session.userName && req.query.page) {
var pageStart = parseInt(req.query.page) * 8
@@ -1177,6 +1280,72 @@ var mixioServer = function(){
else
res.send('-1')
})
app.get('/queryHook', function(req, res){
if(req.session.userName)
{
if(reserveJSON[req.session.userName])
res.send('1')
else
res.send('2')
}
else
{
res.send('0')
}
})
app.get('/startHook', function(req, res){
if(req.session.userName)
{
reserveJSON[req.session.userName] = true
fs.writeFileSync('./reserve/filter.json', JSON.stringify(reserveJSON,false,4))
res.send('1')
}
else
{
res.send('0')
}
})
app.get('/stopHook', function(req, res){
if(req.session.userName)
{
reserveJSON[req.session.userName] = false
fs.writeFileSync('./reserve/filter.json', JSON.stringify(reserveJSON,false,4))
res.send('1')
}
else
{
res.send('0')
}
})
app.get('/clearHook', function(req, res){
if(req.session.userName)
{
var userName = req.session.userName
var hash = 0, i, chr;
if (this.length === 0) return hash;
for (i = 0; i < userName.length; i++) {
chr = userName.charCodeAt(i);
hash = ((hash << 5) - hash) + chr;
hash |= 0;
}
reserveDBs[hash%8].run("delete from `reserve` where userName = ?",[userName, ],function(err){
if(err)
{
console.log(err.message)
res.send('-1')
}
else
res.send('1')
})
}
else
res.send('0')
})
app.get('/endHost', function(req,res){
var userName = req.session.userName
var projectName = req.query.projectName
@@ -1210,13 +1379,30 @@ var mixioServer = function(){
sqlite3.OPEN_READWRITE,
function (err) {
if (err) {
return console.log(err.message)
console.log(err.message)
}
db.run('delete from devices')
console.log('[INFO] Database Connected!')
}
)
reserveDBs = []
for(var i = 1;i<=8;i = i+1)
{
reserveDBs.push(
new sqlite3.Database(
'./reserve/'+i+".db",
sqlite3.OPEN_READWRITE,
function(err){
if(err)
console.log(err.message)
}
)
)
}
var reserveJSON = JSON.parse(fs.readFileSync('./reserve/filter.json'),"utf8")
return new Promise(resolve=>{
plainServer.listen(1883, function () {

Binary file not shown.

BIN
src/reserve/1.db Normal file

Binary file not shown.

BIN
src/reserve/2.db Normal file

Binary file not shown.

BIN
src/reserve/3.db Normal file

Binary file not shown.

BIN
src/reserve/4.db Normal file

Binary file not shown.

BIN
src/reserve/5.db Normal file

Binary file not shown.

BIN
src/reserve/6.db Normal file

Binary file not shown.

BIN
src/reserve/7.db Normal file

Binary file not shown.

BIN
src/reserve/8.db Normal file

Binary file not shown.

3
src/reserve/filter.json Normal file
View File

@@ -0,0 +1,3 @@
{
"1371033826@qq.com": true
}