|
|
<!DOCTYPE html>
|
|
|
<html lang="zh-CN">
|
|
|
|
|
|
<head>
|
|
|
<meta charset="UTF-8">
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
|
<title>识别系统</title>
|
|
|
<style>
|
|
|
body {
|
|
|
font-family: Arial, sans-serif;
|
|
|
margin: 20px;
|
|
|
padding: 20px;
|
|
|
background-color: #f8f8f8;
|
|
|
color: #333;
|
|
|
}
|
|
|
|
|
|
h1 {
|
|
|
text-align: center;
|
|
|
color: #009688;
|
|
|
}
|
|
|
|
|
|
p {
|
|
|
color: #666;
|
|
|
}
|
|
|
|
|
|
ul {
|
|
|
list-style-type: square;
|
|
|
margin-left: 20px;
|
|
|
}
|
|
|
|
|
|
table {
|
|
|
width: 100%;
|
|
|
border-collapse: collapse;
|
|
|
margin-top: 20px;
|
|
|
}
|
|
|
|
|
|
th,
|
|
|
td {
|
|
|
border: 1px solid #ddd;
|
|
|
padding: 8px;
|
|
|
text-align: center;
|
|
|
}
|
|
|
|
|
|
th {
|
|
|
background-color: #f2f2f2;
|
|
|
}
|
|
|
|
|
|
img {
|
|
|
max-width: 100%;
|
|
|
height: auto;
|
|
|
margin-top: 20px;
|
|
|
}
|
|
|
|
|
|
.module {
|
|
|
padding: 10px;
|
|
|
margin: 10px;
|
|
|
border: 1px solid #009688;
|
|
|
background-color: #e0f2f1;
|
|
|
cursor: pointer;
|
|
|
transition: background-color 0.3s;
|
|
|
}
|
|
|
|
|
|
.module:hover {
|
|
|
background-color: #b2dfdb;
|
|
|
}
|
|
|
|
|
|
.return-btn {
|
|
|
display: block;
|
|
|
margin-top: 10px;
|
|
|
padding: 10px;
|
|
|
background-color: #138b5b;
|
|
|
color: #fff;
|
|
|
text-align: center;
|
|
|
text-decoration: none;
|
|
|
cursor: pointer;
|
|
|
border-radius: 5px;
|
|
|
}
|
|
|
|
|
|
.return-btn:hover {
|
|
|
background-color: #517900;
|
|
|
}
|
|
|
|
|
|
.link_button {
|
|
|
margin: 10px 5%;
|
|
|
padding: 10px 18px;
|
|
|
color: #fff;
|
|
|
font-size: 14px;
|
|
|
font-weight: bold;
|
|
|
border-radius: 4px;
|
|
|
background: #08fd6a;
|
|
|
text-decoration: none;
|
|
|
top: 20px;
|
|
|
position: relative;
|
|
|
width: 600px;
|
|
|
}
|
|
|
|
|
|
.custom-file-upload {
|
|
|
border: 1px solid #ccc;
|
|
|
display: inline-block;
|
|
|
padding: 6px 12px;
|
|
|
cursor: pointer;
|
|
|
background-color: #f1f1f1;
|
|
|
color: #333;
|
|
|
border-radius: 4px;
|
|
|
font-size: 16px;
|
|
|
}
|
|
|
|
|
|
.custom-file-upload:hover {
|
|
|
background-color: #e1e1e1;
|
|
|
}
|
|
|
|
|
|
.chart-container {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
}
|
|
|
|
|
|
#uploadChart {
|
|
|
max-width: 1000px;
|
|
|
max-height: 600px;
|
|
|
}
|
|
|
a {
|
|
|
color: #000;
|
|
|
text-decoration: none;
|
|
|
}
|
|
|
</style>
|
|
|
|
|
|
<script>
|
|
|
document.addEventListener('DOMContentLoaded', function () {//从后端获取用户名
|
|
|
var params = new URLSearchParams(window.location.search);
|
|
|
var username = params.get('username');
|
|
|
if (username) {
|
|
|
document.getElementById('username1').textContent = username;
|
|
|
}
|
|
|
});
|
|
|
|
|
|
document.addEventListener('DOMContentLoaded', function () {//从后端获取这个用户的身份(user/admin)
|
|
|
var params = new URLSearchParams(window.location.search);
|
|
|
if (userId === 'admin') {
|
|
|
document.getElementById('managementBtn').style.display = 'block'; // 显示后台管理按钮
|
|
|
} else {
|
|
|
document.getElementById('managementBtn').style.display = 'none'; // 隐藏后台管理按钮
|
|
|
}
|
|
|
});
|
|
|
</script>
|
|
|
</head>
|
|
|
|
|
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
|
|
|
|
|
<body>
|
|
|
<!-- 把后端获取的用户名显示在欢迎标题上 -->
|
|
|
<h1>欢迎您,尊敬的 <span id="username1"></span></h1>
|
|
|
<p>欢迎访问识别系统!</p>
|
|
|
|
|
|
<!-- 按钮列表 -->
|
|
|
<div id="moduleSelection">
|
|
|
<div class="module" onclick="openModule('reservation')">识别查询</div>
|
|
|
<div class="module" onclick="openModule('management')" id="managementBtn">后台管理</div>
|
|
|
<div class="module" onclick="logout()" id="managementBtn">退出登录</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div id="reservation" style="display: none;">
|
|
|
<h2>识别模块</h2>
|
|
|
<p>在这里上传你的图片进行识别。</p>
|
|
|
<form id="uploadForm" enctype="multipart/form-data">
|
|
|
<label for="fileInput" class="custom-file-upload">
|
|
|
<input type="file" id="fileInput" name="image" accept="image/*">
|
|
|
选择文件
|
|
|
</label>
|
|
|
<button class="return-btn" type="button" onclick="uploadImage()">上传并识别</button>
|
|
|
</form>
|
|
|
<a href="#" class="return-btn" onclick="goBack()">返回</a>
|
|
|
</div>
|
|
|
|
|
|
<div id="management" style="display: none;">
|
|
|
<h2>系统后台数据查询与管理模块</h2>
|
|
|
<table width="90%" class="table" id="userTable">
|
|
|
<tr>
|
|
|
<th>用户名</th>
|
|
|
<th>密码</th>
|
|
|
<th>身份</th>
|
|
|
<th>邮箱</th>
|
|
|
<th>上传次数</th>
|
|
|
<th>操作</th>
|
|
|
</tr>
|
|
|
</table>
|
|
|
<h1>查询用户上传次数</h1>
|
|
|
<div>
|
|
|
<label for="username">用户名:</label>
|
|
|
<input type="text" id="username">
|
|
|
<button onclick="searchUser()">查询</button>
|
|
|
</div>
|
|
|
<div id="result"></div>
|
|
|
<h1>上传文件统计</h1>
|
|
|
<div>
|
|
|
<div class="chart-container">
|
|
|
<canvas id="uploadChart" width="800" height="400"></canvas>
|
|
|
</div>
|
|
|
</div>
|
|
|
<script>
|
|
|
function logout() {
|
|
|
fetch(`/logout`).then(() => {
|
|
|
window.location.href = '/welcome.html'
|
|
|
})
|
|
|
}
|
|
|
|
|
|
|
|
|
let userId;
|
|
|
function searchUser() {
|
|
|
const username = document.getElementById('username').value;
|
|
|
fetch(`/api/user-images-count?username=${encodeURIComponent(username)}`)
|
|
|
.then(response => response.json())
|
|
|
.then(data => {
|
|
|
const resultDiv = document.getElementById('result');
|
|
|
if (data.error) {
|
|
|
resultDiv.innerText = data.error;
|
|
|
} else {
|
|
|
resultDiv.innerText = `${username} 上传了 ${data.imageCount} 张图片`;
|
|
|
}
|
|
|
})
|
|
|
.catch(error => {
|
|
|
console.error('Error:', error);
|
|
|
document.getElementById('result').innerText = '查询过程中发生错误';
|
|
|
});
|
|
|
}
|
|
|
let chartInstance;
|
|
|
function renderChart() {
|
|
|
fetch('/api/userUploads')
|
|
|
.then(response => response.json())
|
|
|
.then(data => {
|
|
|
const ctx = document.getElementById('uploadChart').getContext('2d');
|
|
|
const labels = data.map(item => item.username);
|
|
|
const values = data.map(item => item.upload_count);
|
|
|
if (chartInstance) {
|
|
|
chartInstance.destroy();
|
|
|
}
|
|
|
chartInstance = new Chart(ctx, {
|
|
|
type: 'bar',
|
|
|
data: {
|
|
|
labels: labels,
|
|
|
datasets: [{
|
|
|
label: '上传文件数量',
|
|
|
data: values,
|
|
|
backgroundColor: 'rgba(75, 192, 192, 0.2)',
|
|
|
borderColor: 'rgba(75, 192, 192, 1)',
|
|
|
borderWidth: 1
|
|
|
}]
|
|
|
},
|
|
|
options: {
|
|
|
scales: {
|
|
|
y: {
|
|
|
beginAtZero: true
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
});
|
|
|
}
|
|
|
|
|
|
|
|
|
document.addEventListener('DOMContentLoaded', function () {
|
|
|
const userTable = document.getElementById('userTable');
|
|
|
fetch('/api/users')
|
|
|
.then(response => response.json())
|
|
|
.then(users => {
|
|
|
users.forEach(user => {
|
|
|
const row = userTable.insertRow();
|
|
|
row.innerHTML = `
|
|
|
<td><input type="text" value="${user.name}" data-oldname="${user.name}" /></td>
|
|
|
<td><input type="text" value="${user.passwd}" /></td>
|
|
|
<td>${user.id}</td>
|
|
|
<td><input type="text" value="${user.msg}" /></td>
|
|
|
<td>${user.imageCount}</td>
|
|
|
<td>
|
|
|
<button onclick="updateUser(this)">更新</button>
|
|
|
<button onclick="deleteUser(this)">删除</button>
|
|
|
</td>
|
|
|
`;
|
|
|
});
|
|
|
});
|
|
|
renderChart()
|
|
|
});
|
|
|
|
|
|
function updateUser(button) {
|
|
|
const row = button.parentElement.parentElement;
|
|
|
const name = row.cells[0].children[0].value;
|
|
|
const passwd = row.cells[1].children[0].value;
|
|
|
const id = row.cells[2].children[0].value;
|
|
|
const msg = row.cells[3].children[0].value;
|
|
|
const oldName = row.cells[0].children[0].getAttribute('data-oldname');
|
|
|
|
|
|
fetch('/api/updateUser', {
|
|
|
method: 'POST',
|
|
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
|
body: new URLSearchParams({ name, passwd, id, msg, oldName })
|
|
|
})
|
|
|
.then(response => response.json())
|
|
|
.then(data => {
|
|
|
alert(data.message);
|
|
|
});
|
|
|
}
|
|
|
|
|
|
function deleteUser(button) {
|
|
|
const row = button.parentElement.parentElement;
|
|
|
const name = row.cells[0].children[0].value;
|
|
|
|
|
|
fetch('/api/deleteUser', {
|
|
|
method: 'POST',
|
|
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
|
body: new URLSearchParams({ name })
|
|
|
})
|
|
|
.then(response => response.json())
|
|
|
.then(data => {
|
|
|
alert(data.message);
|
|
|
if (data.message === '用户删除成功') {
|
|
|
row.remove();
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
|
|
|
|
|
|
</script>
|
|
|
|
|
|
<a href="#" class="return-btn" onclick="goBack()">返回模块选择</a>
|
|
|
</div>
|
|
|
|
|
|
<!-- 页尾的一些用户友好内容 -->
|
|
|
<h2>联系我们</h2>
|
|
|
<p>如有任何关于系统的疑问或建议,请联系我们:</p>
|
|
|
<address>
|
|
|
电子邮件:<a href="mailto:aa893824054@163.com">aa893824054@163.com</a><br>
|
|
|
电话:184-7635-1355
|
|
|
</address>
|
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>
|
|
|
<script>
|
|
|
async function calculateHash(file) {
|
|
|
return new Promise((resolve, reject) => {
|
|
|
const reader = new FileReader();
|
|
|
reader.onload = function(event) {
|
|
|
const wordArray = CryptoJS.lib.WordArray.create(event.target.result);
|
|
|
const hash = CryptoJS.SHA256(wordArray);
|
|
|
resolve(hash.toString(CryptoJS.enc.Hex));
|
|
|
};
|
|
|
reader.onerror = reject;
|
|
|
reader.readAsArrayBuffer(file);
|
|
|
});
|
|
|
}
|
|
|
|
|
|
function getHostname() {
|
|
|
var hostname = window.location.hostname;
|
|
|
console.log("当前页面的主机名是:" + hostname);
|
|
|
}
|
|
|
getHostname(); // 调用函数来获取主机名
|
|
|
|
|
|
// var port_count = 0 //(只有使用顺序分配策略时候才取消注释)
|
|
|
|
|
|
async function uploadImage() {
|
|
|
const fileInput = document.getElementById('fileInput');
|
|
|
const file = fileInput.files[0];
|
|
|
var urlParams = new URLSearchParams(window.location.search);
|
|
|
var username = urlParams.get('username');
|
|
|
var ports=[8084, 8085, 8086, 8087,8088]//识别功能端口组,一个口代表一个识别服务器
|
|
|
var randomPort = ports[Math.floor(Math.random() * ports.length)];// 从端口数组中随机选择一个端口
|
|
|
var host = window.location.hostname; // 获取当前页面的主机名
|
|
|
|
|
|
|
|
|
if (!file) {
|
|
|
alert('请选择一个文件');
|
|
|
return;
|
|
|
}
|
|
|
try {
|
|
|
const hashHex = await calculateHash(file);
|
|
|
console.log('文件哈希值:', hashHex);
|
|
|
|
|
|
const formData = new FormData(document.getElementById("uploadForm"));
|
|
|
fetch('http://' + host + ':' + randomPort + '/api/upload?user_name=' + username + '&fileHash=' + hashHex, {//随机分配策略
|
|
|
// fetch('http://' + host + ':' + ports[port_count] + '/api/upload?user_name=' + username + '&fileHash=' + hashHex, {//顺序分配策略
|
|
|
method: 'POST',
|
|
|
body: formData
|
|
|
})
|
|
|
.then(response => response.json())
|
|
|
.then(data => {
|
|
|
alert("识别结果: " + data.fileName);
|
|
|
renderChart();
|
|
|
// port_count = (port_count + 1) % ports.length;// 更新索引以循环使用端口数组(顺序分配时使用,用随机策略时要注释掉)
|
|
|
})
|
|
|
.catch(error => console.error('Error:', error));
|
|
|
} catch (error) {
|
|
|
console.error('Error calculating hash:', error);
|
|
|
alert('计算文件哈希值时发生错误');
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function openModule(moduleId) {//打开模块的功能
|
|
|
var modules = document.getElementsByClassName('module');
|
|
|
for (var i = 0; i < modules.length; i++) {
|
|
|
modules[i].style.display = 'none';
|
|
|
}
|
|
|
document.getElementById('moduleSelection').style.display = 'none';
|
|
|
document.getElementById(moduleId).style.display = 'block';
|
|
|
}
|
|
|
|
|
|
|
|
|
document.addEventListener('DOMContentLoaded', function () {//监听程序,用来解决:点击返回按钮后重新出现“后台管理”按钮的问题
|
|
|
var params = new URLSearchParams(window.location.search);
|
|
|
|
|
|
if (username) {
|
|
|
}
|
|
|
updateManagementButtonDisplay(userId);
|
|
|
})
|
|
|
|
|
|
fetch('/user-info')
|
|
|
.then(response => {
|
|
|
if (!response.ok) {
|
|
|
throw new Error('未登录');
|
|
|
}
|
|
|
return response.json();
|
|
|
})
|
|
|
.then(data => {
|
|
|
document.getElementById('username1').textContent = data.username;
|
|
|
userId = data.id
|
|
|
username = data.username
|
|
|
updateManagementButtonDisplay(userId);
|
|
|
})
|
|
|
.catch(error => {
|
|
|
alert(error.message);
|
|
|
window.location.href = 'welcome.html';
|
|
|
});
|
|
|
|
|
|
|
|
|
function updateManagementButtonDisplay(userId) {//根据身份设定“后台管理”按钮是否隐藏
|
|
|
if (userId === 'admin') {
|
|
|
document.getElementById('managementBtn').style.display = 'block';
|
|
|
} else {
|
|
|
document.getElementById('managementBtn').style.display = 'none';
|
|
|
}
|
|
|
}
|
|
|
|
|
|
function goBack() {//返回功能,同时也是“不断监测id来决定是否隐藏’后台管理‘按钮”的功能的组成部分
|
|
|
var modules = document.getElementsByClassName('module');
|
|
|
for (var i = 0; i < modules.length; i++) {
|
|
|
modules[i].style.display = 'block';
|
|
|
}
|
|
|
document.getElementById("moduleSelection").style.display = 'block';
|
|
|
document.getElementById("reservation").style.display = 'none';
|
|
|
document.getElementById("management").style.display = 'none';
|
|
|
|
|
|
var params = new URLSearchParams(window.location.search);
|
|
|
updateManagementButtonDisplay(userId);
|
|
|
}
|
|
|
</script>
|
|
|
</body>
|
|
|
|
|
|
</html> |