diff --git a/docs/docs.go b/docs/docs.go
index 7a46e285..91af347b 100644
--- a/docs/docs.go
+++ b/docs/docs.go
@@ -589,6 +589,65 @@ const docTemplate = `{
}
}
},
+ "/api/v1/projects/{id}/pending-payment": {
+ "get": {
+ "description": "只返回指定项目下当前用户已有且未过期的待支付订单,不重新占用库存或刷新有效期",
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "payment"
+ ],
+ "summary": "获取当前用户的待支付订单",
+ "parameters": [
+ {
+ "type": "string",
+ "description": "项目ID",
+ "name": "id",
+ "in": "path",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "allOf": [
+ {
+ "$ref": "#/definitions/payment.Response"
+ },
+ {
+ "type": "object",
+ "properties": {
+ "data": {
+ "$ref": "#/definitions/payment.PendingPaymentResponseData"
+ }
+ }
+ }
+ ]
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/payment.Response"
+ }
+ },
+ "404": {
+ "description": "Not Found",
+ "schema": {
+ "$ref": "#/definitions/project.ProjectResponse"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/payment.Response"
+ }
+ }
+ }
+ }
+ },
"/api/v1/projects/{id}/receivers": {
"get": {
"consumes": [
@@ -977,6 +1036,29 @@ const docTemplate = `{
}
}
},
+ "payment.PendingPaymentResponseData": {
+ "type": "object",
+ "properties": {
+ "amount": {
+ "type": "string"
+ },
+ "has_pending": {
+ "type": "boolean"
+ },
+ "pay_url": {
+ "type": "string"
+ }
+ }
+ },
+ "payment.Response": {
+ "type": "object",
+ "properties": {
+ "data": {},
+ "error_msg": {
+ "type": "string"
+ }
+ }
+ },
"project.CreateProjectRequestBody": {
"type": "object",
"required": [
diff --git a/docs/swagger.json b/docs/swagger.json
index 04f9deae..8ff4ed27 100644
--- a/docs/swagger.json
+++ b/docs/swagger.json
@@ -580,6 +580,65 @@
}
}
},
+ "/api/v1/projects/{id}/pending-payment": {
+ "get": {
+ "description": "只返回指定项目下当前用户已有且未过期的待支付订单,不重新占用库存或刷新有效期",
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "payment"
+ ],
+ "summary": "获取当前用户的待支付订单",
+ "parameters": [
+ {
+ "type": "string",
+ "description": "项目ID",
+ "name": "id",
+ "in": "path",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "allOf": [
+ {
+ "$ref": "#/definitions/payment.Response"
+ },
+ {
+ "type": "object",
+ "properties": {
+ "data": {
+ "$ref": "#/definitions/payment.PendingPaymentResponseData"
+ }
+ }
+ }
+ ]
+ }
+ },
+ "400": {
+ "description": "Bad Request",
+ "schema": {
+ "$ref": "#/definitions/payment.Response"
+ }
+ },
+ "404": {
+ "description": "Not Found",
+ "schema": {
+ "$ref": "#/definitions/project.ProjectResponse"
+ }
+ },
+ "500": {
+ "description": "Internal Server Error",
+ "schema": {
+ "$ref": "#/definitions/payment.Response"
+ }
+ }
+ }
+ }
+ },
"/api/v1/projects/{id}/receivers": {
"get": {
"consumes": [
@@ -968,6 +1027,29 @@
}
}
},
+ "payment.PendingPaymentResponseData": {
+ "type": "object",
+ "properties": {
+ "amount": {
+ "type": "string"
+ },
+ "has_pending": {
+ "type": "boolean"
+ },
+ "pay_url": {
+ "type": "string"
+ }
+ }
+ },
+ "payment.Response": {
+ "type": "object",
+ "properties": {
+ "data": {},
+ "error_msg": {
+ "type": "string"
+ }
+ }
+ },
"project.CreateProjectRequestBody": {
"type": "object",
"required": [
diff --git a/docs/swagger.yaml b/docs/swagger.yaml
index 8461a3c5..e31a2652 100644
--- a/docs/swagger.yaml
+++ b/docs/swagger.yaml
@@ -170,6 +170,21 @@ definitions:
error_msg:
type: string
type: object
+ payment.PendingPaymentResponseData:
+ properties:
+ amount:
+ type: string
+ has_pending:
+ type: boolean
+ pay_url:
+ type: string
+ type: object
+ payment.Response:
+ properties:
+ data: {}
+ error_msg:
+ type: string
+ type: object
project.CreateProjectRequestBody:
properties:
allow_same_ip:
@@ -772,6 +787,42 @@ paths:
$ref: '#/definitions/project.ProjectResponse'
tags:
- project
+ /api/v1/projects/{id}/pending-payment:
+ get:
+ description: 只返回指定项目下当前用户已有且未过期的待支付订单,不重新占用库存或刷新有效期
+ parameters:
+ - description: 项目ID
+ in: path
+ name: id
+ required: true
+ type: string
+ produces:
+ - application/json
+ responses:
+ "200":
+ description: OK
+ schema:
+ allOf:
+ - $ref: '#/definitions/payment.Response'
+ - properties:
+ data:
+ $ref: '#/definitions/payment.PendingPaymentResponseData'
+ type: object
+ "400":
+ description: Bad Request
+ schema:
+ $ref: '#/definitions/payment.Response'
+ "404":
+ description: Not Found
+ schema:
+ $ref: '#/definitions/project.ProjectResponse'
+ "500":
+ description: Internal Server Error
+ schema:
+ $ref: '#/definitions/payment.Response'
+ summary: 获取当前用户的待支付订单
+ tags:
+ - payment
/api/v1/projects/{id}/receivers:
get:
consumes:
diff --git a/frontend/components/common/receive/ReceiveContent.tsx b/frontend/components/common/receive/ReceiveContent.tsx
index 4d7edc94..389194eb 100644
--- a/frontend/components/common/receive/ReceiveContent.tsx
+++ b/frontend/components/common/receive/ReceiveContent.tsx
@@ -17,6 +17,7 @@ import {ReceiveVerify, ReceiveVerifyRef} from '@/components/common/receive/Recei
import services from '@/lib/services';
import {BasicUserInfo} from '@/lib/services/core';
import {GetProjectResponseData} from '@/lib/services/project';
+import {PendingPaymentData} from '@/lib/services/payment';
import {formatDate, formatDateTimeWithSeconds, copyToClipboard} from '@/lib/utils';
import {motion} from 'motion/react';
import {Separator} from '@/components/ui/separator';
@@ -46,7 +47,11 @@ interface ReceiveButtonProps {
user: BasicUserInfo | null;
currentTime: Date;
isVerifying: boolean;
+ isCheckingPendingPayment: boolean;
+ isContinuingPayment: boolean;
+ pendingPayment: PendingPaymentData | null;
onReceive: () => void;
+ onContinuePayment: () => void;
}
/**
@@ -57,11 +62,17 @@ const ReceiveButton = ({
user,
currentTime,
isVerifying,
+ isCheckingPendingPayment,
+ isContinuingPayment,
+ pendingPayment,
onReceive,
+ onContinuePayment,
}: ReceiveButtonProps) => {
const now = currentTime;
const startTime = new Date(project.start_time);
const endTime = new Date(project.end_time);
+ const priceNum = Number(project.price || '0');
+ const isPaid = priceNum > 0;
if (now < startTime) {
const timeRemaining = getTimeRemainingText(startTime, now);
@@ -82,6 +93,28 @@ const ReceiveButton = ({
);
}
+ if (isPaid && project.available_items_count <= 0 && isCheckingPendingPayment) {
+ return (
+
+ );
+ }
+
+ if (pendingPayment?.has_pending && pendingPayment.pay_url) {
+ return (
+
+ );
+ }
+
if (project.available_items_count <= 0) {
return (