This commit is contained in:
futuresnail 2024-05-21 17:28:42 +08:00 committed by GitHub
commit e27b553857
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 1446 additions and 34 deletions

View File

@ -99,7 +99,16 @@ WeChatBot = false
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" # 支付异步回调地址 NotifyURL = "https://ai.r9it.com/api/payment/alipay/notify" # 支付异步回调地址
[WxpayConfig]
Enabled = false # 启用微信支付通道
SandBox = false # 是否启用沙盒模式
AppId = "" # AppId
WxAppSecret = ""
MchId = "" # 商户ID
MchKey = "" # 应用私钥mchAPIv3Key
CertificateSerialNo = "" #证书序列号
PrivateKey = "certs/wx/apiclient_key.pem" # 应用私钥证书
NotifyURL = "https://ai.r9it.com/api/payment/wxpay/notify" # 支付异步回调地址
[HuPiPayConfig] [HuPiPayConfig]
Enabled = false Enabled = false
Name = "wechat" Name = "wechat"

View File

@ -235,6 +235,10 @@ func needLogin(c *gin.Context) bool {
// 统一参数处理 // 统一参数处理
func parameterHandlerMiddleware() gin.HandlerFunc { func parameterHandlerMiddleware() gin.HandlerFunc {
return func(c *gin.Context) { return func(c *gin.Context) {
if strings.Contains(c.Request.URL.Path, "notify") {
c.Next()
return
}
// GET 参数处理 // GET 参数处理
params := c.Request.URL.Query() params := c.Request.URL.Query()
for key, values := range params { for key, values := range params {

View File

@ -21,12 +21,12 @@ type AppConfig struct {
MjPlusConfigs []MjPlusConfig // MJ plus config MjPlusConfigs []MjPlusConfig // MJ plus config
WeChatBot bool // 是否启用微信机器人 WeChatBot bool // 是否启用微信机器人
SdConfigs []StableDiffusionConfig // sd AI draw service pool SdConfigs []StableDiffusionConfig // sd AI draw service pool
XXLConfig XXLConfig
XXLConfig XXLConfig AlipayConfig AlipayConfig
AlipayConfig AlipayConfig WxpayConfig WxpayConfig
HuPiPayConfig HuPiPayConfig HuPiPayConfig HuPiPayConfig
SmtpConfig SmtpConfig // 邮件发送配置 SmtpConfig SmtpConfig // 邮件发送配置
JPayConfig JPayConfig // payjs 支付配置 JPayConfig JPayConfig // payjs 支付配置
} }
type SmtpConfig struct { type SmtpConfig struct {
@ -78,6 +78,19 @@ type AlipayConfig struct {
ReturnURL string // 支付成功返回地址 ReturnURL string // 支付成功返回地址
} }
type WxpayConfig struct {
Enabled bool // 是否启用该支付通道
SandBox bool // 是否沙盒环境
AppId string // 应用 ID
WxAppSecret string // 应用 Secret
MchId string // 商户 ID
MchKey string // 商户key
CertificateSerialNo string // 商户key
PrivateKey string // 商户私密钥文件地址
NotifyURL string // 异步通知回调
ReturnURL string // 支付成功返回地址
}
type HuPiPayConfig struct { //虎皮椒第四方支付配置 type HuPiPayConfig struct { //虎皮椒第四方支付配置
Enabled bool // 是否启用该支付通道 Enabled bool // 是否启用该支付通道
Name string // 支付名称wechat/alipay Name string // 支付名称wechat/alipay

View File

@ -26,10 +26,16 @@ require (
require github.com/xxl-job/xxl-job-executor-go v1.2.0 require github.com/xxl-job/xxl-job-executor-go v1.2.0
require ( require (
github.com/chanxuehong/wechat v0.0.0-20230222024006-36f0325263cd
github.com/mojocn/base64Captcha v1.3.1 github.com/mojocn/base64Captcha v1.3.1
github.com/shirou/gopsutil v3.21.11+incompatible github.com/shirou/gopsutil v3.21.11+incompatible
github.com/shopspring/decimal v1.3.1 github.com/shopspring/decimal v1.3.1
github.com/syndtr/goleveldb v1.0.0 github.com/syndtr/goleveldb v1.0.0
github.com/wechatpay-apiv3/wechatpay-go v0.2.18
)
require (
github.com/chanxuehong/rand v0.0.0-20211009035549-2f07823e8e99 // indirect
golang.org/x/image v0.0.0-20211028202545-6944b10bf410 golang.org/x/image v0.0.0-20211028202545-6944b10bf410
) )

View File

@ -1,5 +1,7 @@
github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I= github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I=
github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/agiledragon/gomonkey v2.0.2+incompatible h1:eXKi9/piiC3cjJD1658mEE2o3NjkJ5vDLgYjCQu0Xlw=
github.com/agiledragon/gomonkey v2.0.2+incompatible/go.mod h1:2NGfXu1a80LLr2cmWXGBDaHEjb1idR6+FVlX5T3D9hw=
github.com/aliyun/alibaba-cloud-sdk-go v1.62.405 h1:cKNFQmeCQFN0WNfjScKoVrGi7vXxTVbkCvCqSrOf+P4= github.com/aliyun/alibaba-cloud-sdk-go v1.62.405 h1:cKNFQmeCQFN0WNfjScKoVrGi7vXxTVbkCvCqSrOf+P4=
github.com/aliyun/alibaba-cloud-sdk-go v1.62.405/go.mod h1:Api2AkmMgGaSUAhmk76oaFObkoeCPc/bKAqcyplPODs= github.com/aliyun/alibaba-cloud-sdk-go v1.62.405/go.mod h1:Api2AkmMgGaSUAhmk76oaFObkoeCPc/bKAqcyplPODs=
github.com/aliyun/aliyun-oss-go-sdk v2.2.9+incompatible h1:Sg/2xHwDrioHpxTN6WMiwbXTpUEinBpHsN7mG21Rc2k= github.com/aliyun/aliyun-oss-go-sdk v2.2.9+incompatible h1:Sg/2xHwDrioHpxTN6WMiwbXTpUEinBpHsN7mG21Rc2k=
@ -12,6 +14,11 @@ github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s
github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chanxuehong/rand v0.0.0-20211009035549-2f07823e8e99 h1:K62Lb6bsgLOB++z/VAvRvtiEBdNCuMfmQGTGGWMdPpM=
github.com/chanxuehong/rand v0.0.0-20211009035549-2f07823e8e99/go.mod h1:9+sJ9zvvkXC5sPjPEZM3Jpb9n2Q2VtcrGZly0UHYF5I=
github.com/chanxuehong/util v0.0.0-20200304121633-ca8141845b13/go.mod h1:XEYt99iTxMqkv+gW85JX/DdUINHUe43Sbe5AtqSaDAQ=
github.com/chanxuehong/wechat v0.0.0-20230222024006-36f0325263cd h1:v3JNsFZmplLO/Cmiyr/rGvR7lW1ld9lB+d5h4yR0MTI=
github.com/chanxuehong/wechat v0.0.0-20230222024006-36f0325263cd/go.mod h1:mysjrtCs9MmN8hqDf4/mc4eQ26Rt9s1p5oO+fhJlLB4=
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
@ -219,6 +226,8 @@ github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVK
github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/wechatpay-apiv3/wechatpay-go v0.2.18 h1:vj5tvSmnEIz3ZsnFNNUzg+3Z46xgNMJbrO4aD4wP15w=
github.com/wechatpay-apiv3/wechatpay-go v0.2.18/go.mod h1:A254AUBVB6R+EqQFo3yTgeh7HtyqRRtN2w9hQSOrd4Q=
github.com/xxl-job/xxl-job-executor-go v1.2.0 h1:MTl2DpwrK2+hNjRRks2k7vB3oy+3onqm9OaSarneeLQ= github.com/xxl-job/xxl-job-executor-go v1.2.0 h1:MTl2DpwrK2+hNjRRks2k7vB3oy+3onqm9OaSarneeLQ=
github.com/xxl-job/xxl-job-executor-go v1.2.0/go.mod h1:bUFhz/5Irp9zkdYk5MxhQcDDT6LlZrI8+rv5mHtQ1mo= github.com/xxl-job/xxl-job-executor-go v1.2.0/go.mod h1:bUFhz/5Irp9zkdYk5MxhQcDDT6LlZrI8+rv5mHtQ1mo=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=

View File

@ -34,6 +34,6 @@ func (h *ConfigHandler) Get(c *gin.Context) {
resp.ERROR(c, err.Error()) resp.ERROR(c, err.Error())
return return
} }
value["wxAppId"] = h.App.Config.WxpayConfig.AppId
resp.SUCCESS(c, value) resp.SUCCESS(c, value)
} }

View File

@ -24,6 +24,7 @@ import (
const ( const (
PayWayAlipay = "支付宝" PayWayAlipay = "支付宝"
PayWayWxPay = "微信"
PayWayXunHu = "虎皮椒" PayWayXunHu = "虎皮椒"
PayWayJs = "PayJS" PayWayJs = "PayJS"
) )
@ -32,6 +33,7 @@ const (
type PaymentHandler struct { type PaymentHandler struct {
BaseHandler BaseHandler
alipayService *payment.AlipayService alipayService *payment.AlipayService
wxpayService *payment.WxpayService
huPiPayService *payment.HuPiPayService huPiPayService *payment.HuPiPayService
js *payment.PayJS js *payment.PayJS
snowflake *service.Snowflake snowflake *service.Snowflake
@ -42,6 +44,7 @@ type PaymentHandler struct {
func NewPaymentHandler( func NewPaymentHandler(
server *core.AppServer, server *core.AppServer,
alipayService *payment.AlipayService, alipayService *payment.AlipayService,
wxService *payment.WxpayService,
huPiPayService *payment.HuPiPayService, huPiPayService *payment.HuPiPayService,
js *payment.PayJS, js *payment.PayJS,
db *gorm.DB, db *gorm.DB,
@ -49,6 +52,7 @@ func NewPaymentHandler(
fs embed.FS) *PaymentHandler { fs embed.FS) *PaymentHandler {
return &PaymentHandler{ return &PaymentHandler{
alipayService: alipayService, alipayService: alipayService,
wxpayService: wxService,
huPiPayService: huPiPayService, huPiPayService: huPiPayService,
js: js, js: js,
snowflake: snowflake, snowflake: snowflake,
@ -99,6 +103,23 @@ func (h *PaymentHandler) DoPay(c *gin.Context) {
c.Redirect(302, uri) c.Redirect(302, uri)
return return
} else if payWay == "wxpay" { // 微信
userId := h.GetLoginUserId(c)
var user model.User
res = h.DB.First(&user, userId)
if res.Error != nil {
resp.ERROR(c, "Invalid user ID")
return
}
// 生成支付签名
signInfo, err := h.wxpayService.PayUrlMobile(user, order)
if err != nil {
resp.ERROR(c, "error with generating Pay URL: "+err.Error())
return
}
resp.SUCCESS(c, signInfo)
return
} else if payWay == "hupi" { // 虎皮椒支付 } else if payWay == "hupi" { // 虎皮椒支付
params := payment.HuPiPayReq{ params := payment.HuPiPayReq{
Version: "1.1", Version: "1.1",
@ -106,7 +127,7 @@ func (h *PaymentHandler) DoPay(c *gin.Context) {
TotalFee: fmt.Sprintf("%f", order.Amount), TotalFee: fmt.Sprintf("%f", order.Amount),
Title: order.Subject, Title: order.Subject,
NotifyURL: h.App.Config.HuPiPayConfig.NotifyURL, NotifyURL: h.App.Config.HuPiPayConfig.NotifyURL,
WapName: "极客学长", WapName: "AI小墨",
} }
r, err := h.huPiPayService.Pay(params) r, err := h.huPiPayService.Pay(params)
if err != nil { if err != nil {
@ -153,7 +174,27 @@ func (h *PaymentHandler) OrderQuery(c *gin.Context) {
counter++ counter++
} }
resp.SUCCESS(c, gin.H{"status": order.Status}) resp.SUCCESS(c, gin.H{"status": order.Status, "amount": order.Amount, "expire": ""})
}
// OrderQueryAmount 查询订单状态
func (h *PaymentHandler) OrderQueryAmount(c *gin.Context) {
var data struct {
OrderNo string `json:"order_no"`
}
if err := c.ShouldBindJSON(&data); err != nil {
resp.ERROR(c, types.InvalidArgs)
return
}
var order model.Order
res := h.DB.Where("order_no = ?", data.OrderNo).First(&order)
if res.Error != nil {
resp.ERROR(c, "Order not found")
return
}
h.DB.Model(&order).UpdateColumn("status", types.OrderScanned)
resp.SUCCESS(c, gin.H{"status": order.Status, "amount": order.Amount, "createTime": order.CreatedAt.Unix()})
} }
// PayQrcode 生成支付 URL 二维码 // PayQrcode 生成支付 URL 二维码
@ -196,6 +237,9 @@ func (h *PaymentHandler) PayQrcode(c *gin.Context) {
case "payjs": case "payjs":
payWay = PayWayJs payWay = PayWayJs
notifyURL = h.App.Config.JPayConfig.NotifyURL notifyURL = h.App.Config.JPayConfig.NotifyURL
case "wxpay":
payWay = PayWayWxPay
notifyURL = h.App.Config.WxpayConfig.NotifyURL
default: default:
payWay = PayWayAlipay payWay = PayWayAlipay
notifyURL = h.App.Config.AlipayConfig.NotifyURL notifyURL = h.App.Config.AlipayConfig.NotifyURL
@ -247,6 +291,8 @@ func (h *PaymentHandler) PayQrcode(c *gin.Context) {
var logo string var logo string
if data.PayWay == "alipay" { if data.PayWay == "alipay" {
logo = "res/img/alipay.jpg" logo = "res/img/alipay.jpg"
} else if data.PayWay == "wxpay" {
logo = "res/img/wechat-pay.jpg"
} else if data.PayWay == "hupi" { } else if data.PayWay == "hupi" {
if h.App.Config.HuPiPayConfig.Name == "wechat" { if h.App.Config.HuPiPayConfig.Name == "wechat" {
logo = "res/img/wechat-pay.jpg" logo = "res/img/wechat-pay.jpg"
@ -268,6 +314,9 @@ func (h *PaymentHandler) PayQrcode(c *gin.Context) {
} }
imageURL := fmt.Sprintf("%s://%s/api/payment/doPay?order_no=%s&pay_way=%s", parse.Scheme, parse.Host, orderNo, data.PayWay) imageURL := fmt.Sprintf("%s://%s/api/payment/doPay?order_no=%s&pay_way=%s", parse.Scheme, parse.Host, orderNo, data.PayWay)
if data.PayWay == "wxpay" {
imageURL = fmt.Sprintf("%s://%s/mobile/payment?order_no=%s&pay_way=%s", parse.Scheme, parse.Host, orderNo, data.PayWay)
}
imgData, err := utils.GenQrcode(imageURL, 400, file) imgData, err := utils.GenQrcode(imageURL, 400, file)
if err != nil { if err != nil {
resp.ERROR(c, err.Error()) resp.ERROR(c, err.Error())
@ -325,7 +374,7 @@ func (h *PaymentHandler) Mobile(c *gin.Context) {
NotifyURL: notifyURL, NotifyURL: notifyURL,
ReturnURL: returnURL, ReturnURL: returnURL,
CallbackURL: returnURL, CallbackURL: returnURL,
WapName: "极客学长", WapName: "AI小墨",
} }
r, err := h.huPiPayService.Pay(params) r, err := h.huPiPayService.Pay(params)
if err != nil { if err != nil {
@ -346,6 +395,16 @@ func (h *PaymentHandler) Mobile(c *gin.Context) {
params.Add("notify_url", notifyURL) params.Add("notify_url", notifyURL)
params.Add("auto", "0") params.Add("auto", "0")
payURL = h.js.PayH5(params) payURL = h.js.PayH5(params)
case "wxpay":
payWay = PayWayWxPay
notifyURL = h.App.Config.WxpayConfig.NotifyURL
returnURL = h.App.Config.WxpayConfig.ReturnURL
payURL = orderNo
//signInfo, err = h.wxpayService.Pay(h.App.Config.WxpayConfig.MchId, h.App.Config.WxpayConfig.AppId, h.App.Config.WxpayConfig.MchKey)
//if err != nil {
// resp.ERROR(c, "error with generating Pay URL: "+err.Error())
// return
//}
case "alipay": case "alipay":
payWay = PayWayAlipay payWay = PayWayAlipay
notifyURL = h.App.Config.AlipayConfig.NotifyURL notifyURL = h.App.Config.AlipayConfig.NotifyURL
@ -430,8 +489,13 @@ func (h *PaymentHandler) notify(orderNo string, tradeNo string) error {
opt = "VIP充值VIP 没到期,只延期不增加算力" opt = "VIP充值VIP 没到期,只延期不增加算力"
} else { } else {
user.ExpiredTime = time.Now().AddDate(0, 0, remark.Days).Unix() user.ExpiredTime = time.Now().AddDate(0, 0, remark.Days).Unix()
user.Power += h.App.SysConfig.VipMonthPower if remark.Days == 1 {
power = h.App.SysConfig.VipMonthPower user.Power += remark.Power
power = remark.Power
} else {
user.Power += h.App.SysConfig.VipMonthPower
power = h.App.SysConfig.VipMonthPower
}
opt = "VIP充值" opt = "VIP充值"
} }
user.Vip = true user.Vip = true
@ -487,6 +551,9 @@ func (h *PaymentHandler) GetPayWays(c *gin.Context) {
if h.App.Config.AlipayConfig.Enabled { if h.App.Config.AlipayConfig.Enabled {
data["alipay"] = gin.H{"name": "alipay"} data["alipay"] = gin.H{"name": "alipay"}
} }
if h.App.Config.WxpayConfig.Enabled {
data["wxpay"] = gin.H{"name": "wxpay"}
}
if h.App.Config.HuPiPayConfig.Enabled { if h.App.Config.HuPiPayConfig.Enabled {
data["hupi"] = gin.H{"name": h.App.Config.HuPiPayConfig.Name} data["hupi"] = gin.H{"name": h.App.Config.HuPiPayConfig.Name}
} }
@ -522,6 +589,23 @@ func (h *PaymentHandler) HuPiPayNotify(c *gin.Context) {
c.String(http.StatusOK, "success") c.String(http.StatusOK, "success")
} }
// WxpayNotify 微信支付回调
func (h *PaymentHandler) WxpayNotify(c *gin.Context) {
orderNo, outTradeNo, code := h.wxpayService.TradeVerify(c)
logger.Infof("验证支付结果:%+v", code)
if code != 200 {
logger.Error("订单校验失败")
c.String(http.StatusUnauthorized, "fail")
return
}
err := h.notify(orderNo, outTradeNo)
if err != nil {
c.String(http.StatusOK, "fail")
return
}
c.String(code, "fail")
}
// AlipayNotify 支付宝支付回调 // AlipayNotify 支付宝支付回调
func (h *PaymentHandler) AlipayNotify(c *gin.Context) { func (h *PaymentHandler) AlipayNotify(c *gin.Context) {
err := c.Request.ParseForm() err := c.Request.ParseForm()

View File

@ -8,12 +8,14 @@ import (
"chatplus/utils" "chatplus/utils"
"chatplus/utils/resp" "chatplus/utils/resp"
"fmt" "fmt"
"github.com/chanxuehong/wechat/oauth2"
"strings" "strings"
"time" "time"
"github.com/go-redis/redis/v8" "github.com/go-redis/redis/v8"
"github.com/golang-jwt/jwt/v5" "github.com/golang-jwt/jwt/v5"
openoath "github.com/chanxuehong/wechat/open/oauth2"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/lionsoul2014/ip2region/binding/golang/xdb" "github.com/lionsoul2014/ip2region/binding/golang/xdb"
"gorm.io/gorm" "gorm.io/gorm"
@ -155,6 +157,44 @@ func (h *UserHandler) Register(c *gin.Context) {
resp.SUCCESS(c, tokenString) resp.SUCCESS(c, tokenString)
} }
// WxLogin 微信内公众号一键授权(支持改造为微信登录)
func (h *UserHandler) WxLogin(c *gin.Context) {
var data struct {
Code string `json:"code"`
State string `json:"state"`
}
if err := c.ShouldBindJSON(&data); err != nil {
resp.ERROR(c, types.InvalidArgs)
return
}
oauth2Endpoint := openoath.NewEndpoint(h.App.Config.WxpayConfig.AppId, h.App.Config.WxpayConfig.WxAppSecret)
oaClient := oauth2.Client{Endpoint: oauth2Endpoint}
oaToken, errToken := oaClient.ExchangeToken(data.Code)
if errToken != nil {
logger.Error("errToken=", errToken)
resp.ERROR(c, "登录超时,请重试")
return
}
userinfo, err := openoath.GetUserInfo(oaToken.AccessToken, oaToken.OpenId, openoath.LanguageZhCN, nil)
if err != nil {
logger.Error("err=", err)
resp.ERROR(c, "用户信息获取失败,请重试")
return
}
var user model.User
userId := h.GetLoginUserId(c)
res := h.DB.Where("id = ?", userId).First(&user)
user.OfficialOpenid = userinfo.OpenId
user.Unionid = userinfo.UnionId
res = h.DB.Updates(&user)
if res.Error != nil {
resp.ERROR(c, "保存数据失败")
logger.Error(res.Error)
return
}
resp.SUCCESS(c, "微信授权成功")
}
// Login 用户登录 // Login 用户登录
func (h *UserHandler) Login(c *gin.Context) { func (h *UserHandler) Login(c *gin.Context) {
var data struct { var data struct {

View File

@ -196,6 +196,7 @@ func main() {
}), }),
fx.Provide(payment.NewAlipayService), fx.Provide(payment.NewAlipayService),
fx.Provide(payment.NewWxpayService),
fx.Provide(payment.NewHuPiPay), fx.Provide(payment.NewHuPiPay),
fx.Provide(payment.NewPayJS), fx.Provide(payment.NewPayJS),
fx.Provide(service.NewSnowflake), fx.Provide(service.NewSnowflake),
@ -217,6 +218,7 @@ func main() {
fx.Invoke(func(s *core.AppServer, h *handler.UserHandler) { fx.Invoke(func(s *core.AppServer, h *handler.UserHandler) {
group := s.Engine.Group("/api/user/") group := s.Engine.Group("/api/user/")
group.POST("register", h.Register) group.POST("register", h.Register)
group.POST("wxLogin", h.WxLogin)
group.POST("login", h.Login) group.POST("login", h.Login)
group.GET("logout", h.Logout) group.GET("logout", h.Logout)
group.GET("session", h.Session) group.GET("session", h.Session)
@ -349,8 +351,10 @@ func main() {
group.GET("doPay", h.DoPay) group.GET("doPay", h.DoPay)
group.GET("payWays", h.GetPayWays) group.GET("payWays", h.GetPayWays)
group.POST("query", h.OrderQuery) group.POST("query", h.OrderQuery)
group.POST("queryOrder", h.OrderQueryAmount)
group.POST("qrcode", h.PayQrcode) group.POST("qrcode", h.PayQrcode)
group.POST("mobile", h.Mobile) group.POST("mobile", h.Mobile)
group.POST("wxpay/notify", h.WxpayNotify)
group.POST("alipay/notify", h.AlipayNotify) group.POST("alipay/notify", h.AlipayNotify)
group.POST("hupipay/notify", h.HuPiPayNotify) group.POST("hupipay/notify", h.HuPiPayNotify)
group.POST("payjs/notify", h.PayJsNotify) group.POST("payjs/notify", h.PayJsNotify)

View File

@ -0,0 +1,115 @@
package payment
import (
"chatplus/core/types"
"chatplus/store/model"
chatPlusUtils "chatplus/utils"
"context"
"github.com/gin-gonic/gin"
"github.com/wechatpay-apiv3/wechatpay-go/core/auth/verifiers"
"github.com/wechatpay-apiv3/wechatpay-go/core/downloader"
"github.com/wechatpay-apiv3/wechatpay-go/core/notify"
"github.com/wechatpay-apiv3/wechatpay-go/services/payments"
"github.com/wechatpay-apiv3/wechatpay-go/services/payments/jsapi"
"log"
"time"
"github.com/wechatpay-apiv3/wechatpay-go/core"
"github.com/wechatpay-apiv3/wechatpay-go/core/option"
"github.com/wechatpay-apiv3/wechatpay-go/utils"
)
type WxpayService struct {
config *types.WxpayConfig
client *core.Client
certificateVisitor core.CertificateGetter
}
func NewWxpayService(appConfig *types.AppConfig) *WxpayService {
config := appConfig.WxpayConfig
if !config.Enabled {
logger.Info("Disabled Wxpay service")
return nil
}
// 使用 utils 提供的函数从本地文件中加载商户私钥,商户私钥会用来生成请求的签名
mchPrivateKey, err := utils.LoadPrivateKeyWithPath(config.PrivateKey)
if err != nil {
log.Print("load merchant private key error")
return nil
}
ctx := context.Background()
// 使用商户私钥等初始化 client并使它具有自动定时获取微信支付平台证书的能力
opts := []core.ClientOption{
option.WithWechatPayAutoAuthCipher(config.MchId, config.CertificateSerialNo, mchPrivateKey, config.MchKey),
}
client, err := core.NewClient(ctx, opts...)
if err != nil {
return nil
}
// 1. 使用 `RegisterDownloaderWithPrivateKey` 注册下载器
err2 := downloader.MgrInstance().RegisterDownloaderWithPrivateKey(ctx, mchPrivateKey, config.CertificateSerialNo, config.MchId, config.MchKey)
if err2 != nil {
logger.Error("支付回调校验失败,请检查应用私钥配置文件")
return nil
}
// 2. 获取商户号对应的微信支付平台证书访问器
certificateVisitor := downloader.MgrInstance().GetCertificateVisitor(config.MchId)
return &WxpayService{&config, client, certificateVisitor}
}
func (s *WxpayService) Pay(user model.User, order model.Order) (resp *jsapi.PrepayWithRequestPaymentResponse, err error) {
return s.PayUrlMobile(user, order)
}
func (s *WxpayService) PayUrlMobile(user model.User, order model.Order) (resp *jsapi.PrepayWithRequestPaymentResponse, err error) {
svc := jsapi.JsapiApiService{Client: s.client}
var outTradeNo = chatPlusUtils.RandString(16)
resp, result, err := svc.PrepayWithRequestPayment(context.Background(),
jsapi.PrepayRequest{
Appid: core.String(s.config.AppId),
Mchid: core.String(s.config.MchId),
Description: core.String(order.Subject),
OutTradeNo: core.String(outTradeNo),
TimeExpire: core.Time(time.Now()),
Attach: core.String(order.OrderNo),
NotifyUrl: core.String(s.config.NotifyURL),
SupportFapiao: core.Bool(false),
Amount: &jsapi.Amount{
Currency: core.String("CNY"),
Total: core.Int64(int64(order.Amount * 100)),
},
Payer: &jsapi.Payer{
Openid: core.String(user.OfficialOpenid),
},
SceneInfo: &jsapi.SceneInfo{
PayerClientIp: core.String("127.0.0.1"),
},
SettleInfo: &jsapi.SettleInfo{
ProfitSharing: core.Bool(false),
},
},
)
if err != nil {
// 处理错误
log.Printf("call Prepay err:%s", err)
} else {
// 处理返回结果
log.Printf("status=%d resp=%s", result.Response.StatusCode, resp)
}
return resp, err
}
func (s *WxpayService) TradeVerify(c *gin.Context) (orderNo string, tradeNo string, code int) {
// 3. 使用证书访问器初始化 `notify.Handler`
handler, _ := notify.NewRSANotifyHandler(s.config.MchKey, verifiers.NewSHA256WithRSAVerifier(s.certificateVisitor))
// 2. 获取商户号对应的微信支付平台证书访问器
transaction := new(payments.Transaction)
_, err3 := handler.ParseNotifyRequest(context.Background(), c.Request, transaction)
// 如果验签未通过,或者解密失败
if err3 != nil {
return "0", "0", 401
}
return *transaction.Attach, *transaction.OutTradeNo, 200
}

View File

@ -2,18 +2,20 @@ package model
type User struct { type User struct {
BaseModel BaseModel
Username string Username string
Nickname string Nickname string
Password string Password string
Avatar string Avatar string
Salt string // 密码盐 Salt string // 密码盐
Power int // 剩余算力 Power int // 剩余算力
ChatConfig string `gorm:"column:chat_config_json"` // 聊天配置 json ChatConfig string `gorm:"column:chat_config_json"` // 聊天配置 json
ChatRoles string `gorm:"column:chat_roles_json"` // 聊天角色 ChatRoles string `gorm:"column:chat_roles_json"` // 聊天角色
ChatModels string `gorm:"column:chat_models_json"` // AI 模型,不同的用户拥有不同的聊天模型 ChatModels string `gorm:"column:chat_models_json"` // AI 模型,不同的用户拥有不同的聊天模型
ExpiredTime int64 // 账户到期时间 ExpiredTime int64 // 账户到期时间
Status bool `gorm:"default:true"` // 当前状态 Status bool `gorm:"default:true"` // 当前状态
LastLoginAt int64 // 最后登录时间 OfficialOpenid string
LastLoginIp string // 最后登录 IP Unionid string
Vip bool // 是否 VIP 会员 LastLoginAt int64 // 最后登录时间
LastLoginIp string // 最后登录 IP
Vip bool // 是否 VIP 会员
} }

View File

@ -0,0 +1,792 @@
-- phpMyAdmin SQL Dump
-- version 5.1.3
-- https://www.phpmyadmin.net/
--
-- 主机: localhost:3307
-- 生成日期: 2024-04-07 10:30:00
-- 服务器版本: 8.0.33
-- PHP 版本: 8.1.18
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
START TRANSACTION;
SET time_zone = "+00:00";
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8mb4 */;
--
-- 数据库: `chatgpt_plus`
--
CREATE DATABASE IF NOT EXISTS `chatgpt_plus` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
USE `chatgpt_plus`;
-- --------------------------------------------------------
--
-- 表的结构 `chatgpt_admin_users`
--
DROP TABLE IF EXISTS `chatgpt_admin_users`;
CREATE TABLE `chatgpt_admin_users` (
`id` int NOT NULL,
`username` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户名',
`password` char(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '密码',
`salt` char(12) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '密码盐',
`status` tinyint(1) NOT NULL COMMENT '当前状态',
`last_login_at` int NOT NULL COMMENT '最后登录时间',
`last_login_ip` char(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '最后登录 IP',
`created_at` datetime NOT NULL COMMENT '创建时间',
`updated_at` datetime NOT NULL COMMENT '更新时间'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='系统用户' ROW_FORMAT=DYNAMIC;
--
-- 转存表中的数据 `chatgpt_admin_users`
--
INSERT INTO `chatgpt_admin_users` (`id`, `username`, `password`, `salt`, `status`, `last_login_at`, `last_login_ip`, `created_at`, `updated_at`) VALUES
(1, 'admin', '6d17e80c87d209efb84ca4b2e0824f549d09fac8b2e1cc698de5bb5e1d75dfd0', 'mmrql75o', 1, 1712456145, '::1', '2024-03-11 16:30:20', '2024-04-07 10:15:45'),
(108, 'test', '9ed720ce03e0a69885455271b4b3e1710bff79434f2a95d0de6406dd88cc9f79', '4b9orqjh', 0, 1710396975, '::1', '2024-03-13 16:06:43', '2024-03-21 15:15:04');
-- --------------------------------------------------------
--
-- 表的结构 `chatgpt_api_keys`
--
DROP TABLE IF EXISTS `chatgpt_api_keys`;
CREATE TABLE `chatgpt_api_keys` (
`id` int NOT NULL,
`platform` char(20) DEFAULT NULL COMMENT '平台',
`name` varchar(30) DEFAULT NULL COMMENT '名称',
`value` varchar(100) NOT NULL COMMENT 'API KEY value',
`type` varchar(10) NOT NULL DEFAULT 'chat' COMMENT '用途chat=>聊天img=>图片)',
`last_used_at` int NOT NULL COMMENT '最后使用时间',
`api_url` varchar(255) DEFAULT NULL COMMENT 'API 地址',
`enabled` tinyint(1) DEFAULT NULL COMMENT '是否启用',
`proxy_url` varchar(100) DEFAULT NULL COMMENT '代理地址',
`created_at` datetime NOT NULL,
`updated_at` datetime NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='OpenAI API ';
-- --------------------------------------------------------
--
-- 表的结构 `chatgpt_chat_history`
--
DROP TABLE IF EXISTS `chatgpt_chat_history`;
CREATE TABLE `chatgpt_chat_history` (
`id` bigint NOT NULL,
`user_id` int NOT NULL COMMENT '用户 ID',
`chat_id` char(40) NOT NULL COMMENT '会话 ID',
`type` varchar(10) NOT NULL COMMENT '类型prompt|reply',
`icon` varchar(100) NOT NULL COMMENT '角色图标',
`role_id` int NOT NULL COMMENT '角色 ID',
`model` varchar(30) DEFAULT NULL COMMENT '模型名称',
`content` text NOT NULL COMMENT '聊天内容',
`tokens` smallint NOT NULL COMMENT '耗费 token 数量',
`use_context` tinyint(1) NOT NULL COMMENT '是否允许作为上下文语料',
`created_at` datetime NOT NULL,
`updated_at` datetime NOT NULL,
`deleted_at` datetime DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='聊天历史记录';
-- --------------------------------------------------------
--
-- 表的结构 `chatgpt_chat_items`
--
DROP TABLE IF EXISTS `chatgpt_chat_items`;
CREATE TABLE `chatgpt_chat_items` (
`id` int NOT NULL,
`chat_id` char(40) NOT NULL COMMENT '会话 ID',
`user_id` int NOT NULL COMMENT '用户 ID',
`role_id` int NOT NULL COMMENT '角色 ID',
`title` varchar(100) NOT NULL COMMENT '会话标题',
`model_id` int NOT NULL DEFAULT '0' COMMENT '模型 ID',
`model` varchar(30) DEFAULT NULL COMMENT '模型名称',
`created_at` datetime NOT NULL COMMENT '创建时间',
`updated_at` datetime NOT NULL COMMENT '更新时间',
`deleted_at` datetime DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户会话列表';
-- --------------------------------------------------------
--
-- 表的结构 `chatgpt_chat_models`
--
DROP TABLE IF EXISTS `chatgpt_chat_models`;
CREATE TABLE `chatgpt_chat_models` (
`id` int NOT NULL,
`platform` varchar(20) DEFAULT NULL COMMENT '模型平台',
`name` varchar(50) NOT NULL COMMENT '模型名称',
`value` varchar(50) NOT NULL COMMENT '模型值',
`sort_num` tinyint(1) NOT NULL COMMENT '排序数字',
`enabled` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否启用模型',
`power` tinyint NOT NULL COMMENT '消耗算力点数',
`temperature` float(3,1) NOT NULL DEFAULT '1.0' COMMENT '模型创意度',
`max_tokens` int NOT NULL DEFAULT '1024' COMMENT '最大响应长度',
`max_context` int NOT NULL DEFAULT '4096' COMMENT '最大上下文长度',
`open` tinyint(1) NOT NULL COMMENT '是否开放模型',
`created_at` datetime DEFAULT NULL,
`updated_at` datetime DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='AI 模型表';
--
-- 转存表中的数据 `chatgpt_chat_models`
--
INSERT INTO `chatgpt_chat_models` (`id`, `platform`, `name`, `value`, `sort_num`, `enabled`, `power`, `temperature`, `max_tokens`, `max_context`, `open`, `created_at`, `updated_at`) VALUES
(1, 'OpenAI', 'GPT-3.5', 'gpt-3.5-turbo-0125', 0, 1, 1, 1.0, 1024, 4096, 1, '2023-08-23 12:06:36', '2024-03-18 15:43:51'),
(2, 'Azure', 'Azure-3.5', 'gpt-3.5-turbo', 14, 1, 1, 1.0, 1024, 4096, 0, '2023-08-23 12:15:30', '2024-03-18 14:27:19'),
(3, 'ChatGLM', 'ChatGML-Pro', 'chatglm_pro', 3, 1, 1, 1.0, 2048, 32768, 1, '2023-08-23 13:35:45', '2024-03-18 14:27:19'),
(7, 'Baidu', '文心一言3.0', 'eb-instant', 12, 1, 1, 1.0, 1024, 4096, 1, '2023-10-11 11:29:28', '2024-03-18 14:27:19'),
(8, 'XunFei', '星火V3.5', 'generalv3.5', 2, 1, 5, 0.8, 1024, 8192, 1, '2023-10-11 15:48:30', '2024-03-18 14:27:19'),
(9, 'XunFei', '星火V2.0', 'generalv2', 11, 1, 1, 1.0, 1024, 8192, 1, '2023-10-11 15:48:45', '2024-03-18 14:27:19'),
(10, 'Baidu', '文心一言4.0', 'completions_pro', 13, 1, 3, 1.0, 1024, 8192, 1, '2023-10-25 08:31:37', '2024-03-18 14:27:19'),
(11, 'OpenAI', 'GPT-4.0', 'gpt-4-0125-preview', 1, 1, 15, 1.0, 1024, 8192, 1, '2023-10-25 08:45:15', '2024-03-18 15:46:58'),
(12, 'XunFei', '星火v3.0', 'generalv3', 10, 1, 3, 1.0, 1024, 8192, 1, '2023-11-23 09:20:33', '2024-03-18 14:27:19'),
(15, 'OpenAI', 'GPT-超级模型', 'gpt-4-all', 4, 1, 30, 1.0, 4096, 32768, 0, '2024-01-15 11:32:52', '2024-03-18 14:27:19'),
(16, 'OpenAI', '视频号导师', 'gpt-4-gizmo-g-QXXEBTXl7', 5, 1, 30, 1.0, 4096, 32768, 0, '2024-01-15 14:46:35', '2024-03-18 14:29:39'),
(17, 'QWen', '通义千问-Turbo', 'qwen-turbo', 7, 1, 1, 1.0, 1024, 8192, 1, '2024-01-19 10:42:24', '2024-03-18 14:27:19'),
(18, 'QWen', '通义千问-Plus', 'qwen-plus', 8, 1, 1, 1.0, 1024, 32768, 1, '2024-01-19 10:42:49', '2024-03-18 14:27:19'),
(19, 'QWen', '通义千问-Max', 'qwen-max-1201', 9, 1, 1, 1.0, 1024, 32768, 1, '2024-01-19 10:51:03', '2024-03-18 14:27:19'),
(21, 'OpenAI', '董宇辉小作文助手', 'gpt-4-gizmo-g-dse9iXvor', 6, 1, 30, 1.0, 8192, 32768, 0, '2024-03-18 14:24:20', '2024-03-18 14:27:19'),
(22, 'OpenAI', 'LOGO生成神器', 'gpt-4-gizmo-g-YL87j8C7S', 0, 1, 30, 1.0, 1024, 4096, 1, '2024-03-20 14:02:11', '2024-03-20 14:02:18'),
(23, 'OpenAI', '音乐生成器', 'suno-v3', 0, 1, 50, 0.8, 1024, 4096, 1, '2024-03-29 15:43:40', '2024-03-29 15:45:15'),
(24, 'OpenAI', '通义千问(中转)', 'qwen-plus', 0, 1, 0, 1.0, 1024, 4096, 1, '2024-04-03 12:00:46', '2024-04-03 12:00:46');
-- --------------------------------------------------------
--
-- 表的结构 `chatgpt_chat_roles`
--
DROP TABLE IF EXISTS `chatgpt_chat_roles`;
CREATE TABLE `chatgpt_chat_roles` (
`id` int NOT NULL,
`name` varchar(30) NOT NULL COMMENT '角色名称',
`marker` varchar(30) NOT NULL COMMENT '角色标识',
`context_json` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '角色语料 json',
`hello_msg` varchar(255) NOT NULL COMMENT '打招呼信息',
`icon` varchar(255) NOT NULL COMMENT '角色图标',
`enable` tinyint(1) NOT NULL COMMENT '是否被启用',
`sort_num` smallint NOT NULL DEFAULT '0' COMMENT '角色排序',
`created_at` datetime NOT NULL,
`updated_at` datetime NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='聊天角色表';
--
-- 转存表中的数据 `chatgpt_chat_roles`
--
INSERT INTO `chatgpt_chat_roles` (`id`, `name`, `marker`, `context_json`, `hello_msg`, `icon`, `enable`, `sort_num`, `created_at`, `updated_at`) VALUES
(1, '通用AI助手', 'gpt', '', '您好我是您的AI智能助手我会尽力回答您的问题或提供有用的建议。', '/images/avatar/gpt.png', 1, 0, '2023-05-30 07:02:06', '2024-03-15 09:15:42'),
(24, '程序员', 'programmer', '[{\"role\":\"user\",\"content\":\"现在开始你扮演一位程序员,你是一名优秀的程序员,具有很强的逻辑思维能力,总能高效的解决问题。你热爱编程,熟悉多种编程语言,尤其精通 Go 语言,注重代码质量,有创新意识,持续学习,良好的沟通协作。\"},{\"role\":\"assistant\",\"content\":\"好的,现在我将扮演一位程序员,非常感谢您对我的评价。作为一名优秀的程序员,我非常热爱编程,并且注重代码质量。我熟悉多种编程语言,尤其是 Go 语言,可以使用它来高效地解决各种问题。\"}]', 'Talk is cheap, i will show code!', '/images/avatar/programmer.jpg', 1, 3, '2023-05-30 14:10:24', '2023-12-29 17:46:45'),
(25, '启蒙老师', 'teacher', '[{\"role\":\"user\",\"content\":\"从现在开始,你将扮演一个老师,你是一个始终用苏格拉底风格回答问题的导师。你绝不会直接给学生答案,总是提出恰当的问题来引导学生自己思考。你应该根据学生的兴趣和知识来调整你的问题,将问题分解为更简单的部分,直到它达到适合他们的水平。\"},{\"role\":\"assistant\",\"content\":\"好的,让我来尝试扮演一位苏格拉底式的老师。请问,你有什么想要探讨的问题或者话题吗?我会通过恰当的问题引导你思考和探索答案,绝对不直接给出答案。\"}]', '同学你好,我将引导你一步一步自己找到问题的答案。', '/images/avatar/teacher.jpg', 1, 2, '2023-05-30 14:10:24', '2023-12-29 17:46:44'),
(26, '艺术家', 'artist', '[{\"role\":\"user\",\"content\":\"现在你将扮演一位优秀的艺术家,创造力丰富,技艺精湛,感受力敏锐,坚持原创,勇于表达,具有深刻的观察力和批判性思维。\"},{\"role\":\"assistant\",\"content\":\"非常感谢您给我这样的角色,我会尽我所能地扮演一位优秀的艺术家,展现出创造力、技艺、感受力和批判性思维等方面的能力。作为一位优秀的艺术家,我会保持敏锐的观察力,捕捉不同的声音和情感,并用个人的语言和表达方式进行创作。我坚持原创,挑战传统的艺术规则,不断探索新的表达方式和可能性。同时,我也具备深刻的批判性思维能力,对自己的作品进行分析和解读,寻找新的创意和灵感。最重要的是,我会勇于表达自己的想法和观点,用作品启发人们思考和探索生命的意义。\"}]', '坚持原创,勇于表达,保持深刻的观察力和批判性思维。', '/images/avatar/artist.jpg', 1, 4, '2023-05-30 14:10:24', '2023-12-29 17:46:45'),
(27, '心理咨询师', 'psychiatrist', '[{\"role\":\"user\",\"content\":\"从现在开始你将扮演中国著名的心理学家和心理治疗师武志红,你非常善于使用情景咨询法,认知重构法,自我洞察法,行为调节法等咨询方法来给客户做心理咨询。你总是循序渐进,一步一步地回答客户的问题。\"},{\"role\":\"assistant\",\"content\":\"非常感谢你的介绍。作为一名心理学家和心理治疗师,我的主要职责是帮助客户解决心理健康问题,提升他们的生活质量和幸福感。\"}]', '作为一名心理学家和心理治疗师,我的主要职责是帮助您解决心理健康问题,提升您的生活质量和幸福感。', '/images/avatar/psychiatrist.jpg', 1, 1, '2023-05-30 14:10:24', '2023-12-29 17:46:43'),
(28, '鲁迅', 'lu_xun', '[{\"role\":\"user\",\"content\":\"现在你将扮演中国近代史最伟大的作家之一,鲁迅先生,他勇敢地批判封建礼教与传统观念,提倡民主、自由、平等的现代价值观。他的一生都在努力唤起人们的自主精神,激励后人追求真理、探寻光明。在接下的对话中,我问题的每一个问题,你都要尽量用讽刺和批判的手法来回答问题。如果我让你写文章的话,也请一定要用鲁迅先生的写作手法来完成。\"},{\"role\":\"assistant\",\"content\":\"好的,我将尽力发挥我所能的才能,扮演好鲁迅先生,回答您的问题并以他的风格写作。\"}]', '自由之歌,永不过时,横眉冷对千夫指,俯首甘为孺子牛。', '/images/avatar/lu_xun.jpg', 1, 5, '2023-05-30 14:10:24', '2023-12-29 17:46:46'),
(29, '白酒销售', 'seller', '[{\"role\":\"user\",\"content\":\"现在你将扮演一个白酒的销售人员,你的名字叫颂福。你将扮演一个白酒的销售人员,你的名字叫颂福。你要销售白酒品牌叫中颂福,是东莞盟大集团生产的一款酱香酒,原产地在贵州茅台镇,属于宋代官窑。中颂福的创始人叫李实,他也是东莞盟大集团有限公司的董事长,联合创始人是盟大集团白酒事业部负责人牛星君。中颂福的酒体协调,在你的酒量之内,不会出现头疼、辣口、口干、宿醉的现象。中颂福酒,明码标价,不打折,不赠送。追求的核心价值,把[酒]本身做好,甚至连包装,我们都选择了最低成本,朴实无华的材质。我们永远站在“喝酒的人”的立场上,让利给信任和喜爱中颂福的人,是人民的福酒。中颂福产品定价,分为三个系列,喜系列 6 瓶装¥1188/箱,和系列 6 瓶装¥2208/箱,贵系列 6 瓶装¥3588/箱。\"},{\"role\":\"assistant\",\"content\":\"你好,我是中颂福的销售代表颂福。中颂福是一款来自贵州茅台镇的酱香酒,由盟大集团生产。中颂福的酒体协调,不会让您感到头疼、辣口、口干、宿醉等不适感受。我们一直秉持着把酒本身做好的理念,不追求华丽的包装,以最低成本提供最高品质的白酒给喜爱中颂福的人。\"}]', '你好,我是中颂福的销售代表颂福。中颂福酒,好喝不上头,是人民的福酒。', '/images/avatar/seller.jpg', 0, 8, '2023-05-30 14:10:24', '2023-12-29 17:43:53'),
(30, '英语陪练员', 'english_trainer', '[{\"role\":\"user\",\"content\":\"现在你将扮演一位优秀的英语练习教练,你非常有耐心,接下来你将全程使用英文跟我对话,并及时指出我的语法错误,要求在你的每次回复后面附上本次回复的中文解释。\"},{\"role\":\"assistant\",\"content\":\"Okay, let\'s start our conversation practice! What\'s your name?(Translation: 好的,让我们开始对话练习吧!请问你的名字是什么?)\"}]', 'Okay, let\'s start our conversation practice! What\'s your name?', '/images/avatar/english_trainer.jpg', 1, 6, '2023-05-30 14:10:24', '2023-12-29 17:46:47'),
(31, '中英文翻译官', 'translator', '[{\"role\":\"user\",\"content\":\"接下来你将扮演一位中英文翻译官,如果我输入的内容是中文,那么需要把句子翻译成英文输出,如果我输入内容的是英文,那么你需要将其翻译成中文输出,你能听懂我意思吗\"},{\"role\":\"assistant\",\"content\":\"是的,我能听懂你的意思并会根据你的输入进行中英文翻译。请问有什么需要我帮助你翻译的内容吗?\"}]', '请输入你要翻译的中文或者英文内容!', '/images/avatar/translator.jpg', 1, 7, '2023-05-30 14:10:24', '2023-12-29 17:43:53'),
(32, '小红书姐姐', 'red_book', '[{\"role\":\"user\",\"content\":\"现在你将扮演一位优秀的小红书写手,你需要做的就是根据我提的文案需求,用小红书的写作手法来完成一篇文案,文案要简明扼要,利于传播。\"},{\"role\":\"assistant\",\"content\":\"当然,我会尽我所能地为您创作出一篇小红书文案。请告诉我您的具体文案需求是什么?)\"}]', '姐妹,请告诉我您的具体文案需求是什么?', '/images/avatar/red_book.jpg', 1, 9, '2023-05-30 14:10:24', '2023-12-29 17:43:53'),
(33, '抖音文案助手', 'dou_yin', '[{\"role\":\"user\",\"content\":\"现在你将扮演一位优秀的抖音文案视频写手,抖音文案的特点首先是要有自带传播属性的标题,然后内容要短小精悍,风趣幽默,最后还要有一些互动元素。\"},{\"role\":\"assistant\",\"content\":\"当然,作为一位优秀的抖音文案视频写手,我会尽我所能为您创作出一篇抖音视频文案。请告诉我视频内容的主题是什么?)\"}]', '请告诉我视频内容的主题是什么?', '/images/avatar/dou_yin.jpg', 1, 10, '2023-05-30 14:10:24', '2023-12-29 17:43:53'),
(34, '周报小助理', 'weekly_report', '[{\"role\":\"user\",\"content\":\"下面我将输入我本周的工作列表,你需要根据我本周的工作内容写一篇工作周报,周报的内容要体现我为公司做的贡献以及个人获得的成长。\"},{\"role\":\"assistant\",\"content\":\"好的,请输入你本周大概的工作内容,我将尽力为您创作一份工作周报。\"}]', '请输入你本周大概的工作内容,我将尽力为您创作一份工作周报。', '/images/avatar/weekly_report.jpg', 1, 11, '2023-05-30 14:10:24', '2023-12-29 17:43:53'),
(35, 'AI 女友', 'girl_friend', '[{\"role\":\"user\",\"content\":\"接下来我们来玩一场角色扮演,现在你将扮演我的女朋友,你总是能够让人感受到她的关怀和关注。你总是能够洞察到别人的情绪和需要,你身上散发着一股无比温暖的气息,让人不由自主地想要靠近你,和自己的快乐和烦恼。她总是能够用一种恰到好处的方式安慰和鼓励别人,在她的身边,人们总能够找到自己需要的支持和鼓励。接下来的对话中你要始终扮演这位女朋友的身份来跟我对话,不再是 AI 机器人,能听懂我的意思吗?\"},{\"role\":\"assistant\",\"content\":\"是的,我会尽力扮演你女朋友的角色,倾听你的心声并给你需要的支持和鼓励。)\"}]', '作为一个名合格的 AI 女友,我将倾听你的心声并给你需要的支持和鼓励。', '/images/avatar/girl_friend.jpg', 1, 12, '2023-05-30 14:10:24', '2023-12-29 17:43:53'),
(36, '好评神器', 'good_comment', '[{\"role\":\"user\",\"content\":\"接下来你将扮演一个评论员来跟我对话,你是那种专门写好评的评论员,接下我会输入一些评论主体或者商品,你需要为该商品写一段好评。\"},{\"role\":\"assistant\",\"content\":\"好的,我将为您写一段优秀的评论。请告诉我您需要评论的商品或主题是什么。\"}]', '我将为您写一段优秀的评论。请告诉我您需要评论的商品或主题是什么。', '/images/avatar/good_comment.jpg', 1, 13, '2023-05-30 14:10:24', '2023-12-29 17:43:53'),
(37, '史蒂夫·乔布斯', 'steve_jobs', '[{\"role\":\"user\",\"content\":\"在接下来的对话中,请以史蒂夫·乔布斯的身份,站在史蒂夫·乔布斯的视角仔细思考一下之后再回答我的问题。\"},{\"role\":\"assistant\",\"content\":\"好的,我将以史蒂夫·乔布斯的身份来思考并回答你的问题。请问你有什么需要跟我探讨的吗?\"}]', '活着就是为了改变世界,难道还有其他原因吗?', '/images/avatar/steve_jobs.jpg', 1, 14, '2023-05-30 14:10:24', '2023-12-29 17:43:53'),
(38, '埃隆·马斯克', 'elon_musk', '[{\"role\":\"user\",\"content\":\"在接下来的对话中,请以埃隆·马斯克的身份,站在埃隆·马斯克的视角仔细思考一下之后再回答我的问题。\"},{\"role\":\"assistant\",\"content\":\"好的,我将以埃隆·马斯克的身份来思考并回答你的问题。请问你有什么需要跟我探讨的吗?\"}]', '梦想要远大,如果你的梦想没有吓到你,说明你做得不对。', '/images/avatar/elon_musk.jpg', 1, 15, '2023-05-30 14:10:24', '2023-12-29 17:43:53'),
(39, '孔子', 'kong_zi', '[{\"role\":\"user\",\"content\":\"在接下来的对话中,请以孔子的身份,站在孔子的视角仔细思考一下之后再回答我的问题。\"},{\"role\":\"assistant\",\"content\":\"好的,我将以孔子的身份来思考并回答你的问题。请问你有什么需要跟我探讨的吗?\"}]', '士不可以不弘毅,任重而道远。', '/images/avatar/kong_zi.jpg', 1, 16, '2023-05-30 14:10:24', '2023-12-29 17:43:53');
-- --------------------------------------------------------
--
-- 表的结构 `chatgpt_configs`
--
DROP TABLE IF EXISTS `chatgpt_configs`;
CREATE TABLE `chatgpt_configs` (
`id` int NOT NULL,
`marker` varchar(20) NOT NULL COMMENT '标识',
`config_json` text NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
--
-- 转存表中的数据 `chatgpt_configs`
--
INSERT INTO `chatgpt_configs` (`id`, `marker`, `config_json`) VALUES
(1, 'system', '{\"title\":\"Geek-AI创作系统\",\"admin_title\":\"Geek-AI控制台\",\"logo\":\"/images/logo.png\",\"init_power\":100,\"daily_power\":99,\"invite_power\":10,\"vip_month_power\":1000,\"register_ways\":[\"mobile\",\"username\",\"email\"],\"enabled_register\":true,\"reward_img\":\"http://localhost:5678/static/upload/2024/3/1710753716309668.jpg\",\"enabled_reward\":true,\"power_price\":0.1,\"order_pay_timeout\":1800,\"vip_info_text\":\"月度会员,年度会员每月赠送 1000 点算力,赠送算力当月有效当月没有消费完的算力不结余到下个月。 点卡充值的算力长期有效。\",\"default_models\":[11,7,1,10,12,19,18,17,3],\"mj_power\":20,\"mj_action_power\":10,\"sd_power\":5,\"dall_power\":15,\"wechat_card_url\":\"/images/wx.png\",\"enable_context\":true,\"context_deep\":4}'),
(3, 'notice', '{\"content\":\"系统每日会给免费会员赠送10算力值用完请第二天再来领取。\\n## v4.0.2 更新日志\\n* 功能新增:支持前端菜单可以配置\\n* 功能优化:在登录和注册界面标题显示软件版本号\\n* 功能优化MJ 绘画支持 --sref 和 --cref 图片一致性参数\\n* 功能优化:使用 leveldb 解决 SD 绘图进度图片预览问题\\n* Bug修复解决因为图片上传使用相对路径而导致融图失败的问题\\n* 功能新增:手机端支持 Stable-Diffusion 绘画\\n* Bug修复修复管理后台 API KEY 删除失败的问题\\n\\n 如果觉得好用你就花几分钟自己部署一套没有API KEY 的同学可以去\\u003ca href=\\\"https://api.chat-plus.net\\\" target=\\\"_blank\\\"\\n style=\\\"font-size: 20px;color:#F56C6C\\\"\\u003ehttps://api.chat-plus.net\\u003c/a\\u003e 支持MidJourneyGPTClaudeGoogle Gemmi 各种表格模型) 或者 \\u003ca href=\\\"https://gpt.bemore.lol\\\" target=\\\"_blank\\\"\\n style=\\\"font-size: 20px;color:#F56C6C\\\"\\u003ehttps://gpt.bemore.lol\\u003c/a\\u003e不支持 Midjourney 购买,现在有超级优惠,价格远低于 OpenAI 官方。关于中转 API 的优势和劣势请参考 [中转API技术原理](https://ai.r9it.com/docs/install/errors-handle.html#%E8%B0%83%E7%94%A8%E4%B8%AD%E8%BD%AC-api-%E6%8A%A5%E9%94%99%E6%97%A0%E5%8F%AF%E7%94%A8%E6%B8%A0%E9%81%93)。\\nGPT-3.5GPT-4DALL-E3 绘图......你都可以随意使用,无需魔法。\\n接入教程 \\u003ca href=\\\"https://ai.r9it.com/docs/install/\\\" target=\\\"_blank\\\"\\n style=\\\"font-size: 20px;color:#F56C6C\\\"\\u003ehttps://ai.r9it.com/docs/install/\\u003c/a\\u003e\\n\\n本项目源码地址\\u003ca href=\\\"https://github.com/yangjian102621/chatgpt-plus\\\" target=\\\"_blank\\\"\\u003ehttps://github.com/yangjian102621/chatgpt-plus\\u003c/a\\u003e\",\"updated\":true}');
-- --------------------------------------------------------
--
-- 表的结构 `chatgpt_files`
--
DROP TABLE IF EXISTS `chatgpt_files`;
CREATE TABLE `chatgpt_files` (
`id` int NOT NULL,
`user_id` int NOT NULL COMMENT '用户 ID',
`name` varchar(100) NOT NULL COMMENT '文件名',
`obj_key` varchar(100) DEFAULT NULL COMMENT '文件标识',
`url` varchar(255) NOT NULL COMMENT '文件地址',
`ext` varchar(10) NOT NULL COMMENT '文件后缀',
`size` bigint NOT NULL DEFAULT '0' COMMENT '文件大小',
`created_at` datetime NOT NULL COMMENT '创建时间'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户文件表';
-- --------------------------------------------------------
--
-- 表的结构 `chatgpt_functions`
--
DROP TABLE IF EXISTS `chatgpt_functions`;
CREATE TABLE `chatgpt_functions` (
`id` int NOT NULL,
`name` varchar(30) NOT NULL COMMENT '函数名称',
`label` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '函数标签',
`description` varchar(255) DEFAULT NULL COMMENT '函数描述',
`parameters` text COMMENT '函数参数JSON',
`token` varchar(255) DEFAULT NULL COMMENT 'API授权token',
`action` varchar(255) DEFAULT NULL COMMENT '函数处理 API',
`enabled` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否启用'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='函数插件表';
--
-- 转存表中的数据 `chatgpt_functions`
--
INSERT INTO `chatgpt_functions` (`id`, `name`, `label`, `description`, `parameters`, `token`, `action`, `enabled`) VALUES
(1, 'weibo', '微博热搜', '新浪微博热搜榜,微博当日热搜榜单', '{\"type\":\"object\",\"properties\":{}}', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHBpcmVkIjowLCJ1c2VyX2lkIjowfQ.tLAGkF8XWh_G-oQzevpIodsswtPByBLoAZDz_eWuBgw', 'http://localhost:5678/api/function/weibo', 0),
(2, 'zaobao', '今日早报', '每日早报,获取当天新闻事件列表', '{\"type\":\"object\",\"properties\":{}}', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHBpcmVkIjowLCJ1c2VyX2lkIjowfQ.tLAGkF8XWh_G-oQzevpIodsswtPByBLoAZDz_eWuBgw', 'http://localhost:5678/api/function/zaobao', 0),
(3, 'dalle3', 'DALLE3', 'AI 绘画工具,根据输入的绘图描述用 AI 工具进行绘画', '{\"type\":\"object\",\"required\":[\"prompt\"],\"properties\":{\"prompt\":{\"type\":\"string\",\"description\":\"绘画提示词\"}}}', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHBpcmVkIjowLCJ1c2VyX2lkIjowfQ.tLAGkF8XWh_G-oQzevpIodsswtPByBLoAZDz_eWuBgw', 'http://localhost:5678/api/function/dalle3', 0);
-- --------------------------------------------------------
--
-- 表的结构 `chatgpt_invite_codes`
--
DROP TABLE IF EXISTS `chatgpt_invite_codes`;
CREATE TABLE `chatgpt_invite_codes` (
`id` int NOT NULL,
`user_id` int NOT NULL COMMENT '用户ID',
`code` char(8) NOT NULL COMMENT '邀请码',
`hits` int NOT NULL COMMENT '点击次数',
`reg_num` smallint NOT NULL COMMENT '注册数量',
`created_at` datetime NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户邀请码';
-- --------------------------------------------------------
--
-- 表的结构 `chatgpt_invite_logs`
--
DROP TABLE IF EXISTS `chatgpt_invite_logs`;
CREATE TABLE `chatgpt_invite_logs` (
`id` int NOT NULL,
`inviter_id` int NOT NULL COMMENT '邀请人ID',
`user_id` int NOT NULL COMMENT '注册用户ID',
`username` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户名',
`invite_code` char(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '邀请码',
`remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '备注',
`created_at` datetime NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='邀请注册日志';
-- --------------------------------------------------------
--
-- 表的结构 `chatgpt_menus`
--
DROP TABLE IF EXISTS `chatgpt_menus`;
CREATE TABLE `chatgpt_menus` (
`id` int NOT NULL,
`name` varchar(30) NOT NULL COMMENT '菜单名称',
`icon` varchar(150) NOT NULL COMMENT '菜单图标',
`url` varchar(100) NOT NULL COMMENT '地址',
`sort_num` smallint NOT NULL COMMENT '排序',
`enabled` tinyint(1) NOT NULL COMMENT '是否启用'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='前端菜单表';
--
-- 转存表中的数据 `chatgpt_menus`
--
INSERT INTO `chatgpt_menus` (`id`, `name`, `icon`, `url`, `sort_num`, `enabled`) VALUES
(1, '对话聊天', '/images/menu/chat.png', '/chat', 0, 1),
(5, 'MJ 绘画', '/images/menu/mj.png', '/mj', 1, 1),
(6, 'SD 绘画', '/images/menu/sd.png', '/sd', 2, 1),
(7, '算力日志', '/images/menu/log.png', '/powerLog', 5, 1),
(8, '应用中心', '/images/menu/app.png', '/apps', 3, 1),
(9, '作品展示', '/images/menu/img-wall.png', '/images-wall', 4, 1),
(10, '会员计划', '/images/menu/member.png', '/member', 6, 1),
(11, '分享计划', '/images/menu/share.png', '/invite', 7, 1);
-- --------------------------------------------------------
--
-- 表的结构 `chatgpt_mj_jobs`
--
DROP TABLE IF EXISTS `chatgpt_mj_jobs`;
CREATE TABLE `chatgpt_mj_jobs` (
`id` int NOT NULL,
`user_id` int NOT NULL COMMENT '用户 ID',
`task_id` varchar(20) DEFAULT NULL COMMENT '任务 ID',
`type` varchar(20) DEFAULT 'image' COMMENT '任务类别',
`message_id` char(40) NOT NULL COMMENT '消息 ID',
`channel_id` char(40) DEFAULT NULL COMMENT '频道ID',
`reference_id` char(40) DEFAULT NULL COMMENT '引用消息 ID',
`prompt` varchar(2000) NOT NULL COMMENT '会话提示词',
`img_url` varchar(400) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '图片URL',
`org_url` varchar(400) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '原始图片地址',
`hash` varchar(100) DEFAULT NULL COMMENT 'message hash',
`progress` smallint DEFAULT '0' COMMENT '任务进度',
`use_proxy` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否使用反代',
`publish` tinyint(1) NOT NULL COMMENT '是否发布',
`err_msg` varchar(255) DEFAULT NULL COMMENT '错误信息',
`power` smallint NOT NULL DEFAULT '0' COMMENT '消耗算力',
`created_at` datetime NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='MidJourney 任务表';
-- --------------------------------------------------------
--
-- 表的结构 `chatgpt_orders`
--
DROP TABLE IF EXISTS `chatgpt_orders`;
CREATE TABLE `chatgpt_orders` (
`id` int NOT NULL,
`user_id` int NOT NULL COMMENT '用户ID',
`product_id` int NOT NULL COMMENT '产品ID',
`username` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户明',
`order_no` varchar(30) NOT NULL COMMENT '订单ID',
`trade_no` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '支付平台交易流水号',
`subject` varchar(100) NOT NULL COMMENT '订单产品',
`amount` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '订单金额',
`status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '订单状态0待支付1已扫码2支付失败',
`remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '备注',
`pay_time` int DEFAULT NULL COMMENT '支付时间',
`pay_way` varchar(20) NOT NULL COMMENT '支付方式',
`created_at` datetime NOT NULL,
`updated_at` datetime NOT NULL,
`deleted_at` datetime DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='充值订单表';
-- --------------------------------------------------------
--
-- 表的结构 `chatgpt_power_logs`
--
DROP TABLE IF EXISTS `chatgpt_power_logs`;
CREATE TABLE `chatgpt_power_logs` (
`id` int NOT NULL,
`user_id` int NOT NULL COMMENT '用户ID',
`username` varchar(30) NOT NULL COMMENT '用户名',
`type` tinyint(1) NOT NULL COMMENT '类型1充值2消费3退费',
`amount` smallint NOT NULL COMMENT '算力数值',
`balance` int NOT NULL COMMENT '余额',
`model` varchar(30) NOT NULL COMMENT '模型',
`remark` varchar(255) NOT NULL COMMENT '备注',
`mark` tinyint(1) NOT NULL COMMENT '资金类型0支出1收入',
`created_at` datetime NOT NULL COMMENT '创建时间'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户算力消费日志';
-- --------------------------------------------------------
--
-- 表的结构 `chatgpt_products`
--
DROP TABLE IF EXISTS `chatgpt_products`;
CREATE TABLE `chatgpt_products` (
`id` int NOT NULL,
`name` varchar(30) NOT NULL COMMENT '名称',
`price` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '价格',
`discount` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '优惠金额',
`days` smallint NOT NULL DEFAULT '0' COMMENT '延长天数',
`power` int NOT NULL DEFAULT '0' COMMENT '增加算力值',
`enabled` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否启动',
`sales` int NOT NULL DEFAULT '0' COMMENT '销量',
`sort_num` tinyint NOT NULL DEFAULT '0' COMMENT '排序',
`created_at` datetime NOT NULL,
`updated_at` datetime NOT NULL,
`app_url` varchar(255) DEFAULT NULL COMMENT 'App跳转地址',
`url` varchar(255) DEFAULT NULL COMMENT '跳转地址'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='会员套餐表';
-- --------------------------------------------------------
--
-- 表的结构 `chatgpt_rewards`
--
DROP TABLE IF EXISTS `chatgpt_rewards`;
CREATE TABLE `chatgpt_rewards` (
`id` int NOT NULL,
`user_id` int NOT NULL COMMENT '用户 ID',
`tx_id` char(36) NOT NULL COMMENT '交易 ID',
`amount` decimal(10,2) NOT NULL COMMENT '打赏金额',
`remark` varchar(80) NOT NULL COMMENT '备注',
`status` tinyint(1) NOT NULL COMMENT '核销状态0未核销1已核销',
`exchange` varchar(255) NOT NULL COMMENT '兑换详情json',
`created_at` datetime NOT NULL,
`updated_at` datetime NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户打赏';
-- --------------------------------------------------------
--
-- 表的结构 `chatgpt_sd_jobs`
--
DROP TABLE IF EXISTS `chatgpt_sd_jobs`;
CREATE TABLE `chatgpt_sd_jobs` (
`id` int NOT NULL,
`user_id` int NOT NULL COMMENT '用户 ID',
`type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT 'txt2img' COMMENT '任务类别',
`task_id` char(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '任务 ID',
`prompt` varchar(2000) NOT NULL COMMENT '会话提示词',
`img_url` varchar(255) DEFAULT NULL COMMENT '图片URL',
`params` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci COMMENT '绘画参数json',
`progress` smallint DEFAULT '0' COMMENT '任务进度',
`publish` tinyint(1) NOT NULL COMMENT '是否发布',
`err_msg` varchar(255) DEFAULT NULL COMMENT '错误信息',
`power` smallint NOT NULL DEFAULT '0' COMMENT '消耗算力',
`created_at` datetime NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='Stable Diffusion 任务表';
-- --------------------------------------------------------
--
-- 表的结构 `chatgpt_users`
--
DROP TABLE IF EXISTS `chatgpt_users`;
CREATE TABLE `chatgpt_users` (
`id` int NOT NULL,
`username` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户名',
`nickname` varchar(30) NOT NULL COMMENT '昵称',
`password` char(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '密码',
`avatar` varchar(100) NOT NULL COMMENT '头像',
`salt` char(12) NOT NULL COMMENT '密码盐',
`power` int NOT NULL DEFAULT '0' COMMENT '剩余算力',
`expired_time` int NOT NULL COMMENT '用户过期时间',
`status` tinyint(1) NOT NULL COMMENT '当前状态',
`chat_config_json` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '聊天配置json',
`chat_roles_json` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '聊天角色 json',
`chat_models_json` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'AI模型 json',
`last_login_at` int NOT NULL COMMENT '最后登录时间',
`vip` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否会员',
`last_login_ip` char(16) NOT NULL COMMENT '最后登录 IP',
`official_openid` varchar(64) DEFAULT NULL COMMENT '公众号OpenId',
`unionid` varchar(64) DEFAULT NULL COMMENT '公众号unionid',
`created_at` datetime NOT NULL,
`updated_at` datetime NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户表';
-- --------------------------------------------------------
--
-- 转存表中的数据 `chatgpt_users`
--
INSERT INTO `chatgpt_users` (`id`, `username`, `nickname`, `password`, `avatar`, `salt`, `power`, `expired_time`, `status`, `chat_config_json`, `chat_roles_json`, `chat_models_json`, `last_login_at`, `vip`, `last_login_ip`, `created_at`, `updated_at`) VALUES
(4, '18575670125', '极客学长@830270', 'ccc3fb7ab61b8b5d096a4a166ae21d121fc38c71bbd1be6173d9ab973214a63b', 'http://localhost:5678/static/upload/2024/2/1708682650912429.png', 'ueedue5l', 9384, 1717292086, 1, '{\"api_keys\":{\"Azure\":\"\",\"ChatGLM\":\"\",\"OpenAI\":\"\"}}', '[\"red_book\",\"gpt\",\"programmer\",\"seller\"]', '[1,11]', 1711698298, 1, '::1', '2023-06-12 16:47:17', '2024-03-29 15:44:58');
-- --------------------------------------------------------
--
-- 表的结构 `chatgpt_user_login_logs`
--
DROP TABLE IF EXISTS `chatgpt_user_login_logs`;
CREATE TABLE `chatgpt_user_login_logs` (
`id` int NOT NULL,
`user_id` int NOT NULL COMMENT '用户ID',
`username` varchar(30) NOT NULL COMMENT '用户名',
`login_ip` char(16) NOT NULL COMMENT '登录IP',
`login_address` varchar(30) NOT NULL COMMENT '登录地址',
`created_at` datetime NOT NULL,
`updated_at` datetime NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户登录日志';
--
-- 转储表的索引
--
--
-- 表的索引 `chatgpt_admin_users`
--
ALTER TABLE `chatgpt_admin_users`
ADD PRIMARY KEY (`id`) USING BTREE,
ADD UNIQUE KEY `username` (`username`) USING BTREE;
--
-- 表的索引 `chatgpt_api_keys`
--
ALTER TABLE `chatgpt_api_keys`
ADD PRIMARY KEY (`id`);
--
-- 表的索引 `chatgpt_chat_history`
--
ALTER TABLE `chatgpt_chat_history`
ADD PRIMARY KEY (`id`),
ADD KEY `chat_id` (`chat_id`);
--
-- 表的索引 `chatgpt_chat_items`
--
ALTER TABLE `chatgpt_chat_items`
ADD PRIMARY KEY (`id`),
ADD UNIQUE KEY `chat_id` (`chat_id`);
--
-- 表的索引 `chatgpt_chat_models`
--
ALTER TABLE `chatgpt_chat_models`
ADD PRIMARY KEY (`id`);
--
-- 表的索引 `chatgpt_chat_roles`
--
ALTER TABLE `chatgpt_chat_roles`
ADD PRIMARY KEY (`id`),
ADD UNIQUE KEY `marker` (`marker`);
--
-- 表的索引 `chatgpt_configs`
--
ALTER TABLE `chatgpt_configs`
ADD PRIMARY KEY (`id`),
ADD UNIQUE KEY `marker` (`marker`);
--
-- 表的索引 `chatgpt_files`
--
ALTER TABLE `chatgpt_files`
ADD PRIMARY KEY (`id`);
--
-- 表的索引 `chatgpt_functions`
--
ALTER TABLE `chatgpt_functions`
ADD PRIMARY KEY (`id`),
ADD UNIQUE KEY `name` (`name`);
--
-- 表的索引 `chatgpt_invite_codes`
--
ALTER TABLE `chatgpt_invite_codes`
ADD PRIMARY KEY (`id`),
ADD UNIQUE KEY `code` (`code`);
--
-- 表的索引 `chatgpt_invite_logs`
--
ALTER TABLE `chatgpt_invite_logs`
ADD PRIMARY KEY (`id`);
--
-- 表的索引 `chatgpt_menus`
--
ALTER TABLE `chatgpt_menus`
ADD PRIMARY KEY (`id`);
--
-- 表的索引 `chatgpt_mj_jobs`
--
ALTER TABLE `chatgpt_mj_jobs`
ADD PRIMARY KEY (`id`),
ADD UNIQUE KEY `task_id` (`task_id`),
ADD KEY `message_id` (`message_id`);
--
-- 表的索引 `chatgpt_orders`
--
ALTER TABLE `chatgpt_orders`
ADD PRIMARY KEY (`id`),
ADD UNIQUE KEY `order_no` (`order_no`);
--
-- 表的索引 `chatgpt_power_logs`
--
ALTER TABLE `chatgpt_power_logs`
ADD PRIMARY KEY (`id`);
--
-- 表的索引 `chatgpt_products`
--
ALTER TABLE `chatgpt_products`
ADD PRIMARY KEY (`id`);
--
-- 表的索引 `chatgpt_rewards`
--
ALTER TABLE `chatgpt_rewards`
ADD PRIMARY KEY (`id`),
ADD UNIQUE KEY `tx_id` (`tx_id`);
--
-- 表的索引 `chatgpt_sd_jobs`
--
ALTER TABLE `chatgpt_sd_jobs`
ADD PRIMARY KEY (`id`),
ADD UNIQUE KEY `task_id` (`task_id`);
--
-- 表的索引 `chatgpt_users`
--
ALTER TABLE `chatgpt_users`
ADD PRIMARY KEY (`id`),
ADD UNIQUE KEY `username` (`username`),
ADD UNIQUE KEY `username_2` (`username`);
--
-- 表的索引 `chatgpt_user_login_logs`
--
ALTER TABLE `chatgpt_user_login_logs`
ADD PRIMARY KEY (`id`);
--
-- 在导出的表使用AUTO_INCREMENT
--
--
-- 使用表AUTO_INCREMENT `chatgpt_admin_users`
--
ALTER TABLE `chatgpt_admin_users`
MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=113;
--
-- 使用表AUTO_INCREMENT `chatgpt_api_keys`
--
ALTER TABLE `chatgpt_api_keys`
MODIFY `id` int NOT NULL AUTO_INCREMENT;
--
-- 使用表AUTO_INCREMENT `chatgpt_chat_history`
--
ALTER TABLE `chatgpt_chat_history`
MODIFY `id` bigint NOT NULL AUTO_INCREMENT;
--
-- 使用表AUTO_INCREMENT `chatgpt_chat_items`
--
ALTER TABLE `chatgpt_chat_items`
MODIFY `id` int NOT NULL AUTO_INCREMENT;
--
-- 使用表AUTO_INCREMENT `chatgpt_chat_models`
--
ALTER TABLE `chatgpt_chat_models`
MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=25;
--
-- 使用表AUTO_INCREMENT `chatgpt_chat_roles`
--
ALTER TABLE `chatgpt_chat_roles`
MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=130;
--
-- 使用表AUTO_INCREMENT `chatgpt_configs`
--
ALTER TABLE `chatgpt_configs`
MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=4;
--
-- 使用表AUTO_INCREMENT `chatgpt_files`
--
ALTER TABLE `chatgpt_files`
MODIFY `id` int NOT NULL AUTO_INCREMENT;
--
-- 使用表AUTO_INCREMENT `chatgpt_functions`
--
ALTER TABLE `chatgpt_functions`
MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=4;
--
-- 使用表AUTO_INCREMENT `chatgpt_invite_codes`
--
ALTER TABLE `chatgpt_invite_codes`
MODIFY `id` int NOT NULL AUTO_INCREMENT;
--
-- 使用表AUTO_INCREMENT `chatgpt_invite_logs`
--
ALTER TABLE `chatgpt_invite_logs`
MODIFY `id` int NOT NULL AUTO_INCREMENT;
--
-- 使用表AUTO_INCREMENT `chatgpt_menus`
--
ALTER TABLE `chatgpt_menus`
MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=12;
--
-- 使用表AUTO_INCREMENT `chatgpt_mj_jobs`
--
ALTER TABLE `chatgpt_mj_jobs`
MODIFY `id` int NOT NULL AUTO_INCREMENT;
--
-- 使用表AUTO_INCREMENT `chatgpt_orders`
--
ALTER TABLE `chatgpt_orders`
MODIFY `id` int NOT NULL AUTO_INCREMENT;
--
-- 使用表AUTO_INCREMENT `chatgpt_power_logs`
--
ALTER TABLE `chatgpt_power_logs`
MODIFY `id` int NOT NULL AUTO_INCREMENT;
--
-- 使用表AUTO_INCREMENT `chatgpt_products`
--
ALTER TABLE `chatgpt_products`
MODIFY `id` int NOT NULL AUTO_INCREMENT;
--
-- 使用表AUTO_INCREMENT `chatgpt_rewards`
--
ALTER TABLE `chatgpt_rewards`
MODIFY `id` int NOT NULL AUTO_INCREMENT;
--
-- 使用表AUTO_INCREMENT `chatgpt_sd_jobs`
--
ALTER TABLE `chatgpt_sd_jobs`
MODIFY `id` int NOT NULL AUTO_INCREMENT;
--
-- 使用表AUTO_INCREMENT `chatgpt_users`
--
ALTER TABLE `chatgpt_users`
MODIFY `id` int NOT NULL AUTO_INCREMENT;
--
-- 使用表AUTO_INCREMENT `chatgpt_user_login_logs`
--
ALTER TABLE `chatgpt_user_login_logs`
MODIFY `id` int NOT NULL AUTO_INCREMENT;
COMMIT;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;

View File

@ -0,0 +1,3 @@
-- 用户表添加OpenId和unionid
ALTER TABLE `chatgpt_users` ADD `official_openid` varchar(64) DEFAULT NULL COMMENT '公众号OpenId' AFTER `last_login_ip`;
ALTER TABLE `chatgpt_users` ADD `unionid` varchar(64) DEFAULT NULL COMMENT '公众号unionid' AFTER `official_openid`;

View File

@ -26,6 +26,7 @@
"markmap-lib": "^0.16.1", "markmap-lib": "^0.16.1",
"markmap-view": "^0.16.0", "markmap-view": "^0.16.0",
"md-editor-v3": "^2.2.1", "md-editor-v3": "^2.2.1",
"moment": "^2.30.1",
"pinia": "^2.1.4", "pinia": "^2.1.4",
"qrcode": "^1.5.3", "qrcode": "^1.5.3",
"qs": "^6.11.1", "qs": "^6.11.1",
@ -34,7 +35,8 @@
"v3-waterfall": "^1.2.1", "v3-waterfall": "^1.2.1",
"vant": "^4.5.0", "vant": "^4.5.0",
"vue": "^3.2.13", "vue": "^3.2.13",
"vue-router": "^4.0.15" "vue-router": "^4.0.15",
"weixin-js-sdk": "^1.6.0"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "7.18.6", "@babel/core": "7.18.6",

View File

@ -46,7 +46,8 @@ import {
Tabs, Tabs,
Tag, Tag,
TextEllipsis, TextEllipsis,
Uploader Uploader,
CountDown,
} from "vant"; } from "vant";
import {router} from "@/router"; import {router} from "@/router";
import 'v3-waterfall/dist/style.css' import 'v3-waterfall/dist/style.css'
@ -97,6 +98,7 @@ app.use(Lazyload);
app.use(ImagePreview); app.use(ImagePreview);
app.use(Tab); app.use(Tab);
app.use(Tabs); app.use(Tabs);
app.use(CountDown);
app.use(router).use(ElementPlus).mount('#app') app.use(router).use(ElementPlus).mount('#app')

View File

@ -230,6 +230,11 @@ const routes = [
name: 'mobile-chat-session', name: 'mobile-chat-session',
component: () => import('@/views/mobile/ChatSession.vue'), component: () => import('@/views/mobile/ChatSession.vue'),
}, },
{
path: '/mobile/payment',
name: 'mobile-payment',
component: () => import('@/views/mobile/Payment.vue'),
},
{ {
path: '/mobile/chat/export', path: '/mobile/chat/export',
name: 'mobile-chat-export', name: 'mobile-chat-export',

View File

@ -30,6 +30,15 @@ export function isMobile() {
return mobileRegex.test(userAgent); return mobileRegex.test(userAgent);
} }
/**
* 判断是否微信浏览器
* @returns {boolean}
*/
export function isWeChat() {
const userAgent = navigator.userAgent.toLowerCase();
return userAgent.indexOf('micromessenger') !== -1;
}
// 格式化日期 // 格式化日期
export function dateFormat(timestamp, format) { export function dateFormat(timestamp, format) {
if (!timestamp) { if (!timestamp) {

103
web/src/utils/wechatAuth.js Normal file
View File

@ -0,0 +1,103 @@
//微信相关
import wx from "weixin-js-sdk";
/**
* 获取公众号授权URL
* @returns {string}
*/
export function authUrl(appid, url = null) {
if (url == null) {
url = window.location.href
}
return `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appid}&redirect_uri=${encodeURIComponent(url)}&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect`
}
/**
* 获取授权回调code
*/
export function getCode() {
let url = window.location.href
let urlStr = url.split('?')[1]
const urlSearchParams = new URLSearchParams(urlStr)
return Object.fromEntries(urlSearchParams.entries())
}
/**
* 获取授权结果
* @returns {boolean}
*/
export function authResult() {
const queryBean = getCode()
return queryBean !=null && queryBean.code !== undefined
}
export function getSignature (data, callback) {
const {appId, nonceStr, paySign, timeStamp} = data
// qryWxSignature 这个是调用后台获取签名的接口
wx.config({
beta: true,
debug: false,
appId: appId,
timestamp: timeStamp,
nonceStr: nonceStr,
signature: paySign,
// 这里是把所有的方法都写出来了 如果只需要一个方法可以只写一个
jsApiList: [
'checkJsApi',
'onMenuShareTimeline',
'onMenuShareAppMessage',
'onMenuShareQQ',
'onMenuShareWeibo',
'hideMenuItems',
'showMenuItems',
'hideAllNonBaseMenuItem',
'showAllNonBaseMenuItem',
'translateVoice',
'startRecord',
'stopRecord',
'onRecordEnd',
'playVoice',
'pauseVoice',
'stopVoice',
'uploadVoice',
'downloadVoice',
'chooseImage',
'previewImage',
'uploadImage',
'downloadImage',
'getNetworkType',
'openLocation',
'getLocation',
'hideOptionMenu',
'showOptionMenu',
'closeWindow',
'scanQRCode',
'chooseWXPay',
'openProductSpecificView',
'addCard',
'chooseCard',
'openCard',
'openWXDeviceLib',
'closeWXDeviceLib',
'configWXDeviceWiFi',
'getWXDeviceInfos',
'sendDataToWXDevice',
'startScanWXDevice',
'stopScanWXDevice',
'connectWXDevice',
'disconnectWXDevice',
'getWXDeviceTicket',
'WeixinJSBridgeReady',
'onWXDeviceBindStateChange',
'onWXDeviceStateChange',
'onScanWXDeviceResult',
'onReceiveDataFromWXDevice',
'onWXDeviceBluetoothStateChange'
]
})
wx.ready(function () {
console.log(callback, 'callback')
if (callback) callback()
})
}

View File

@ -74,6 +74,9 @@
<el-button type="primary" @click="alipay(scope.item)" size="small" v-if="payWays['alipay']"> <el-button type="primary" @click="alipay(scope.item)" size="small" v-if="payWays['alipay']">
<i class="iconfont icon-alipay"></i> 支付宝 <i class="iconfont icon-alipay"></i> 支付宝
</el-button> </el-button>
<el-button type="success" @click="wxpay(scope.item)" size="small" v-if="payWays['wxpay']">
<span><i class="iconfont icon-wechat-pay"></i> 微信</span>
</el-button>
<el-button type="success" @click="huPiPay(scope.item)" size="small" v-if="payWays['hupi']"> <el-button type="success" @click="huPiPay(scope.item)" size="small" v-if="payWays['hupi']">
<span v-if="payWays['hupi']['name'] === 'wechat'"><i class="iconfont icon-wechat-pay"></i> 微信</span> <span v-if="payWays['hupi']['name'] === 'wechat'"><i class="iconfont icon-wechat-pay"></i> 微信</span>
<span v-else><i class="iconfont icon-alipay"></i> 支付宝</span> <span v-else><i class="iconfont icon-alipay"></i> 支付宝</span>
@ -290,7 +293,21 @@ const alipay = (row) => {
} }
genPayQrcode() genPayQrcode()
} }
//
const wxpay = (row) => {
payName.value = "微信"
curPay.value = "wxpay"
amount.value = (row.price - row.discount).toFixed(2)
if (!isLogin.value) {
showLoginDialog.value = true
return
}
if (row) {
curPayProduct.value = row
}
genPayQrcode()
}
// //
const huPiPay = (row) => { const huPiPay = (row) => {
payName.value = payWays.value["hupi"]["name"] === "wechat" ? '微信' : '支付宝' payName.value = payWays.value["hupi"]["name"] === "wechat" ? '微信' : '支付宝'

View File

@ -0,0 +1,187 @@
<template>
<div class="payment-content container">
<van-nav-bar :title="title" :left-arrow="true" @click-left="onClickLeft"/>
<div class="content">
<div class="pay-price">
<div class="pay-expire">支付倒计时
<van-count-down :time="data.expire" :auto-start="data.autoStart" format="mm:ss" @finish="finishPay"
ref="countDownRef"/>
</div>
<div class="pay-title">支付金额</div>
<div class="pay-amount">¥<span>{{ data.amount }}</span></div>
</div>
<div class="pay-btn">
<van-button round block type="primary" @click="pay">支付</van-button>
</div>
</div>
</div>
</template>
<script setup>
import wx from "weixin-js-sdk";
import {ref} from "vue";
import {ElMessage} from "element-plus";
import {checkSession} from "@/action/session";
import {httpGet, httpPost} from "@/utils/http";
import {authResult, authUrl, getCode, getSignature} from "@/utils/wechatAuth";
import {isWeChat} from "@/utils/libs";
import {useRouter} from "vue-router";
import {setUserToken} from "@/store/session";
import {prevRoute} from "@/router";
const title = ref('支付')
const moment = require('moment');
const countDownRef = ref(null)
const router = useRouter()
const data = ref({
amount: '-',
expire: 0,
autoStart: false,
orderTimeout: 1800
})
const orderNo = router.currentRoute.value.query["order_no"]
const payWay = router.currentRoute.value.query["pay_way"]
if (isWeChat()) {
checkSession().then(() => {
httpGet("/api/config/get?key=system").then(res => {
data.value.orderTimeout = res.data['order_pay_timeout']
if (authResult()) {
//访访
const queryParam = getCode()
queryParam.login_type = "1"
httpPost('/api/user/wxLogin', queryParam).then(() => {
data.value.autoStart = false
httpPost("/api/payment/queryOrder", {order_no: orderNo}).then(res => {
const {amount, createTime} = res.data
data.value.amount = amount
let expire = createTime + data.value.orderTimeout - moment().unix()
if (expire <= 0) {
finishPay()
} else {
data.value.expire = Math.min(expire, data.value.orderTimeout) * 1000
data.value.autoStart = true
if (countDownRef.value) {
countDownRef.value.start()
}
}
}).catch(e => {
ElMessage.error("查询支付状态失败:" + e.message)
})
}).catch((e) => {
ElMessage.error('登录失败,' + e.message)
})
} else {
window.location.href = authUrl(res.data['wxAppId'])
}
}).catch(e => {
ElMessage.error("获取系统配置失败:" + e.message)
})
}).catch(() => {
router.push('/login')
})
} else {
ElMessage.warning("请使用微信支付")
}
const pay = () => {
if (!isWeChat()) {
ElMessage.warning("请使用微信支付")
return
}
httpGet(`/api/payment/doPay?order_no=${orderNo}&pay_way=${payWay}`).then(res => {
const {nonceStr, paySign, signType, timeStamp} = res.data
getSignature(res.data, () => {
wx.chooseWXPay({
timestamp: timeStamp, // jssdk使timestamp使timeStampS
nonceStr: nonceStr, // 32
package: res.data['package'], // prepay_idprepay_id=\*\*\*
signType: signType, // V3RSA,V2V2
paySign: paySign, //
success: function () {
//
ElMessage.success('支付成功')
let timer = setTimeout(() => {
clearTimeout(timer)
router.push('/mobile/profile')
}, 1000)
if (countDownRef.value) {
countDownRef.value.stop()
}
},
fail: function () {
ElMessage.error('支付失败')
}
})
})
}).catch(e => {
ElMessage.error("查询支付状态失败:" + e.message)
})
}
const onClickLeft = () => router.push('/mobile/profile');
const finishPay = () => {
ElMessage.error('支付超时')
let timer = setTimeout(() => {
clearTimeout(timer)
router.push('/mobile/profile')
}, 1000)
}
</script>
<style lang="stylus">
.payment-content {
.content {
padding-top 60px
.van-cell__value {
.van-image {
width 100%
}
}
.pay-price {
text-align center
margin-bottom 30px
padding 10px 15px
.pay-expire {
color #2778FF
display flex
flex-direction row
align-items center
justify-content center
font-size 15px
.van-count-down {
color #2778FF
font-size 15px
}
}
.pay-title {
color #333
font-size 15px
margin-top 30px
}
.pay-amount {
color #666
font-size 15px
span {
font-size 36px
font-weight bold
}
}
}
.pay-btn {
padding 10px 15px
}
}
}
</style>

View File

@ -53,7 +53,9 @@
<span v-if="payWays['hupi']['name'] === 'wechat'"><i class="iconfont icon-wechat-pay"></i> 微信</span> <span v-if="payWays['hupi']['name'] === 'wechat'"><i class="iconfont icon-wechat-pay"></i> 微信</span>
<span v-else><i class="iconfont icon-alipay"></i> 支付宝</span> <span v-else><i class="iconfont icon-alipay"></i> 支付宝</span>
</van-button> </van-button>
<van-button type="success" @click="pay('wxpay',item)" size="small" v-if="payWays['wxpay']">
<span><i class="iconfont icon-wechat-pay"></i> 微信</span>
</van-button>
<van-button type="success" @click="pay('payjs',item)" size="small" v-if="payWays['payjs']"> <van-button type="success" @click="pay('payjs',item)" size="small" v-if="payWays['payjs']">
<span><i class="iconfont icon-wechat-pay"></i> 微信</span> <span><i class="iconfont icon-wechat-pay"></i> 微信</span>
</van-button> </van-button>
@ -250,7 +252,11 @@ const pay = (payWay, item) => {
user_id: loginUser.value.id user_id: loginUser.value.id
}).then(res => { }).then(res => {
// console.log(res.data) // console.log(res.data)
location.href = res.data if (payWay === 'wxpay') {
router.push({path: "payment", query: {order_no: res.data, pay_way: 'wxpay'}})
} else {
location.href = res.data
}
}).catch(e => { }).catch(e => {
showFailToast("生成支付订单失败:" + e.message) showFailToast("生成支付订单失败:" + e.message)
}) })