# CLAUDE.md ## 项目概述 QRGen — 从零手搓的 QR 码生成器,Rust workspace (core + cli + gui + web),完整实现 ISO/IEC 18004 国际标准。GUI + CLI + Web + Library 四种使用方式。 ## 构建命令 ```bash # 安装前端依赖(首次或 package.json 变更后) cd gui/src-frontend && pnpm install && cd ../.. # 全 workspace 编译检查 cargo check # 全部测试 cargo test # 82 tests # 仅核心库 cargo test -p qr-core cargo build -p qr-core # CLI 构建 cargo build --release -p qrgen cargo run -p qrgen -- "Hello World" # Web 服务 cargo run -p qrgen-web # → http://localhost:3000 # GUI 开发模式 cd gui/src-frontend && pnpm dev # 终端1: Vite 热更新 cargo run -p qrgen-gui # 终端2: Tauri 窗口 # GUI 前端类型检查 cd gui/src-frontend && pnpm tsc --noEmit # GUI 前端构建 cd gui/src-frontend && pnpm build # GUI 完整打包(生成 NSIS 安装包) # beforeBuildCommand 用 npm(Tauri CWD 在 src-frontend/,pnpm 不在 PATH) cd gui/src-frontend && pnpm build && cd .. src-frontend/node_modules/.bin/tauri.cmd build # Docker 构建(Web 服务) docker build -t qrgen-web -f web/Dockerfile . # Rust lint cargo clippy -- -D warnings ``` ## 架构 Cargo workspace 四层。 ``` QRGen/ ├── core/ # Rust 库 crate(零 Tauri 依赖) │ └── src/ │ ├── qr.rs # 顶层 API — QrCode::encode(),9 步流水线 │ ├── version.rs # 40 版本容量表 + 自动选择 │ ├── ecc/ │ │ ├── galois.rs # GF(2⁸) 运算 + exp/log 预计算表 │ │ └── reed_solomon.rs # RS 纠错码 + 数据交错 │ ├── encoder/ │ │ ├── mode.rs # 4 种编码模式 (数字/字母/字节/汉字 Shift JIS) │ │ ├── segment.rs # 字符串分析 + 自动分段 │ │ └── bitstream.rs # 比特流拼接 + 终止符/填充 │ ├── matrix/ │ │ ├── grid.rs # 模块矩阵 (含 reserved 保留区) │ │ ├── patterns.rs # 定位/对齐/时序图案 + BCH(15,5) + BCH(18,6) │ │ │ # 含 finder separator 四边预留 │ │ ├── placement.rs # 蛇形数据排列 │ │ └── mask.rs # 8 种掩码 + 四规则惩罚评分 │ └── render/ │ ├── png.rs # PNG 输出 (image crate, 直接边界检测 margin) │ ├── svg.rs # SVG 输出 (预分配容量) │ └── ascii.rs # 终端 ASCII (██/ ) ├── cli/ # CLI 命令行 (依赖 core + clap + anyhow) │ └── src/main.rs # Args { content, -o, -l, -v, -s, -m, --invert } │ # 含路径遍历防护(拒绝 .. 组件) ├── gui/ # Tauri 桌面应用 (依赖 core + tauri-plugin-*) │ ├── capabilities/default.json # ACL 权限 (store/dialog/clipboard/fs) │ ├── src/ │ │ ├── main.rs # Windows 子系统入口 │ │ └── lib.rs # 5 个 Tauri commands + AppState │ ├── src-frontend/ # React 18 + TypeScript + TailwindCSS │ │ └── src/ │ │ ├── App.tsx # 三栏 + 底部输入布局 │ │ ├── components/ # ModePanel / QrPreview / ExportPanel / HistoryList / ErrorBoundary │ │ ├── modes/ # Text/Url/Wifi/VCard/Email/Phone/Sms │ │ ├── hooks/ # useQrEncode (200ms 防抖, Store 缓存, WiFi 脱敏) │ │ ├── store/ # QrProvider + useReducer │ │ ├── types/ # ModeType / QrState / QrAction / HistoryEntry │ │ └── utils/ # qrText.ts — 共享文本构造函数 │ ├── tauri.conf.json # 窗口 900×650 + CSP + NSIS 打包 │ └── WebView2Loader.dll # WebView2 运行时(打包用) ├── web/ # Web 服务 (依赖 core + axum + tokio) │ ├── Dockerfile # rust-alpine 多阶段构建 → 17.7MB │ ├── src/ │ │ ├── main.rs # axum: GET / + GET /api/qr?text=&level=&margin=&size=&fmt= │ │ └── templates/ │ │ └── index.html # 内嵌 GUI 风格界面(三栏+7模式+实时预览) ├── .dockerignore # 排除 target/ gui/ test/ └── Cargo.toml # Workspace: core + cli + gui + web ``` ## IPC 接口(Rust → GUI Frontend) | Command | 参数 | 返回值 | 功能 | |---------|------|--------|------| | `encode_qr` | `text: String, level: String, margin: u8` | `Result` | 编码文本为 QR,返回 SVG + 版本/尺寸/掩码 | | `export_png` | `text: String, level: String, margin: u8, module_size: u8` | `Result, String>` | 编码并导出 PNG 字节 | | `save_history` | `entry: HistoryEntry` | `Result<(), String>` | 添加历史记录(最多 50 条) | | `load_history` | — | `Result, String>` | 加载全部历史记录 | | `clear_history` | — | `Result<(), String>` | 清空历史记录 | ## Web API | Endpoint | 参数 | 返回 | |----------|------|------| | `GET /` | — | HTML 页面(内嵌 7 种编码模式) | | `GET /api/qr` | `text`, `level`(L/M/Q/H), `margin`(1-20), `size`(2-20), `fmt`(svg) | PNG 或 SVG | ## 前端状态管理 ``` QrState { mode → 当前编码模式 (text/url/wifi/vcard/email/phone/sms) formData → 各模式表单数据 (Record) config → { level: L|M|Q|H, margin: 1-10, moduleSize: 2-20 } preview → { svg, version, size, mask } | null history → HistoryEntry[] (最多 50 条, FIFO, 含 formData 字段用于恢复) loading → boolean } Action: SET_MODE | SET_FORM_DATA | SET_CONFIG | SET_PREVIEW | SET_LOADING | SET_HISTORY | ADD_HISTORY | REMOVE_HISTORY | RESET ``` ## 编码模式文本格式 | 模式 | QR 内容格式 | |------|-----------| | text | 原始文本 | | url | 原始 URL(失焦自动补全 `https://`) | | wifi | `WIFI:T:;S:;P:;;` | | vcard | `BEGIN:VCARD\nVERSION:3.0\nFN:...\nTEL:...\nEMAIL:...\nORG:...\nADR:...\nEND:VCARD` | | email | `mailto:?subject=&body=` | | phone | `tel:` | | sms | `smsto::` | ## 关键约束 - **Rust 工具链**:`stable-x86_64-pc-windows-gnu`,MinGW-Builds GCC 15.2.0 - **MinGW 兼容**:`.cargo/config.toml` 已添加 `-lmcfgthread` 链接标志 - **qr-core 纯算法**:除 `image` (PNG) 外无外部依赖,不依赖任何 QR 编码库 - **WebView2**:Windows 10+ 自带,打包需 `WebView2Loader.dll` - **GUI beforeBuildCommand**:Tauri CWD 在 `gui/src-frontend/`,用 `npm run build`(非 pnpm) - **GUI 导出**:需 `tauri-plugin-fs` + `fs:allow-write-file` + `$HOME/**` scope - **Docker 构建**:`web/Dockerfile` 用 sed 移除 gui 成员避免拉 Tauri 依赖 ## 已知坑位 - **PNG margin**:不能用 `saturating_sub` 检测 margin——它在 0 处回绕,导致 quiet zone 全黑 - **Finder separator**:必须预留四边隔离带(不只是右侧和底部),否则数据模块会破坏 finder 检测 - **Tauri 导出**:`tauri-plugin-fs` 需同时在 Cargo.toml、lib.rs `.plugin()` 和 capabilities 三处注册 ## 测试覆盖 | 层级 | 数量 | 说明 | |------|------|------| | 单元测试 | 58 | Galois 运算、RS 编码、模式编码、掩码评分、格式信息等 | | 集成测试 | 24 | 端到端编码、渲染输出验证、边距、特殊字符、自动版本选择、格式信息 roundtrip | | 总计 | 82 | `cargo test` 全部通过 | ## 版本号升级清单 | 文件 | 字段 | 说明 | |------|------|------| | `Cargo.toml` | `[workspace.package] version` | Rust 全量自动继承 | | `gui/tauri.conf.json` | `version` | 打包版本号 | | `gui/tauri.conf.json` | 窗口 `title` | 窗口标题栏 | Release 操作: - `git tag vX.Y.Z && git push --tags` - `tea release create --login cloud --repo Serendipity/QRGen --tag vX.Y.Z`