初始版本
This commit is contained in:
203
firmware_upgrade.html
Normal file
203
firmware_upgrade.html
Normal file
@@ -0,0 +1,203 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>设备固件更新</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Segoe UI', consolas, sans-serif;
|
||||
background: #f4f6fb;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.container {
|
||||
max-width: 90%;
|
||||
min-width: 400px;
|
||||
margin: 30px 30px;
|
||||
background: #fff;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 2px 12px rgba(0,0,0,0.08);
|
||||
padding: 32px 24px 24px 24px;
|
||||
}
|
||||
h2 {
|
||||
text-align: center;
|
||||
color: #2d3a4b;
|
||||
}
|
||||
.form-group {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
label {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
color: #4a5a6a;
|
||||
}
|
||||
input[type="file"] {
|
||||
width: 100%;
|
||||
}
|
||||
input[type="text"], textarea {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
padding: 10px;
|
||||
border: 1px solid #d1d5db;
|
||||
border-radius: 4px;
|
||||
font-size: 10px;
|
||||
}
|
||||
button {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
background: #3b82f6;
|
||||
color: #fff;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
button:disabled {
|
||||
background: #a5b4fc;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
.progress-bar {
|
||||
width: 100%;
|
||||
background: #e5e7eb;
|
||||
border-radius: 4px;
|
||||
height: 18px;
|
||||
margin-top: 12px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.progress {
|
||||
height: 100%;
|
||||
background: #16a34a;
|
||||
width: 0%;
|
||||
transition: width 0.3s;
|
||||
}
|
||||
.status {
|
||||
margin-top: 10px;
|
||||
text-align: center;
|
||||
color: #16a34a;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h2>设备固件更新</h2>
|
||||
<div class="form-group">
|
||||
<label for="firmwareFile">选择固件文件</label>
|
||||
<input type="file" id="firmwareFile" accept=".bin,.hex,.img">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="version">固件版本信息</label>
|
||||
<textarea id="version" readonly style="background:#f3f4f6;height:100px;resize:vertical;"></textarea>
|
||||
</div>
|
||||
<button id="uploadBtn" disabled>升级</button>
|
||||
<div class="progress-bar" id="progressBar">
|
||||
<div class="progress" id="progress"></div>
|
||||
</div>
|
||||
<div class="status" id="status"></div>
|
||||
</div>
|
||||
<script>
|
||||
// 页面加载时获取版本信息并设置为placeholder
|
||||
window.addEventListener('DOMContentLoaded', function() {
|
||||
fetch('/api/version_info').then(res => {
|
||||
if (!res.ok) throw new Error('获取版本信息失败');
|
||||
return res.text();
|
||||
}).then(text => {
|
||||
versionInput.placeholder = text;
|
||||
}).catch(() => {
|
||||
versionInput.placeholder = '获取版本信息失败';
|
||||
});
|
||||
});
|
||||
const firmwareFile = document.getElementById('firmwareFile');
|
||||
const versionInput = document.getElementById('version');
|
||||
const uploadBtn = document.getElementById('uploadBtn');
|
||||
const progress = document.getElementById('progress');
|
||||
const status = document.getElementById('status');
|
||||
|
||||
function checkEnable() {
|
||||
uploadBtn.disabled = !(firmwareFile.files.length > 0 && versionInput.value.trim() !== '');
|
||||
}
|
||||
|
||||
|
||||
firmwareFile.addEventListener('change', function() {
|
||||
checkEnable();
|
||||
const file = firmwareFile.files[0];
|
||||
if (file) {
|
||||
const reader = new FileReader();
|
||||
const bytesToRead = 256;
|
||||
const blob = file.slice(0, bytesToRead);
|
||||
reader.onload = function(e) {
|
||||
let text = '';
|
||||
try {
|
||||
// 优先用utf-8解码,支持中英文混合
|
||||
text = new TextDecoder('utf-8').decode(new Uint8Array(e.target.result));
|
||||
} catch (err) {
|
||||
try {
|
||||
text = new TextDecoder('gb18030').decode(new Uint8Array(e.target.result));
|
||||
} catch (err2) {
|
||||
// fallback: latin1
|
||||
text = new TextDecoder('latin1').decode(new Uint8Array(e.target.result));
|
||||
}
|
||||
}
|
||||
// 处理换行(\r\n/\r/\n)
|
||||
text = text.replace(/\r\n|\r|\n/g, '\n');
|
||||
versionInput.value = text;
|
||||
checkEnable();
|
||||
};
|
||||
reader.readAsArrayBuffer(blob);
|
||||
} else {
|
||||
versionInput.value = '';
|
||||
}
|
||||
});
|
||||
versionInput.addEventListener('input', checkEnable);
|
||||
|
||||
uploadBtn.addEventListener('click', function() {
|
||||
uploadBtn.disabled = true;
|
||||
status.textContent = '';
|
||||
progress.style.width = '0%';
|
||||
const file = firmwareFile.files[0];
|
||||
if (!file) {
|
||||
status.textContent = '未选择固件文件';
|
||||
uploadBtn.disabled = false;
|
||||
return;
|
||||
}
|
||||
const chunkSize = 128;
|
||||
const totalChunks = Math.ceil(file.size / chunkSize);
|
||||
let currentChunk = 0;
|
||||
|
||||
function sendChunk() {
|
||||
if (currentChunk >= totalChunks) {
|
||||
status.textContent = '升级完成!';
|
||||
uploadBtn.disabled = false;
|
||||
progress.style.width = '100%';
|
||||
return;
|
||||
}
|
||||
const start = currentChunk * chunkSize;
|
||||
const end = Math.min(file.size, start + chunkSize);
|
||||
const chunk = file.slice(start, end);
|
||||
const formData = new FormData();
|
||||
formData.append('chunk', chunk);
|
||||
formData.append('index', currentChunk);
|
||||
formData.append('total', totalChunks);
|
||||
// 可根据后端实际接口调整URL和参数
|
||||
fetch('/api/upload_firmware', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
}).then(res => {
|
||||
if (!res.ok) throw new Error('网络错误');
|
||||
return res.text();
|
||||
}).then(() => {
|
||||
currentChunk++;
|
||||
progress.style.width = ((currentChunk / totalChunks) * 100) + '%';
|
||||
status.textContent = `正在升级:${currentChunk}/${totalChunks}`;
|
||||
sendChunk();
|
||||
}).catch(err => {
|
||||
status.textContent = '升级失败: ' + err.message;
|
||||
uploadBtn.disabled = false;
|
||||
});
|
||||
}
|
||||
sendChunk();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
Reference in New Issue
Block a user