From 11fbe20102fdaa5350a63981e592426dde4bcad2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=88=AA=E5=AE=87?= <3364451258@qq.com> Date: Fri, 19 Jun 2026 20:39:07 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20GUI=20=E7=AB=AF=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E8=A7=A3=E7=A0=81=E5=8A=9F=E8=83=BD=20=E2=80=94=20=E9=80=89?= =?UTF-8?q?=E6=8B=A9=E5=9B=BE=E7=89=87=E8=A7=A3=E7=A0=81=20QR=20=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 decode_qr Tauri command(接收图片字节,返回解码文本) - ExportPanel 新增「选择图片解码」按钮 + 解码结果展示 - fs:allow-read-file 权限,支持 /c/Users/33644 和 C:\Users\33644\AppData\Local\Temp 路径 --- gui/capabilities/default.json | 4 ++ gui/gen/schemas/capabilities.json | 2 +- .../src/components/ExportPanel.tsx | 47 ++++++++++++++++++- gui/src/lib.rs | 7 +++ 4 files changed, 57 insertions(+), 3 deletions(-) diff --git a/gui/capabilities/default.json b/gui/capabilities/default.json index 5c12982..e9b1e11 100644 --- a/gui/capabilities/default.json +++ b/gui/capabilities/default.json @@ -11,6 +11,10 @@ { "identifier": "fs:allow-write-file", "allow": [{ "path": "$HOME/**" }] + }, + { + "identifier": "fs:allow-read-file", + "allow": [{ "path": "$HOME/**" }, { "path": "$TEMP/**" }] } ] } diff --git a/gui/gen/schemas/capabilities.json b/gui/gen/schemas/capabilities.json index cef8b88..e0b158f 100644 --- a/gui/gen/schemas/capabilities.json +++ b/gui/gen/schemas/capabilities.json @@ -1 +1 @@ -{"default":{"identifier":"default","description":"QRGen 默认权限","local":true,"windows":["main"],"permissions":["core:default","store:default","dialog:default","clipboard-manager:default",{"identifier":"fs:allow-write-file","allow":[{"path":"$HOME/**"}]}]}} \ No newline at end of file +{"default":{"identifier":"default","description":"QRGen 默认权限","local":true,"windows":["main"],"permissions":["core:default","store:default","dialog:default","clipboard-manager:default",{"identifier":"fs:allow-write-file","allow":[{"path":"$HOME/**"}]},{"identifier":"fs:allow-read-file","allow":[{"path":"$HOME/**"},{"path":"$TEMP/**"}]}]}} \ No newline at end of file diff --git a/gui/src-frontend/src/components/ExportPanel.tsx b/gui/src-frontend/src/components/ExportPanel.tsx index 57b8547..3ad3172 100644 --- a/gui/src-frontend/src/components/ExportPanel.tsx +++ b/gui/src-frontend/src/components/ExportPanel.tsx @@ -2,8 +2,8 @@ import { useState } from 'react'; import { useQrState } from '../store/qrContext'; import { invoke } from '@tauri-apps/api/core'; import { writeText } from '@tauri-apps/plugin-clipboard-manager'; -import { save } from '@tauri-apps/plugin-dialog'; -import { writeFile } from '@tauri-apps/plugin-fs'; +import { open, save } from '@tauri-apps/plugin-dialog'; +import { readFile, writeFile } from '@tauri-apps/plugin-fs'; import type { QrConfig } from '../types'; import { buildEncodedText } from '../utils/qrText'; @@ -11,6 +11,30 @@ export default function ExportPanel() { const { state, dispatch } = useQrState(); const [exporting, setExporting] = useState(false); const [errorMsg, setErrorMsg] = useState(null); + const [decodedText, setDecodedText] = useState(null); + const [decoding, setDecoding] = useState(false); + + const handleDecode = async () => { + setDecoding(true); + setErrorMsg(null); + setDecodedText(null); + try { + const filePath = await open({ + filters: [{ name: '图片文件', extensions: ['png', 'jpg', 'jpeg', 'webp', 'bmp'] }], + multiple: false, + }); + if (!filePath) { + setDecoding(false); + return; + } + const bytes = await readFile(filePath); + const text: string = await invoke('decode_qr', { imageBytes: Array.from(bytes) }); + setDecodedText(text); + } catch (e) { + setErrorMsg(`解码失败: ${e}`); + } + setDecoding(false); + }; const handleCopySvg = async () => { if (!state.preview?.svg) return; @@ -139,6 +163,25 @@ export default function ExportPanel() { > 导出 SVG + + {/* 解码区 */} +
+
+ 解码 +
+ + {decodedText && ( +
+ {decodedText} +
+ )} +
); } diff --git a/gui/src/lib.rs b/gui/src/lib.rs index 12bc750..c6ca74e 100644 --- a/gui/src/lib.rs +++ b/gui/src/lib.rs @@ -104,6 +104,12 @@ fn load_history(state: tauri::State) -> Result, Stri Ok(history.clone()) } +/// 解码 QR 码图片,返回文本内容 +#[tauri::command] +fn decode_qr(image_bytes: Vec) -> Result { + qr_core::decoder::decode_image(&image_bytes).map(|r| r.text) +} + /// 清空历史记录 #[tauri::command] fn clear_history(state: tauri::State) -> Result<(), String> { @@ -125,6 +131,7 @@ pub fn run() { .invoke_handler(tauri::generate_handler![ encode_qr, export_png, + decode_qr, save_history, load_history, clear_history,