diff --git a/README.md b/README.md index 257506c..9e03a55 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ ## TODO -后台交易备注 +手动充值备注 关闭支付弹窗 兜底手动操作 -限速 +后台限制 ip - edge.area_id 可为空,代表节点无固定地区 - 后台展示 mac, ip:port,实际地区 diff --git a/web/routes.go b/web/routes.go index 8cbb7a3..f8a4776 100644 --- a/web/routes.go +++ b/web/routes.go @@ -238,6 +238,7 @@ func adminRouter(api fiber.Router) { trade.Post("/page", handlers.PageTradeByAdmin) trade.Post("/page/of-user", handlers.PageTradeOfUserByAdmin) trade.Post("/complete", handlers.TradeCompleteByAdmin) + trade.Post("/convert", handlers.TradeConvertByAdmin) trade.Post("/update/remark", handlers.TradeUpdateRemarkByAdmin) trade.Post("/check", handlers.TradeCheck) diff --git a/web/services/proxy.go b/web/services/proxy.go index c042bc0..76cc0ba 100644 --- a/web/services/proxy.go +++ b/web/services/proxy.go @@ -46,8 +46,8 @@ func rebuildFreeChans(proxyID int32, addr netip.Addr) error { return err } - chans := make([]netip.AddrPort, 10000) - for i := range 10000 { + chans := make([]netip.AddrPort, 30000) + for i := range 30000 { chans[i] = netip.AddrPortFrom(addr, uint16(i+10000)) } diff --git a/web/services/trade.go b/web/services/trade.go index d7257e9..7cbb8ee 100644 --- a/web/services/trade.go +++ b/web/services/trade.go @@ -357,9 +357,49 @@ func (s *tradeService) OnCompleteTrade(user *m.User, interNo string, outerNo str // 转换交易 func (s *tradeService) ConvertTradeToBalance(admin *m.Admin, ref *TradeRef) error { - trade, err := q.Trade.Where(q.Trade.InnerNo.Eq(ref.TradeNo)).First() + + // 检查订单状态 + result, err := s.CheckTrade(ref) if err != nil { - return err + return core.NewServErr("检查订单状态失败", err) + } + if result.Status != m.TradeStatusSuccess { + switch result.Status { + case m.TradeStatusPending: + return core.NewBizErr("订单未支付") + case m.TradeStatusCanceled: + return core.NewBizErr("订单已过期") + } + } + + // 获取交易信息 + trade, err := q.Trade. + Where(q.Trade.InnerNo.Eq(ref.TradeNo)). + Take() + if err != nil { + return core.NewBizErr("获取交易信息失败", err) + } + + // 检查交易状态 + switch trade.Status { + case m.TradeStatusCanceled: + return core.NewBizErr("交易已取消") + case m.TradeStatusSuccess: + return nil // 跳过更新交易信息 + case m.TradeStatusPending: + } + + // 恢复购买信息;如果反序列化失败,检查开头 init 函数中是否注册了对应的 struct 类型 + tradeKey := tradeProductKey(ref.TradeNo) + detailBytes, err := g.Redis.Get(context.Background(), tradeKey).Bytes() + if err != nil { + return core.NewServErr("恢复购买信息失败", err) + } + + var detail TradeDetail + r := bytes.NewReader(detailBytes) + if err := gob.NewDecoder(r).Decode(&detail); err != nil { + return core.NewServErr("解析购买信息失败", err) } user, err := q.User.Where(q.User.ID.Eq(trade.UserID)).First() @@ -368,7 +408,33 @@ func (s *tradeService) ConvertTradeToBalance(admin *m.Admin, ref *TradeRef) erro } return q.Q.Transaction(func(q *q.Query) error { - return User.UpdateBalance(q, user, trade.Payment, "管理员订单补余额", &admin.ID, nil) + + // 更新交易信息 + r, err := q.Trade. + Where( + q.Trade.InnerNo.Eq(ref.TradeNo), + q.Trade.Status.Eq(int(m.TradeStatusPending)), + ). + UpdateSimple( + q.Trade.Status.Value(int(m.TradeStatusSuccess)), + q.Trade.OuterNo.Value(result.TransId), + q.Trade.Payment.Value(result.Success.Actual), + q.Trade.Acquirer.Value(int(result.Success.Acquirer)), + q.Trade.CompletedAt.Value(result.Success.Time), + ) + if err != nil { + return core.NewServErr("更新交易信息失败", err) + } + if r.RowsAffected == 0 { + return core.NewBizErr("交易状态已过期") + } + + // 更新用户余额 + if err := User.UpdateBalance(q, user, detail.Actual, "管理员订单补余额", &admin.ID, nil); err != nil { + return err + } + + return nil }) } diff --git a/web/services/verifier.go b/web/services/verifier.go index a1a1da4..51a08f6 100644 --- a/web/services/verifier.go +++ b/web/services/verifier.go @@ -74,7 +74,7 @@ func (s *verifierService) SendSms(ctx context.Context, phone string, purpose Ver } if response.Body.Code == nil || *response.Body.Code != "OK" { _ = g.Redis.Del(ctx, key, keyLock).Err() - return VerifierServiceError("验证码发送失败") + return VerifierServiceError(fmt.Sprintf("验证码发送失败: %s", *response.Body.Message)) } }