diff --git a/Cargo.lock b/Cargo.lock index f874137..2590835 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,6 +19,29 @@ dependencies = [ "tracing", ] +[[package]] +name = "actix-files" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c0d87f10d70e2948ad40e8edea79c8e77c6c66e0250a4c1f09b690465199576" +dependencies = [ + "actix-http", + "actix-service", + "actix-utils", + "actix-web", + "bitflags", + "bytes", + "derive_more", + "futures-core", + "http-range", + "log", + "mime", + "mime_guess", + "percent-encoding", + "pin-project-lite", + "v_htmlescape", +] + [[package]] name = "actix-http" version = "3.11.1" @@ -952,6 +975,12 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "http-range" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21dec9db110f5f872ed9699c3ecf50cf16f423502706ba5c72462e28d3157573" + [[package]] name = "httparse" version = "1.10.1" @@ -1393,6 +1422,16 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "mime_guess" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase", +] + [[package]] name = "miniz_oxide" version = "0.8.9" @@ -1875,6 +1914,7 @@ dependencies = [ name = "rust-backend" version = "0.1.0" dependencies = [ + "actix-files", "actix-web", "chrono", "dotenvy", @@ -2672,6 +2712,12 @@ version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" +[[package]] +name = "unicase" +version = "2.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" + [[package]] name = "unicode-bidi" version = "0.3.18" @@ -2739,6 +2785,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "v_htmlescape" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e8257fbc510f0a46eb602c10215901938b5c2a7d5e70fc11483b1d3c9b5b18c" + [[package]] name = "vcpkg" version = "0.2.15" diff --git a/Cargo.toml b/Cargo.toml index e1f8f78..d0cf83b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" edition = "2024" [dependencies] +actix-files = "0.6.8" actix-web = "4.11.0" chrono = {version = "0.4.41", features=["serde"]} dotenvy = "0.15.7" diff --git a/src/main.rs b/src/main.rs index 6e078a0..f30e602 100644 --- a/src/main.rs +++ b/src/main.rs @@ -266,12 +266,11 @@ async fn generate_temp_token_handler( } // 获取天气数据详情 -// 修改获取天气数据详情接口(移除路径中的id参数) #[get("/weather/details")] async fn get_weather_details( pool: web::Data, - claims: Option>, // 原有JWT的claims变为可选 - query: web::Query, // 用于获取URL参数temp_token和id + claims: Option>, + query: web::Query, ) -> impl Responder { let jwt_secret = match std::env::var("JWT_SECRET") { Ok(secret) => secret, @@ -284,9 +283,12 @@ async fn get_weather_details( } }; + // 标记是否使用临时token + let mut is_temp_token = false; // 1. 优先检查临时token(URL参数) let (openid, weather_id) = if let Some(temp_token) = query.get("temp_token").and_then(|v| v.as_str()) { + is_temp_token = true; // 标记为临时token访问 // 验证临时token let temp_claims = match auth::verify_temp_token(temp_token, &jwt_secret) { Ok(c) => c, @@ -327,20 +329,17 @@ async fn get_weather_details( }); }; - // 后续逻辑:校验openid对资源的权限(复用原有逻辑) - match db::get_weather_details(pool.get_ref(), weather_id).await { - Ok(weather_data) => { - if weather_data.openid != openid { + // 获取天气数据 + let weather_data = match db::get_weather_details(pool.get_ref(), weather_id).await { + Ok(data) => { + if data.openid != openid { return HttpResponse::Forbidden().json(ErrorResponse { error: "无权限访问该数据".to_string(), errcode: Some(403), errmsg: None, }); } - HttpResponse::Ok().json(serde_json::json!({ - "success": true, - "data": weather_data - })) + data } Err(error_msg) => { eprintln!("获取天气数据详情失败: {}", error_msg); @@ -349,12 +348,59 @@ async fn get_weather_details( } else { 500 }; - HttpResponse::Ok().json(serde_json::json!({ + return HttpResponse::Ok().json(serde_json::json!({ "success": false, "errcode": errcode, "errmsg": error_msg - })) + })); } + }; + // 根据访问方式返回不同格式 + if is_temp_token { + // 临时token访问:返回HTML页面,数据交由前端afterbody.js渲染 + // 读取模板文件 + let index_html = match TEMPLATES_DIR.get_file("index.html") { + Some(file) => file.contents_utf8().unwrap_or_default(), + None => { + return HttpResponse::InternalServerError().json(ErrorResponse { + error: "无法找到模板文件".to_string(), + errcode: Some(500), + errmsg: None, + }); + } + }; + + // 将天气数据序列化为JSON字符串,供前端JS使用 + let weather_data_json = serde_json::to_string(&weather_data).unwrap_or_default(); + + // 生成数据注入脚本:将数据挂载到window对象,供afterbody.js访问 + let data_script = format!( + r#" + + "#, + weather_data_json + ); + + // 将数据脚本插入到模板中,同时显示详细信息容器 + let rendered_html = index_html + .replace("", &data_script) + .replace( + "style=\"display: none;\"", + "", // 显示详细信息容器,供前端渲染内容 + ); + + HttpResponse::Ok() + .content_type("text/html; charset=utf-8") + .body(rendered_html) + } else { + // JWT访问:返回JSON数据 + HttpResponse::Ok().json(serde_json::json!({ + "success": true, + "data": weather_data + })) } } @@ -458,6 +504,34 @@ async fn delete_weather( } } +// 在 main.rs 中添加以下函数,用于处理静态文件请求 +async fn serve_static_files(path: web::Path) -> impl Responder { + // 获取请求的文件路径(例如 "css/style.css") + let file_path = path.into_inner(); + + // 从嵌入的 STATIC_DIR 中查找文件 + match STATIC_DIR.get_file(&file_path) { + Some(file) => { + // 根据文件扩展名设置 Content-Type + let content_type = match file_path.split('.').last() { + Some("css") => "text/css", + Some("js") => "application/javascript", + Some("html") => "text/html", + Some("ttf") | Some("woff") | Some("woff2") => "font/woff2", // 字体文件 + _ => "application/octet-stream", // 默认类型 + }; + + HttpResponse::Ok() + .content_type(content_type) + .body(file.contents()) + } + None => { + // 文件不存在时返回 404 + HttpResponse::NotFound().body("静态文件不存在") + } + } +} + // 创建服务器配置的函数 fn create_server_config( pool: PgPool, @@ -475,6 +549,8 @@ fn create_server_config( .app_data(web::Data::new(pool)) .app_data(web::Data::new(http_client)) // 公开接口(无需验证) + // 注册静态文件服务:处理 /static/* 路径的请求 + .service(web::resource("/static/{tail:.*}").route(web::get().to(serve_static_files))) .service(login) .service(get_weather_details) // 新增 // 需要验证的接口(使用 from_fn 包装中间件) diff --git a/static/js/afterbody.js b/static/js/afterbody.js index 4307112..8416b82 100644 --- a/static/js/afterbody.js +++ b/static/js/afterbody.js @@ -42,6 +42,8 @@ document.addEventListener('DOMContentLoaded', function() { if (versionElement) { versionElement.textContent = `版本号: ${version}`; } + + console.log(window.weatherData) }); // 下载按钮 @@ -365,10 +367,6 @@ document.getElementById('downloadBtn').addEventListener('click', function() { }, 2000); // 假设下载需要2秒完成,你可以根据实际情况调整 }); -// 获取记录内容 -document.getElementById('viewDetailsBtn').addEventListener('click', function() { -}); - // 工具函数 // 函数用于将日期格式化为 xxxx-xx-xx 形式 diff --git a/templates/index.html b/templates/index.html index 46a1d34..d18955c 100644 --- a/templates/index.html +++ b/templates/index.html @@ -2,11 +2,11 @@ KaTeX示例 - - - - - + + + + + @@ -75,7 +75,7 @@
- +