payment for mobile page is ready

This commit is contained in:
RockYang 2024-09-19 19:03:03 +08:00
parent 4976b967e7
commit 16ac57ced3
7 changed files with 112 additions and 60 deletions

View File

@ -71,6 +71,14 @@ TikaHost = "http://tika:9998"
AccessToken = "xxl-job-api-token" # 执行器 API 通信 token AccessToken = "xxl-job-api-token" # 执行器 API 通信 token
RegistryKey = "chatgpt-plus" # 任务注册 key RegistryKey = "chatgpt-plus" # 任务注册 key
[SmtpConfig] # 注意阿里云服务器禁用了25号端口请使用 465 端口,并开启 TLS 连接
UseTls = false
Host = "smtp.163.com"
Port = 25
AppName = "极客学长"
From = "test@163.com" # 发件邮箱人地址
Password = "" #邮箱 stmp 服务授权码
[AlipayConfig] [AlipayConfig]
Enabled = false # 启用支付宝支付通道 Enabled = false # 启用支付宝支付通道
SandBox = false # 是否启用沙盒模式 SandBox = false # 是否启用沙盒模式
@ -80,31 +88,12 @@ TikaHost = "http://tika:9998"
PublicKey = "certs/alipay/appPublicCert.crt" # 应用公钥证书 PublicKey = "certs/alipay/appPublicCert.crt" # 应用公钥证书
AlipayPublicKey = "certs/alipay/alipayPublicCert.crt" # 支付宝公钥证书 AlipayPublicKey = "certs/alipay/alipayPublicCert.crt" # 支付宝公钥证书
RootCert = "certs/alipay/alipayRootCert.crt" # 支付宝根证书 RootCert = "certs/alipay/alipayRootCert.crt" # 支付宝根证书
NotifyURL = "https://ai.r9it.com/api/payment/alipay/notify" # 支付异步回调地址
[HuPiPayConfig] [HuPiPayConfig]
Enabled = false Enabled = false
Name = "wechat"
AppId = "" AppId = ""
AppSecret = "" AppSecret = ""
ApiURL = "https://api.xunhupay.com" ApiURL = "https://api.xunhupay.com"
NotifyURL = "https://ai.r9it.com/api/payment/hupipay/notify"
[SmtpConfig] # 注意阿里云服务器禁用了25号端口请使用 465 端口,并开启 TLS 连接
UseTls = false
Host = "smtp.163.com"
Port = 25
AppName = "极客学长"
From = "test@163.com" # 发件邮箱人地址
Password = "" #邮箱 stmp 服务授权码
[JPayConfig] # PayJs 支付配置
Enabled = false
Name = "wechat" # 请不要改动
AppId = "" # 商户 ID
PrivateKey = "" # 秘钥
ApiURL = "https://payjs.cn"
NotifyURL = "https://ai.r9it.com/api/payment/payjs/notify" # 异步回调地址,域名改成你自己的
# 微信商户支付 # 微信商户支付
[WechatPayConfig] [WechatPayConfig]
@ -114,6 +103,11 @@ TikaHost = "http://tika:9998"
SerialNo = "" # API 证书序列号 SerialNo = "" # API 证书序列号
PrivateKey = "certs/alipay/privateKey.txt" # API 证书私钥文件路径,跟支付宝一样,把私钥文件拷贝到对应的路径,证书路径要映射到容器内 PrivateKey = "certs/alipay/privateKey.txt" # API 证书私钥文件路径,跟支付宝一样,把私钥文件拷贝到对应的路径,证书路径要映射到容器内
ApiV3Key = "" # APIV3 私钥,这个是你自己在微信支付平台设置的 ApiV3Key = "" # APIV3 私钥,这个是你自己在微信支付平台设置的
NotifyURL = "https://ai.r9it.com/api/payment/wechat/notify" # 支付成功异步回调地址,域名改成自己的
ReturnURL = "" # 支付成功同步回调地址
# 易支付
[GeekPayConfig]
Enabled = true
AppId = "" # 商户ID
PrivateKey = "" # 商户私钥
ApiURL = "https://pay.geekai.cn"
Methods = ["alipay", "wxpay", "qqpay", "jdpay", "douyin", "paypal"] # 支持的支付方式

View File

