diff --git a/README.md b/README.md index 809b72f..f1938d4 100644 --- a/README.md +++ b/README.md @@ -43,10 +43,9 @@ - Python 依赖:镜像已默认使用腾讯云 PyPI 源 `https://mirrors.cloud.tencent.com/pypi/simple` - 预构建:在本地构建并推送到腾讯云 TCR,服务器直接拉取镜像,避免远端构建时慢下载 -## 前端扫码 -- 优先使用浏览器原生 `BarcodeDetector` 实时识别 -- 非安全上下文或不支持时,自动切换为“拍照识别”方式 -- 识别成功自动填充并触发查询 +## 移动端兼容 +- iPhone 输入时不再自动放大:移动端下统一设置输入与按钮字体为 16px +- 采用响应式布局,保证手机与桌面一致可用 ## 项目结构 - `app/` 后端 FastAPI diff --git a/static/app.js b/static/app.js index b37e8ac..d291af6 100644 --- a/static/app.js +++ b/static/app.js @@ -8,20 +8,6 @@ const importStatus = qs('#importStatus'); const tabs = document.querySelectorAll('.tab'); const searchSection = qs('#searchSection'); const importSection = qs('#importSection'); -const scanBtn = qs('#scanBtn'); -const scannerModal = qs('#scannerModal'); -const closeScanner = qs('#closeScanner'); -let scannerInst = null; -let videoEl = null; -let mediaStream = null; -const scannerMessage = qs('#scannerMessage'); -const captureInput = qs('#captureInput'); -const toggleTorchBtn = qs('#toggleTorch'); -const zoomInput = qs('#zoom'); -const zoomWrap = qs('#zoomWrap'); -let detector = null; -let videoTrack = null; -let loopReq = null; // 无分页模式 let currentTab = 'search'; @@ -87,140 +73,7 @@ function render(items) { searchBtn.addEventListener('click', search); input.addEventListener('keydown', e => { if (e.key === 'Enter') search(); }); -async function openScanner(){ - scannerModal.classList.remove('hidden'); - scannerMessage.textContent = '正在请求摄像头权限...'; - scannerMessage.classList.remove('hidden'); - const isSecure = location.protocol === 'https:' || location.hostname === 'localhost'; - try{ - if(!isSecure){ - scannerMessage.textContent = '非安全上下文,已切换为拍照识别方式'; - captureInput.click(); - return; - } - if('BarcodeDetector' in window){ - const supported = await window.BarcodeDetector.getSupportedFormats(); - const wanted = ['ean_13','ean_8','code_128','code_39','upc_a','upc_e']; - const useFormats = wanted.filter(f=>supported.includes(f)); - detector = new window.BarcodeDetector({ formats: useFormats.length?useFormats:supported }); - mediaStream = await navigator.mediaDevices.getUserMedia({ video: { facingMode: 'environment' } }); - videoEl = document.createElement('video'); - videoEl.autoplay = true; - videoEl.playsInline = true; - videoEl.srcObject = mediaStream; - const host = document.getElementById('scanner'); - host.innerHTML = ''; - host.appendChild(videoEl); - await videoEl.play(); - scannerMessage.classList.add('hidden'); - try{ - videoTrack = mediaStream.getVideoTracks()[0]; - const caps = videoTrack.getCapabilities ? videoTrack.getCapabilities() : {}; - if(caps.torch){ toggleTorchBtn.classList.remove('hidden'); } - else { toggleTorchBtn.classList.add('hidden'); } - if(caps.zoom){ - zoomWrap.classList.remove('hidden'); - const min = caps.zoom.min ?? 1; - const max = caps.zoom.max ?? 5; - zoomInput.min = String(min); - zoomInput.max = String(max); - zoomInput.value = String(min); - } else { - zoomWrap.classList.add('hidden'); - } - }catch(_){ } - const canvas = document.createElement('canvas'); - const ctx = canvas.getContext('2d'); - const tick = async()=>{ - try{ - const w = videoEl.videoWidth || 640; - const h = videoEl.videoHeight || 480; - const size = Math.min(w, h); - const sx = (w - size)/2; - const sy = (h - size)/2; - canvas.width = size; - canvas.height = size; - ctx.drawImage(videoEl, sx, sy, size, size, 0, 0, size, size); - const codes = await detector.detect(canvas); - if(codes && codes.length){ - const text = codes[0].rawValue; - input.value = text; - currentQuery = text; - fetchResults(); - closeScannerFn(); - return; - } - }catch(_){ } - if(!scannerModal.classList.contains('hidden')){ loopReq = requestAnimationFrame(tick); } - }; - loopReq = requestAnimationFrame(tick); - } else { - scannerMessage.textContent = '浏览器不支持实时扫码,已切换为拍照识别方式'; - captureInput.click(); - } - }catch(e){ - scannerMessage.textContent = '无法启用摄像头,已切换为拍照识别方式'; - captureInput.click(); - } -} - -function closeScannerFn(){ - try{ if(scannerInst){ scannerInst.stop().then(()=>scannerInst.clear()); } }catch(_){ } - try{ if(mediaStream){ mediaStream.getTracks().forEach(t=>t.stop()); mediaStream=null; } }catch(_){ } - try{ const host = document.getElementById('scanner'); if(host){ host.innerHTML=''; } }catch(_){ } - try{ if(scannerMessage){ scannerMessage.textContent=''; scannerMessage.classList.add('hidden'); } }catch(_){ } - try{ if(loopReq){ cancelAnimationFrame(loopReq); loopReq=null; } }catch(_){ } - scannerModal.classList.add('hidden'); -} - -captureInput.addEventListener('change', async ()=>{ - const file = captureInput.files?.[0]; - if(!file){ return; } - try{ - if('BarcodeDetector' in window){ - const img = await createImageBitmap(file); - const detector = new window.BarcodeDetector({ formats: ['ean_13','ean_8','code_128','code_39','upc_a','upc_e'] }); - const codes = await detector.detect(img); - if(codes && codes.length){ - const text = codes[0].rawValue; - input.value = text; - currentQuery = text; - fetchResults(); - } else { - scannerMessage.textContent = '未识别到条码,请重试或手动输入'; - scannerMessage.classList.remove('hidden'); - } - } else { - scannerMessage.textContent = '当前浏览器不支持条码识别,请手动输入'; - scannerMessage.classList.remove('hidden'); - } - }catch(_){ - scannerMessage.textContent = '识别失败,请重试或手动输入'; - scannerMessage.classList.remove('hidden'); - } finally { - captureInput.value = ''; - } -}); - -toggleTorchBtn.addEventListener('click', async ()=>{ - try{ - if(!videoTrack) return; - const settings = videoTrack.getSettings ? videoTrack.getSettings() : {}; - const torchOn = settings.torch === true; - await videoTrack.applyConstraints({ advanced: [{ torch: !torchOn }] }); - }catch(_){ } -}); - -zoomInput.addEventListener('input', async ()=>{ - try{ - if(!videoTrack) return; - const z = Number(zoomInput.value); - await videoTrack.applyConstraints({ advanced: [{ zoom: z }] }); - }catch(_){ } -}); - -scanBtn.addEventListener('click', openScanner); -closeScanner.addEventListener('click', closeScannerFn); +// 扫码功能已移除 // 无分页控件 diff --git a/static/index.html b/static/index.html index 33164d0..1b6608e 100644 --- a/static/index.html +++ b/static/index.html @@ -2,7 +2,7 @@ - + 益选便利店商品查询 @@ -16,16 +16,7 @@

