diff --git a/src/handlers/payment.rs b/src/handlers/payment.rs index 58ba62c..f33f17e 100644 --- a/src/handlers/payment.rs +++ b/src/handlers/payment.rs @@ -596,6 +596,9 @@ pub struct PaymentPageQuery { /// JWT: 从 URL 参数传入(外部浏览器无 Cookie 时使用) #[serde(default)] pub jwt: Option, + /// 复用已有待支付订单的 order_no(不创建新订单) + #[serde(default)] + pub resume: Option, } #[get("/payment/page")] @@ -615,18 +618,38 @@ pub async fn payment_page( let pkg = get_package_info(&query.package_) .ok_or_else(|| AppError::BadRequest("无效的套餐类型".to_string()))?; - let order_no = Uuid::new_v4().to_string(); - let expires_at = pkg.days.map(|d| Utc::now() + chrono::Duration::days(d)); + // 复用已有待支付订单(如果提供了 resume order_no) + let order_no = if let Some(ref resume_no) = query.resume { + let existing: Option<(i32, String)> = sqlx::query_as( + r#"SELECT user_id, status FROM payment_orders WHERE order_no = $1"#, + ) + .bind(resume_no) + .fetch_optional(pool.get_ref()) + .await + .map_err(|e| AppError::Database(format!("查询订单失败: {}", e)))?; - db::create_payment_order( - pool.get_ref(), - claims.user_id, - &order_no, - &query.package_, - pkg.amount, - expires_at, - ) - .await?; + match existing { + Some((uid, status)) if uid == claims.user_id && status == "pending" => { + resume_no.clone() + } + _ => { + // 订单不存在/不属于该用户/已支付 → 创建新订单 + let new_no = Uuid::new_v4().to_string(); + let expires_at = pkg.days.map(|d| Utc::now() + chrono::Duration::days(d)); + db::create_payment_order( + pool.get_ref(), claims.user_id, &new_no, &query.package_, pkg.amount, expires_at, + ).await?; + new_no + } + } + } else { + let new_no = Uuid::new_v4().to_string(); + let expires_at = pkg.days.map(|d| Utc::now() + chrono::Duration::days(d)); + db::create_payment_order( + pool.get_ref(), claims.user_id, &new_no, &query.package_, pkg.amount, expires_at, + ).await?; + new_no + }; let base_url = std::env::var("APP_BASE_URL") .unwrap_or_else(|_| "https://dev.xmclassmate.top".to_string());