fix: 统一字段命名为 camelCase 并修复详情 API

- models.rs: 将 inspectiontype/assignmentnumber 的 serde rename 改为
  inspectionType/assignmentNumber,与前端 TypeScript 接口保持一致
- models.rs: 为 WeatherDataBrief 添加 isFavorite 字段支持
- models.rs: WeatherData.is_favorite 添加 skip_deserializing 避免 POST
  请求解析失败,同时使用 default 处理数据库 NULL 值
- handlers/weather.rs: get_weather_details 支持 string 和 number 类型的
  id 参数解析
- IMPROVEMENTS.md: 新增第十三章记录本次对话经验(serde 配置、config
  路径解析、TOML 结构等)
This commit is contained in:
2026-04-17 20:47:00 +08:00
parent bdbba2cd60
commit 61b1174b30
6 changed files with 124 additions and 15 deletions

View File

@@ -118,8 +118,8 @@ pub async fn create_pool() -> Result<PgPool, Box<dyn Error>> {
// 获取天气数据详情
pub async fn get_weather_details(pool: &PgPool, weather_id: i32) -> Result<WeatherData, String> {
let query = r#"
SELECT
wd.id, wd.title, wd.date, wd.hour, wd.min,
SELECT
wd.id, wd.title, wd.date, wd.hour, wd.min,
wd.longitude, wd.latitude,
wd.daysincejanfirst, wd.theta, wd.solardeclination,
wd.sunaltitude, wd.overallcloudiness, wd.lowcloudiness,

View File

@@ -113,9 +113,13 @@ pub async fn get_weather_details(
};
(temp_claims.openid, temp_claims.resource_id)
} else if let Some(claims) = claims {
let weather_id = match query.get("id").and_then(|v| v.as_i64()) {
Some(id) => id as i32,
None => {
let weather_id = match query.get("id") {
Some(v) if v.is_i64() => v.as_i64().unwrap() as i32,
Some(v) if v.is_string() => {
v.as_str().and_then(|s| s.parse::<i32>().ok()).unwrap_or(0)
}
Some(v) if v.is_number() => v.as_f64().unwrap() as i32,
_ => {
return HttpResponse::BadRequest().json(ErrorResponse {
error: "缺少资源ID参数id".to_string(),
errcode: Some(400),

View File

@@ -63,13 +63,13 @@ fn create_server_config(
.service(web::resource("/static/{tail:.*}").route(web::get().to(serve_static_files)))
// API 接口
.service(login) // #[post("/api/login")]
.service(get_weather_details) // #[get("/weather/details")]
// 受保护接口JWT
.service(
web::scope("")
.wrap(from_fn(jwt_middleware))
.service(post_weather_data) // #[post("/api/post-weather-data")]
.service(get_weather_brief) // #[get("/api/weather")]
.service(get_weather_details) // #[get("/weather/details")] ← 移入受保护作用域
.service(generate_temp_token_handler) // #[post("/api/generate-temp-token/{resource_id}")]
.service(delete_weather) // #[delete("/api/weather/delete/{id}")]
.service(get_current_user_profile) // #[get("/api/user/profile")]

View File

@@ -113,6 +113,7 @@ pub struct WeatherDataBrief {
pub longitude: String,
pub latitude: String,
#[serde(rename = "isFavorite", default)]
pub is_favorite: bool,
}
@@ -134,7 +135,7 @@ pub struct WeatherData {
#[sqlx(rename = "areatype")]
pub area_type: String,
#[serde(rename = "assignmentnumber")]
#[serde(rename = "assignmentNumber")]
#[sqlx(rename = "assignmentnumber")]
pub assignment_number: Option<String>,
@@ -186,7 +187,7 @@ pub struct WeatherData {
#[sqlx(rename = "hour")]
pub hours: i32,
#[serde(rename = "inspectiontype")]
#[serde(rename = "inspectionType")]
#[sqlx(rename = "inspectiontype")]
pub inspection_type: Option<String>,
@@ -266,6 +267,8 @@ pub struct WeatherData {
#[sqlx(rename = "windspeedsuitability")]
pub wind_speed_suitability: String,
#[serde(skip_deserializing)]
#[serde(rename = "isFavorite", default)]
pub is_favorite: bool,
}