HanvonAttendanceService/device-api-dump/loglist.html

392 lines
12 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Log File Browser</title>
<script src="resources/plugins/jquery.1.12.4.min.js"></script>
<script src="resources/plugins/bootstrap-3.3.0/js/bootstrap.min.js"></script>
<script src="resources/plugins/waves-0.7.5/waves.min.js"></script>
<script src="resources/plugins/jquery.cookie.js"></script>
<script src="resources/js/notify.js"></script>
<script src="resources/js/common.js"></script>
<script src="resources/js/lang.js"></script>
<style>
* {
box-sizing: border-box;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
body {
margin: 0 auto;
padding: 20px;
background-color: #f5f7fa;
color: #333;
}
header {
display: flex;
align-items: center;
margin-bottom: 20px;
padding-bottom: 15px;
border-bottom: 1px solid #e0e6ed;
}
h1 {
margin: 0;
font-size: 24px;
color: #2c3e50;
flex-grow: 1;
}
.btn {
padding: 8px 16px;
background-color: #3498db;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
transition: background-color 0.2s;
}
.btn:hover {
background-color: #2980b9;
}
.btn.back {
background-color: #7f8c8d;
}
.btn.back:hover {
background-color: #34495e;
}
#file-list {
background: white;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.05);
overflow: hidden;
}
.list-header {
padding: 12px 20px;
background-color: #3498db;
color: white;
font-weight: bold;
display: grid;
grid-template-columns: 1fr 100px;
}
.file-item {
padding: 12px 20px;
border-bottom: 1px solid #eee;
display: grid;
grid-template-columns: 1fr 100px;
cursor: pointer;
transition: background-color 0.2s;
}
.file-item:hover {
background-color: #f8f9fa;
}
.file-name {
font-weight: 500;
color: #2c3e50;
word-break: break-all;
}
.file-size {
color: #7f8c8d;
text-align: right;
font-size: 0.9em;
}
#file-content {
background: white;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.05);
padding: 20px;
margin-top: 20px;
display: none;
}
.content-header {
display: flex;
align-items: center;
margin-bottom: 15px;
padding-bottom: 10px;
border-bottom: 1px solid #eee;
}
#content-title {
margin: 0;
font-size: 20px;
color: #2c3e50;
flex-grow: 1;
word-break: break-all;
}
#file-text {
white-space: pre-wrap;
font-family: monospace;
font-size: 14px;
line-height: 1.5;
background-color: #f8f9fa;
padding: 15px;
border-radius: 4px;
max-height: 60vh;
overflow: auto;
}
.empty-message {
text-align: center;
padding: 40px 20px;
color: #7f8c8d;
}
.loading {
padding: 20px;
text-align: center;
color: #7f8c8d;
}
.content-header {
display: flex;
gap: 16px; /* 控制按钮间距,按需调整 */
}
/* 新增网格布局样式 */
#list-container {
display: grid;
grid-template-columns: repeat(5, 1fr); /* 一行4列 */
gap: 16px; /* 项目间距 */
padding: 16px;
}
.file-item {
background: white;
border: 1px solid #e0e6ed;
border-radius: 8px;
padding: 12px;
cursor: pointer;
transition: all 0.3s ease;
overflow: hidden; /* 防止内容溢出 */
text-overflow: ellipsis;
}
.file-item:hover {
box-shadow: 0 4px 12px rgba(0,0,0,0.08);
transform: translateY(-2px);
border-color: #3498db;
}
.file-name {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-size: 14px;
}
/* 响应式适配 */
@media (max-width: 1200px) {
#list-container {
grid-template-columns: repeat(3, 1fr); /* 中等屏幕显示3列 */
}
}
@media (max-width: 768px) {
#list-container {
grid-template-columns: repeat(2, 1fr); /* 小屏幕显示2列 */
}
}
@media (max-width: 480px) {
#list-container {
grid-template-columns: 1fr; /* 超小屏幕显示1列 */
}
}
</style>
</head>
<body>
<header>
<h1>Log File Browser</h1>
<button id="refresh-btn" class="btn">Refresh list</button>
</header>
<div id="file-list">
<div class="list-header">
<span>file name</span>
</div>
<div id="list-container">
<div class="loading">Loading file list...</div>
</div>
</div>
<div id="file-content">
<div class="content-header">
<h2 id="content-title"></h2>
<button id="copy-btn" class="btn">Copy</button>
<button id="back-btn" class="btn back">Return to list</button>
</div>
<pre id="file-text"></pre>
</div>
<script>
check_permission();
const listContainer = document.getElementById('list-container');
const fileContent = document.getElementById('file-content');
const contentTitle = document.getElementById('content-title');
const fileText = document.getElementById('file-text');
const refreshBtn = document.getElementById('refresh-btn');
const backBtn = document.getElementById('back-btn');
// 获取日志文件列表适配新版后端API
async function loglist_get() {
const payload = {
password: $.cookie("pwd"),
cmd: 'getdir',
path: '/data/log'
};
try {
const response = await $.ajax({
url: debugserver + '/api',
type: 'POST',
contentType: "application/json",
dataType: "json",
data: JSON.stringify(payload)
});
// 转换后端数据结构为前端需要的格式
return {
status: response.result ? 'success' : 'error',
files: response.files.map(filename => ({ name: filename }))
};
} catch (error) {
console.error("API request failed:", error);
return {
status: 'error',
message: 'Failed to obtain file list'
};
}
}
async function renderFileList() {
listContainer.innerHTML = '<div class="loading">Loading file list...</div>';
const result = await loglist_get();
if (result.status === 'success' && result.files && result.files.length > 0) {
// 按文件名中的时间戳倒序排序(新文件在前)
result.files.sort((a, b) => {
// 提取文件名中的时间戳格式如20250731-15-36-55.log
const timestampA = a.name.split('.')[0]; // 去掉后缀
const timestampB = b.name.split('.')[0];
// 按字符串倒序排列(新文件在前)
return timestampB.localeCompare(timestampA);
});
let listHTML = '';
result.files.forEach(file => {
listHTML += `
<div class="file-item" data-filename="${file.name}">
<div class="file-name">${file.name}</div>
</div>
`;
});
listContainer.innerHTML = listHTML;
// 添加点击事件处理(保持不变)
document.querySelectorAll('.file-item').forEach(item => {
item.addEventListener('click', async () => {
const filename = item.dataset.filename;
await showFileContent(filename);
});
});
} else {
const errorMsg = result.message || 'Log file not found';
listContainer.innerHTML = `<div class="empty-message">${errorMsg}</div>`;
}
}
// 获取文件内容连接真实API
async function fetchFileContent(filename) {
const payload = {
password: $.cookie("pwd"),
cmd: 'getfile',
path: '/data/log/'+filename
};
try {
const response = await $.ajax({
url: debugserver + '/api',
type: 'POST',
contentType: "application/json",
dataType: "json",
data: JSON.stringify(payload)
});
return {
status: response.result ? 'success' : 'error',
file: response.base64
};
} catch (error) {
console.error("API request failed:", error);
return {
status: 'error',
message: 'Failed to getfile'
};
}
}
async function showFileContent(filename) {
fileContent.style.display = 'block';
contentTitle.textContent = filename;
fileText.textContent = 'loading...';
const result=await fetchFileContent(filename);
if (result.status === 'success')
{
const base64Data = result.file;
const binaryString = atob(base64Data);
const bytes = new Uint8Array(binaryString.length);
for (let i = 0; i < binaryString.length; i++) {
bytes[i] = binaryString.charCodeAt(i);
}
const decoder = new TextDecoder('utf-8');
const utf8Text = decoder.decode(bytes);
fileText.textContent = utf8Text;
}
else
fileText.textContent = `error: ${result.message || 'Unknown error'}`;
fileContent.scrollIntoView({ behavior: 'smooth' });
}
// 返回文件列表
function backToList() {
fileContent.style.display = 'none';
document.querySelector('header').scrollIntoView({ behavior: 'smooth' });
}
// 事件监听
refreshBtn.addEventListener('click', renderFileList);
backBtn.addEventListener('click', backToList);
// 初始化
document.addEventListener('DOMContentLoaded', renderFileList);
// 在JS中添加以下代码
// 获取复制按钮DOM
const copyBtn = document.getElementById('copy-btn');
// 复制功能实现
async function copyFileContent() {
const content = fileText.innerText;
try {
// 现代浏览器方案Clipboard API
if (navigator.clipboard) {
await navigator.clipboard.writeText(content);
notify('Copied to clipboard!');
return;
}
// 兼容旧浏览器的回退方案
const textarea = document.createElement('textarea');
textarea.value = content;
textarea.setAttribute('readonly', '');
textarea.style.position = 'absolute';
textarea.style.left = '-9999px';
document.body.appendChild(textarea);
// 选择并复制
textarea.select();
document.execCommand('copy');
document.body.removeChild(textarea);
notify('Copied!');
} catch (err) {
console.error('Copy failed:', err);
notify('Copy failed! Please copy manually');
}
}
// 事件绑定在DOMContentLoaded或初始化时添加
copyBtn.addEventListener('click', copyFileContent);
</script>
</body>
</html>