益选便利店商品查询

@@ -40,21 +31,6 @@
- - diff --git a/static/styles.css b/static/styles.css index aa43aae..7a65bbc 100644 --- a/static/styles.css +++ b/static/styles.css @@ -9,12 +9,6 @@ h1{font-size:20px;margin:8px 0 16px} .hidden{display:none} .search{display:flex;gap:8px;margin-bottom:16px} input{flex:1;padding:10px;border:1px solid #ccc;border-radius:6px;background:#fff;color:#111} -.search-input{position:relative;flex:1} -.search-input input{width:100%;padding-right:44px} -.scan-btn{position:absolute;right:8px;top:50%;transform:translateY(-50%);border:1px solid #ddd;background:#fafafa;color:#111;border-radius:6px;padding:6px 10px;display:flex;align-items:center;justify-content:center;cursor:pointer} -.scan-btn:hover{background:#f0f0f0} -.scan-btn:active{background:#e6e6e6} -.scan-btn svg{display:block} button{padding:10px 14px;border:0;border-radius:6px;background:#1976d2;color:#fff} .results{display:flex;flex-direction:column;gap:12px} .card{border:1px solid #eee;border-radius:10px;padding:12px;box-shadow:0 1px 2px rgba(0,0,0,0.04)} @@ -30,18 +24,11 @@ mark{background:#ffec99} .loading{color:#1976d2} .status{margin-top:8px;color:#555} .import{margin-top:12px;display:flex;gap:8px;align-items:center} -.scanner-message{margin-bottom:8px;color:#555} -.scanner-message.hidden{display:none} -.modal{position:fixed;inset:0;background:rgba(0,0,0,0.4);display:flex;align-items:center;justify-content:center} -.modal.hidden{display:none} -.modal-content{background:#fff;border-radius:10px;padding:12px;width:92%;max-width:480px} -.scanner-area{position:relative} -.scanner-controls{display:flex;gap:10px;align-items:center;justify-content:flex-end;margin:8px 0} -.scanner-overlay{position:absolute;inset:0;border:2px dashed rgba(25,118,210,0.6);border-radius:8px;pointer-events:none} @media (max-width:600px){ .container{padding:12px} .tab{padding:8px 12px} .prices{flex-direction:column} .import{flex-direction:column;align-items:stretch} .search{display:grid;grid-template-columns:4fr 1fr;gap:8px} + input, button{font-size:16px} } diff --git a/部署文档.md b/部署文档.md index 14f98ef..cce60e3 100644 --- a/部署文档.md +++ b/部署文档.md @@ -46,7 +46,6 @@ ## 常见问题 - 502 或无法访问:确认容器已启动且端口映射为 `57777:57777` -- 浏览器不支持扫码:`BarcodeDetector` 在部分旧设备不可用,仍可通过手动输入条码查询 - 中文显示乱码:仅限命令行输出,页面显示正常;确保浏览器编码为 UTF-8 ## 一键命令汇总