fix(camera): remove post-capture photo revalidation

This commit is contained in:
xsl
2026-10-16 16:01:25 +08:00
parent 6a628f837b
commit 5e07985b19
9 changed files with 54 additions and 67 deletions
+9 -60
View File
@@ -590,62 +590,14 @@
c.width = Math.round(img.width * scale); c.height = Math.round(img.height * scale);
c.getContext('2d').drawImage(img, 0, 0, c.width, c.height);
var url = c.toDataURL('image/jpeg', 0.88);
shutterLock = true; // 校验期间不接受新的拍摄/选图
showCamStatus('照片检查中…');
checkStill(url, CAM_STEPS[step].target, { mode: 'file', ignoreDirection: true, step: step, seq: seq }).then(function (err) {
if (seq !== camSeq || step !== camStep) return; // 期间已退出/重置
hideCamStatus();
shutterLock = false;
if (err) { toast(err); voice.play(VOICE.fail, { cut: true }); return; } // 不合格:停在本步重拍
onPhotoCaptured(url);
});
captureDiagnostics[step] = { mode: IS_MOCK ? 'mock' : 'file', check_stage: 'none', direction_checked: false };
onPhotoCaptured(url);
};
img.onerror = function () { toast('照片读取失败,请重新选择'); };
img.src = reader.result;
};
reader.readAsDataURL(f);
}
// Live final frames and file uploads share all local quality gates. Files may
// be mirrored by the system camera; their side direction remains unverified.
function checkStill(dataUrl, target, options) {
options = options || { mode: 'file', ignoreDirection: true, step: camStep, seq: camSeq };
function remember(sample) { if (options.seq === camSeq) captureDiagnostics[options.step] = sample; }
if (IS_MOCK) { remember({ mode: 'mock' }); return Promise.resolve(''); }
if (!modelsOk || typeof faceapi === 'undefined') {
if (modelsPromise && !options.waited) {
options.waited = true;
return new Promise(function (resolve) {
var timer = setTimeout(resolve, 8000);
modelsPromise.then(function () { clearTimeout(timer); resolve(); }, function () { clearTimeout(timer); resolve(); });
}).then(function () { return checkStill(dataUrl, target, options); });
}
// Keep existing unsupported-device access, explicitly marked for admin.
// Never silently treat an unavailable local engine as a passed check.
remember({ mode: 'unchecked', reason: 'model-unavailable' });
return Promise.resolve('');
}
return new Promise(function (resolve) {
var img = new Image();
img.onload = function () {
faceapi
.detectAllFaces(img, new faceapi.TinyFaceDetectorOptions({ inputSize: DETECT_INPUT_SIZE, scoreThreshold: CaptureQuality.scoreThreshold(target) }))
.withFaceLandmarks()
.then(function (faces) {
var d = faces[0], box = d && d.detection.box;
var verdict = CaptureQuality.evaluate(d, { count: faces.length, target: target,
width: img.naturalWidth, height: img.naturalHeight,
offsetX: box ? (box.x + box.width / 2) / img.naturalWidth - .5 : 0,
luma: box ? faceLuma(box, img) : null,
mirrored: options.mode === 'live' && sideYawFlip, ignoreDirection: options.ignoreDirection });
if (!verdict.ok) { resolve(verdict.hint + ',请重新拍摄'); return; }
remember(Object.assign({ mode: options.mode, direction_checked: !options.ignoreDirection }, verdict.observation));
resolve('');
}, function () { resolve('照片检查失败,请重新拍摄'); });
};
img.onerror = function () { resolve('照片读取失败,请重新选择'); };
img.src = dataUrl;
});
}
function showCamStatus(text) { var s = $('#cam-status'); s.textContent = text; s.classList.add('show'); }
function hideCamStatus() { $('#cam-status').classList.remove('show'); }
// 降级模式:快门调起系统相机,拍完/选完在 change 里推进流程
@@ -1043,7 +995,11 @@
if (holdState.frames === 1) {
okSince = holdState.since;
}
if (held.ready) { okSince = 0; holdState = null; doCapture(); }
if (held.ready) {
// Observations describe the last accepted PREVIEW, not the saved JPEG.
captureDiagnostics[camStep] = Object.assign({ mode: 'live', check_stage: 'preview', direction_checked: true }, verdict.observation);
okSince = 0; holdState = null; doCapture();
}
}
/* ─── 拍照流程(三步,顺序对齐 Figma:正脸 → 右脸出镜 → 左脸出镜) ─── */
@@ -1084,6 +1040,7 @@
// 照片就绪(已通过校验)后推进流程:存图→「拍摄完成」→300ms 过渡→下一步;三步严格按顺序,本步合格才进下一步
function onPhotoCaptured(dataUrl) {
if (!captureDiagnostics[camStep]) captureDiagnostics[camStep] = { mode: IS_MOCK ? 'mock' : 'unchecked', check_stage: 'none', direction_checked: false };
trackCapture(['front', 'right', 'left'][camStep]);
shutterLock = true; // 推进窗口上锁(停顿期间不检测、不接受快门),直到下一步/送检
photos[camStep] = dataUrl;
@@ -1168,15 +1125,7 @@
capturing = false;
if (seq !== camSeq) return; // 期间已退出/重置:不再推进(遮罩仍正常淡出)
if (!shot) { shutterLock = false; okSince = 0; toast('相机尚未就绪,请稍候'); return; } // 重置 okSince:避免陈旧累积立即再抓
var step = camStep;
checkStill(shot, CAM_STEPS[step].target, { mode: 'live', ignoreDirection: false, step: step, seq: seq }).then(function (error) {
if (seq !== camSeq || step !== camStep) return;
if (error) {
shutterLock = false; holdState = null; okSince = 0;
setHint(error, false); armNudge(); return;
}
onPhotoCaptured(shot);
});
onPhotoCaptured(shot); // No second local detection after capture.
}, 300);
}, 300);
}