feat: web 端 GUI 风格界面 + SVG 支持 + 预览清晰度修复

- index.html: 完整复刻 GUI 三栏布局(模式/预览/设置)
  7 种编码模式切换,实时防抖预览,下载 PNG/SVG/复制
- main.rs: API 新增 fmt=svg 参数,预览用 PNG size=8 避免拉伸模糊
- Dockerfile: 多阶段构建(alpine),部署就绪

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-06-18 11:52:08 +08:00
parent 6ba79a99d3
commit dcd53b2691
2 changed files with 253 additions and 102 deletions
+13 -7
View File
@@ -19,6 +19,9 @@ struct QrParams {
margin: u8,
#[serde(default = "default_size")]
size: u8,
/// fmt=svg 返回 SVG,否则返回 PNG
#[serde(default)]
fmt: String,
}
fn default_level() -> String { "M".into() }
@@ -40,7 +43,7 @@ async fn index() -> Html<&'static str> {
Html(include_str!("templates/index.html"))
}
/// QR 码生成 API → PNG 图片
/// QR 码生成 API → PNG 或 SVG
async fn generate_qr(Query(params): Query<QrParams>) -> impl IntoResponse {
let level = match parse_level(&params.level) {
Ok(l) => l,
@@ -58,12 +61,15 @@ async fn generate_qr(Query(params): Query<QrParams>) -> impl IntoResponse {
Err(e) => return (StatusCode::BAD_REQUEST, e).into_response(),
};
let png = match qr.to_png_bytes(params.size) {
Ok(b) => b,
Err(e) => return (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()).into_response(),
};
([(header::CONTENT_TYPE, "image/png")], png).into_response()
if params.fmt == "svg" {
let svg = qr.to_svg();
([(header::CONTENT_TYPE, "image/svg+xml")], svg).into_response()
} else {
match qr.to_png_bytes(params.size) {
Ok(b) => ([(header::CONTENT_TYPE, "image/png")], b).into_response(),
Err(e) => (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()).into_response(),
}
}
}
#[tokio::main]