From a05b46dfe27cb9c6cf1c321019b6df797b9d4b4e Mon Sep 17 00:00:00 2001 From: Milky0217 Date: Thu, 7 May 2026 16:58:55 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=20POST=20/api/paymen?= =?UTF-8?q?t/sync-order=20=E6=8E=A5=E5=8F=A3=EF=BC=8C=E7=94=A8=E4=BA=8E?= =?UTF-8?q?=E5=BC=BA=E5=88=B6=E5=90=8C=E6=AD=A5=E8=AE=A2=E5=8D=95=E4=BC=9A?= =?UTF-8?q?=E5=91=98=E7=8A=B6=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/handlers/mod.rs | 1 + src/handlers/payment.rs | 37 +++++++++++++++++++++++++++++++++++++ src/main.rs | 3 ++- 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/handlers/mod.rs b/src/handlers/mod.rs index c79a455..e757139 100644 --- a/src/handlers/mod.rs +++ b/src/handlers/mod.rs @@ -41,6 +41,7 @@ pub use payment::create_order; pub use payment::generate_code; pub use payment::get_user_quota; pub use payment::mock_confirm; +pub use payment::sync_order; pub use payment::payment_index; pub use payment::payment_login_status; pub use payment::payment_page; diff --git a/src/handlers/payment.rs b/src/handlers/payment.rs index bb44a6e..d121a0e 100644 --- a/src/handlers/payment.rs +++ b/src/handlers/payment.rs @@ -936,6 +936,43 @@ pub async fn mock_confirm( }))) } +/// POST /api/payment/sync-order — 根据订单号强制同步会员状态 +/// +/// 用户支付完成后,若前端会员状态未刷新,可调用此接口同步确认订单并获取最新状态。 +#[post("/api/payment/sync-order")] +pub async fn sync_order( + pool: web::Data, + claims: web::ReqData, + body: web::Json, +) -> Result { + let user_id = claims.user_id; + + // 尝试确认订单(幂等) + let _ = db::confirm_payment_order(pool.get_ref(), &body.order_id, user_id).await; + + // 查询最新状态 + let user = sqlx::query_as::<_, (bool, Option>)>( + r#"SELECT is_paid, paid_expires_at FROM users WHERE id = $1"#, + ) + .bind(user_id) + .fetch_optional(pool.get_ref()) + .await + .map_err(|e| AppError::Database(format!("查询用户失败: {}", e)))? + .ok_or_else(|| AppError::NotFound("用户不存在".to_string()))?; + + let (is_paid, paid_expires_at) = user; + let is_paid_active = is_paid && (paid_expires_at.is_none() || paid_expires_at.unwrap() > Utc::now()); + + Ok(HttpResponse::Ok().json(serde_json::json!({ + "success": true, + "data": { + "is_paid": is_paid, + "is_paid_active": is_paid_active, + "paid_expires_at": paid_expires_at, + } + }))) +} + /// GET /api/user/quota #[get("/api/user/quota")] pub async fn get_user_quota( diff --git a/src/main.rs b/src/main.rs index 3ac7c45..be02909 100644 --- a/src/main.rs +++ b/src/main.rs @@ -21,7 +21,7 @@ use handlers::{ admin_get_user, admin_update_user_payment, add_favorite, alipay_notify, alipay_pay_page, create_order, delete_weather, generate_code, generate_temp_token_handler, get_current_user_profile, get_favorites, get_user_quota, get_weather_brief, get_weather_details, - health_check, login, mock_login, mock_confirm, payment_index, payment_login_status, payment_page, payment_success, + health_check, login, mock_login, mock_confirm, sync_order, payment_index, payment_login_status, payment_page, payment_success, post_weather_data, refresh_token, remove_favorite, root, save_user_profile, serve_static_files, web_generate_login_code, web_login_confirm, web_login_auto_confirm, @@ -96,6 +96,7 @@ fn create_server_config( .service(admin_update_user_payment) .service(create_order) .service(mock_confirm) + .service(sync_order) .service(get_user_quota) .service(get_favorites) .service(add_favorite)