tinydb-update
This commit is contained in:
@@ -69,6 +69,11 @@
|
|||||||
<i class="fa fa-fw fa-table"></i>
|
<i class="fa fa-fw fa-table"></i>
|
||||||
<span class="lang" key="DATAMANAGE"></span></a>
|
<span class="lang" key="DATAMANAGE"></span></a>
|
||||||
</li>
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="tinydata" id="tiny_data">
|
||||||
|
<i class="fa fa-fw fa-database"></i>
|
||||||
|
<span>Tiny DB</span></a>
|
||||||
|
</li>
|
||||||
<li class="nav-item active">
|
<li class="nav-item active">
|
||||||
<a class="nav-link" href="webapps" id="share_app">
|
<a class="nav-link" href="webapps" id="share_app">
|
||||||
<i class="fa fa-fw fa-share"></i>
|
<i class="fa fa-fw fa-share"></i>
|
||||||
|
|||||||
30
ejs/data.ejs
30
ejs/data.ejs
@@ -72,6 +72,11 @@
|
|||||||
<i class="fa fa-fw fa-table"></i>
|
<i class="fa fa-fw fa-table"></i>
|
||||||
<span class="lang" key="DATAMANAGE"></span></a>
|
<span class="lang" key="DATAMANAGE"></span></a>
|
||||||
</li>
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="tinydata" id="tiny_data">
|
||||||
|
<i class="fa fa-fw fa-database"></i>
|
||||||
|
<span>Tiny DB</span></a>
|
||||||
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="webapps" id="share_app">
|
<a class="nav-link" href="webapps" id="share_app">
|
||||||
<i class="fa fa-fw fa-share"></i>
|
<i class="fa fa-fw fa-share"></i>
|
||||||
@@ -146,7 +151,7 @@
|
|||||||
|
|
||||||
<div class="row" >
|
<div class="row" >
|
||||||
|
|
||||||
<div class="col-xl-4">
|
<div class="col-xl-6">
|
||||||
<div class="card shadow mb-4" style="border-radius:10px;min-height:660px">
|
<div class="card shadow mb-4" style="border-radius:10px;min-height:660px">
|
||||||
<div style="position: absolute;right:20px;top:20px" class="d-none d-md-block">
|
<div style="position: absolute;right:20px;top:20px" class="d-none d-md-block">
|
||||||
<span>主题 </span><input id="topicFilter" class="form-control form-control-sm" style="display:inline;width:100px;min-width:100px"></input>
|
<span>主题 </span><input id="topicFilter" class="form-control form-control-sm" style="display:inline;width:100px;min-width:100px"></input>
|
||||||
@@ -172,7 +177,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xl-4">
|
<div class="col-xl-6">
|
||||||
<div class="card shadow mb-4" style="border-radius:10px">
|
<div class="card shadow mb-4" style="border-radius:10px">
|
||||||
|
|
||||||
<div class="card-body" style="overflow:auto;height:660px">
|
<div class="card-body" style="overflow:auto;height:660px">
|
||||||
@@ -182,27 +187,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xl-4">
|
|
||||||
<div class="card shadow mb-4" style="border-radius:10px;min-height:660px">
|
|
||||||
<div class="card-header py-3">
|
|
||||||
<h6 class="m-0 font-weight-bold text-primary">TinyDB</h6>
|
|
||||||
</div>
|
|
||||||
<div class="card-body" style="overflow:auto;">
|
|
||||||
<table id="special_table" class="table table-striped table-bordered" style="width:100%">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>键</th>
|
|
||||||
<th>值</th>
|
|
||||||
<th>更新时间</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody id="special_data">
|
|
||||||
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -67,6 +67,11 @@
|
|||||||
<i class="fa fa-fw fa-table"></i>
|
<i class="fa fa-fw fa-table"></i>
|
||||||
<span class="lang" key="DATAMANAGE"></span></a>
|
<span class="lang" key="DATAMANAGE"></span></a>
|
||||||
</li>
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="tinydata" id="tiny_data">
|
||||||
|
<i class="fa fa-fw fa-database"></i>
|
||||||
|
<span>Tiny DB</span></a>
|
||||||
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="webapps" id="share_app">
|
<a class="nav-link" href="webapps" id="share_app">
|
||||||
<i class="fa fa-fw fa-share"></i>
|
<i class="fa fa-fw fa-share"></i>
|
||||||
|
|||||||
584
ejs/tinydb.ejs
Normal file
584
ejs/tinydb.ejs
Normal file
@@ -0,0 +1,584 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<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 - TinyDB</title>
|
||||||
|
<link rel="shortcut icon" href="img/shortcut.png"/>
|
||||||
|
|
||||||
|
<!-- Custom fonts for this template-->
|
||||||
|
<link rel="stylesheet" href="css/all.css">
|
||||||
|
<link rel="stylesheet" href="css/dataTables.bootstrap4.min.css">
|
||||||
|
<link rel="stylesheet" href="css/flatpkr.css">
|
||||||
|
|
||||||
|
<!-- Bootstrap core JavaScript-->
|
||||||
|
<script src="js/jquery.min.js"></script>
|
||||||
|
<script src="js/lang.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/jquery.dataTables.min.js"></script>
|
||||||
|
<script src="js/flatpkr.js"></script>
|
||||||
|
<script src="js/dataTables.bootstrap4.min.js"></script>
|
||||||
|
<script src="js/tools.js"></script>
|
||||||
|
<script>var projectPass = "<%=projectPass%>";</script>
|
||||||
|
<script>var userName = "<%=userName%>";</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.card {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
box-shadow: 0 0.15rem 1.75rem 0 rgba(58, 59, 69, 0.15);
|
||||||
|
border: 1px solid #e3e6f0;
|
||||||
|
}
|
||||||
|
.card-header {
|
||||||
|
background-color: #f8f9fc;
|
||||||
|
border-bottom: 1px solid #e3e6f0;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.btn-primary {
|
||||||
|
background-color: #4e73df;
|
||||||
|
border-color: #4e73df;
|
||||||
|
}
|
||||||
|
.btn-success {
|
||||||
|
background-color: #1cc88a;
|
||||||
|
border-color: #1cc88a;
|
||||||
|
}
|
||||||
|
.btn-danger {
|
||||||
|
background-color: #e74a3b;
|
||||||
|
border-color: #e74a3b;
|
||||||
|
}
|
||||||
|
.table-responsive {
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
.action-buttons {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.alert {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.form-group {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
.new-row {
|
||||||
|
background-color: #f8fff8;
|
||||||
|
}
|
||||||
|
.new-row input, .new-row textarea {
|
||||||
|
border: 1px solid #c1e6c1;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</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 -->
|
||||||
|
<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">
|
||||||
|
<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="tinydata" id="tiny_data">
|
||||||
|
<i class="fa fa-fw fa-database"></i>
|
||||||
|
<span>Tiny DB</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" style="margin-left:10px;font-size:1.5rem;display:inline-block;cursor:pointer">TinyDB 数据管理</h1>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<!-- Begin Page Content -->
|
||||||
|
<div class="container-fluid">
|
||||||
|
<!-- 警告信息 -->
|
||||||
|
<div class="alert alert-success" id="successAlert" role="alert">
|
||||||
|
操作成功!
|
||||||
|
</div>
|
||||||
|
<div class="alert alert-danger" id="errorAlert" role="alert">
|
||||||
|
操作失败!
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<!-- 数据列表 -->
|
||||||
|
<div class="col-xl-12">
|
||||||
|
<div class="card shadow mb-4">
|
||||||
|
<div class="card-header py-3 d-flex flex-row align-items-center justify-content-between">
|
||||||
|
<h6 class="m-0 font-weight-bold text-primary">数据列表</h6>
|
||||||
|
<div>
|
||||||
|
<button class="btn btn-success btn-sm" id="refreshData">
|
||||||
|
<i class="fa fa-sync-alt"></i> 刷新
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-primary btn-sm" id="addNewRow">
|
||||||
|
<i class="fa fa-plus"></i> 新增
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-info btn-sm" id="searchBtn" data-toggle="modal" data-target="#searchModal">
|
||||||
|
<i class="fa fa-search"></i> 搜索
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-bordered" id="dataTable" width="100%" cellspacing="0">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th width="25%">标签</th>
|
||||||
|
<th width="60%">值</th>
|
||||||
|
<th width="15%">操作</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="dataTableBody">
|
||||||
|
<!-- 数据将通过JavaScript动态填充 -->
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- /.container-fluid -->
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<!-- End of Main Content -->
|
||||||
|
|
||||||
|
<!-- Footer -->
|
||||||
|
<footer class="sticky-footer bg-white">
|
||||||
|
<div class="container my-auto">
|
||||||
|
<div class="copyright text-center my-auto">
|
||||||
|
<span>Copyright © mixio.mixly.org 2021</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<!-- End of Content Wrapper -->
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<!-- End of Page Wrapper -->
|
||||||
|
|
||||||
|
<!-- 搜索模态框 -->
|
||||||
|
<div class="modal fade" id="searchModal" tabindex="-1" role="dialog" aria-labelledby="searchModalLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title" id="searchModalLabel">搜索数据</h5>
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<form id="searchForm">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="searchTag">标签关键字</label>
|
||||||
|
<input type="text" class="form-control" id="searchTag" placeholder="输入标签关键字">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="searchType">返回类型</label>
|
||||||
|
<select class="form-control" id="searchType">
|
||||||
|
<option value="both">标签和值</option>
|
||||||
|
<option value="tag">仅标签</option>
|
||||||
|
<option value="value">仅值</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="searchCount">返回数量</label>
|
||||||
|
<input type="number" class="form-control" id="searchCount" value="10" min="1" max="100">
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
|
||||||
|
<button type="button" class="btn btn-primary" id="performSearch">搜索</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Page level custom scripts -->
|
||||||
|
<script src="js/sb-admin-2.min.js?v=2"></script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
// 全局变量
|
||||||
|
let currentData = [];
|
||||||
|
|
||||||
|
// 从localStorage获取用户信息
|
||||||
|
function getUserInfo() {
|
||||||
|
return {
|
||||||
|
user: userName,
|
||||||
|
secret: projectPass
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 显示/隐藏警告信息
|
||||||
|
function showAlert(message, type) {
|
||||||
|
const alertId = type === 'success' ? 'successAlert' : 'errorAlert';
|
||||||
|
const alert = $('#' + alertId);
|
||||||
|
alert.text(message);
|
||||||
|
alert.fadeIn();
|
||||||
|
setTimeout(() => {
|
||||||
|
alert.fadeOut();
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加新行
|
||||||
|
$('#addNewRow').on('click', function() {
|
||||||
|
const tbody = $('#dataTableBody');
|
||||||
|
|
||||||
|
// 检查是否已经存在新行
|
||||||
|
if ($('.new-row').length > 0) {
|
||||||
|
showAlert('请先保存或取消当前新增的数据', 'error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const newRow = $('<tr class="new-row">');
|
||||||
|
newRow.append($('<td>').append($('<input type="text" class="form-control form-control-sm" placeholder="输入标签">')));
|
||||||
|
newRow.append($('<td>').append($('<textarea class="form-control form-control-sm" rows="2" placeholder="输入值"></textarea>')));
|
||||||
|
|
||||||
|
const actions = $('<td class="action-buttons">');
|
||||||
|
actions.append($('<button class="btn btn-sm btn-success mr-1 save-new-btn">').html('<i class="fa fa-check"></i> 保存'));
|
||||||
|
actions.append($('<button class="btn btn-sm btn-secondary cancel-new-btn">').html('<i class="fa fa-times"></i> 取消'));
|
||||||
|
|
||||||
|
newRow.append(actions);
|
||||||
|
tbody.prepend(newRow);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 保存新数据
|
||||||
|
$(document).on('click', '.save-new-btn', function() {
|
||||||
|
const row = $(this).closest('tr');
|
||||||
|
const tagInput = row.find('input');
|
||||||
|
const valueInput = row.find('textarea');
|
||||||
|
|
||||||
|
const tag = tagInput.val().trim();
|
||||||
|
const value = valueInput.val().trim();
|
||||||
|
|
||||||
|
if (!tag) {
|
||||||
|
showAlert('标签不能为空', 'error');
|
||||||
|
tagInput.focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!value) {
|
||||||
|
showAlert('值不能为空', 'error');
|
||||||
|
valueInput.focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const userInfo = getUserInfo();
|
||||||
|
|
||||||
|
// 发送请求到后端
|
||||||
|
$.ajax({
|
||||||
|
url: '/tinydb',
|
||||||
|
method: 'POST',
|
||||||
|
data: {
|
||||||
|
user: userInfo.user,
|
||||||
|
secret: userInfo.secret,
|
||||||
|
action: 'update',
|
||||||
|
tag: tag,
|
||||||
|
value: value
|
||||||
|
},
|
||||||
|
success: function(response) {
|
||||||
|
if (response.status === 'success') {
|
||||||
|
showAlert('数据添加成功', 'success');
|
||||||
|
loadData();
|
||||||
|
} else {
|
||||||
|
showAlert('添加失败: ' + response.message, 'error');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function() {
|
||||||
|
showAlert('网络错误,请稍后重试', 'error');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 取消新增
|
||||||
|
$(document).on('click', '.cancel-new-btn', function() {
|
||||||
|
$(this).closest('tr').remove();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 加载数据列表
|
||||||
|
function loadData() {
|
||||||
|
const userInfo = getUserInfo();
|
||||||
|
console.log(userInfo)
|
||||||
|
if (!userInfo.user || !userInfo.secret) {
|
||||||
|
showAlert('未找到用户信息,请重新登录', 'error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: '/tinydb',
|
||||||
|
method: 'POST',
|
||||||
|
data: {
|
||||||
|
user: userInfo.user,
|
||||||
|
secret: userInfo.secret,
|
||||||
|
action: 'search',
|
||||||
|
no: 1,
|
||||||
|
count: 100,
|
||||||
|
type: 'both'
|
||||||
|
},
|
||||||
|
success: function(response) {
|
||||||
|
if (response.status === 'success') {
|
||||||
|
currentData = response.data;
|
||||||
|
renderDataTable(currentData);
|
||||||
|
} else {
|
||||||
|
showAlert('加载数据失败: ' + response.message, 'error');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function() {
|
||||||
|
showAlert('网络错误,请稍后重试', 'error');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 渲染数据表格
|
||||||
|
function renderDataTable(data) {
|
||||||
|
const tbody = $('#dataTableBody');
|
||||||
|
tbody.empty();
|
||||||
|
|
||||||
|
if (data.length === 0) {
|
||||||
|
tbody.append('<tr><td colspan="3" class="text-center">暂无数据</td></tr>');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.forEach(item => {
|
||||||
|
const row = $('<tr>');
|
||||||
|
row.append($('<td>').text(item.tag));
|
||||||
|
row.append($('<td>').text(item.value));
|
||||||
|
|
||||||
|
const actions = $('<td class="action-buttons">');
|
||||||
|
actions.append($('<button class="btn btn-sm btn-primary mr-1 edit-btn">').html('<i class="fa fa-edit"></i>').attr('data-tag', item.tag).attr('data-value', item.value));
|
||||||
|
actions.append($('<button class="btn btn-sm btn-danger delete-btn">').html('<i class="fa fa-trash"></i>').attr('data-tag', item.tag));
|
||||||
|
|
||||||
|
row.append(actions);
|
||||||
|
tbody.append(row);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 绑定编辑按钮事件
|
||||||
|
$('.edit-btn').on('click', function() {
|
||||||
|
const tag = $(this).data('tag');
|
||||||
|
const value = $(this).data('value');
|
||||||
|
|
||||||
|
// 将当前行转换为编辑模式
|
||||||
|
const row = $(this).closest('tr');
|
||||||
|
row.empty();
|
||||||
|
|
||||||
|
row.append($('<td>').append($('<input readonly type="text" class="form-control form-control-sm" value="' + tag + '">')));
|
||||||
|
row.append($('<td>').append($('<textarea class="form-control form-control-sm" rows="2">' + value + '</textarea>')));
|
||||||
|
|
||||||
|
const actions = $('<td class="action-buttons">');
|
||||||
|
actions.append($('<button class="btn btn-sm btn-success mr-1 save-edit-btn">').html('<i class="fa fa-check"></i> 保存'));
|
||||||
|
actions.append($('<button class="btn btn-sm btn-secondary cancel-edit-btn">').html('<i class="fa fa-times"></i> 取消'));
|
||||||
|
|
||||||
|
row.append(actions);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 保存编辑
|
||||||
|
$(document).on('click', '.save-edit-btn', function() {
|
||||||
|
const row = $(this).closest('tr');
|
||||||
|
const tagInput = row.find('input');
|
||||||
|
const valueInput = row.find('textarea');
|
||||||
|
|
||||||
|
const newTag = tagInput.val().trim();
|
||||||
|
const newValue = valueInput.val().trim();
|
||||||
|
const oldTag = $(this).data('old-tag'); // 如果需要保留原标签用于更新
|
||||||
|
|
||||||
|
if (!newTag) {
|
||||||
|
showAlert('标签不能为空', 'error');
|
||||||
|
tagInput.focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!newValue) {
|
||||||
|
showAlert('值不能为空', 'error');
|
||||||
|
valueInput.focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const userInfo = getUserInfo();
|
||||||
|
|
||||||
|
// 发送请求到后端
|
||||||
|
$.ajax({
|
||||||
|
url: '/tinydb',
|
||||||
|
method: 'POST',
|
||||||
|
data: {
|
||||||
|
user: userInfo.user,
|
||||||
|
secret: userInfo.secret,
|
||||||
|
action: 'update',
|
||||||
|
tag: newTag,
|
||||||
|
value: newValue
|
||||||
|
},
|
||||||
|
success: function(response) {
|
||||||
|
if (response.status === 'success') {
|
||||||
|
showAlert('数据更新成功', 'success');
|
||||||
|
loadData();
|
||||||
|
} else {
|
||||||
|
showAlert('更新失败: ' + response.message, 'error');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function() {
|
||||||
|
showAlert('网络错误,请稍后重试', 'error');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 取消编辑
|
||||||
|
$(document).on('click', '.cancel-edit-btn', function() {
|
||||||
|
loadData(); // 重新加载数据恢复原状
|
||||||
|
});
|
||||||
|
|
||||||
|
// 绑定删除按钮事件
|
||||||
|
$('.delete-btn').on('click', function() {
|
||||||
|
const tag = $(this).data('tag');
|
||||||
|
|
||||||
|
if (confirm(`确定要删除标签为 "${tag}" 的数据吗?`)) {
|
||||||
|
deleteData(tag);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除数据
|
||||||
|
function deleteData(tag) {
|
||||||
|
const userInfo = getUserInfo();
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: '/tinydb',
|
||||||
|
method: 'POST',
|
||||||
|
data: {
|
||||||
|
user: userInfo.user,
|
||||||
|
secret: userInfo.secret,
|
||||||
|
action: 'delete',
|
||||||
|
tag: tag
|
||||||
|
},
|
||||||
|
success: function(response) {
|
||||||
|
if (response.status === 'success') {
|
||||||
|
showAlert('数据删除成功', 'success');
|
||||||
|
loadData();
|
||||||
|
} else {
|
||||||
|
showAlert('删除失败: ' + response.message, 'error');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function() {
|
||||||
|
showAlert('网络错误,请稍后重试', 'error');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 搜索数据
|
||||||
|
$('#performSearch').on('click', function() {
|
||||||
|
const userInfo = getUserInfo();
|
||||||
|
const tag = $('#searchTag').val();
|
||||||
|
const type = $('#searchType').val();
|
||||||
|
const count = $('#searchCount').val();
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: '/tinydb',
|
||||||
|
method: 'POST',
|
||||||
|
data: {
|
||||||
|
user: userInfo.user,
|
||||||
|
secret: userInfo.secret,
|
||||||
|
action: 'search',
|
||||||
|
tag: tag,
|
||||||
|
type: type,
|
||||||
|
count: count
|
||||||
|
},
|
||||||
|
success: function(response) {
|
||||||
|
if (response.status === 'success') {
|
||||||
|
currentData = response.data;
|
||||||
|
renderDataTable(currentData);
|
||||||
|
$('#searchModal').modal('hide');
|
||||||
|
showAlert('搜索完成', 'success');
|
||||||
|
} else {
|
||||||
|
showAlert('搜索失败: ' + response.message, 'error');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function() {
|
||||||
|
showAlert('网络错误,请稍后重试', 'error');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 绑定刷新按钮事件
|
||||||
|
$('#refreshData').on('click', function() {
|
||||||
|
loadData();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 初始化页面
|
||||||
|
loadData();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
55
js/data.js
55
js/data.js
@@ -1,48 +1,4 @@
|
|||||||
function init_special_table(rows) {
|
|
||||||
var tableBody = $('#special_data');
|
|
||||||
tableBody.empty();
|
|
||||||
|
|
||||||
rows.forEach(function(row) {
|
|
||||||
var tr = $('<tr></tr>');
|
|
||||||
tr.append('<td>' + (row.topic || '') + '</td>');
|
|
||||||
tr.append('<td>' + (row.message || '') + '</td>');
|
|
||||||
tr.append('<td>' + (row.time || '') + '</td>');
|
|
||||||
tableBody.append(tr);
|
|
||||||
});
|
|
||||||
|
|
||||||
// 初始化DataTable(如果已初始化则销毁重新初始化)
|
|
||||||
if ($.fn.DataTable.isDataTable('#special_table')) {
|
|
||||||
$('#special_table').DataTable().destroy();
|
|
||||||
}
|
|
||||||
$('#special_table').DataTable({
|
|
||||||
"pageLength": 10,
|
|
||||||
"order": [[2, "desc"]],
|
|
||||||
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": ": 以降序排列此列"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function get_data() {
|
function get_data() {
|
||||||
$.get('queryHook', function(res) {
|
$.get('queryHook', function(res) {
|
||||||
@@ -61,17 +17,10 @@ function get_data() {
|
|||||||
$("#prj_num_bar").css("width", (res['count'] * 100 / max) + "%")
|
$("#prj_num_bar").css("width", (res['count'] * 100 / max) + "%")
|
||||||
|
|
||||||
// 筛选数据:topic不以$开头的存入globalRows,以$开头的存入globalRows2并去掉$
|
// 筛选数据:topic不以$开头的存入globalRows,以$开头的存入globalRows2并去掉$
|
||||||
globalRows = res["rows"].filter(row => !row.topic || !row.topic.startsWith('$'));
|
globalRows = res["rows"]
|
||||||
globalRows2 = res["rows"]
|
|
||||||
.filter(row => row.topic && row.topic.startsWith('$'))
|
|
||||||
.map(row => ({
|
|
||||||
...row,
|
|
||||||
topic: row.topic.substring(1) // 去掉开头的$
|
|
||||||
}));
|
|
||||||
|
|
||||||
init_table(globalRows) // 初始化表格使用非$开头的数据
|
init_table(globalRows) // 初始化表格使用非$开头的数据
|
||||||
sync_chart()
|
sync_chart()
|
||||||
init_special_table(globalRows2)
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -226,7 +226,8 @@ var JSLang = {
|
|||||||
"mic": "语音识别",
|
"mic": "语音识别",
|
||||||
"tinydb": "下拉选项",
|
"tinydb": "下拉选项",
|
||||||
"resolution": "分辨率",
|
"resolution": "分辨率",
|
||||||
"fps": "帧率"
|
"fps": "帧率",
|
||||||
|
'tdb': "TinyDB"
|
||||||
},
|
},
|
||||||
"tw": {
|
"tw": {
|
||||||
"beepAudio": "Audio",
|
"beepAudio": "Audio",
|
||||||
@@ -455,7 +456,8 @@ var JSLang = {
|
|||||||
"mic": "麥克風",
|
"mic": "麥克風",
|
||||||
"tinydb": "下拉選項",
|
"tinydb": "下拉選項",
|
||||||
"resolution": "分辨率",
|
"resolution": "分辨率",
|
||||||
"fps": "幀率"
|
"fps": "幀率",
|
||||||
|
'tdb': "TinyDB"
|
||||||
},
|
},
|
||||||
"en": {
|
"en": {
|
||||||
"beepAudio": "Beep Audio",
|
"beepAudio": "Beep Audio",
|
||||||
@@ -684,7 +686,8 @@ var JSLang = {
|
|||||||
"mic": "Microphone",
|
"mic": "Microphone",
|
||||||
"tinydb": "Options",
|
"tinydb": "Options",
|
||||||
"resolution": "Resolution",
|
"resolution": "Resolution",
|
||||||
"fps": "FPS"
|
"fps": "FPS",
|
||||||
|
'tdb': "TinyDB"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
19
mixio.js
19
mixio.js
@@ -1167,7 +1167,7 @@ var mixioServer = async function() {
|
|||||||
hash |= 0;
|
hash |= 0;
|
||||||
}
|
}
|
||||||
var targetDB = reserveDBs[Math.abs(hash) % 8]
|
var targetDB = reserveDBs[Math.abs(hash) % 8]
|
||||||
targetDB.get("select count(*) from `reserve` where userName = ?", [userName, ], function(err, row) {
|
targetDB.get("select count(*) from `reserve` where userName = ? and topic not like '$%'", [userName, ], function(err, row) {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.log(err.message)
|
console.log(err.message)
|
||||||
} else {
|
} else {
|
||||||
@@ -1409,7 +1409,7 @@ var mixioServer = async function() {
|
|||||||
if (row) {
|
if (row) {
|
||||||
res.json({ status: 'success', value: row.message });
|
res.json({ status: 'success', value: row.message });
|
||||||
} else {
|
} else {
|
||||||
res.json({ status: 'error', message: '变量不存在' });
|
res.json({ status: 'success', value: "None" });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1948,6 +1948,19 @@ var mixioServer = async function() {
|
|||||||
res.redirect('/')
|
res.redirect('/')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
app.get('/tinydata', function(req, res) {
|
||||||
|
if (req.session.userName) {
|
||||||
|
ejs.renderFile(__dirname + '/ejs/tinydb.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) {
|
app.get('/projects-mixly', function(req, res) {
|
||||||
ejs.renderFile(__dirname + '/ejs/projects.ejs', {
|
ejs.renderFile(__dirname + '/ejs/projects.ejs', {
|
||||||
isMixly: 1,
|
isMixly: 1,
|
||||||
@@ -2007,7 +2020,7 @@ var mixioServer = async function() {
|
|||||||
hash = ((hash << 5) - hash) + chr;
|
hash = ((hash << 5) - hash) + chr;
|
||||||
hash |= 0;
|
hash |= 0;
|
||||||
}
|
}
|
||||||
reserveDBs[Math.abs(hash) % 8].all("select * from `reserve` where userName=?", [req.session.userName], function(err, rows) {
|
reserveDBs[Math.abs(hash) % 8].all("select * from `reserve` where userName=? and topic not like '$%'", [req.session.userName], function(err, rows) {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.log(err)
|
console.log(err)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user