@ -58,6 +58,7 @@ type AlipayConfig struct {
AlipayPublicKey string // 支付宝公钥文件路径 AlipayPublicKey string // 支付宝公钥文件路径
RootCert string // Root 秘钥路径 RootCert string // Root 秘钥路径
NotifyURL string // 异步通知地址 NotifyURL string // 异步通知地址
ReturnURL string // 同步通知地址
} }
type WechatPayConfig struct { type WechatPayConfig struct {
@ -76,6 +77,7 @@ type HuPiPayConfig struct { //虎皮椒第四方支付配置
AppSecret string // app 密钥 AppSecret string // app 密钥
ApiURL string // 支付网关 ApiURL string // 支付网关
NotifyURL string // 异步通知地址 NotifyURL string // 异步通知地址
ReturnURL string // 同步通知地址
} }
// GeekPayConfig GEEK支付配置 // GeekPayConfig GEEK支付配置
@ -85,6 +87,7 @@ type GeekPayConfig struct {
PrivateKey string // 私钥 PrivateKey string // 私钥
ApiURL string // API 网关 ApiURL string // API 网关
NotifyURL string // 异步通知地址 NotifyURL string // 异步通知地址
ReturnURL string // 同步通知地址
Methods []string // 支付方式 Methods []string // 支付方式
} }

View File

