mirror of
https://github.com/yangjian102621/geekai.git
synced 2025-09-17 16:56:38 +08:00
wechat payment for pc is ready
This commit is contained in:
parent
8cb66ad01b
commit
e874178782
@ -74,7 +74,6 @@ type WechatPayConfig struct {
|
||||
|
||||
type HuPiPayConfig struct { //虎皮椒第四方支付配置
|
||||
Enabled bool // 是否启用该支付通道
|
||||
Name string // 支付名称,如:wechat/alipay
|
||||
AppId string // App ID
|
||||
AppSecret string // app 密钥
|
||||
ApiURL string // 支付网关
|
||||
@ -85,11 +84,12 @@ type HuPiPayConfig struct { //虎皮椒第四方支付配置
|
||||
// GeekPayConfig GEEK支付配置
|
||||
type GeekPayConfig struct {
|
||||
Enabled bool
|
||||
AppId string // 商户 ID
|
||||
PrivateKey string // 私钥
|
||||
ApiURL string // API 网关
|
||||
NotifyURL string // 异步通知地址
|
||||
ReturnURL string // 同步回调地址
|
||||
AppId string // 商户 ID
|
||||
PrivateKey string // 私钥
|
||||
ApiURL string // API 网关
|
||||
NotifyURL string // 异步通知地址
|
||||
ReturnURL string // 同步回调地址
|
||||
Methods []string // 支付方式
|
||||
}
|
||||
|
||||
type XXLConfig struct { // XXL 任务调度配置
|
||||
|
@ -80,7 +80,7 @@ func (h *PaymentHandler) Pay(c *gin.Context) {
|
||||
userId := c.Query("user_id")
|
||||
|
||||
var product model.Product
|
||||
err := h.DB.Debug().Where("id", productId).First(&product).Error
|
||||
err := h.DB.Where("id", productId).First(&product).Error
|
||||
if err != nil {
|
||||
resp.ERROR(c, "Product not found")
|
||||
return
|
||||
@ -150,7 +150,7 @@ func (h *PaymentHandler) Pay(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
} else if order.PayWay == "hupi" { // 虎皮椒支付
|
||||
params := payment.HuPiPayReq{
|
||||
r, err := h.huPiPayService.Pay(payment.HuPiPayParams{
|
||||
Version: "1.1",
|
||||
TradeOrderId: orderNo,
|
||||
TotalFee: fmt.Sprintf("%f", order.Amount),
|
||||
@ -158,23 +158,25 @@ func (h *PaymentHandler) Pay(c *gin.Context) {
|
||||
NotifyURL: h.App.Config.HuPiPayConfig.NotifyURL,
|
||||
ReturnURL: h.App.Config.HuPiPayConfig.ReturnURL,
|
||||
WapName: "GeekAI助手",
|
||||
}
|
||||
r, err := h.huPiPayService.Pay(params)
|
||||
})
|
||||
if err != nil {
|
||||
resp.ERROR(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
c.Redirect(302, r.URL)
|
||||
payURL = r.URL
|
||||
} else if order.PayWay == "wechat" {
|
||||
//uri, err := h.wechatPayService.PayUrlNative(order.OrderNo, int(order.Amount*100), order.Subject)
|
||||
uri, err := h.wechatPayService.PayUrlNative(payment.WechatPayParams{})
|
||||
payURL, err = h.wechatPayService.PayUrlNative(payment.WechatPayParams{
|
||||
OutTradeNo: orderNo,
|
||||
TotalFee: int(order.Amount * 100),
|
||||
Subject: order.Subject,
|
||||
NotifyURL: h.App.Config.WechatPayConfig.NotifyURL,
|
||||
ReturnURL: h.App.Config.WechatPayConfig.ReturnURL,
|
||||
})
|
||||
if err != nil {
|
||||
resp.ERROR(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
c.Redirect(302, uri)
|
||||
} else if order.PayWay == "geek" {
|
||||
params := payment.GeekPayParams{
|
||||
OutTradeNo: orderNo,
|
||||
@ -201,11 +203,9 @@ func (h *PaymentHandler) Pay(c *gin.Context) {
|
||||
// 异步通知回调公共逻辑
|
||||
func (h *PaymentHandler) notify(orderNo string, tradeNo string) error {
|
||||
var order model.Order
|
||||
res := h.DB.Where("order_no = ?", orderNo).First(&order)
|
||||
if res.Error != nil {
|
||||
err := fmt.Errorf("error with fetch order: %v", res.Error)
|
||||
logger.Error(err)
|
||||
return err
|
||||
err := h.DB.Where("order_no = ?", orderNo).First(&order).Error
|
||||
if err != nil {
|
||||
return fmt.Errorf("error with fetch order: %v", err)
|
||||
}
|
||||
|
||||
h.lock.Lock()
|
||||
@ -217,17 +217,15 @@ func (h *PaymentHandler) notify(orderNo string, tradeNo string) error {
|
||||
}
|
||||
|
||||
var user model.User
|
||||
err := h.DB.First(&user, order.UserId).Error
|
||||
err = h.DB.First(&user, order.UserId).Error
|
||||
if err != nil {
|
||||
return fmt.Errorf("error with fetch user info: %v", res.Error)
|
||||
return fmt.Errorf("error with fetch user info: %v", err)
|
||||
}
|
||||
|
||||
var remark types.OrderRemark
|
||||
err = utils.JsonDecode(order.Remark, &remark)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("error with decode order remark: %v", err)
|
||||
logger.Error(err)
|
||||
return err
|
||||
return fmt.Errorf("error with decode order remark: %v", err)
|
||||
}
|
||||
|
||||
// 增加用户算力
|
||||
@ -266,15 +264,12 @@ func (h *PaymentHandler) GetPayWays(c *gin.Context) {
|
||||
payWays = append(payWays, gin.H{"pay_way": "alipay", "pay_type": "alipay"})
|
||||
}
|
||||
if h.App.Config.HuPiPayConfig.Enabled {
|
||||
payWays = append(payWays, gin.H{"pay_way": "hupi", "pay_type": h.App.Config.HuPiPayConfig.Name})
|
||||
payWays = append(payWays, gin.H{"pay_way": "hupi", "pay_type": "wxpay"})
|
||||
}
|
||||
if h.App.Config.GeekPayConfig.Enabled {
|
||||
payWays = append(payWays, gin.H{"pay_way": "geek", "pay_type": "alipay"})
|
||||
payWays = append(payWays, gin.H{"pay_way": "geek", "pay_type": "wxpay"})
|
||||
payWays = append(payWays, gin.H{"pay_way": "geek", "pay_type": "qqpay"})
|
||||
payWays = append(payWays, gin.H{"pay_way": "geek", "pay_type": "jdpay"})
|
||||
payWays = append(payWays, gin.H{"pay_way": "geek", "pay_type": "douyin"})
|
||||
payWays = append(payWays, gin.H{"pay_way": "geek", "pay_type": "paypal"})
|
||||
for _, v := range h.App.Config.GeekPayConfig.Methods {
|
||||
payWays = append(payWays, gin.H{"pay_way": "geek", "pay_type": v})
|
||||
}
|
||||
}
|
||||
if h.App.Config.WechatPayConfig.Enabled {
|
||||
payWays = append(payWays, gin.H{"pay_way": "wechat", "pay_type": "wxpay"})
|
||||
@ -292,15 +287,17 @@ func (h *PaymentHandler) HuPiPayNotify(c *gin.Context) {
|
||||
|
||||
orderNo := c.Request.Form.Get("trade_order_id")
|
||||
tradeNo := c.Request.Form.Get("open_order_id")
|
||||
logger.Infof("收到虎皮椒订单支付回调,订单 NO:%s,交易流水号:%s", orderNo, tradeNo)
|
||||
logger.Infof("收到虎皮椒订单支付回调,%+v", c.Request.Form)
|
||||
|
||||
if err = h.huPiPayService.Check(tradeNo); err != nil {
|
||||
if err = h.huPiPayService.Check(orderNo); err != nil {
|
||||
logger.Error("订单校验失败:", err)
|
||||
c.String(http.StatusOK, "fail")
|
||||
return
|
||||
}
|
||||
|
||||
err = h.notify(orderNo, tradeNo)
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
c.String(http.StatusOK, "fail")
|
||||
return
|
||||
}
|
||||
@ -316,18 +313,18 @@ func (h *PaymentHandler) AlipayNotify(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// TODO:验证交易签名
|
||||
res := h.alipayService.TradeVerify(c.Request)
|
||||
logger.Infof("验证支付结果:%+v", res)
|
||||
if !res.Success() {
|
||||
logger.Error("订单校验失败:", res.Message)
|
||||
result := h.alipayService.TradeVerify(c.Request)
|
||||
logger.Infof("收到支付宝商号订单支付回调:%+v", result)
|
||||
if !result.Success() {
|
||||
logger.Error("订单校验失败:", result.Message)
|
||||
c.String(http.StatusOK, "fail")
|
||||
return
|
||||
}
|
||||
|
||||
tradeNo := c.Request.Form.Get("trade_no")
|
||||
err = h.notify(res.OutTradeNo, tradeNo)
|
||||
err = h.notify(result.OutTradeNo, tradeNo)
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
c.String(http.StatusOK, "fail")
|
||||
return
|
||||
}
|
||||
@ -358,6 +355,7 @@ func (h *PaymentHandler) GeekPayNotify(c *gin.Context) {
|
||||
|
||||
err := h.notify(params["out_trade_no"], params["trade_no"])
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
c.String(http.StatusOK, "fail")
|
||||
return
|
||||
}
|
||||
@ -374,6 +372,7 @@ func (h *PaymentHandler) WechatPayNotify(c *gin.Context) {
|
||||
}
|
||||
|
||||
result := h.wechatPayService.TradeVerify(c.Request)
|
||||
logger.Infof("收到微信商号订单支付回调:%+v", result)
|
||||
if !result.Success() {
|
||||
logger.Error("订单校验失败:", err)
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
@ -385,6 +384,7 @@ func (h *PaymentHandler) WechatPayNotify(c *gin.Context) {
|
||||
|
||||
err = h.notify(result.OutTradeNo, result.TradeId)
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
c.String(http.StatusOK, "fail")
|
||||
return
|
||||
}
|
||||
|
@ -377,6 +377,7 @@ func main() {
|
||||
group.POST("notify/alipay", h.AlipayNotify)
|
||||
group.GET("notify/geek", h.GeekPayNotify)
|
||||
group.POST("notify/wechat", h.WechatPayNotify)
|
||||
group.POST("notify/hupi", h.HuPiPayNotify)
|
||||
}),
|
||||
fx.Invoke(func(s *core.AppServer, h *admin.ProductHandler) {
|
||||
group := s.Engine.Group("/api/admin/product/")
|
||||
|
@ -8,6 +8,7 @@ package payment
|
||||
// * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
@ -108,7 +109,13 @@ func (s *GeekPayService) sendRequest(endpoint string, params map[string]string)
|
||||
apiURL := fmt.Sprintf("%s/mapi.php", endpoint)
|
||||
logger.Infof(apiURL)
|
||||
|
||||
resp, err := http.PostForm(apiURL, form)
|
||||
tr := &http.Transport{
|
||||
TLSClientConfig: &tls.Config{
|
||||
InsecureSkipVerify: true, // 取消 SSL 证书验证
|
||||
},
|
||||
}
|
||||
client := &http.Client{Transport: tr}
|
||||
resp, err := client.PostForm(apiURL, form)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ func NewHuPiPay(config *types.AppConfig) *HuPiPayService {
|
||||
}
|
||||
}
|
||||
|
||||
type HuPiPayReq struct {
|
||||
type HuPiPayParams struct {
|
||||
AppId string `json:"appid"`
|
||||
Version string `json:"version"`
|
||||
TradeOrderId string `json:"trade_order_id"`
|
||||
@ -53,7 +53,7 @@ type HuPiPayReq struct {
|
||||
WapUrl string `json:"wap_url"`
|
||||
}
|
||||
|
||||
type HuPiResp struct {
|
||||
type HuPiPayResp struct {
|
||||
Openid interface{} `json:"openid"`
|
||||
UrlQrcode string `json:"url_qrcode"`
|
||||
URL string `json:"url"`
|
||||
@ -62,7 +62,7 @@ type HuPiResp struct {
|
||||
}
|
||||
|
||||
// Pay 执行支付请求操作
|
||||
func (s *HuPiPayService) Pay(params HuPiPayReq) (HuPiResp, error) {
|
||||
func (s *HuPiPayService) Pay(params HuPiPayParams) (HuPiPayResp, error) {
|
||||
data := url.Values{}
|
||||
simple := strconv.FormatInt(time.Now().Unix(), 10)
|
||||
params.AppId = s.appId
|
||||
@ -80,22 +80,22 @@ func (s *HuPiPayService) Pay(params HuPiPayReq) (HuPiResp, error) {
|
||||
apiURL := fmt.Sprintf("%s/payment/do.html", s.apiURL)
|
||||
resp, err := http.PostForm(apiURL, data)
|
||||
if err != nil {
|
||||
return HuPiResp{}, fmt.Errorf("error with requst api: %v", err)
|
||||
return HuPiPayResp{}, fmt.Errorf("error with requst api: %v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
all, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return HuPiResp{}, fmt.Errorf("error with reading response: %v", err)
|
||||
return HuPiPayResp{}, fmt.Errorf("error with reading response: %v", err)
|
||||
}
|
||||
|
||||
var res HuPiResp
|
||||
var res HuPiPayResp
|
||||
err = utils.JsonDecode(string(all), &res)
|
||||
if err != nil {
|
||||
return HuPiResp{}, fmt.Errorf("error with decode payment result: %v", err)
|
||||
return HuPiPayResp{}, fmt.Errorf("error with decode payment result: %v", err)
|
||||
}
|
||||
|
||||
if res.ErrCode != 0 {
|
||||
return HuPiResp{}, fmt.Errorf("error with generate pay url: %s", res.ErrMsg)
|
||||
return HuPiPayResp{}, fmt.Errorf("error with generate pay url: %s", res.ErrMsg)
|
||||
}
|
||||
|
||||
return res, nil
|
||||
@ -127,10 +127,10 @@ func (s *HuPiPayService) Sign(params url.Values) string {
|
||||
}
|
||||
|
||||
// Check 校验订单状态
|
||||
func (s *HuPiPayService) Check(tradeNo string) error {
|
||||
func (s *HuPiPayService) Check(outTradeNo string) error {
|
||||
data := url.Values{}
|
||||
data.Add("appid", s.appId)
|
||||
data.Add("open_order_id", tradeNo)
|
||||
data.Add("out_trade_order", outTradeNo)
|
||||
stamp := strconv.FormatInt(time.Now().Unix(), 10)
|
||||
data.Add("time", stamp)
|
||||
data.Add("nonce_str", stamp)
|
||||
|
@ -65,7 +65,6 @@ func (s *WechatPayService) PayUrlNative(params WechatPayParams) (string, error)
|
||||
Set("out_trade_no", params.OutTradeNo).
|
||||
Set("time_expire", expire).
|
||||
Set("notify_url", params.NotifyURL).
|
||||
Set("return_url", params.ReturnURL).
|
||||
SetBodyMap("amount", func(bm gopay.BodyMap) {
|
||||
bm.Set("total", params.TotalFee).
|
||||
Set("currency", "CNY")
|
||||
@ -91,7 +90,6 @@ func (s *WechatPayService) PayUrlH5(params WechatPayParams) (string, error) {
|
||||
Set("out_trade_no", params.OutTradeNo).
|
||||
Set("time_expire", expire).
|
||||
Set("notify_url", params.NotifyURL).
|
||||
Set("return_url", params.ReturnURL).
|
||||
SetBodyMap("amount", func(bm gopay.BodyMap) {
|
||||
bm.Set("total", params.TotalFee).
|
||||
Set("currency", "CNY")
|
||||
|
@ -2,53 +2,6 @@
|
||||
background-color: #282c34;
|
||||
height 100%
|
||||
|
||||
.el-dialog {
|
||||
.el-dialog__body {
|
||||
.pay-container {
|
||||
.amount {
|
||||
text-align center
|
||||
|
||||
span {
|
||||
color #f56c6c
|
||||
}
|
||||
}
|
||||
|
||||
.count-down {
|
||||
display flex
|
||||
justify-content center
|
||||
}
|
||||
|
||||
.pay-qrcode {
|
||||
display flex
|
||||
justify-content center
|
||||
|
||||
.el-image {
|
||||
width 360px;
|
||||
height 360px;
|
||||
}
|
||||
}
|
||||
|
||||
.tip {
|
||||
display flex
|
||||
justify-content center
|
||||
|
||||
.el-icon {
|
||||
font-size 24px
|
||||
}
|
||||
|
||||
.text {
|
||||
font-size: 16px
|
||||
margin-left 10px
|
||||
}
|
||||
}
|
||||
|
||||
.tip.success {
|
||||
color #07c160
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
text-align center
|
||||
background-color #25272d
|
||||
@ -223,4 +176,17 @@
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.pay-dialog {
|
||||
.product-info {
|
||||
text-align center
|
||||
color #333333
|
||||
font-size 16px
|
||||
|
||||
.price {
|
||||
color #f56c6c
|
||||
font-weight 700
|
||||
}
|
||||
}
|
||||
}
|
@ -156,14 +156,14 @@
|
||||
<el-tooltip content="删除" placement="top" effect="light">
|
||||
<el-button type="danger" :icon="Delete" @click="removeImage(slotProp.item)" circle/>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="分享" placement="top" effect="light" v-if="slotProp.item.publish">
|
||||
<el-tooltip content="取消分享" placement="top" effect="light" v-if="!slotProp.item.publish">
|
||||
<el-button type="warning"
|
||||
@click="publishImage(slotProp.item, false)"
|
||||
circle>
|
||||
<i class="iconfont icon-cancel-share"></i>
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="取消分享" placement="top" effect="light" v-else>
|
||||
<el-tooltip content="分享" placement="top" effect="light" v-else>
|
||||
<el-button type="success" @click="publishImage(slotProp.item, true)" circle>
|
||||
<i class="iconfont icon-share-bold"></i>
|
||||
</el-button>
|
||||
|
@ -106,8 +106,12 @@
|
||||
|
||||
</div>
|
||||
|
||||
<el-dialog v-model="showDialog" :show-close=false hide-footer width="auto">
|
||||
<div style="padding-bottom: 10px">
|
||||
<el-dialog v-model="showDialog" :show-close=false :close-on-click-modal="false" hide-footer width="auto" class="pay-dialog">
|
||||
<div v-if="qrImg !== ''">
|
||||
<div class="product-info">请使用微信扫码支付:<span class="price">¥{{price}}</span></div>
|
||||
<el-image :src="qrImg" fit="cover" />
|
||||
</div>
|
||||
<div style="padding-bottom: 10px; text-align: center">
|
||||
<el-button type="success" @click="payCallback(true)">支付成功</el-button>
|
||||
<el-button type="danger" @click="payCallback(false)">支付失败</el-button>
|
||||
</div>
|
||||
@ -128,6 +132,7 @@ import UserOrder from "@/components/UserOrder.vue";
|
||||
import {useSharedStore} from "@/store/sharedata";
|
||||
import BindEmail from "@/components/BindEmail.vue";
|
||||
import ThirdLogin from "@/components/ThirdLogin.vue";
|
||||
import QRCode from "qrcode";
|
||||
|
||||
const list = ref([])
|
||||
const vipImg = ref("/images/vip.png")
|
||||
@ -150,6 +155,8 @@ const vipInfoText = ref("")
|
||||
const store = useSharedStore()
|
||||
const profileKey = ref(0)
|
||||
const showDialog = ref(false)
|
||||
const qrImg = ref("")
|
||||
const price = ref(0)
|
||||
|
||||
|
||||
onMounted(() => {
|
||||
@ -200,9 +207,20 @@ const pay = (product, payWay) => {
|
||||
user_id: user.value.id,
|
||||
device: "jump"
|
||||
}).then(res => {
|
||||
window.open(res.data, '_blank');
|
||||
loading.value = false
|
||||
showDialog.value = true
|
||||
loading.value = false
|
||||
if (payWay.pay_way === 'wechat') {
|
||||
price.value = Number((product.price - product.discount).toFixed(2))
|
||||
QRCode.toDataURL(res.data, {width: 300, height: 300, margin: 2}, (error, url) => {
|
||||
if (error) {
|
||||
console.error(error)
|
||||
} else {
|
||||
qrImg.value = url;
|
||||
}
|
||||
})
|
||||
} else {
|
||||
window.open(res.data, '_blank');
|
||||
}
|
||||
}).catch(e => {
|
||||
setTimeout(() => {
|
||||
ElMessage.error("生成支付订单失败:" + e.message)
|
||||
@ -225,6 +243,7 @@ const payCallback = (success) => {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="stylus">
|
||||
|
@ -26,6 +26,7 @@
|
||||
<el-row>
|
||||
<el-table :data="items" :row-key="row => row.id" table-layout="auto">
|
||||
<el-table-column prop="order_no" label="订单号"/>
|
||||
<el-table-column prop="trade_no" label="交易号"/>
|
||||
<el-table-column prop="username" label="下单用户"/>
|
||||
<el-table-column prop="subject" label="产品名称"/>
|
||||
<el-table-column prop="amount" label="订单金额"/>
|
||||
|
Loading…
Reference in New Issue
Block a user