增加了进度条,提升等待感知[ci][0.2.4]
All checks were successful
CI / docker-ci (push) Successful in 34s

This commit is contained in:
2025-11-27 12:21:08 +08:00
parent 835426b133
commit 281ade6ac9

View File

@@ -43,17 +43,21 @@
.preview-box h3 {margin-top: 0;color: #334155; } .preview-box h3 {margin-top: 0;color: #334155; }
.preview-box img { max-width: 100%;max-height: 300px;border: 1px solid #e2e8f0;border-radius: 8px;object-fit: contain;} .preview-box img { max-width: 100%;max-height: 300px;border: 1px solid #e2e8f0;border-radius: 8px;object-fit: contain;}
.result-box {flex: 1;} .result-box {flex: 1;}
.result-box h3 { margin-top: 0; color: #334155;} .result-box h3 { margin-top: 0; color: #334155;}
.form-controls { display: flex;gap: 8px;margin-bottom: 12px;flex-wrap: wrap;} .form-controls { display: flex;gap: 8px;margin-bottom: 12px;flex-wrap: wrap;}
#kvForm {border: 1px solid #e2e8f0; border-radius: 8px; padding: 12px; max-height: 300px; overflow: auto;margin-bottom: 12px;background: white;} #kvForm {border: 1px solid #e2e8f0; border-radius: 8px; padding: 12px; max-height: 300px; overflow: auto;margin-bottom: 12px;background: white;}
.form-row {display: grid;grid-template-columns: 1fr 1fr auto;gap: 8px; margin-bottom: 6px; } .form-row {display: grid;grid-template-columns: 1fr 1fr auto;gap: 8px; margin-bottom: 6px; }
.form-row input {padding: 8px;border: 1px solid #cbd5e1;border-radius: 4px;} .form-row input {padding: 8px;border: 1px solid #cbd5e1;border-radius: 4px;}
#resultBox { width: 100%;min-height: 200px;font-family: ui-monospace, SFMono-Regular, Menlo, monospace;font-size: 14px; padding: 12px; border: 1px solid #e2e8f0; #resultBox { width: 100%;min-height: 200px;font-family: ui-monospace, SFMono-Regular, Menlo, monospace;font-size: 14px; padding: 12px; border: 1px solid #e2e8f0;
border-radius: 8px; resize: vertical;box-sizing: border-box; } border-radius: 8px; resize: vertical;box-sizing: border-box; }
.status-message { padding: 10px; margin: 10px 0; border-radius: 6px; display: none; } .status-message { padding: 10px; margin: 10px 0; border-radius: 6px; display: none; }
.status-message.success { background-color: #d4edda; color: #155724; border: 1px solid #c3e6cb; } .status-message.success { background-color: #d4edda; color: #155724; border: 1px solid #c3e6cb; }
.status-message.error { background-color: #f8d7da;color: #721c24; border: 1px solid #f5c6cb; } .status-message.error { background-color: #f8d7da;color: #721c24; border: 1px solid #f5c6cb; }
.action-buttons { margin-top: 16px; display: flex; gap: 8px; flex-wrap: wrap; } .action-buttons { margin-top: 16px; display: flex; gap: 8px; flex-wrap: wrap; }
.progress {position: relative; height: 12px; background: #e2e8f0; border-radius: 8px; overflow: hidden;}
.progress-bar {height: 100%; width: 0; background: linear-gradient(90deg, #4f46e5 0%, #60a5fa 100%); transition: width .2s ease;}
.progress-wrap {display:none; margin-top: 8px;}
.progress-text {margin-top: 6px; font-size: 12px; color: #334155;}
</style> </style>
</head> </head>
<body> <body>
@@ -90,6 +94,10 @@
<button type="submit" class="btn btn-primary">上传并识别</button> <button type="submit" class="btn btn-primary">上传并识别</button>
</form> </form>
<div class="status-message" id="uploadMsg"></div> <div class="status-message" id="uploadMsg"></div>
<div class="progress-wrap" id="progressWrap">
<div class="progress"><div class="progress-bar" id="progressBar"></div></div>
<div class="progress-text" id="progressText"></div>
</div>
</div> </div>
<div class="preview-container"> <div class="preview-container">
@@ -136,9 +144,25 @@ const kvForm = document.getElementById('kvForm');
const addFieldBtn = document.getElementById('addFieldBtn'); const addFieldBtn = document.getElementById('addFieldBtn');
const syncFromTextBtn = document.getElementById('syncFromTextBtn'); const syncFromTextBtn = document.getElementById('syncFromTextBtn');
const dropArea = document.getElementById('dropArea'); const dropArea = document.getElementById('dropArea');
const progressWrap = document.getElementById('progressWrap');
const progressBar = document.getElementById('progressBar');
const progressText = document.getElementById('progressText');
let currentImageRel = ''; let currentImageRel = '';
function setProgress(p, text){
const v = Math.max(0, Math.min(100, Math.round(p||0)));
progressBar.style.width = v + '%';
progressText.textContent = (text||'') + (text? ' ' : '') + v + '%';
}
function showProgress(){
progressWrap.style.display = 'block';
}
function hideProgress(){
progressWrap.style.display = 'none';
setProgress(0, '');
}
async function convertToJpeg(file){ async function convertToJpeg(file){
const url = URL.createObjectURL(file); const url = URL.createObjectURL(file);
let img; let img;
@@ -315,27 +339,39 @@ uploadForm.addEventListener('submit', async (e) => {
return; return;
} }
showProgress();
setProgress(5, '转换为JPG');
let jpegFile = file; let jpegFile = file;
try { try {
jpegFile = await convertToJpeg(file); jpegFile = await convertToJpeg(file);
setProgress(50, '转换为JPG');
preview.src = URL.createObjectURL(jpegFile); preview.src = URL.createObjectURL(jpegFile);
} catch (_) { } catch (_) {
jpegFile = file; jpegFile = file;
setProgress(50, '转换为JPG');
} }
const formData = new FormData(); const formData = new FormData();
formData.append('file', jpegFile); formData.append('file', jpegFile);
try { try {
let prog = 50;
setProgress(prog, '识别中');
const timer = setInterval(() => {
prog = Math.min(95, prog + 1);
setProgress(prog, '识别中');
}, 120);
const resp = await fetch('/elastic/upload/', { const resp = await fetch('/elastic/upload/', {
method: 'POST', method: 'POST',
credentials: 'same-origin', credentials: 'same-origin',
headers: { 'X-CSRFToken': getCookie('csrftoken') || '' }, headers: { 'X-CSRFToken': getCookie('csrftoken') || '' },
body: formData, body: formData,
}); });
clearInterval(timer);
const data = await resp.json(); const data = await resp.json();
if (!resp.ok || data.status !== 'success') { if (!resp.ok || data.status !== 'success') {
throw new Error(data.message || '上传识别失败'); throw new Error(data.message || '上传识别失败');
} }
setProgress(100, '识别完成');
uploadMsg.textContent = data.message || '识别成功'; uploadMsg.textContent = data.message || '识别成功';
uploadMsg.className = 'status-message success'; uploadMsg.className = 'status-message success';
uploadMsg.style.display = 'block'; uploadMsg.style.display = 'block';
@@ -343,10 +379,12 @@ uploadForm.addEventListener('submit', async (e) => {
renderFormFromObject(data.data || {}); renderFormFromObject(data.data || {});
currentImageRel = data.image; currentImageRel = data.image;
confirmBtn.disabled = false; confirmBtn.disabled = false;
setTimeout(hideProgress, 800);
} catch (e) { } catch (e) {
uploadMsg.textContent = e.message || '发生错误'; uploadMsg.textContent = e.message || '发生错误';
uploadMsg.className = 'status-message error'; uploadMsg.className = 'status-message error';
uploadMsg.style.display = 'block'; uploadMsg.style.display = 'block';
progressText.textContent = '识别失败';
} }
}); });