This commit is contained in:
@@ -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 = '识别失败';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user