@ -73,14 +73,21 @@ func NewPaymentHandler(
} }
func (h *PaymentHandler) Pay(c *gin.Context) { func (h *PaymentHandler) Pay(c *gin.Context) {
payWay := c.Query("pay_way") var data struct {
payType := c.Query("pay_type") PayWay string `json:"pay_way"`
productId := c.Query("product_id") PayType string `json:"pay_type"`
device := c.Query("device") ProductId int `json:"product_id"`
userId := c.Query("user_id") UserId int `json:"user_id"`
Device string `json:"device"`
Host string `json:"host"`
}
if err := c.ShouldBindJSON(&data); err != nil {
resp.ERROR(c, types.InvalidArgs)
return
}
var product model.Product var product model.Product
err := h.DB.Where("id", productId).First(&product).Error err := h.DB.Where("id", data.ProductId).First(&product).Error
if err != nil { if err != nil {
resp.ERROR(c, "Product not found") resp.ERROR(c, "Product not found")
return return
@ -92,36 +99,73 @@ func (h *PaymentHandler) Pay(c *gin.Context) {
return return
} }
var user model.User var user model.User
err = h.DB.Where("id", userId).First(&user).Error err = h.DB.Where("id", data.UserId).First(&user).Error
if err != nil { if err != nil {
resp.NotAuth(c) resp.NotAuth(c)
return return
} }
amount, _ := decimal.NewFromFloat(product.Price).Sub(decimal.NewFromFloat(product.Discount)).Float64() amount, _ := decimal.NewFromFloat(product.Price).Sub(decimal.NewFromFloat(product.Discount)).Float64()
var payURL string var payURL, returnURL, notifyURL string
if payWay == "alipay" { // 支付宝 switch data.PayWay {
returnURL := fmt.Sprintf("%s/payReturn", utils.GetBaseURL(h.App.Config.AlipayConfig.NotifyURL)) case "alipay":
if h.App.Config.AlipayConfig.NotifyURL != "" { // 用于本地调试支付
notifyURL = h.App.Config.AlipayConfig.NotifyURL
} else {
notifyURL = fmt.Sprintf("%s/api/payment/notify/alipay", data.Host)
}
if h.App.Config.AlipayConfig.ReturnURL != "" { // 用于本地调试支付
returnURL = h.App.Config.AlipayConfig.ReturnURL
} else {
returnURL = fmt.Sprintf("%s/payReturn", data.Host)
}
money := fmt.Sprintf("%.2f", amount) money := fmt.Sprintf("%.2f", amount)
payURL, err = h.alipayService.PayPC(payment.AlipayParams{ payURL, err = h.alipayService.PayPC(payment.AlipayParams{
OutTradeNo: orderNo, OutTradeNo: orderNo,
Subject: product.Name, Subject: product.Name,
TotalFee: money, TotalFee: money,
ReturnURL: returnURL, ReturnURL: returnURL,
NotifyURL: h.App.Config.AlipayConfig.NotifyURL, NotifyURL: notifyURL,
}) })
if err != nil { if err != nil {
resp.ERROR(c, "error with generate pay url: "+err.Error()) resp.ERROR(c, "error with generate pay url: "+err.Error())
return return
} }
} else if payWay == "hupi" { // 虎皮椒支付 break
returnURL := fmt.Sprintf("%s/payReturn", utils.GetBaseURL(h.App.Config.HuPiPayConfig.NotifyURL)) case "wechat":
if h.App.Config.WechatPayConfig.NotifyURL != "" {
notifyURL = h.App.Config.WechatPayConfig.NotifyURL
} else {
notifyURL = fmt.Sprintf("%s/api/payment/notify/wechat", data.Host)
}
payURL, err = h.wechatPayService.PayUrlNative(payment.WechatPayParams{
OutTradeNo: orderNo,
TotalFee: int(amount * 100),
Subject: product.Name,
NotifyURL: notifyURL,
})
if err != nil {
resp.ERROR(c, err.Error())
return
}
break
case "hupi":
if h.App.Config.HuPiPayConfig.NotifyURL != "" {
notifyURL = h.App.Config.HuPiPayConfig.NotifyURL
} else {
notifyURL = fmt.Sprintf("%s/api/payment/notify/hupi", data.Host)
}
if h.App.Config.HuPiPayConfig.ReturnURL != "" {
returnURL = h.App.Config.HuPiPayConfig.ReturnURL
} else {
returnURL = fmt.Sprintf("%s/payReturn", data.Host)
}
r, err := h.huPiPayService.Pay(payment.HuPiPayParams{ r, err := h.huPiPayService.Pay(payment.HuPiPayParams{
Version: "1.1", Version: "1.1",
TradeOrderId: orderNo, TradeOrderId: orderNo,
TotalFee: fmt.Sprintf("%f", amount), TotalFee: fmt.Sprintf("%f", amount),
Title: product.Name, Title: product.Name,
NotifyURL: h.App.Config.HuPiPayConfig.NotifyURL, NotifyURL: notifyURL,
ReturnURL: returnURL, ReturnURL: returnURL,
WapName: "GeekAI助手", WapName: "GeekAI助手",
}) })
@ -129,23 +173,21 @@ func (h *PaymentHandler) Pay(c *gin.Context) {
resp.ERROR(c, err.Error()) resp.ERROR(c, err.Error())
return return
} }
payURL = r.URL payURL = r.URL
} else if payWay == "wechat" { break
payURL, err = h.wechatPayService.PayUrlNative(payment.WechatPayParams{ case "geek":
OutTradeNo: orderNo, if h.App.Config.GeekPayConfig.NotifyURL != "" {
TotalFee: int(amount * 100), notifyURL = h.App.Config.GeekPayConfig.NotifyURL
Subject: product.Name, } else {
NotifyURL: h.App.Config.WechatPayConfig.NotifyURL, notifyURL = fmt.Sprintf("%s/api/payment/notify/geek", data.Host)
})
if err != nil {
resp.ERROR(c, err.Error())
return
} }
} else if payWay == "geek" { if h.App.Config.GeekPayConfig.ReturnURL != "" {
returnURL := fmt.Sprintf("%s/payReturn", utils.GetBaseURL(h.App.Config.GeekPayConfig.NotifyURL)) data.Host = utils.GetBaseURL(h.App.Config.GeekPayConfig.ReturnURL)
if device == "wechat" { }
returnURL = fmt.Sprintf("%s/mobile/profile", utils.GetBaseURL(h.App.Config.GeekPayConfig.NotifyURL)) if data.Device == "wechat" { // 微信客户端打开,调回手机端用户中心页面
returnURL = fmt.Sprintf("%s/mobile/profile", data.Host)
} else {
returnURL = fmt.Sprintf("%s/payReturn", data.Host)
} }
params := payment.GeekPayParams{ params := payment.GeekPayParams{
OutTradeNo: orderNo, OutTradeNo: orderNo,
@ -153,10 +195,10 @@ func (h *PaymentHandler) Pay(c *gin.Context) {
Name: product.Name, Name: product.Name,
Money: fmt.Sprintf("%f", amount), Money: fmt.Sprintf("%f", amount),
ClientIP: c.ClientIP(), ClientIP: c.ClientIP(),
Device: device, Device: data.Device,
Type: payType, Type: data.PayType,
ReturnURL: returnURL, ReturnURL: returnURL,
NotifyURL: h.App.Config.GeekPayConfig.NotifyURL, NotifyURL: notifyURL,
} }
res, err := h.geekPayService.Pay(params) res, err := h.geekPayService.Pay(params)
@ -165,6 +207,9 @@ func (h *PaymentHandler) Pay(c *gin.Context) {
return return
} }
payURL = res.PayURL payURL = res.PayURL
default:
resp.ERROR(c, "不支持的支付渠道")
return
} }
// 创建订单 // 创建订单
@ -183,8 +228,8 @@ func (h *PaymentHandler) Pay(c *gin.Context) {
Subject: product.Name, Subject: product.Name,
Amount: amount, Amount: amount,
Status: types.OrderNotPaid, Status: types.OrderNotPaid,
PayWay: payWay, PayWay: data.PayWay,
PayType: payType, PayType: data.PayType,
Remark: utils.JsonEncode(remark), Remark: utils.JsonEncode(remark),
} }
err = h.DB.Create(&order).Error err = h.DB.Create(&order).Error

