Files
FWupdater/win.app/web/firmware_upgrade.html
2025-09-07 11:10:19 +08:00

204 lines
7.1 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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>