feat: support balance pay
This commit is contained in:
@@ -5,12 +5,14 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"quyun/app/jobs"
|
||||||
"quyun/app/models"
|
"quyun/app/models"
|
||||||
"quyun/app/requests"
|
"quyun/app/requests"
|
||||||
"quyun/database/conds"
|
"quyun/database/conds"
|
||||||
"quyun/database/fields"
|
"quyun/database/fields"
|
||||||
"quyun/database/schemas/public/model"
|
"quyun/database/schemas/public/model"
|
||||||
"quyun/providers/ali"
|
"quyun/providers/ali"
|
||||||
|
"quyun/providers/job"
|
||||||
"quyun/providers/wepay"
|
"quyun/providers/wepay"
|
||||||
|
|
||||||
"github.com/go-pay/gopay/wechat/v3"
|
"github.com/go-pay/gopay/wechat/v3"
|
||||||
@@ -28,6 +30,7 @@ type ListQuery struct {
|
|||||||
type posts struct {
|
type posts struct {
|
||||||
wepay *wepay.Client
|
wepay *wepay.Client
|
||||||
oss *ali.OSSClient
|
oss *ali.OSSClient
|
||||||
|
job *job.Job
|
||||||
}
|
}
|
||||||
|
|
||||||
// List posts
|
// List posts
|
||||||
@@ -276,6 +279,22 @@ func (ctl *posts) Buy(ctx fiber.Ctx, id int64, user *model.Users) (*wechat.JSAPI
|
|||||||
}
|
}
|
||||||
|
|
||||||
payPrice := post.Price * int64(post.Discount) / 100
|
payPrice := post.Price * int64(post.Discount) / 100
|
||||||
|
if user.Balance >= payPrice {
|
||||||
|
err = models.Users.SetBalance(ctx.Context(), user.ID, user.Balance-payPrice)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "余额支付失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := ctl.job.Add(&jobs.BalancePayNotify{OrderNo: order.OrderNo}); err != nil {
|
||||||
|
log.Errorf("add job error:%v", err)
|
||||||
|
return nil, errors.Wrap(err, "Failed to add job")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &wechat.JSAPIPayParams{
|
||||||
|
AppId: "balance",
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
prePayResp, err := ctl.wepay.V3TransactionJsapi(ctx.Context(), func(bm *wepay.BodyMap) {
|
prePayResp, err := ctl.wepay.V3TransactionJsapi(ctx.Context(), func(bm *wepay.BodyMap) {
|
||||||
bm.
|
bm.
|
||||||
Expire(30 * time.Minute).
|
Expire(30 * time.Minute).
|
||||||
|
|||||||
88
backend/app/jobs/balance_pay_notify.go
Normal file
88
backend/app/jobs/balance_pay_notify.go
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
package jobs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"quyun/app/models"
|
||||||
|
"quyun/database/fields"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
. "github.com/riverqueue/river"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
_ "go.ipao.vip/atom"
|
||||||
|
"go.ipao.vip/atom/contracts"
|
||||||
|
_ "go.ipao.vip/atom/contracts"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ contracts.JobArgs = (*BalancePayNotify)(nil)
|
||||||
|
|
||||||
|
type BalancePayNotify struct {
|
||||||
|
OrderNo string `json:"order_no"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s BalancePayNotify) InsertOpts() InsertOpts {
|
||||||
|
return InsertOpts{
|
||||||
|
Queue: QueueDefault,
|
||||||
|
Priority: PriorityDefault,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (BalancePayNotify) Kind() string { return "balance_pay_notify" }
|
||||||
|
func (a BalancePayNotify) UniqueID() string { return a.Kind() }
|
||||||
|
|
||||||
|
var _ Worker[BalancePayNotify] = (*BalancePayNotifyWorker)(nil)
|
||||||
|
|
||||||
|
// @provider(job)
|
||||||
|
type BalancePayNotifyWorker struct {
|
||||||
|
WorkerDefaults[BalancePayNotify]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *BalancePayNotifyWorker) Work(ctx context.Context, job *Job[BalancePayNotify]) error {
|
||||||
|
log := log.WithField("job", job.Args.Kind())
|
||||||
|
|
||||||
|
log.Infof("[Start] Working on job with strings: %+v", job.Args)
|
||||||
|
defer log.Infof("[End] Finished %s", job.Args.Kind())
|
||||||
|
|
||||||
|
order, err := models.Orders.GetByOrderNo(context.Background(), job.Args.OrderNo)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("GetByOrderNo error:%v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if order.Status != fields.OrderStatusPending {
|
||||||
|
log.Infof("Order %s is paid, processing...", job.Args.OrderNo)
|
||||||
|
return JobCancel(fmt.Errorf("Order already paid, currently status: %d", order.Status))
|
||||||
|
}
|
||||||
|
|
||||||
|
order.PaymentMethod = "balance"
|
||||||
|
order.Status = fields.OrderStatusCompleted
|
||||||
|
log.Infof("Updated order details: %+v", order)
|
||||||
|
tx, err := models.Transaction(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "Transaction error")
|
||||||
|
}
|
||||||
|
defer tx.Rollback()
|
||||||
|
|
||||||
|
if err := models.Users.BuyPosts(context.Background(), order.UserID, order.PostID, order.Price); err != nil {
|
||||||
|
log.Errorf("BuyPosts error:%v", err)
|
||||||
|
return errors.Wrap(err, "BuyPosts error")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := models.Orders.Update(context.Background(), order); err != nil {
|
||||||
|
log.Errorf("Update order error:%v", err)
|
||||||
|
return errors.Wrap(err, "Update order error")
|
||||||
|
}
|
||||||
|
if err := tx.Commit(); err != nil {
|
||||||
|
log.Errorf("Commit error:%v", err)
|
||||||
|
return errors.Wrap(err, "Commit error")
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Infof("Successfully processed order %s", order.OrderNo)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *BalancePayNotifyWorker) NextRetry(job *Job[BalancePayNotify]) time.Time {
|
||||||
|
return time.Now().Add(30 * time.Second)
|
||||||
|
}
|
||||||
@@ -474,3 +474,21 @@ func (m *usersModel) RevokePosts(ctx context.Context, userID, postID int64) erro
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetBalance
|
||||||
|
func (m *usersModel) SetBalance(ctx context.Context, id int64, balance int64) error {
|
||||||
|
tbl := table.Users
|
||||||
|
stmt := tbl.
|
||||||
|
UPDATE(tbl.Balance).
|
||||||
|
SET(Int64(balance)).
|
||||||
|
WHERE(
|
||||||
|
tbl.ID.EQ(Int64(id)),
|
||||||
|
)
|
||||||
|
m.log.Infof("sql: %s", stmt.DebugSql())
|
||||||
|
|
||||||
|
if _, err := stmt.ExecContext(ctx, db); err != nil {
|
||||||
|
m.log.Errorf("error updating user balance: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
11
backend/database/migrations/20250512113213_alter_user.sql
Normal file
11
backend/database/migrations/20250512113213_alter_user.sql
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
-- +goose Up
|
||||||
|
-- +goose StatementBegin
|
||||||
|
ALTER TABLE public.users
|
||||||
|
ADD balance int8 DEFAULT 0 NOT NULL;
|
||||||
|
-- +goose StatementEnd
|
||||||
|
|
||||||
|
-- +goose Down
|
||||||
|
-- +goose StatementBegin
|
||||||
|
ALTER TABLE public.users
|
||||||
|
DROP COLUMN balance;
|
||||||
|
-- +goose StatementEnd
|
||||||
@@ -19,6 +19,6 @@ type Medias struct {
|
|||||||
MimeType string `json:"mime_type"`
|
MimeType string `json:"mime_type"`
|
||||||
Size int64 `json:"size"`
|
Size int64 `json:"size"`
|
||||||
Path string `json:"path"`
|
Path string `json:"path"`
|
||||||
Hash string `json:"hash"`
|
|
||||||
Metas fields.Json[fields.MediaMetas] `json:"metas"`
|
Metas fields.Json[fields.MediaMetas] `json:"metas"`
|
||||||
|
Hash string `json:"hash"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ type Posts struct {
|
|||||||
DeletedAt *time.Time `json:"deleted_at"`
|
DeletedAt *time.Time `json:"deleted_at"`
|
||||||
Status fields.PostStatus `json:"status"`
|
Status fields.PostStatus `json:"status"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
|
HeadImages fields.Json[[]int64] `json:"head_images"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
Content string `json:"content"`
|
Content string `json:"content"`
|
||||||
Price int64 `json:"price"`
|
Price int64 `json:"price"`
|
||||||
@@ -27,5 +28,4 @@ type Posts struct {
|
|||||||
Likes int64 `json:"likes"`
|
Likes int64 `json:"likes"`
|
||||||
Tags fields.Json[[]string] `json:"tags"`
|
Tags fields.Json[[]string] `json:"tags"`
|
||||||
Assets fields.Json[[]fields.MediaAsset] `json:"assets"`
|
Assets fields.Json[[]fields.MediaAsset] `json:"assets"`
|
||||||
HeadImages fields.Json[[]int64] `json:"head_images"`
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,4 +23,5 @@ type Users struct {
|
|||||||
Avatar *string `json:"avatar"`
|
Avatar *string `json:"avatar"`
|
||||||
Metas fields.Json[fields.UserMetas] `json:"metas"`
|
Metas fields.Json[fields.UserMetas] `json:"metas"`
|
||||||
AuthToken fields.Json[fields.UserAuthToken] `json:"auth_token"`
|
AuthToken fields.Json[fields.UserAuthToken] `json:"auth_token"`
|
||||||
|
Balance int64 `json:"balance"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,8 +23,8 @@ type mediasTable struct {
|
|||||||
MimeType postgres.ColumnString
|
MimeType postgres.ColumnString
|
||||||
Size postgres.ColumnInteger
|
Size postgres.ColumnInteger
|
||||||
Path postgres.ColumnString
|
Path postgres.ColumnString
|
||||||
Hash postgres.ColumnString
|
|
||||||
Metas postgres.ColumnString
|
Metas postgres.ColumnString
|
||||||
|
Hash postgres.ColumnString
|
||||||
|
|
||||||
AllColumns postgres.ColumnList
|
AllColumns postgres.ColumnList
|
||||||
MutableColumns postgres.ColumnList
|
MutableColumns postgres.ColumnList
|
||||||
@@ -71,10 +71,10 @@ func newMediasTableImpl(schemaName, tableName, alias string) mediasTable {
|
|||||||
MimeTypeColumn = postgres.StringColumn("mime_type")
|
MimeTypeColumn = postgres.StringColumn("mime_type")
|
||||||
SizeColumn = postgres.IntegerColumn("size")
|
SizeColumn = postgres.IntegerColumn("size")
|
||||||
PathColumn = postgres.StringColumn("path")
|
PathColumn = postgres.StringColumn("path")
|
||||||
HashColumn = postgres.StringColumn("hash")
|
|
||||||
MetasColumn = postgres.StringColumn("metas")
|
MetasColumn = postgres.StringColumn("metas")
|
||||||
allColumns = postgres.ColumnList{IDColumn, CreatedAtColumn, NameColumn, MimeTypeColumn, SizeColumn, PathColumn, HashColumn, MetasColumn}
|
HashColumn = postgres.StringColumn("hash")
|
||||||
mutableColumns = postgres.ColumnList{CreatedAtColumn, NameColumn, MimeTypeColumn, SizeColumn, PathColumn, HashColumn, MetasColumn}
|
allColumns = postgres.ColumnList{IDColumn, CreatedAtColumn, NameColumn, MimeTypeColumn, SizeColumn, PathColumn, MetasColumn, HashColumn}
|
||||||
|
mutableColumns = postgres.ColumnList{CreatedAtColumn, NameColumn, MimeTypeColumn, SizeColumn, PathColumn, MetasColumn, HashColumn}
|
||||||
)
|
)
|
||||||
|
|
||||||
return mediasTable{
|
return mediasTable{
|
||||||
@@ -87,8 +87,8 @@ func newMediasTableImpl(schemaName, tableName, alias string) mediasTable {
|
|||||||
MimeType: MimeTypeColumn,
|
MimeType: MimeTypeColumn,
|
||||||
Size: SizeColumn,
|
Size: SizeColumn,
|
||||||
Path: PathColumn,
|
Path: PathColumn,
|
||||||
Hash: HashColumn,
|
|
||||||
Metas: MetasColumn,
|
Metas: MetasColumn,
|
||||||
|
Hash: HashColumn,
|
||||||
|
|
||||||
AllColumns: allColumns,
|
AllColumns: allColumns,
|
||||||
MutableColumns: mutableColumns,
|
MutableColumns: mutableColumns,
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ type postsTable struct {
|
|||||||
DeletedAt postgres.ColumnTimestamp
|
DeletedAt postgres.ColumnTimestamp
|
||||||
Status postgres.ColumnInteger
|
Status postgres.ColumnInteger
|
||||||
Title postgres.ColumnString
|
Title postgres.ColumnString
|
||||||
|
HeadImages postgres.ColumnString
|
||||||
Description postgres.ColumnString
|
Description postgres.ColumnString
|
||||||
Content postgres.ColumnString
|
Content postgres.ColumnString
|
||||||
Price postgres.ColumnInteger
|
Price postgres.ColumnInteger
|
||||||
@@ -31,7 +32,6 @@ type postsTable struct {
|
|||||||
Likes postgres.ColumnInteger
|
Likes postgres.ColumnInteger
|
||||||
Tags postgres.ColumnString
|
Tags postgres.ColumnString
|
||||||
Assets postgres.ColumnString
|
Assets postgres.ColumnString
|
||||||
HeadImages postgres.ColumnString
|
|
||||||
|
|
||||||
AllColumns postgres.ColumnList
|
AllColumns postgres.ColumnList
|
||||||
MutableColumns postgres.ColumnList
|
MutableColumns postgres.ColumnList
|
||||||
@@ -78,6 +78,7 @@ func newPostsTableImpl(schemaName, tableName, alias string) postsTable {
|
|||||||
DeletedAtColumn = postgres.TimestampColumn("deleted_at")
|
DeletedAtColumn = postgres.TimestampColumn("deleted_at")
|
||||||
StatusColumn = postgres.IntegerColumn("status")
|
StatusColumn = postgres.IntegerColumn("status")
|
||||||
TitleColumn = postgres.StringColumn("title")
|
TitleColumn = postgres.StringColumn("title")
|
||||||
|
HeadImagesColumn = postgres.StringColumn("head_images")
|
||||||
DescriptionColumn = postgres.StringColumn("description")
|
DescriptionColumn = postgres.StringColumn("description")
|
||||||
ContentColumn = postgres.StringColumn("content")
|
ContentColumn = postgres.StringColumn("content")
|
||||||
PriceColumn = postgres.IntegerColumn("price")
|
PriceColumn = postgres.IntegerColumn("price")
|
||||||
@@ -86,9 +87,8 @@ func newPostsTableImpl(schemaName, tableName, alias string) postsTable {
|
|||||||
LikesColumn = postgres.IntegerColumn("likes")
|
LikesColumn = postgres.IntegerColumn("likes")
|
||||||
TagsColumn = postgres.StringColumn("tags")
|
TagsColumn = postgres.StringColumn("tags")
|
||||||
AssetsColumn = postgres.StringColumn("assets")
|
AssetsColumn = postgres.StringColumn("assets")
|
||||||
HeadImagesColumn = postgres.StringColumn("head_images")
|
allColumns = postgres.ColumnList{IDColumn, CreatedAtColumn, UpdatedAtColumn, DeletedAtColumn, StatusColumn, TitleColumn, HeadImagesColumn, DescriptionColumn, ContentColumn, PriceColumn, DiscountColumn, ViewsColumn, LikesColumn, TagsColumn, AssetsColumn}
|
||||||
allColumns = postgres.ColumnList{IDColumn, CreatedAtColumn, UpdatedAtColumn, DeletedAtColumn, StatusColumn, TitleColumn, DescriptionColumn, ContentColumn, PriceColumn, DiscountColumn, ViewsColumn, LikesColumn, TagsColumn, AssetsColumn, HeadImagesColumn}
|
mutableColumns = postgres.ColumnList{CreatedAtColumn, UpdatedAtColumn, DeletedAtColumn, StatusColumn, TitleColumn, HeadImagesColumn, DescriptionColumn, ContentColumn, PriceColumn, DiscountColumn, ViewsColumn, LikesColumn, TagsColumn, AssetsColumn}
|
||||||
mutableColumns = postgres.ColumnList{CreatedAtColumn, UpdatedAtColumn, DeletedAtColumn, StatusColumn, TitleColumn, DescriptionColumn, ContentColumn, PriceColumn, DiscountColumn, ViewsColumn, LikesColumn, TagsColumn, AssetsColumn, HeadImagesColumn}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return postsTable{
|
return postsTable{
|
||||||
@@ -101,6 +101,7 @@ func newPostsTableImpl(schemaName, tableName, alias string) postsTable {
|
|||||||
DeletedAt: DeletedAtColumn,
|
DeletedAt: DeletedAtColumn,
|
||||||
Status: StatusColumn,
|
Status: StatusColumn,
|
||||||
Title: TitleColumn,
|
Title: TitleColumn,
|
||||||
|
HeadImages: HeadImagesColumn,
|
||||||
Description: DescriptionColumn,
|
Description: DescriptionColumn,
|
||||||
Content: ContentColumn,
|
Content: ContentColumn,
|
||||||
Price: PriceColumn,
|
Price: PriceColumn,
|
||||||
@@ -109,7 +110,6 @@ func newPostsTableImpl(schemaName, tableName, alias string) postsTable {
|
|||||||
Likes: LikesColumn,
|
Likes: LikesColumn,
|
||||||
Tags: TagsColumn,
|
Tags: TagsColumn,
|
||||||
Assets: AssetsColumn,
|
Assets: AssetsColumn,
|
||||||
HeadImages: HeadImagesColumn,
|
|
||||||
|
|
||||||
AllColumns: allColumns,
|
AllColumns: allColumns,
|
||||||
MutableColumns: mutableColumns,
|
MutableColumns: mutableColumns,
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ type usersTable struct {
|
|||||||
Avatar postgres.ColumnString
|
Avatar postgres.ColumnString
|
||||||
Metas postgres.ColumnString
|
Metas postgres.ColumnString
|
||||||
AuthToken postgres.ColumnString
|
AuthToken postgres.ColumnString
|
||||||
|
Balance postgres.ColumnInteger
|
||||||
|
|
||||||
AllColumns postgres.ColumnList
|
AllColumns postgres.ColumnList
|
||||||
MutableColumns postgres.ColumnList
|
MutableColumns postgres.ColumnList
|
||||||
@@ -77,8 +78,9 @@ func newUsersTableImpl(schemaName, tableName, alias string) usersTable {
|
|||||||
AvatarColumn = postgres.StringColumn("avatar")
|
AvatarColumn = postgres.StringColumn("avatar")
|
||||||
MetasColumn = postgres.StringColumn("metas")
|
MetasColumn = postgres.StringColumn("metas")
|
||||||
AuthTokenColumn = postgres.StringColumn("auth_token")
|
AuthTokenColumn = postgres.StringColumn("auth_token")
|
||||||
allColumns = postgres.ColumnList{IDColumn, CreatedAtColumn, UpdatedAtColumn, DeletedAtColumn, StatusColumn, OpenIDColumn, UsernameColumn, AvatarColumn, MetasColumn, AuthTokenColumn}
|
BalanceColumn = postgres.IntegerColumn("balance")
|
||||||
mutableColumns = postgres.ColumnList{CreatedAtColumn, UpdatedAtColumn, DeletedAtColumn, StatusColumn, OpenIDColumn, UsernameColumn, AvatarColumn, MetasColumn, AuthTokenColumn}
|
allColumns = postgres.ColumnList{IDColumn, CreatedAtColumn, UpdatedAtColumn, DeletedAtColumn, StatusColumn, OpenIDColumn, UsernameColumn, AvatarColumn, MetasColumn, AuthTokenColumn, BalanceColumn}
|
||||||
|
mutableColumns = postgres.ColumnList{CreatedAtColumn, UpdatedAtColumn, DeletedAtColumn, StatusColumn, OpenIDColumn, UsernameColumn, AvatarColumn, MetasColumn, AuthTokenColumn, BalanceColumn}
|
||||||
)
|
)
|
||||||
|
|
||||||
return usersTable{
|
return usersTable{
|
||||||
@@ -95,6 +97,7 @@ func newUsersTableImpl(schemaName, tableName, alias string) usersTable {
|
|||||||
Avatar: AvatarColumn,
|
Avatar: AvatarColumn,
|
||||||
Metas: MetasColumn,
|
Metas: MetasColumn,
|
||||||
AuthToken: AuthTokenColumn,
|
AuthToken: AuthTokenColumn,
|
||||||
|
Balance: BalanceColumn,
|
||||||
|
|
||||||
AllColumns: allColumns,
|
AllColumns: allColumns,
|
||||||
MutableColumns: mutableColumns,
|
MutableColumns: mutableColumns,
|
||||||
|
|||||||
@@ -92,35 +92,40 @@ const handleBuy = async () => {
|
|||||||
buying.value = true;
|
buying.value = true;
|
||||||
try {
|
try {
|
||||||
const response = await postApi.buy(article.value.id);
|
const response = await postApi.buy(article.value.id);
|
||||||
|
|
||||||
const payData = response.data;
|
const payData = response.data;
|
||||||
|
|
||||||
// 调用微信支付
|
if (payData.AppID != "balance") {
|
||||||
window.WeixinJSBridge.invoke(
|
// 调用微信支付
|
||||||
"getBrandWCPayRequest",
|
window.WeixinJSBridge.invoke(
|
||||||
{
|
"getBrandWCPayRequest",
|
||||||
...payData,
|
{
|
||||||
},
|
...payData,
|
||||||
async function (res) {
|
},
|
||||||
if (res.err_msg === "get_brand_wcpay_request:ok") {
|
async function (res) {
|
||||||
// 支付成功,刷新文章数据
|
if (res.err_msg === "get_brand_wcpay_request:ok") {
|
||||||
fetchArticle();
|
// 支付成功,刷新文章数据
|
||||||
await updateMediaSource();
|
fetchArticle();
|
||||||
} else if (res.err_msg === "get_brand_wcpay_request:cancel") {
|
await updateMediaSource();
|
||||||
// 用户取消支付
|
} else if (res.err_msg === "get_brand_wcpay_request:cancel") {
|
||||||
console.log("Payment cancelled");
|
// 用户取消支付
|
||||||
alert("支付已取消");
|
console.log("Payment cancelled");
|
||||||
} else {
|
alert("支付已取消");
|
||||||
// 支付失败或取消
|
} else {
|
||||||
console.error("Payment failed:", res.err_msg);
|
// 支付失败或取消
|
||||||
alert(
|
console.error("Payment failed:", res.err_msg);
|
||||||
"支付失败:" +
|
alert(
|
||||||
(res.err_msg === "get_brand_wcpay_request:cancel"
|
"支付失败:" +
|
||||||
? "支付已取消"
|
(res.err_msg === "get_brand_wcpay_request:cancel"
|
||||||
: "支付异常")
|
? "支付已取消"
|
||||||
);
|
: "支付异常")
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
);
|
||||||
);
|
} else {
|
||||||
|
alert("余额支付成功");
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Failed to initiate payment:", error);
|
console.error("Failed to initiate payment:", error);
|
||||||
alert("发起支付失败,请稍后重试");
|
alert("发起支付失败,请稍后重试");
|
||||||
@@ -225,7 +230,7 @@ onUnmounted(() => {
|
|||||||
</div>
|
</div>
|
||||||
<button @click="handleBuy" :disabled="buying"
|
<button @click="handleBuy" :disabled="buying"
|
||||||
class="bg-orange-600 text-white px-8 py-2 rounded hover:bg-orange-500 active:bg-orange-600 transition-colors disabled:opacity-50">
|
class="bg-orange-600 text-white px-8 py-2 rounded hover:bg-orange-500 active:bg-orange-600 transition-colors disabled:opacity-50">
|
||||||
<span v-if="buying">处理中...</span>
|
<span v-if="buying">购买中...</span>
|
||||||
<span v-else>立即购买</span>
|
<span v-else>立即购买</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user