From adb87f27b5faf0313a11d114057b13865a0d5efd Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Sat, 13 Sep 2025 21:31:05 +0100 Subject: [PATCH] emblemscanner: native wasm works --- scanner/CLAUDE.md | 3 +- scanner/app.json | 5 +- scanner/pages/camera/camera.js | 4 +- scanner/pages/camwebview/camwebview.js | 99 ------- scanner/pages/camwebview/camwebview.wxml | 1 - scanner/pages/camwebview/camwebview.wxss | 1 - scanner/pages/debugentry/debugentry.js | 72 ----- scanner/pages/debugentry/debugentry.json | 3 - scanner/pages/debugentry/debugentry.wxml | 1 - scanner/pages/debugentry/debugentry.wxss | 1 - scanner/pages/debuguploaded/debuguploaded.js | 67 ----- .../pages/debuguploaded/debuguploaded.json | 3 - .../pages/debuguploaded/debuguploaded.wxml | 7 - .../pages/debuguploaded/debuguploaded.wxss | 13 - scanner/pages/emblemscanner/emblemscanner.js | 255 ++++++++++++++---- .../pages/emblemscanner/emblemscanner.wxml | 48 ++-- scanner/pages/emblemscanner/qrprocessor.js | 25 -- scanner/pages/emblemscanner/upload.js | 71 +++++ scanner/pages/index/index.js | 4 +- .../test.js => productinfo/productinfo.js} | 15 +- .../productinfo.json} | 0 scanner/pages/productinfo/productinfo.wxml | 1 + scanner/pages/productinfo/productinfo.wxss | 1 + scanner/pages/test/test.json | 8 - scanner/pages/test/test.wxml | 2 - scanner/pages/test/test.wxss | 0 scanner/utils.js | 22 +- 27 files changed, 333 insertions(+), 399 deletions(-) delete mode 100644 scanner/pages/camwebview/camwebview.js delete mode 100644 scanner/pages/camwebview/camwebview.wxml delete mode 100644 scanner/pages/camwebview/camwebview.wxss delete mode 100644 scanner/pages/debugentry/debugentry.js delete mode 100644 scanner/pages/debugentry/debugentry.json delete mode 100644 scanner/pages/debugentry/debugentry.wxml delete mode 100644 scanner/pages/debugentry/debugentry.wxss delete mode 100644 scanner/pages/debuguploaded/debuguploaded.js delete mode 100644 scanner/pages/debuguploaded/debuguploaded.json delete mode 100644 scanner/pages/debuguploaded/debuguploaded.wxml delete mode 100644 scanner/pages/debuguploaded/debuguploaded.wxss create mode 100644 scanner/pages/emblemscanner/upload.js rename scanner/pages/{test/test.js => productinfo/productinfo.js} (77%) rename scanner/pages/{camwebview/camwebview.json => productinfo/productinfo.json} (100%) create mode 100644 scanner/pages/productinfo/productinfo.wxml create mode 100644 scanner/pages/productinfo/productinfo.wxss delete mode 100644 scanner/pages/test/test.json delete mode 100644 scanner/pages/test/test.wxml delete mode 100644 scanner/pages/test/test.wxss diff --git a/scanner/CLAUDE.md b/scanner/CLAUDE.md index b7f17c8..f2b72b8 100644 --- a/scanner/CLAUDE.md +++ b/scanner/CLAUDE.md @@ -19,7 +19,8 @@ This is a WeChat Mini Program called "徵象" (emblem-scanner) for QR code scann **Key Components:** - Camera system with device-specific zoom rules fetched from API - WebAssembly-based QR processing in worker thread for performance -- Dual camera modes: native camera (`pages/camera/`) and web view (`pages/camwebview/`) +- New emblemscanner (`pages/emblemscanner/`) for unified QR scanning experience +- Legacy camera page (`pages/camera/`) kept for reference to worker integration - Upload and verification system connecting to themblem.com API **Global Data:** diff --git a/scanner/app.json b/scanner/app.json index 20fc997..5b88f17 100644 --- a/scanner/app.json +++ b/scanner/app.json @@ -3,12 +3,9 @@ "pages/index/index", "pages/camera/camera", "pages/emblemscanner/emblemscanner", + "pages/productinfo/productinfo", "pages/test_result_page/test_result_page", - "pages/debugentry/debugentry", - "pages/debuguploaded/debuguploaded", - "pages/camwebview/camwebview", "pages/camentry/camentry", - "pages/test/test", "pages/article/article", "pages/nav/nav", "pages/chat/chat", diff --git a/scanner/pages/camera/camera.js b/scanner/pages/camera/camera.js index f6a1742..4f1d45d 100644 --- a/scanner/pages/camera/camera.js +++ b/scanner/pages/camera/camera.js @@ -274,8 +274,8 @@ Page({ // this is from the debug backend sigifying the upload has succeeded // we have no product info to show here because "ok" is the only returned information // just show a temporary page - info("redirecting to debuguploaded"); - wx.redirectTo({ url: '/pages/debuguploaded/debuguploaded' }) + info("redirecting to test result page"); + wx.redirectTo({ url: '/pages/test_result_page/test_result_page?qr_code=' + encodeURIComponent(upload_result.qr_code || 'unknown') }) } else { this.show_verifyfailed(); } diff --git a/scanner/pages/camwebview/camwebview.js b/scanner/pages/camwebview/camwebview.js deleted file mode 100644 index d533063..0000000 --- a/scanner/pages/camwebview/camwebview.js +++ /dev/null @@ -1,99 +0,0 @@ -// pages/camwebview/camwebview.js - -import { - get_camera_rule, - get_phone_model, -} from '../../utils.js' - -function make_query(zoom, ai_chat_mode) { - var gd = getApp().globalData; - var ret = "zoom=" + zoom; - var ui = wx.getStorageSync('userinfo'); - ret += "&phonemodel=" + encodeURIComponent(get_phone_model()); - ret += "&realip=" + (gd.real_ip || ""); - ret += "&emblem_id=" + (ui.emblem_id || ""); - ret += "&nick_name=" + encodeURIComponent(ui.nickName || ""); - ret += "&tenant=" + (gd.tenant_id || ""); - ret += "&tk=" + Date.now(); - if (ai_chat_mode) { - ret += "&ai_chat_mode=" + ai_chat_mode; - } - console.log(ret); - return ret; -} - -Page({ - - /** - * 页面的初始数据 - */ - data: { - emblem_camera_url: null, - }, - - /** - * 生命周期函数--监听页面加载 - */ - onLoad(options) { - var ai_chat_mode = options.ai_chat_mode; - get_camera_rule(null, (rule) => { - // we should have rules loaded, so this is effectively sync, before instantiating Page - var zoom = rule.zoom; - this.setData({ - emblem_camera_url: "https://themblem.com/camera-5.0/?" + make_query(zoom, ai_chat_mode), - }); - }) - }, - - /** - * 生命周期函数--监听页面初次渲染完成 - */ - onReady() { - - }, - - /** - * 生命周期函数--监听页面显示 - */ - onShow() { - - }, - - /** - * 生命周期函数--监听页面隐藏 - */ - onHide() { - - }, - - /** - * 生命周期函数--监听页面卸载 - */ - onUnload() { - - }, - - /** - * 页面相关事件处理函数--监听用户下拉动作 - */ - onPullDownRefresh() { - - }, - - /** - * 页面上拉触底事件的处理函数 - */ - onReachBottom() { - - }, - - /** - * 用户点击右上角分享 - */ - onShareAppMessage() { - - }, - - on_message(e) { - } -}) diff --git a/scanner/pages/camwebview/camwebview.wxml b/scanner/pages/camwebview/camwebview.wxml deleted file mode 100644 index 318e85d..0000000 --- a/scanner/pages/camwebview/camwebview.wxml +++ /dev/null @@ -1 +0,0 @@ - diff --git a/scanner/pages/camwebview/camwebview.wxss b/scanner/pages/camwebview/camwebview.wxss deleted file mode 100644 index f8a8e54..0000000 --- a/scanner/pages/camwebview/camwebview.wxss +++ /dev/null @@ -1 +0,0 @@ -/* pages/camwebview/camwebview.wxss */ \ No newline at end of file diff --git a/scanner/pages/debugentry/debugentry.js b/scanner/pages/debugentry/debugentry.js deleted file mode 100644 index 93212b7..0000000 --- a/scanner/pages/debugentry/debugentry.js +++ /dev/null @@ -1,72 +0,0 @@ -// pages/debugentry/debugentry.js - -import { - goto_camera, -} from '../../utils.js' - -Page({ - - /** - * 页面的初始数据 - */ - data: { - - }, - - /** - * 生命周期函数--监听页面加载 - */ - onLoad(options) { - getApp().globalData.debug = true; - goto_camera(true); - }, - - /** - * 生命周期函数--监听页面初次渲染完成 - */ - onReady() { - - }, - - /** - * 生命周期函数--监听页面显示 - */ - onShow() { - - }, - - /** - * 生命周期函数--监听页面隐藏 - */ - onHide() { - - }, - - /** - * 生命周期函数--监听页面卸载 - */ - onUnload() { - - }, - - /** - * 页面相关事件处理函数--监听用户下拉动作 - */ - onPullDownRefresh() { - - }, - - /** - * 页面上拉触底事件的处理函数 - */ - onReachBottom() { - - }, - - /** - * 用户点击右上角分享 - */ - onShareAppMessage() { - - } -}) diff --git a/scanner/pages/debugentry/debugentry.json b/scanner/pages/debugentry/debugentry.json deleted file mode 100644 index 3928faa..0000000 --- a/scanner/pages/debugentry/debugentry.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "usingComponents": {} -} \ No newline at end of file diff --git a/scanner/pages/debugentry/debugentry.wxml b/scanner/pages/debugentry/debugentry.wxml deleted file mode 100644 index 81c3f3f..0000000 --- a/scanner/pages/debugentry/debugentry.wxml +++ /dev/null @@ -1 +0,0 @@ -Emblem debug entry \ No newline at end of file diff --git a/scanner/pages/debugentry/debugentry.wxss b/scanner/pages/debugentry/debugentry.wxss deleted file mode 100644 index ea05cd2..0000000 --- a/scanner/pages/debugentry/debugentry.wxss +++ /dev/null @@ -1 +0,0 @@ -/* pages/debugentry/debugentry.wxss */ \ No newline at end of file diff --git a/scanner/pages/debuguploaded/debuguploaded.js b/scanner/pages/debuguploaded/debuguploaded.js deleted file mode 100644 index bb04f78..0000000 --- a/scanner/pages/debuguploaded/debuguploaded.js +++ /dev/null @@ -1,67 +0,0 @@ -// pages/debuguploaded/debuguploaded.js - -import { - goto_camera, -} from '../../utils.js' - -Page({ - - /** - * 页面的初始数据 - */ - data: { - - }, - - /** - * 生命周期函数--监听页面加载 - */ - onLoad(options) { - - }, - - /** - * 生命周期函数--监听页面初次渲染完成 - */ - onReady() { - - }, - - /** - * 生命周期函数--监听页面显示 - */ - onShow() { - - }, - - /** - * 生命周期函数--监听页面隐藏 - */ - onHide() { - - }, - - /** - * 生命周期函数--监听页面卸载 - */ - onUnload() { - - }, - - /** - * 页面相关事件处理函数--监听用户下拉动作 - */ - onPullDownRefresh() { - - }, - - /** - * 页面上拉触底事件的处理函数 - */ - onReachBottom() { - - }, - goto_camera() { - goto_camera(true); - }, -}) diff --git a/scanner/pages/debuguploaded/debuguploaded.json b/scanner/pages/debuguploaded/debuguploaded.json deleted file mode 100644 index 3928faa..0000000 --- a/scanner/pages/debuguploaded/debuguploaded.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "usingComponents": {} -} \ No newline at end of file diff --git a/scanner/pages/debuguploaded/debuguploaded.wxml b/scanner/pages/debuguploaded/debuguploaded.wxml deleted file mode 100644 index 55bebba..0000000 --- a/scanner/pages/debuguploaded/debuguploaded.wxml +++ /dev/null @@ -1,7 +0,0 @@ - - -已上传数据到调试后端 - - - - diff --git a/scanner/pages/debuguploaded/debuguploaded.wxss b/scanner/pages/debuguploaded/debuguploaded.wxss deleted file mode 100644 index 5695da5..0000000 --- a/scanner/pages/debuguploaded/debuguploaded.wxss +++ /dev/null @@ -1,13 +0,0 @@ -view.container { - padding-top: 100rpx; - background: #fff; -} - -view.alert { - margin: 0 1rem 1rem; - text-align: center; - font-size: 1.2rem; - padding: 1rem; - border-radius: 1rem; - background-color: #eee; -} \ No newline at end of file diff --git a/scanner/pages/emblemscanner/emblemscanner.js b/scanner/pages/emblemscanner/emblemscanner.js index 32944d0..1e10b91 100644 --- a/scanner/pages/emblemscanner/emblemscanner.js +++ b/scanner/pages/emblemscanner/emblemscanner.js @@ -34,6 +34,16 @@ const { is_emblem_qr_pattern } = require('./libemblemscanner.js'); +// Import upload functionality for verification (self-contained) +const { + upload_image_data_urls +} = require('./upload.js'); + +// Import precheck utilities for image processing +const { + data_url_from_frame +} = require('../../precheck.js'); + // Import QR processing module const { load_qrtool, @@ -72,7 +82,6 @@ Page({ debug_image_data_url: '', debug_last_result: null, qrtool_ready: false, - frame_processing_started: false, // Frame processing statistics frames_processed: 0, frames_skipped: 0, @@ -83,8 +92,8 @@ Page({ camera_rule: null, use_web_view: false, emblem_camera_url: null, - // State machine: initializing -> loading -> scanning -> verifying -> result - app_state: 'initializing', // 'initializing', 'loading', 'scanning_camera', 'scanning_webview', 'verifying', 'result' + // 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' scan_mode: 'unknown', // 'camera', 'webview' no_web_view: false // Override web-view rule, force native camera }, @@ -99,20 +108,23 @@ 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.initializeQRTool(); this.fetchRealIP(); this.fetchTenantID(); + + // Step 2: Load camera rules based on phone model this.loadCameraRules(); }, fetchRealIP() { - fetch_real_ip((err, ip) => { + fetch_real_ip((_err, ip) => { this.setData({ real_ip: ip }); }); }, @@ -129,8 +141,9 @@ Page({ if (is_qrtool_ready()) { this.setData({ qrtool_ready: true }); this.addDebugMessage('QRTool WASM loaded and ready'); - this.transitionToState('loading'); - this.startFrameProcessingMaybe(); + + // Step 4: QRTool loaded, now initialize camera + this.startCameraInit(); } else { setTimeout(checkReady, 100); } @@ -152,8 +165,8 @@ Page({ console.log(`Phone model: ${phone_model}, Using native camera mode`); }, - loadCameraRules() { - get_camera_rule(null, (rule) => { + loadCameraRules(max_zoom = null) { + get_camera_rule(max_zoom, (rule) => { console.log('Camera rule loaded:', rule); const should_use_webview = rule.web_view && !this.data.no_web_view; @@ -178,18 +191,41 @@ Page({ this.addDebugMessage(`Camera rule: zoom=${rule.zoom}, web_view=${rule.web_view}${this.data.no_web_view ? ' (NO_WEB_VIEW)' : ''}`); if (should_use_webview) { + // Step 3a: Go directly to webview scanning (no QRTool needed) this.startWebviewScanning(); } else { - this.startCameraScanning(); + // Step 3b: Load QRTool for camera mode + this.addDebugMessage('Starting QRTool initialization'); + this.transitionToState('loading_qrtool'); + this.initializeQRTool(); } }); }, onCameraReady(e) { console.log('Camera ready', e); + + // Get max zoom from camera initialization + let max_zoom = null; + if (e && e.detail && e.detail.maxZoom) { + max_zoom = e.detail.maxZoom; + this.setData({ + max_zoom: max_zoom + }); + this.addDebugMessage(`Camera max zoom: ${max_zoom}`); + } + this.camera_context = wx.createCameraContext(); - this.addDebugMessage('Camera initialized for WASM processing'); - this.startFrameProcessingMaybe(); + this.addDebugMessage('Camera context created'); + + // Step 5: Set up initial zoom and start scanning + if (this.data.camera_rule) { + this.setupCameraZoom(this.data.camera_rule); + this.addDebugMessage('Initial zoom set up'); + } + + // Step 6: Transition to scanning (which also starts frame processing) + this.startCameraScanning(); }, onCameraError(e) { @@ -249,6 +285,39 @@ Page({ }, + /** + * Set up camera zoom functionality similar to camera.js + */ + setupCameraZoom(rule) { + if (!this.camera_context) { + this.addDebugMessage('Cannot setup zoom: camera context not ready'); + return; + } + + console.log('setupCameraZoom called:', rule); + const zoom = rule.zoom; + const initial_zoom = 2; + + this.setData({ + zoom: initial_zoom, + rule_zoom: zoom + }); + + this.addDebugMessage(`Camera set initial zoom to ${initial_zoom}x, will zoom in to ${zoom}x when QR is found`); + this.camera_context.setZoom({ zoom: initial_zoom }); + + // Set up zoom-in behavior when QR is found + this.on_qr_found = () => { + this.addDebugMessage(`QR found, zoom to ${zoom}x`); + this.camera_context.setZoom({ zoom: zoom }); + this.setData({ + zoom: zoom, + qrmarkers_class: '', + qrarc_class: 'lg' + }); + }; + }, + /** * State Machine: Transition to new state */ @@ -263,33 +332,28 @@ Page({ }, /** - * State: Loading -> Scanning (Camera) + * State: Loading -> Init Camera (prepare camera context) */ - startCameraScanning() { - this.transitionToState('scanning_camera', 'camera'); + startCameraInit() { + this.transitionToState('init_camera', 'camera'); this.setData({ - hint_text: '查找二维码', - busy: false + hint_text: '初始化相机...', + busy: true }); }, /** - * Start frame processing if both QRTool and camera are ready + * State: Init Camera -> Scanning (Camera) + * Also starts frame processing since all conditions are implied to be ready */ - startFrameProcessingMaybe() { - // Already started, nothing to do - if (this.data.frame_processing_started) { - return; - } - - // Check if both are ready - if (!this.data.qrtool_ready || !this.camera_context) { - const qrStatus = this.data.qrtool_ready ? 'ready' : 'not ready'; - const cameraStatus = this.camera_context ? 'ready' : 'not ready'; - this.addDebugMessage(`Cannot start frame processing - QRTool: ${qrStatus}, Camera: ${cameraStatus}`); - return; - } + startCameraScanning() { + this.transitionToState('scanning', 'camera'); + this.setData({ + hint_text: '查找二维码', + busy: false + }); + // Start frame processing - all conditions are implied to be ready at this point this.addDebugMessage('Starting camera frame listener'); this.lastFrameTime = 0; @@ -300,23 +364,21 @@ Page({ // Start the listener this.listener.start(); - - // Mark as started - this.setData({ frame_processing_started: true }); }, + /** * Camera frame callback - receives live camera frames */ onCameraFrame(frame) { // Only process frames when in camera scanning state and QRTool is ready - if (this.data.app_state !== 'scanning_camera' || !this.data.qrtool_ready) { + if (this.data.app_state !== 'scanning') { return; } // Throttle frame processing to avoid overwhelming the system const now = Date.now(); - if (this.lastFrameTime && (now - this.lastFrameTime) < 200) { + if (this.lastFrameTime && (now - this.lastFrameTime) < 100) { this.setData({ frames_skipped: this.data.frames_skipped + 1 }); @@ -349,7 +411,7 @@ Page({ }); if (result) { - this.handleQRResult(result); + this.handleQRResult(result, frame); } } catch (error) { this.addDebugMessage(`Frame processing error: ${error.message}`); @@ -374,7 +436,7 @@ Page({ /** * Handle QR processing result */ - handleQRResult(result) { + handleQRResult(result, frame) { // Update debug info if available if (result.debug_data_url) { this.setData({ @@ -385,10 +447,21 @@ Page({ // Generate hint text const hint = make_hint_text(result); - // Check if we have a valid QR code - if (result.qrcode && result.valid_pattern && result.ok) { - this.addDebugMessage(`QR detected: ${result.qrcode}`); - this.onQRCodeDetected(result.qrcode); + // Check if we have a valid QR code that's ready for upload (like camera.js) + // don't require ok as we only care about the view has a valid qrcode in it + // zooming in so that it's more likely to be clear enough for upload + if (!this.data.qr_found && result.qrcode && result.valid_pattern && is_emblem_qr_pattern(result.qrcode)) { + this.addDebugMessage(`QR detected and ready: ${result.qrcode}`); + + // Trigger zoom-in if function is set up + if (this.on_qr_found) { + this.on_qr_found(); + } + + this.onQRCodeDetected(result.qrcode, frame); + this.setData({ + qr_found: true + }); } else { // Update hint for user guidance this.setData({ hint_text: hint }); @@ -400,23 +473,88 @@ Page({ }, /** - * Handle successful QR code detection + * Handle successful QR code detection - collect images from "ok" frames and verify */ - onQRCodeDetected(qrCode) { - // Start verification process - this.startVerifying(); + onQRCodeDetected(qrCode, frameData) { + // Convert frame data to data URL for upload (only called for "ok" frames) + if (frameData) { + const dataUrl = data_url_from_frame(frameData.width, frameData.height, frameData.data); + this.image_data_urls.push(dataUrl); + this.addDebugMessage(`Collected ${this.image_data_urls.length}/3 good images`); + } - // Simulate verification delay, then go to result - setTimeout(() => { - this.goToResult(qrCode); - }, 2000); + // Need 3 "ok" frames before verification (like camera.js) + if (this.image_data_urls.length >= 3) { + this.addDebugMessage('3 good images collected, starting verification'); + this.startVerifying(); + this.submitImageForVerification(this.image_data_urls, qrCode); + this.image_data_urls = []; // Reset for next scan + } + // If less than 3 images, continue scanning to collect more }, /** - * State: Loading -> Scanning (Web-view) + * Submit images for verification like camera.js + */ + submitImageForVerification(dataUrls, qrCode) { + this.addDebugMessage('Submitting images for verification'); + const begin = Date.now(); + + const success = (res) => { + this.addDebugMessage(`Upload success, code: ${res.statusCode}`); + if (res.statusCode === 200) { + let resp; + if (typeof res.data === "string") { + resp = JSON.parse(res.data); + } else { + resp = res.data; + } + + // Store verification response + getApp().globalData.verify_resp = resp; + + if (resp.serial_code) { + // Let verification animation run for a bit, then show result + const delay = 3000 - (Date.now() - begin); + setTimeout(() => { + this.goToResult(qrCode, resp.serial_code); + }, delay > 0 ? delay : 0); + } else { + this.showVerifyFailed(); + } + } else { + this.showVerifyFailed(); + } + }; + + const fail = (e) => { + this.addDebugMessage(`Upload failed: ${JSON.stringify(e)}`); + this.showVerifyFailed(); + }; + + // Store global data like camera.js + const gd = getApp().globalData; + gd.image_data_urls = dataUrls; + gd.qr_code = qrCode; + + 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 */ startWebviewScanning() { - this.transitionToState('scanning_webview', 'webview'); + this.transitionToState('webview_scanning', 'webview'); this.setData({ hint_text: '查找二维码', busy: false @@ -437,12 +575,16 @@ Page({ /** * State: Any -> Result (jump to return page) */ - goToResult(qrCode) { + goToResult(qrCode, serialCode) { this.transitionToState('result'); if (this.data.return_page) { - wx.navigateTo({ - url: `${this.data.return_page}?qr_code=${encodeURIComponent(qrCode)}`, + // 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)}`; + + wx.redirectTo({ + url: url, success: () => { this.addDebugMessage(`Navigated to: ${this.data.return_page}`); }, @@ -475,8 +617,7 @@ Page({ frames_skipped: 0, total_processing_time: 0, avg_processing_time_ms: 0, - last_frame_time_ms: 0, - frame_processing_started: false + last_frame_time_ms: 0 }); // Reset frame timing diff --git a/scanner/pages/emblemscanner/emblemscanner.wxml b/scanner/pages/emblemscanner/emblemscanner.wxml index 75bc013..06e0c2d 100644 --- a/scanner/pages/emblemscanner/emblemscanner.wxml +++ b/scanner/pages/emblemscanner/emblemscanner.wxml @@ -1,18 +1,36 @@ - - + + + + 加载相机规则... + + + + 初始化QR工具... - - - - 初始化相机... - + + + + + + {{ hint_text }} + + - - + + + + + + + @@ -42,8 +60,8 @@ - - + + @@ -144,8 +162,8 @@ - - + + @@ -194,7 +212,7 @@ 验证失败 - + @@ -206,7 +224,7 @@ 1. 将QR码置于框内 2. 保持稳定 3. 确保光线充足 - + \ No newline at end of file diff --git a/scanner/pages/emblemscanner/qrprocessor.js b/scanner/pages/emblemscanner/qrprocessor.js index 4329dfb..c6d1bb2 100644 --- a/scanner/pages/emblemscanner/qrprocessor.js +++ b/scanner/pages/emblemscanner/qrprocessor.js @@ -10,7 +10,6 @@ var qrtool_ready = false; function load_qrtool() { var m = require('./qrtool.wx.js'); m.onRuntimeInitialized = () => { - console.log("QRTool runtime initialized"); qrtool_ready = true; qrtool = m; } @@ -28,39 +27,17 @@ function is_qrtool_ready() { */ function process_frame(width, height, image_data, camera_sensitivity, enable_debug = false) { if (!qrtool_ready) { - console.log("qrtool not ready"); return null; } - console.log('process_frame called:', { - width, - height, - data_type: typeof image_data, - data_constructor: image_data ? image_data.constructor.name : 'undefined', - data_length: image_data ? image_data.length : 'undefined', - data_byteLength: image_data ? image_data.byteLength : 'undefined', - bytes_per_element: image_data ? image_data.BYTES_PER_ELEMENT : 'undefined', - camera_sensitivity, - enable_debug - }); - try { // Copy frame data to avoid TOCTOU var uca1 = new Uint8ClampedArray(image_data); var uca = new Uint8ClampedArray(uca1); - console.log('Frame data copied:', { - uca_length: uca.length, - uca_bytes_per_element: uca.BYTES_PER_ELEMENT - }); - var buf = qrtool._malloc(uca.length * uca.BYTES_PER_ELEMENT); qrtool.HEAPU8.set(uca, buf); - console.log('Buffer allocated:', { - buffer_size: uca.length * uca.BYTES_PER_ELEMENT - }); - var dot_area_buf = 0; var debug_data_url = null; @@ -75,8 +52,6 @@ function process_frame(width, height, image_data, camera_sensitivity, enable_deb [buf, width, height, dot_area_buf, camera_sensitivity || 1] ); - console.log('qrtool_angle result:', result_str); - if (enable_debug && dot_area_buf) { const dot_area_size = 32; const da_len = dot_area_size * dot_area_size * uca.BYTES_PER_ELEMENT * 4; diff --git a/scanner/pages/emblemscanner/upload.js b/scanner/pages/emblemscanner/upload.js new file mode 100644 index 0000000..9dc0b8a --- /dev/null +++ b/scanner/pages/emblemscanner/upload.js @@ -0,0 +1,71 @@ +function upload_image_data_urls(image_data_urls, success, fail, log) { + do_upload(image_data_urls, success, fail, log); +} + +function check_auto_torch(qrcode, cb) { + var gd = getApp().globalData; + var url = gd.server_url + '/api/v1/check-auto-torch/?qrcode=' + encodeURIComponent(qrcode); + console.log("check_auto_torch:", url); + const fail = (e) => { + console.log("failed to check auto torch", e); + cb(false, null); + }; + const success = (res) => { + if (res.statusCode == 200) { + var resp; + console.log(res.data); + if (typeof res.data == "string") { + resp = JSON.parse(res.data); + } else { + resp = res.data; + } + cb(resp.enable_auto_torch, resp.camera_sensitivity); + } else { + console.log("failed to check auto torch", res.data); + cb(false, null); + } + }; + wx.request({ + url, + method: "GET", + success, + fail, + }); +} + +function do_upload(image_data_urls, success, fail, log) { + var ui = wx.getStorageSync('userinfo'); + var gd = getApp().globalData; + var fd = { + emblem_id: ui.emblem_id, + nick_name: ui.nickName, + realip: gd.real_ip, + qrcode: gd.qr_code, + angle: 0, + phonemodel: gd.phone_model, + image_data_urls, + use_roi_verify: 1, + log, + }; + var ci = gd.caller_info; + if (ci && ci.token) { + fd.token = ci.token; + } + var url = gd.server_url + '/api/v1/qr-verify/'; + console.log("wx.request", url, fd.qrcode, fd.angle, fd.phonemodel, fd.realip); + wx.request({ + url, + method: "POST", + header: { + "Content-Type": "application/json", + }, + data: JSON.stringify(fd), + success, + fail, + }); +} + +module.exports = { + upload_image_data_urls, + check_auto_torch, +}; \ No newline at end of file diff --git a/scanner/pages/index/index.js b/scanner/pages/index/index.js index 15fdb4d..aee203e 100644 --- a/scanner/pages/index/index.js +++ b/scanner/pages/index/index.js @@ -128,7 +128,9 @@ Page({ goto_camera: function () { this.getUserProfile(() => { - goto_camera(false); + wx.navigateTo({ + url: '/pages/emblemscanner/emblemscanner?return_page=/pages/test_result_page/test_result_page' + }); }); }, diff --git a/scanner/pages/test/test.js b/scanner/pages/productinfo/productinfo.js similarity index 77% rename from scanner/pages/test/test.js rename to scanner/pages/productinfo/productinfo.js index f3c8654..c74b1d2 100644 --- a/scanner/pages/test/test.js +++ b/scanner/pages/productinfo/productinfo.js @@ -1,37 +1,44 @@ - -// pages/test/test.js +// pages/productinfo/productinfo.js Page({ /** * Page initial data */ data: { - + url: null, }, /** * Lifecycle function--Called when page load */ onLoad(options) { - + var base_url = getApp().globalData.server_url + '/api/product-info/'; + var url = base_url + options.serial_code + '/'; + console.log(url); + this.setData({ + url: url, + }) }, /** * Lifecycle function--Called when page is initially rendered */ onReady() { + }, /** * Lifecycle function--Called when page show */ onShow() { + }, /** * Lifecycle function--Called when page hide */ onHide() { + }, /** diff --git a/scanner/pages/camwebview/camwebview.json b/scanner/pages/productinfo/productinfo.json similarity index 100% rename from scanner/pages/camwebview/camwebview.json rename to scanner/pages/productinfo/productinfo.json diff --git a/scanner/pages/productinfo/productinfo.wxml b/scanner/pages/productinfo/productinfo.wxml new file mode 100644 index 0000000..790e32e --- /dev/null +++ b/scanner/pages/productinfo/productinfo.wxml @@ -0,0 +1 @@ + diff --git a/scanner/pages/productinfo/productinfo.wxss b/scanner/pages/productinfo/productinfo.wxss new file mode 100644 index 0000000..b72229b --- /dev/null +++ b/scanner/pages/productinfo/productinfo.wxss @@ -0,0 +1 @@ +/* pages/productinfo/productinfo.wxss */ \ No newline at end of file diff --git a/scanner/pages/test/test.json b/scanner/pages/test/test.json deleted file mode 100644 index 0256dff..0000000 --- a/scanner/pages/test/test.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "usingComponents": { - "verifyspin": "/components/verifyspin/verifyspin", - "verifyfailed": "/components/verifyfailed/verifyfailed", - "scanguide": "/components/scanguide/scanguide", - "servicemodal": "/components/servicemodal/servicemodal" - } -} diff --git a/scanner/pages/test/test.wxml b/scanner/pages/test/test.wxml deleted file mode 100644 index 602ec9e..0000000 --- a/scanner/pages/test/test.wxml +++ /dev/null @@ -1,2 +0,0 @@ -a -b diff --git a/scanner/pages/test/test.wxss b/scanner/pages/test/test.wxss deleted file mode 100644 index e69de29..0000000 diff --git a/scanner/utils.js b/scanner/utils.js index e6d1516..fa0963e 100644 --- a/scanner/utils.js +++ b/scanner/utils.js @@ -77,18 +77,16 @@ function get_camera_rule(max_zoom, cb) { function goto_camera(redirect, opts) { var query = opts || ""; - get_camera_rule(null, (rule) => { - console.log("camera rule:", rule); - var url = "/pages/camera/camera?" + query; - if (rule.web_view) { - url = "/pages/camwebview/camwebview?" + query; - } - if (redirect) { - wx.redirectTo({ url }); - } else { - wx.navigateTo({ url }); - } - }); + // Route to emblemscanner with return page for product info + var url = "/pages/emblemscanner/emblemscanner?return_page=/pages/productinfo/productinfo"; + if (query) { + url += "&" + query; + } + if (redirect) { + wx.redirectTo({ url }); + } else { + wx.navigateTo({ url }); + } } function make_new_session_id() {