View File

@ -372,7 +372,7 @@ func main() {
}), }),
fx.Invoke(func(s *core.AppServer, h *handler.PaymentHandler) { fx.Invoke(func(s *core.AppServer, h *handler.PaymentHandler) {
group := s.Engine.Group("/api/payment/") group := s.Engine.Group("/api/payment/")
group.GET("doPay", h.Pay) group.POST("doPay", h.Pay)
group.GET("payWays", h.GetPayWays) group.GET("payWays", h.GetPayWays)
group.POST("notify/alipay", h.AlipayNotify) group.POST("notify/alipay", h.AlipayNotify)
group.GET("notify/geek", h.GeekPayNotify) group.GET("notify/geek", h.GeekPayNotify)

View File

@ -1,4 +1,4 @@
VUE_APP_API_HOST=http://localhost:5678 VUE_APP_API_HOST=http://www.geekai.me:6004
VUE_APP_WS_HOST=ws://localhost:5678 VUE_APP_WS_HOST=ws://localhost:5678
VUE_APP_USER=18888888888 VUE_APP_USER=18888888888
VUE_APP_PASS=12345678 VUE_APP_PASS=12345678

View File

@ -122,7 +122,7 @@
<script setup> <script setup>
import {onMounted, ref} from "vue" import {onMounted, ref} from "vue"
import {ElMessage} from "element-plus"; import {ElMessage} from "element-plus";
import {httpGet} from "@/utils/http"; import {httpGet, httpPost} from "@/utils/http";
import {checkSession, getSystemInfo} from "@/store/cache"; import {checkSession, getSystemInfo} from "@/store/cache";
import UserProfile from "@/components/UserProfile.vue"; import UserProfile from "@/components/UserProfile.vue";
import PasswordDialog from "@/components/PasswordDialog.vue"; import PasswordDialog from "@/components/PasswordDialog.vue";
@ -200,11 +200,16 @@ const pay = (product, payWay) => {
} }
loading.value = true loading.value = true
loadingText.value = "正在生成支付订单..." loadingText.value = "正在生成支付订单..."
httpGet(`${process.env.VUE_APP_API_HOST}/api/payment/doPay`, { let host = process.env.VUE_APP_API_HOST
if (host === '') {
host = `${location.protocol}://${location.host}`;
}
httpPost(`${process.env.VUE_APP_API_HOST}/api/payment/doPay`, {
product_id: product.id, product_id: product.id,
pay_way: payWay.pay_way, pay_way: payWay.pay_way,
pay_type: payWay.pay_type, pay_type: payWay.pay_type,
user_id: user.value.id, user_id: user.value.id,
host: host,
device: "jump" device: "jump"
}).then(res => { }).then(res => {
showDialog.value = true showDialog.value = true

View File

@ -296,11 +296,16 @@ const pay = (product,payWay) => {
message: '正在创建订单', message: '正在创建订单',
forbidClick: true, forbidClick: true,
}); });
httpGet(`${process.env.VUE_APP_API_HOST}/api/payment/doPay`, { let host = process.env.VUE_APP_API_HOST
if (host === '') {
host = `${location.protocol}://${location.host}`;
}
httpPost(`${process.env.VUE_APP_API_HOST}/api/payment/doPay`, {
product_id: product.id, product_id: product.id,
pay_way: payWay.pay_way, pay_way: payWay.pay_way,
pay_type: payWay.pay_type, pay_type: payWay.pay_type,
user_id: userId.value, user_id: userId.value,
host: host,
device: "wechat" device: "wechat"
}).then(res => { }).then(res => {
location.href = res.data location.href = res.data