diff --git a/scanner/pages/emblemscanner/emblemscanner.js b/scanner/pages/emblemscanner/emblemscanner.js index 2d14dc8..002418d 100644 --- a/scanner/pages/emblemscanner/emblemscanner.js +++ b/scanner/pages/emblemscanner/emblemscanner.js @@ -36,7 +36,8 @@ const { // Import upload functionality for verification (self-contained) const { - upload_image_data_urls + upload_image_data_urls, + check_auto_torch } = require('./upload.js'); // Import precheck utilities for image processing @@ -65,8 +66,6 @@ Page({ show_tip: false, show_modal: '', busy: true, - should_check_auto_torch: true, - done_checking_auto_torch: false, camera_sensitivity: 1, qrarc_class: 'sm', qrmarkers_class: 'hidden', @@ -92,9 +91,8 @@ Page({ use_web_view: false, use_worker: false, emblem_camera_url: null, - first_qr_found: false, // Track if first QR has been detected to trigger zoom-in - // State machine: loading_rules -> loading_qrtool -> init_camera -> scanning -> verifying -> result - app_state: 'loading_rules', // 'loading_rules', 'loading_qrtool', 'init_camera', 'scanning', 'webview_scanning', 'verifying', 'result' + // State machine: loading_rules -> loading_qrtool -> init_camera -> qr_detecting -> check_auto_torch -> final_scanning -> verifying -> result + app_state: 'loading_rules', // 'loading_rules', 'loading_qrtool', 'init_camera', 'qr_detecting', 'webview_scanning', 'check_auto_torch', 'final_scanning', 'verifying', 'result' scan_mode: 'unknown', // 'camera', 'webview' no_web_view: false, // Override web-view rule, force native camera worker_processing: false, // Track if worker is currently processing a frame @@ -103,27 +101,16 @@ Page({ onLoad(options) { console.log('QR Scanner module loaded', options); - + + // Store page options for use in onShow + this.pageOptions = options || {}; + const no_web_view = options.no_web_view === '1' || options.no_web_view === 'true'; - + this.setData({ return_page: options.return_page || '/pages/test_result_page/test_result_page', no_web_view: no_web_view }); - - // Initialize image collection for verification - this.image_data_urls = []; - - options = options || {}; - const enable_debug = options.debug || options.scene == 'debug' || false; - - // Step 1: Initialize system and get phone model - this.initializeSystem(enable_debug); - this.fetchRealIP(); - this.fetchTenantID(); - - // Step 2: Load camera rules based on phone model - this.loadCameraRules(); }, fetchRealIP() { @@ -169,10 +156,6 @@ Page({ console.log(`Phone model: ${phone_model}, Use worker: ${use_worker}`); - // Set up worker if needed (like camera.js) - if (use_worker) { - this.setupWorker(); - } }, /** @@ -180,11 +163,11 @@ Page({ */ setupWorker() { // Create worker with local worker file - this.worker = wx.createWorker('/pages/emblemscanner/worker/index.js', { + var worker = wx.createWorker('/pages/emblemscanner/worker/index.js', { useExperimentalWorker: true, }); - this.worker.onMessage((msg) => { + worker.onMessage((msg) => { console.log('Worker message:', msg.type); if (msg.type === "result") { @@ -215,15 +198,22 @@ Page({ // For worker, we need to trigger image collection when we find a good QR if (result.qrcode && is_emblem_qr_pattern(result.qrcode)) { this.addDebugMessage(`Worker QR detected: ${result.qrcode}`); - - // Trigger zoom-in if function is set up - if (this.on_first_qr_found && !this.data.first_qr_found) { - this.on_first_qr_found(); + + // Check auto-torch on first valid QR detection (only when in QR detecting state) + if (this.data.app_state === 'qr_detecting') { + this.startCheckingAutoTorch(result.qrcode); + + // Trigger zoom-in if function is set up + if (this.on_first_qr_found) { + this.on_first_qr_found(); + } + + return; // Exit early, auto-torch check will return to final_scanning } - - if (result.ok) { + + if (this.data.app_state === 'final_scanning' && result.ok) { // Request worker to submit image data - this.worker.postMessage({ type: "ready_to_submit" }); + this.get_worker().postMessage({ type: "ready_to_submit" }); } } @@ -260,6 +250,7 @@ Page({ }); this.addDebugMessage('Worker set up for iPhone processing'); + return worker; }, loadCameraRules(max_zoom = null) { @@ -328,10 +319,8 @@ Page({ onCameraError(e) { console.error('Camera error', e); this.addDebugMessage(`Camera error: ${JSON.stringify(e.detail)}`); - this.setData({ - show_modal: 'verifyfailed', - hint_text: '相机初始化失败' - }); + // Redirect with failure instead of showing modal + this.goToResult(null, null, false); }, toggle_torch() { @@ -342,6 +331,7 @@ Page({ console.log('Torch toggled to:', newFlash); }, + show_scanguide() { this.setData({ show_modal: 'scanguide', @@ -405,7 +395,6 @@ Page({ // Set up zoom-in behavior when QR is found this.on_first_qr_found = () => { - this.setData({ first_qr_found: true }); this.addDebugMessage(`First QR found, zoom to ${zoom}x`); this.camera_context.setZoom({ zoom: zoom }); this.setData({ @@ -441,11 +430,11 @@ Page({ }, /** - * State: Init Camera -> Scanning (Camera) + * State: Init Camera -> QR Detecting (Camera) * Also starts frame processing since all conditions are implied to be ready */ startCameraScanning() { - this.transitionToState('scanning', 'camera'); + this.transitionToState('qr_detecting', 'camera'); this.setData({ hint_text: '查找二维码', busy: false @@ -461,21 +450,10 @@ Page({ }); // Start the listener with worker if using worker mode - if (this.data.use_worker) { - if (!this.worker) { - this.addDebugMessage('Worker not found, cannot start listener'); - this.setData({ - show_modal: 'verifyfailed', - hint_text: '工作线程初始化失败' - }); - return; - } - this.listener.start({ - worker: this.worker - }); - } else { - this.listener.start(); - } + var worker = this.get_worker(); + this.listener.start({ + worker, + }); }, @@ -483,8 +461,8 @@ Page({ * Camera frame callback - receives live camera frames */ onCameraFrame(frame) { - // Only process frames when in camera scanning state - if (this.data.app_state !== 'scanning') { + // Only process frames when in QR detecting or final scanning states + if (this.data.app_state !== 'qr_detecting' && this.data.app_state !== 'final_scanning') { return; } @@ -499,7 +477,7 @@ Page({ this.lastFrameTime = now; // Use worker for iPhone, direct processing for other devices - if (this.data.use_worker && this.worker) { + if (this.data.use_worker) { // Skip if worker is already processing a frame if (this.data.worker_processing) { this.setData({ @@ -524,7 +502,7 @@ Page({ // Set processing flag before sending message this.setData({ worker_processing: true }); - this.worker.postMessage({ + this.get_worker().postMessage({ type: 'frame', width: frame.width, height: frame.height, @@ -623,19 +601,26 @@ Page({ // zooming in so that it's more likely to be clear enough for upload if (result.qrcode && is_emblem_qr_pattern(result.qrcode)) { this.addDebugMessage(`QR detected: ${result.qrcode} ok: ${result.ok}: err ${result.err}`); - - // Trigger zoom-in if function is set up - if (!this.data.first_qr_found && this.on_first_qr_found) { - this.on_first_qr_found(); + + // Check auto-torch on first valid QR detection (only when in QR detecting state) + if (this.data.app_state === 'qr_detecting') { + this.startCheckingAutoTorch(result.qrcode); + + // Trigger zoom-in if function is set up + if (this.on_first_qr_found) { + this.on_first_qr_found(); + } + + return; // Exit early, auto-torch check will return to final_scanning state } - - if (result.ok) { + + if (this.data.app_state === 'final_scanning' && result.ok) { this.onQRCodeDetected(result.qrcode, frame, copiedFrameData); // Pass the copied frame data } } else { // Update hint for user guidance this.setData({ hint_text: hint }); - + if (result.qrcode) { this.addDebugMessage(`QR found but not valid: ${result.qrcode} (${result.err})`); } @@ -699,22 +684,28 @@ Page({ getApp().globalData.verify_resp = resp; if (resp.serial_code) { - // Let verification animation run for a bit, then show result + // Let verification animation run for a bit, then redirect with success const delay = 3000 - (Date.now() - begin); setTimeout(() => { - this.goToResult(qrCode, resp.serial_code); + this.goToResult(qrCode, resp.serial_code, true); }, delay > 0 ? delay : 0); } else { - this.showVerifyFailed(); + // Redirect with failure instead of showing modal + const delay = 3000 - (Date.now() - begin); + setTimeout(() => { + this.goToResult(qrCode, null, false); + }, delay > 0 ? delay : 0); } } else { - this.showVerifyFailed(); + // Redirect with failure instead of showing modal + this.goToResult(qrCode, null, false); } }; const fail = (e) => { this.addDebugMessage(`Upload failed: ${JSON.stringify(e)}`); - this.showVerifyFailed(); + // Redirect with failure instead of showing modal + this.goToResult(qrCode, null, false); }; // Store global data like camera.js @@ -725,15 +716,6 @@ Page({ upload_image_data_urls(dataUrls, success, fail, "emblemscanner verification"); }, - /** - * Show verification failed modal - */ - showVerifyFailed() { - this.setData({ - show_modal: 'verifyfailed', - hint_text: '验证失败' - }); - }, /** * State: Loading Rules -> Webview Scanning @@ -747,7 +729,40 @@ Page({ }, /** - * State: Scanning -> Verifying (only for camera mode) + * State: QR Detecting -> Check Auto-torch + */ + startCheckingAutoTorch(qrcode) { + this.transitionToState('check_auto_torch'); + this.setData({ + hint_text: '检查补光设置...' + }); + + check_auto_torch(qrcode, (auto_torch, camera_sensitivity) => { + this.addDebugMessage(`Auto-torch check: ${auto_torch}, sensitivity: ${camera_sensitivity}`); + + if (auto_torch) { + this.setData({ + camera_flash: 'torch' + }); + this.addDebugMessage('Auto-torch enabled'); + } + + // Update camera sensitivity and continue scanning + this.setData({ + camera_sensitivity: camera_sensitivity || this.data.camera_sensitivity + }); + + // Transition to final_scanning state (ready to collect frames for verification) + this.transitionToState('final_scanning'); + this.setData({ + hint_text: '查找二维码' + }); + }); + }, + + + /** + * State: Final Scanning -> Verifying (show spinner while waiting for backend) */ startVerifying() { this.transitionToState('verifying'); @@ -768,13 +783,22 @@ Page({ /** * State: Any -> Result (jump to return page) */ - goToResult(qrCode, serialCode) { + goToResult(qrCode, serialCode, success = true) { this.transitionToState('result'); - - // Pass both qr_code and serial_code parameters like camera-5.1 does - // serialCode comes from server verification response - const url = `${this.data.return_page}?qr_code=${encodeURIComponent(qrCode)}&serial_code=${encodeURIComponent(serialCode)}`; - + + // Always redirect to return_page, pass ok=1 for success, ok=0 for failure + // Only pass qr_code and serial_code if ok=1 (success) + let url; + if (success && qrCode) { + if (serialCode) { + url = `${this.data.return_page}?ok=1&qr_code=${encodeURIComponent(qrCode)}&serial_code=${encodeURIComponent(serialCode)}`; + } else { + url = `${this.data.return_page}?ok=1&qr_code=${encodeURIComponent(qrCode)}`; + } + } else { + url = `${this.data.return_page}?ok=0`; + } + wx.redirectTo({ url: url, success: () => { @@ -806,8 +830,7 @@ Page({ ok_frames: 0, total_processing_time: 0, avg_processing_time_ms: 0, - last_frame_time_ms: 0, - first_qr_found: false + last_frame_time_ms: 0 }); // Reset frame timing @@ -865,12 +888,11 @@ Page({ const messageData = e.detail.data[0]; if (messageData.qr_code) { // Web-view results go directly to result (no verification step) - this.goToResult(messageData.qr_code); + this.goToResult(messageData.qr_code, messageData.serial_code, true); } else if (messageData.error) { this.addDebugMessage(`Web-view error: ${messageData.error}`); - this.setData({ - hint_text: '识别失败' - }); + // Redirect with failure instead of showing hint + this.goToResult(null, null, false); } } }, @@ -882,10 +904,49 @@ Page({ return is_emblem_qr_pattern(qrCode); }, + /** + * Lifecycle - page show + */ + onShow() { + console.log('EmblemScanner page shown - initializing'); + + // Reset state machine to initial state + this.setData({ + app_state: 'loading_rules', + scan_mode: 'unknown', + busy: true, + hint_text: '查找二维码', + show_modal: '', + worker_processing: false, + verifying_stage: 0, + // Reset frame processing statistics + frames_processed: 0, + frames_skipped: 0, + ok_frames: 0, + total_processing_time: 0, + avg_processing_time_ms: 0, + last_frame_time_ms: 0 + }); + + // Initialize image collection for verification + this.image_data_urls = []; + + const enable_debug = this.pageOptions.debug || this.pageOptions.scene == 'debug' || false; + + // Step 1: Initialize system and get phone model + this.initializeSystem(enable_debug); + this.fetchRealIP(); + this.fetchTenantID(); + + // Step 2: Load camera rules based on phone model + this.loadCameraRules(); + }, + /** * Lifecycle - page hide */ onHide() { + console.log('EmblemScanner page hidden - cleaning up'); this.cleanupListener(); }, @@ -905,6 +966,14 @@ Page({ this.listener = null; this.addDebugMessage('Camera frame listener stopped'); } + }, + + get_worker() { + var gd = getApp().globalData; + if (!gd.emblemscanner_worker) { + gd.emblemscanner_worker = this.setupWorker(); + } + return gd.emblemscanner_worker; } }); \ No newline at end of file diff --git a/scanner/pages/emblemscanner/emblemscanner.wxml b/scanner/pages/emblemscanner/emblemscanner.wxml index 475dbc3..d32e936 100644 --- a/scanner/pages/emblemscanner/emblemscanner.wxml +++ b/scanner/pages/emblemscanner/emblemscanner.wxml @@ -30,8 +30,8 @@ - - + + @@ -145,8 +145,8 @@ - - + + @@ -183,7 +183,7 @@ - + @@ -193,15 +193,6 @@ - - - - 验证失败 - - - - -