1
This commit is contained in:
@@ -19,6 +19,7 @@ func main() {
|
||||
controller.Agent,
|
||||
controller.Customer,
|
||||
controller.Transaction,
|
||||
controller.Payment,
|
||||
})
|
||||
|
||||
// ==================== 静态文件服务(workspace 目录) ====================
|
||||
|
||||
Binary file not shown.
@@ -1,17 +1,20 @@
|
||||
package public
|
||||
|
||||
const (
|
||||
TableNameDrama = "short_drama"
|
||||
TableNameCharacter = "short_drama_character"
|
||||
TableNameEpisode = "short_drama_episode"
|
||||
TableNameGenerationTask = "short_drama_generation_task"
|
||||
TableNameModelConfig = "short_drama_model_config"
|
||||
TableNameScene = "short_drama_scene"
|
||||
TableNameProp = "short_drama_prop"
|
||||
TableNameBackgroundMusic = "short_drama_background_music"
|
||||
TableNameUser = "user"
|
||||
TableNameAgentProfile = "agent_profile"
|
||||
TableNameCustomerProfile = "customer_profile"
|
||||
TableNameAgentTier = "agent_tier"
|
||||
TableNameAccountTransaction = "account_transaction"
|
||||
TableNameDrama = "short_drama"
|
||||
TableNameCharacter = "short_drama_character"
|
||||
TableNameEpisode = "short_drama_episode"
|
||||
TableNameGenerationTask = "short_drama_generation_task"
|
||||
TableNameModelConfig = "short_drama_model_config"
|
||||
TableNameScene = "short_drama_scene"
|
||||
TableNameProp = "short_drama_prop"
|
||||
TableNameBackgroundMusic = "short_drama_background_music"
|
||||
TableNameUser = "user"
|
||||
TableNameAgentProfile = "agent_profile"
|
||||
TableNameCustomerProfile = "customer_profile"
|
||||
TableNameAgentTier = "agent_tier"
|
||||
TableNameAccountTransaction = "account_transaction"
|
||||
TableNamePaymentOrder = "payment_order"
|
||||
TableNamePaymentChannelTrade = "payment_channel_trade"
|
||||
TableNamePaymentConfig = "payment_config"
|
||||
)
|
||||
|
||||
@@ -7,6 +7,8 @@ import (
|
||||
"video-factory/shortdrama/model/dto"
|
||||
"video-factory/shortdrama/model/entity"
|
||||
"video-factory/shortdrama/service"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
type agent struct{}
|
||||
@@ -18,7 +20,7 @@ type createAgentRes struct {
|
||||
}
|
||||
|
||||
func (c *agent) Create(ctx context.Context, req *dto.CreateAgentReq) (res *createAgentRes, err error) {
|
||||
user, err := service.AuthService.CreateAgent(ctx, req.Username, req.Password, req.Name, req.Region, req.TierId)
|
||||
user, err := service.AuthService.CreateAgent(ctx, req.Username, req.Password, req.Phone, req.Name, req.Region, req.TierId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -35,11 +37,15 @@ func (c *agent) List(ctx context.Context, req *dto.ListAgentReq) (res *dto.ListA
|
||||
|
||||
func (c *agent) Update(ctx context.Context, req *dto.UpdateAgentReq) (res *struct{}, err error) {
|
||||
if req.Name != "" {
|
||||
if err := dao.User.UpdateFields(ctx, req.Id, map[string]interface{}{
|
||||
m := g.Map{
|
||||
"name": req.Name,
|
||||
"region": req.Region,
|
||||
"status": req.Status,
|
||||
}); err != nil {
|
||||
}
|
||||
if req.Phone != "" {
|
||||
m["phone"] = req.Phone
|
||||
}
|
||||
if err := dao.User.UpdateFields(ctx, req.Id, m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"video-factory/shortdrama/model/dto"
|
||||
"video-factory/shortdrama/model/entity"
|
||||
"video-factory/shortdrama/service"
|
||||
)
|
||||
|
||||
@@ -28,3 +29,23 @@ func (c *config) Save(ctx context.Context, req *dto.SaveModelConfigReq) (res *st
|
||||
}
|
||||
return nil, service.ConfigService.Save(ctx, req)
|
||||
}
|
||||
|
||||
func (c *config) GetPayment(ctx context.Context, req *dto.GetPaymentConfigReq) (res *dto.GetPaymentConfigRes, err error) {
|
||||
cfg := service.ConfigService.GetPaymentConfig(ctx)
|
||||
if cfg == nil {
|
||||
return &dto.GetPaymentConfigRes{PaymentConfig: &entity.PaymentConfig{}}, nil
|
||||
}
|
||||
return &dto.GetPaymentConfigRes{PaymentConfig: cfg}, nil
|
||||
}
|
||||
|
||||
func (c *config) SavePayment(ctx context.Context, req *dto.SavePaymentConfigReq) (res *struct{}, err error) {
|
||||
return nil, service.ConfigService.SavePaymentConfig(ctx, &entity.PaymentConfig{
|
||||
WechatAppId: req.WechatAppId,
|
||||
WechatMchId: req.WechatMchId,
|
||||
WechatApiKey: req.WechatApiKey,
|
||||
WechatAppSecret: req.WechatAppSecret,
|
||||
AlipayAppId: req.AlipayAppId,
|
||||
AlipayPrivateKey: req.AlipayPrivateKey,
|
||||
AlipayPublicKey: req.AlipayPublicKey,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -74,3 +74,20 @@ func (c *customer) Detail(ctx context.Context, req *struct{ Id int64 }) (res *dt
|
||||
balance := service.AuthService.GetBalance(ctx, req.Id)
|
||||
return &dto.CustomerDetail{User: user, Profile: profile, Balance: balance}, nil
|
||||
}
|
||||
|
||||
func (c *customer) Update(ctx context.Context, req *dto.UpdateCustomerReq) (res *struct{}, err error) {
|
||||
m := g.Map{}
|
||||
if req.Phone != "" {
|
||||
m["phone"] = req.Phone
|
||||
}
|
||||
if req.Name != "" {
|
||||
m["name"] = req.Name
|
||||
}
|
||||
if req.Region != "" {
|
||||
m["region"] = req.Region
|
||||
}
|
||||
if len(m) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, dao.User.UpdateFields(ctx, req.Id, m)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
"video-factory/shortdrama/middleware"
|
||||
"video-factory/shortdrama/model/dto"
|
||||
"video-factory/shortdrama/service"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
type payment struct{}
|
||||
|
||||
var Payment = new(payment)
|
||||
|
||||
func (c *payment) Prepay(ctx context.Context, req *dto.PrepayReq) (res *dto.PrepayRes, err error) {
|
||||
r := g.RequestFromCtx(ctx)
|
||||
userId := middleware.GetUserId(r)
|
||||
|
||||
order, codeUrl, prepayJson, redirectUrl, err := service.PaymentService.Prepay(ctx, userId, req.Amount, req.Channel)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &dto.PrepayRes{
|
||||
OrderNo: order.OrderNo,
|
||||
Channel: order.Channel,
|
||||
CodeUrl: codeUrl,
|
||||
PrepayJson: prepayJson,
|
||||
RedirectUrl: redirectUrl,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *payment) Status(ctx context.Context, req *dto.PaymentStatusReq) (res *dto.PaymentStatusRes, err error) {
|
||||
status, amount, err := service.PaymentService.GetStatus(ctx, req.OrderNo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &dto.PaymentStatusRes{OrderNo: req.OrderNo, Status: status, Amount: amount}, nil
|
||||
}
|
||||
|
||||
func (c *payment) NotifyWechat(ctx context.Context, req *struct{}) (res *struct{}, err error) {
|
||||
r := g.RequestFromCtx(ctx)
|
||||
body := r.GetBody()
|
||||
_ = service.PaymentService.HandleNotify(ctx, "wechat", body)
|
||||
r.Response.WriteString("<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>")
|
||||
r.Exit()
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (c *payment) NotifyAlipay(ctx context.Context, req *struct{}) (res *struct{}, err error) {
|
||||
r := g.RequestFromCtx(ctx)
|
||||
body := r.GetBody()
|
||||
_ = service.PaymentService.HandleNotify(ctx, "alipay", body)
|
||||
r.Response.WriteString("success")
|
||||
r.Exit()
|
||||
return nil, nil
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"video-factory/shortdrama/dao"
|
||||
"video-factory/shortdrama/middleware"
|
||||
@@ -29,7 +30,5 @@ func (c *transaction) List(ctx context.Context, req *dto.ListTransactionReq) (re
|
||||
}
|
||||
|
||||
func (c *transaction) Recharge(ctx context.Context, req *dto.RechargeReq) (res *struct{}, err error) {
|
||||
r := g.RequestFromCtx(ctx)
|
||||
createdBy := middleware.GetRole(r) + ":" + r.GetCtxVar("userId").String()
|
||||
return nil, service.AuthService.Recharge(ctx, req.UserId, req.Amount, createdBy)
|
||||
return nil, service.AuthService.Recharge(ctx, req.UserId, req.Amount, "", fmt.Sprintf("后台充值 %.2f 元", float64(req.Amount)/100))
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ func init() {
|
||||
g.Log().Warningf(ctx, "创建 account_transaction 表失败: %v", err)
|
||||
}
|
||||
_, _ = g.DB().Exec(ctx, "CREATE INDEX IF NOT EXISTS idx_at_user ON "+public.TableNameAccountTransaction+"(user_id)")
|
||||
_, _ = g.DB().Exec(ctx, "ALTER TABLE "+public.TableNameAccountTransaction+" ADD COLUMN order_no TEXT NOT NULL DEFAULT ''")
|
||||
}
|
||||
|
||||
func (d *accountTransactionDao) Insert(ctx context.Context, data *entity.AccountTransaction) (int64, error) {
|
||||
|
||||
@@ -48,6 +48,7 @@ func init() {
|
||||
"max_ref_audio_count", "max_ref_audio_file_size", "max_ref_audio_duration", "ref_audio_formats",
|
||||
"max_ref_image_file_size", "ref_image_formats",
|
||||
"video_query_url",
|
||||
"payment_config",
|
||||
} {
|
||||
if _, err := g.DB().Exec(ctx, `ALTER TABLE `+public.TableNameModelConfig+` DROP COLUMN `+col); err != nil {
|
||||
g.Log().Debugf(ctx, "删除孤儿列 %s 失败(可能已删除): %v", col, err)
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
"video-factory/shortdrama/consts/public"
|
||||
"video-factory/shortdrama/model/entity"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
var PaymentChannelTrade = &paymentChannelTradeDao{}
|
||||
|
||||
type paymentChannelTradeDao struct{}
|
||||
|
||||
func init() {
|
||||
ctx := context.Background()
|
||||
_, err := g.DB().Exec(ctx, `CREATE TABLE IF NOT EXISTS `+public.TableNamePaymentChannelTrade+` (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
order_id INTEGER NOT NULL DEFAULT 0,
|
||||
channel TEXT NOT NULL DEFAULT '',
|
||||
prepay_id TEXT NOT NULL DEFAULT '',
|
||||
code_url TEXT NOT NULL DEFAULT '',
|
||||
trade_no TEXT NOT NULL DEFAULT '',
|
||||
channel_response TEXT NOT NULL DEFAULT '{}',
|
||||
created_at DATETIME
|
||||
)`)
|
||||
if err != nil {
|
||||
g.Log().Warningf(ctx, "创建 payment_channel_trade 表失败: %v", err)
|
||||
}
|
||||
_, _ = g.DB().Exec(ctx, "CREATE INDEX IF NOT EXISTS idx_pct_order ON "+public.TableNamePaymentChannelTrade+"(order_id)")
|
||||
}
|
||||
|
||||
func (d *paymentChannelTradeDao) Insert(ctx context.Context, data *entity.PaymentChannelTrade) (int64, error) {
|
||||
r, err := g.DB().Exec(ctx,
|
||||
"INSERT INTO "+public.TableNamePaymentChannelTrade+" (order_id, channel, prepay_id, code_url, trade_no, channel_response) VALUES (?, ?, ?, ?, ?, ?)",
|
||||
data.OrderId, data.Channel, data.PrepayId, data.CodeUrl, data.TradeNo, data.ChannelResponse)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return r.LastInsertId()
|
||||
}
|
||||
|
||||
func (d *paymentChannelTradeDao) GetByOrderId(ctx context.Context, orderId int64) (*entity.PaymentChannelTrade, error) {
|
||||
var t entity.PaymentChannelTrade
|
||||
err := g.DB().Model(public.TableNamePaymentChannelTrade).Ctx(ctx).Where("order_id", orderId).Scan(&t)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if t.Id == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
return &t, nil
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
"video-factory/shortdrama/consts/public"
|
||||
"video-factory/shortdrama/model/entity"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
var PaymentConfigDao = &paymentConfigDao{}
|
||||
|
||||
type paymentConfigDao struct{}
|
||||
|
||||
func init() {
|
||||
ctx := context.Background()
|
||||
if _, err := g.DB().Exec(ctx, `CREATE TABLE IF NOT EXISTS `+public.TableNamePaymentConfig+` (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
wechat_app_id TEXT NOT NULL DEFAULT '',
|
||||
wechat_mch_id TEXT NOT NULL DEFAULT '',
|
||||
wechat_api_key TEXT NOT NULL DEFAULT '',
|
||||
wechat_app_secret TEXT NOT NULL DEFAULT '',
|
||||
alipay_app_id TEXT NOT NULL DEFAULT '',
|
||||
alipay_private_key TEXT NOT NULL DEFAULT '',
|
||||
alipay_public_key TEXT NOT NULL DEFAULT '',
|
||||
created_at DATETIME,
|
||||
updated_at DATETIME
|
||||
)`); err != nil {
|
||||
g.Log().Warningf(ctx, "创建支付配置表失败: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *paymentConfigDao) GetFirst(ctx context.Context) (res *entity.PaymentConfig, err error) {
|
||||
r, err := g.DB().Model(public.TableNamePaymentConfig).Ctx(ctx).OrderAsc("id").Limit(1).One()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r == nil {
|
||||
return nil, nil
|
||||
}
|
||||
res = new(entity.PaymentConfig)
|
||||
err = r.Struct(&res)
|
||||
return
|
||||
}
|
||||
|
||||
func (d *paymentConfigDao) Save(ctx context.Context, data *entity.PaymentConfig) error {
|
||||
existing, err := d.GetFirst(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if existing != nil {
|
||||
data.Id = existing.Id
|
||||
_, err = g.DB().Model(public.TableNamePaymentConfig).Ctx(ctx).Data(data).Where("id", existing.Id).Update()
|
||||
return err
|
||||
}
|
||||
m := gconv.Map(data, gconv.MapOption{Tags: []string{"orm"}})
|
||||
delete(m, "id")
|
||||
delete(m, "created_at")
|
||||
delete(m, "updated_at")
|
||||
_, err = g.DB().Model(public.TableNamePaymentConfig).Ctx(ctx).Data(m).Insert()
|
||||
return err
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
"video-factory/shortdrama/consts/public"
|
||||
"video-factory/shortdrama/model/entity"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
)
|
||||
|
||||
var PaymentOrder = &paymentOrderDao{}
|
||||
|
||||
type paymentOrderDao struct{}
|
||||
|
||||
func init() {
|
||||
ctx := context.Background()
|
||||
_, err := g.DB().Exec(ctx, `CREATE TABLE IF NOT EXISTS `+public.TableNamePaymentOrder+` (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
order_no TEXT NOT NULL UNIQUE,
|
||||
user_id INTEGER NOT NULL DEFAULT 0,
|
||||
amount INTEGER NOT NULL DEFAULT 0,
|
||||
channel TEXT NOT NULL DEFAULT '',
|
||||
channel_type TEXT NOT NULL DEFAULT '',
|
||||
status TEXT NOT NULL DEFAULT 'pending',
|
||||
subject TEXT NOT NULL DEFAULT '',
|
||||
paid_at DATETIME,
|
||||
notify_raw TEXT NOT NULL DEFAULT '{}',
|
||||
notify_count INTEGER NOT NULL DEFAULT 0,
|
||||
created_at DATETIME,
|
||||
updated_at DATETIME
|
||||
)`)
|
||||
if err != nil {
|
||||
g.Log().Warningf(ctx, "创建 payment_order 表失败: %v", err)
|
||||
}
|
||||
_, _ = g.DB().Exec(ctx, "CREATE INDEX IF NOT EXISTS idx_po_user ON "+public.TableNamePaymentOrder+"(user_id)")
|
||||
}
|
||||
|
||||
func (d *paymentOrderDao) Insert(ctx context.Context, data *entity.PaymentOrder) (int64, error) {
|
||||
r, err := g.DB().Exec(ctx,
|
||||
"INSERT INTO "+public.TableNamePaymentOrder+" (order_no, user_id, amount, channel, channel_type, status, subject) VALUES (?, ?, ?, ?, ?, ?, ?)",
|
||||
data.OrderNo, data.UserId, data.Amount, data.Channel, data.ChannelType, data.Status, data.Subject)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return r.LastInsertId()
|
||||
}
|
||||
|
||||
func (d *paymentOrderDao) GetByOrderNo(ctx context.Context, orderNo string) (*entity.PaymentOrder, error) {
|
||||
var p entity.PaymentOrder
|
||||
err := g.DB().Model(public.TableNamePaymentOrder).Ctx(ctx).Where("order_no", orderNo).Scan(&p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if p.Id == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
return &p, nil
|
||||
}
|
||||
|
||||
func (d *paymentOrderDao) UpdateSuccess(ctx context.Context, id int64, notifyRaw string) error {
|
||||
_, err := g.DB().Exec(ctx,
|
||||
"UPDATE "+public.TableNamePaymentOrder+" SET status='success', paid_at=CURRENT_TIMESTAMP, notify_raw=?, notify_count=notify_count+1, updated_at=CURRENT_TIMESTAMP WHERE id=?",
|
||||
notifyRaw, id)
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *paymentOrderDao) UpdateFail(ctx context.Context, id int64, notifyRaw string) error {
|
||||
_, err := g.DB().Exec(ctx,
|
||||
"UPDATE "+public.TableNamePaymentOrder+" SET status='failed', notify_raw=?, notify_count=notify_count+1, updated_at=CURRENT_TIMESTAMP WHERE id=?",
|
||||
notifyRaw, id)
|
||||
return err
|
||||
}
|
||||
@@ -15,14 +15,15 @@ type ListAgentRes struct {
|
||||
}
|
||||
|
||||
type UpdateAgentReq struct {
|
||||
Id int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Region string `json:"region"`
|
||||
TierId int64 `json:"tier_id"`
|
||||
Id int64 `v:"required" json:"id"`
|
||||
Phone string `json:"phone"`
|
||||
Name string `v:"required" json:"name"`
|
||||
Region string `v:"required" json:"region"`
|
||||
TierId int64 `v:"required" json:"tier_id"`
|
||||
Status int `json:"status"`
|
||||
}
|
||||
|
||||
type RenewAgentReq struct {
|
||||
AgentId int64 `json:"agent_id"`
|
||||
TierId int64 `json:"tier_id"`
|
||||
AgentId int64 `v:"required" json:"agent_id"`
|
||||
TierId int64 `v:"required" json:"tier_id"`
|
||||
}
|
||||
|
||||
@@ -20,17 +20,18 @@ type LoginUser struct {
|
||||
}
|
||||
|
||||
type CreateAgentReq struct {
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
Name string `json:"name"`
|
||||
Region string `json:"region"`
|
||||
TierId int64 `json:"tier_id"`
|
||||
Username string `v:"required" json:"username"`
|
||||
Password string `v:"required" json:"password"`
|
||||
Phone string `v:"required" json:"phone"`
|
||||
Name string `v:"required" json:"name"`
|
||||
Region string `v:"required" json:"region"`
|
||||
TierId int64 `v:"required" json:"tier_id"`
|
||||
}
|
||||
|
||||
type CreateCustomerReq struct {
|
||||
Phone string `json:"phone"`
|
||||
Name string `json:"name"`
|
||||
Region string `json:"region"`
|
||||
Phone string `v:"required" json:"phone"`
|
||||
Name string `v:"required" json:"name"`
|
||||
Region string `v:"required" json:"region"`
|
||||
AgentId int64 `json:"agent_id"`
|
||||
}
|
||||
|
||||
|
||||
@@ -37,3 +37,22 @@ type SaveModelConfigReq struct {
|
||||
PricePerSecond int `json:"pricePerSecond" dc:"每秒价格(分)"`
|
||||
VideoTaskCallbackUrl string `json:"videoTaskCallbackUrl" dc:"视频生成任务回调地址"`
|
||||
}
|
||||
|
||||
type GetPaymentConfigReq struct {
|
||||
g.Meta `path:"/payment" method:"get" tags:"支付配置" summary:"获取支付配置"`
|
||||
}
|
||||
|
||||
type GetPaymentConfigRes struct {
|
||||
*entity.PaymentConfig
|
||||
}
|
||||
|
||||
type SavePaymentConfigReq struct {
|
||||
g.Meta `path:"/payment" method:"post" tags:"支付配置" summary:"保存支付配置"`
|
||||
WechatAppId string `json:"wechatAppId"`
|
||||
WechatMchId string `json:"wechatMchId"`
|
||||
WechatApiKey string `json:"wechatApiKey"`
|
||||
WechatAppSecret string `json:"wechatAppSecret"`
|
||||
AlipayAppId string `json:"alipayAppId"`
|
||||
AlipayPrivateKey string `json:"alipayPrivateKey"`
|
||||
AlipayPublicKey string `json:"alipayPublicKey"`
|
||||
}
|
||||
|
||||
@@ -31,3 +31,10 @@ type CustomerDetail struct {
|
||||
Profile *entity.CustomerProfile `json:"profile"`
|
||||
Balance int64 `json:"balance"`
|
||||
}
|
||||
|
||||
type UpdateCustomerReq struct {
|
||||
Id int64 `v:"required" json:"id"`
|
||||
Phone string `json:"phone"`
|
||||
Name string `json:"name"`
|
||||
Region string `json:"region"`
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package dto
|
||||
|
||||
type PrepayReq struct {
|
||||
Amount int64 `v:"required|min:1" json:"amount"` // 金额(分)
|
||||
Channel string `v:"required|in:wechat,alipay" json:"channel"` // wechat / alipay
|
||||
}
|
||||
|
||||
type PrepayRes struct {
|
||||
OrderNo string `json:"order_no"`
|
||||
Channel string `json:"channel"`
|
||||
CodeUrl string `json:"code_url,omitempty"` // PC扫码二维码内容
|
||||
PrepayJson string `json:"prepay_json,omitempty"` // 手机端调起支付参数(JSON)
|
||||
RedirectUrl string `json:"redirect_url,omitempty"` // Alipay WAP跳转URL
|
||||
}
|
||||
|
||||
type PaymentStatusReq struct {
|
||||
OrderNo string `json:"order_no"`
|
||||
}
|
||||
|
||||
type PaymentStatusRes struct {
|
||||
OrderNo string `json:"order_no"`
|
||||
Status string `json:"status"`
|
||||
Amount int64 `json:"amount"`
|
||||
}
|
||||
@@ -4,12 +4,13 @@ import "github.com/gogf/gf/v2/os/gtime"
|
||||
|
||||
type AccountTransaction struct {
|
||||
Id int64 `orm:"id" json:"id"`
|
||||
UserId int64 `orm:"user_id" json:"user_id"` // FK → user.id (role=customer)
|
||||
Type string `orm:"type" json:"type"` // recharge / deduct / refund
|
||||
Amount int64 `orm:"amount" json:"amount"` // 正数(分)
|
||||
UserId int64 `orm:"user_id" json:"user_id"`
|
||||
Type string `orm:"type" json:"type"` // recharge / deduct / refund
|
||||
Amount int64 `orm:"amount" json:"amount"`
|
||||
BalanceBefore int64 `orm:"balance_before" json:"balance_before"`
|
||||
BalanceAfter int64 `orm:"balance_after" json:"balance_after"`
|
||||
OrderNo string `orm:"order_no" json:"order_no"`
|
||||
Remark string `orm:"remark" json:"remark"`
|
||||
CreatedBy string `orm:"created_by" json:"created_by"` // admin / agent:{id} / system
|
||||
CreatedBy string `orm:"created_by" json:"created_by"`
|
||||
CreatedAt *gtime.Time `orm:"created_at" json:"created_at"`
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package entity
|
||||
|
||||
import "github.com/gogf/gf/v2/os/gtime"
|
||||
|
||||
type PaymentChannelTrade struct {
|
||||
Id int64 `orm:"id" json:"id"`
|
||||
OrderId int64 `orm:"order_id" json:"order_id"`
|
||||
Channel string `orm:"channel" json:"channel"`
|
||||
PrepayId string `orm:"prepay_id" json:"prepay_id"`
|
||||
CodeUrl string `orm:"code_url" json:"code_url"`
|
||||
TradeNo string `orm:"trade_no" json:"trade_no"`
|
||||
ChannelResponse string `orm:"channel_response" json:"channel_response"`
|
||||
CreatedAt *gtime.Time `orm:"created_at" json:"created_at"`
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package entity
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
type PaymentConfig struct {
|
||||
Id int64 `orm:"id" json:"id"`
|
||||
WechatAppId string `orm:"wechat_app_id" json:"wechatAppId"`
|
||||
WechatMchId string `orm:"wechat_mch_id" json:"wechatMchId"`
|
||||
WechatApiKey string `orm:"wechat_api_key" json:"wechatApiKey"`
|
||||
WechatAppSecret string `orm:"wechat_app_secret" json:"wechatAppSecret"`
|
||||
AlipayAppId string `orm:"alipay_app_id" json:"alipayAppId"`
|
||||
AlipayPrivateKey string `orm:"alipay_private_key" json:"alipayPrivateKey"`
|
||||
AlipayPublicKey string `orm:"alipay_public_key" json:"alipayPublicKey"`
|
||||
CreatedAt *gtime.Time `orm:"created_at" json:"createdAt"`
|
||||
UpdatedAt *gtime.Time `orm:"updated_at" json:"updatedAt"`
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package entity
|
||||
|
||||
import "github.com/gogf/gf/v2/os/gtime"
|
||||
|
||||
type PaymentOrder struct {
|
||||
Id int64 `orm:"id" json:"id"`
|
||||
OrderNo string `orm:"order_no" json:"order_no"`
|
||||
UserId int64 `orm:"user_id" json:"user_id"`
|
||||
Amount int64 `orm:"amount" json:"amount"`
|
||||
Channel string `orm:"channel" json:"channel"`
|
||||
ChannelType string `orm:"channel_type" json:"channel_type"`
|
||||
Status string `orm:"status" json:"status"`
|
||||
Subject string `orm:"subject" json:"subject"`
|
||||
PaidAt *gtime.Time `orm:"paid_at" json:"paid_at"`
|
||||
NotifyRaw string `orm:"notify_raw" json:"notify_raw"`
|
||||
NotifyCount int `orm:"notify_count" json:"notify_count"`
|
||||
CreatedAt *gtime.Time `orm:"created_at" json:"created_at"`
|
||||
UpdatedAt *gtime.Time `orm:"updated_at" json:"updated_at"`
|
||||
}
|
||||
@@ -97,7 +97,7 @@ func (s *authService) GetBalance(ctx context.Context, userId int64) int64 {
|
||||
}
|
||||
|
||||
// CreateAgent 创建代理商
|
||||
func (s *authService) CreateAgent(ctx context.Context, username, password, name, region string, tierId int64) (*entity.User, error) {
|
||||
func (s *authService) CreateAgent(ctx context.Context, username, password, phone, name, region string, tierId int64) (*entity.User, error) {
|
||||
tier, err := dao.AgentTier.GetOne(ctx, tierId)
|
||||
if err != nil || tier == nil {
|
||||
return nil, errors.New("代理商等级不存在")
|
||||
@@ -268,7 +268,7 @@ func (s *authService) DeductBalance(ctx context.Context, customerId int64, amoun
|
||||
}
|
||||
|
||||
// Recharge 充值
|
||||
func (s *authService) Recharge(ctx context.Context, customerId int64, amount int64, createdBy string) error {
|
||||
func (s *authService) Recharge(ctx context.Context, customerId int64, amount int64, orderNo, remark string) error {
|
||||
if amount <= 0 {
|
||||
return errors.New("充值金额必须大于0")
|
||||
}
|
||||
@@ -280,14 +280,19 @@ func (s *authService) Recharge(ctx context.Context, customerId int64, amount int
|
||||
if err := dao.CustomerProfile.UpdateBalance(ctx, customerId, newBalance); err != nil {
|
||||
return err
|
||||
}
|
||||
rk := remark
|
||||
if rk == "" {
|
||||
rk = fmt.Sprintf("充值 %.2f 元", float64(amount)/100)
|
||||
}
|
||||
_, err = dao.AccountTransaction.Insert(ctx, &entity.AccountTransaction{
|
||||
UserId: customerId,
|
||||
Type: "recharge",
|
||||
Amount: amount,
|
||||
BalanceBefore: cp.Balance,
|
||||
BalanceAfter: newBalance,
|
||||
Remark: fmt.Sprintf("充值 %.2f 元", float64(amount)/100),
|
||||
CreatedBy: createdBy,
|
||||
OrderNo: orderNo,
|
||||
Remark: rk,
|
||||
CreatedBy: "system",
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -78,6 +78,20 @@ func (s *configService) Save(ctx context.Context, req *dto.SaveModelConfigReq) e
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetPaymentConfig 获取支付配置
|
||||
func (s *configService) GetPaymentConfig(ctx context.Context) *entity.PaymentConfig {
|
||||
cfg, err := dao.PaymentConfigDao.GetFirst(ctx)
|
||||
if err != nil || cfg == nil {
|
||||
return nil
|
||||
}
|
||||
return cfg
|
||||
}
|
||||
|
||||
// SavePaymentConfig 保存支付配置
|
||||
func (s *configService) SavePaymentConfig(ctx context.Context, cfg *entity.PaymentConfig) error {
|
||||
return dao.PaymentConfigDao.Save(ctx, cfg)
|
||||
}
|
||||
|
||||
// syncModelDurationFromAPI 查询模型API,获取模型支持的参数和时长范围
|
||||
func syncModelDurationFromAPI(ctx context.Context, cfg *entity.ModelConfig) {
|
||||
if cfg.VideoApiKey == "" || cfg.VideoBaseUrl == "" || cfg.VideoModelName == "" {
|
||||
@@ -194,6 +208,8 @@ func inferChatTemperature(modelName string) float64 {
|
||||
return 0.7
|
||||
case strings.Contains(modelName, "deepseek"):
|
||||
return 0.7
|
||||
case strings.Contains(modelName, "doubao") || strings.Contains(modelName, "豆包"):
|
||||
return 0.95
|
||||
case strings.Contains(modelName, "glm"):
|
||||
return 0.8
|
||||
case strings.Contains(modelName, "ernie"):
|
||||
|
||||
@@ -0,0 +1,420 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"video-factory/shortdrama/dao"
|
||||
"video-factory/shortdrama/model/entity"
|
||||
)
|
||||
|
||||
type paymentService struct{}
|
||||
|
||||
var PaymentService = new(paymentService)
|
||||
|
||||
type PaymentConfig struct {
|
||||
Wechat WechatConfig `json:"wechat"`
|
||||
Alipay AlipayConfig `json:"alipay"`
|
||||
}
|
||||
|
||||
type WechatConfig struct {
|
||||
AppId string `json:"app_id"`
|
||||
MchId string `json:"mch_id"`
|
||||
ApiKey string `json:"api_key"`
|
||||
AppSecret string `json:"app_secret"`
|
||||
}
|
||||
|
||||
type AlipayConfig struct {
|
||||
AppId string `json:"app_id"`
|
||||
PrivateKey string `json:"private_key"`
|
||||
PublicKey string `json:"public_key"`
|
||||
}
|
||||
|
||||
func (s *paymentService) GetPaymentConfig() PaymentConfig {
|
||||
cfg := ConfigService.GetPaymentConfig(context.Background())
|
||||
if cfg == nil {
|
||||
return PaymentConfig{}
|
||||
}
|
||||
return PaymentConfig{
|
||||
Wechat: WechatConfig{
|
||||
AppId: cfg.WechatAppId,
|
||||
MchId: cfg.WechatMchId,
|
||||
ApiKey: cfg.WechatApiKey,
|
||||
AppSecret: cfg.WechatAppSecret,
|
||||
},
|
||||
Alipay: AlipayConfig{
|
||||
AppId: cfg.AlipayAppId,
|
||||
PrivateKey: cfg.AlipayPrivateKey,
|
||||
PublicKey: cfg.AlipayPublicKey,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Prepay 创建支付订单并调起渠道
|
||||
func (s *paymentService) Prepay(ctx context.Context, userId int64, amount int64, channel string) (*entity.PaymentOrder, string, string, string, error) {
|
||||
if amount < 1 {
|
||||
return nil, "", "", "", errors.New("金额必须大于0")
|
||||
}
|
||||
if channel != "wechat" && channel != "alipay" {
|
||||
return nil, "", "", "", errors.New("不支持的支付渠道")
|
||||
}
|
||||
|
||||
chanType := "native"
|
||||
if channel == "wechat" {
|
||||
chanType = "native"
|
||||
} else {
|
||||
chanType = "precreate"
|
||||
}
|
||||
|
||||
orderNo := s.generateOrderNo()
|
||||
|
||||
order := &entity.PaymentOrder{
|
||||
OrderNo: orderNo,
|
||||
UserId: userId,
|
||||
Amount: amount,
|
||||
Channel: channel,
|
||||
ChannelType: chanType,
|
||||
Status: "pending",
|
||||
Subject: fmt.Sprintf("账户充值 %.2f 元", float64(amount)/100),
|
||||
}
|
||||
id, err := dao.PaymentOrder.Insert(ctx, order)
|
||||
if err != nil {
|
||||
return nil, "", "", "", err
|
||||
}
|
||||
order.Id = id
|
||||
|
||||
pc := s.GetPaymentConfig()
|
||||
var codeUrl, prepayJson, redirectUrl string
|
||||
|
||||
switch channel {
|
||||
case "wechat":
|
||||
codeUrl, prepayJson, err = s.callWechat(ctx, order, pc.Wechat)
|
||||
case "alipay":
|
||||
codeUrl, redirectUrl, err = s.callAlipay(ctx, order, pc.Alipay)
|
||||
}
|
||||
if err != nil {
|
||||
_ = dao.PaymentOrder.UpdateFail(ctx, id, fmt.Sprintf(`{"error":"%s"}`, err.Error()))
|
||||
return nil, "", "", "", err
|
||||
}
|
||||
|
||||
_, _ = dao.PaymentChannelTrade.Insert(ctx, &entity.PaymentChannelTrade{
|
||||
OrderId: id,
|
||||
Channel: channel,
|
||||
CodeUrl: codeUrl,
|
||||
PrepayId: prepayJson,
|
||||
ChannelResponse: "{}",
|
||||
})
|
||||
|
||||
return order, codeUrl, prepayJson, redirectUrl, nil
|
||||
}
|
||||
|
||||
// HandleNotify 处理渠道回调
|
||||
func (s *paymentService) HandleNotify(ctx context.Context, channel string, body []byte) error {
|
||||
pc := s.GetPaymentConfig()
|
||||
var orderNo, tradeNo string
|
||||
|
||||
switch channel {
|
||||
case "wechat":
|
||||
var err error
|
||||
orderNo, tradeNo, err = s.verifyWechatNotify(body, pc.Wechat)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case "alipay":
|
||||
var err error
|
||||
orderNo, tradeNo, err = s.verifyAlipayNotify(body, pc.Alipay)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
return errors.New("未知渠道")
|
||||
}
|
||||
|
||||
order, err := dao.PaymentOrder.GetByOrderNo(ctx, orderNo)
|
||||
if err != nil || order == nil {
|
||||
return errors.New("订单不存在")
|
||||
}
|
||||
if order.Status == "success" {
|
||||
return nil // 防止重复回调
|
||||
}
|
||||
|
||||
rawStr := string(body)
|
||||
if err := dao.PaymentOrder.UpdateSuccess(ctx, order.Id, rawStr); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := dao.PaymentChannelTrade.Insert(ctx, &entity.PaymentChannelTrade{
|
||||
OrderId: order.Id,
|
||||
Channel: channel,
|
||||
TradeNo: tradeNo,
|
||||
ChannelResponse: rawStr,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return AuthService.Recharge(ctx, order.UserId, order.Amount, orderNo, fmt.Sprintf("支付充值 %.2f 元", float64(order.Amount)/100))
|
||||
}
|
||||
|
||||
// GetStatus 查询订单状态
|
||||
func (s *paymentService) GetStatus(ctx context.Context, orderNo string) (string, int64, error) {
|
||||
order, err := dao.PaymentOrder.GetByOrderNo(ctx, orderNo)
|
||||
if err != nil || order == nil {
|
||||
return "", 0, errors.New("订单不存在")
|
||||
}
|
||||
return order.Status, order.Amount, nil
|
||||
}
|
||||
|
||||
func (s *paymentService) generateOrderNo() string {
|
||||
now := time.Now()
|
||||
r := rand.Intn(10000)
|
||||
return fmt.Sprintf("PAY%s%04d", now.Format("20060102150405"), r)
|
||||
}
|
||||
|
||||
// ==================== 微信支付 ====================
|
||||
|
||||
func (s *paymentService) callWechat(ctx context.Context, order *entity.PaymentOrder, cfg WechatConfig) (codeUrl, prepayJson string, err error) {
|
||||
if cfg.AppId == "" || cfg.MchId == "" || cfg.ApiKey == "" {
|
||||
return "", "", errors.New("微信支付未配置")
|
||||
}
|
||||
nonceStr := s.randomStr(32)
|
||||
params := map[string]string{
|
||||
"appid": cfg.AppId,
|
||||
"mch_id": cfg.MchId,
|
||||
"nonce_str": nonceStr,
|
||||
"body": order.Subject,
|
||||
"out_trade_no": order.OrderNo,
|
||||
"total_fee": fmt.Sprintf("%d", order.Amount),
|
||||
"spbill_create_ip": "127.0.0.1",
|
||||
"notify_url": "", // 需要实际外网可访问地址
|
||||
"trade_type": "NATIVE",
|
||||
}
|
||||
sign := s.wechatSign(params, cfg.ApiKey)
|
||||
params["sign"] = sign
|
||||
|
||||
xmlReq := s.mapToXML(params)
|
||||
resp, err := http.Post("https://api.mch.weixin.qq.com/pay/unifiedorder", "text/xml", strings.NewReader(xmlReq))
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("调用微信下单失败: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
b, _ := io.ReadAll(resp.Body)
|
||||
|
||||
result := s.xmlToMap(string(b))
|
||||
if result["return_code"] != "SUCCESS" || result["result_code"] != "SUCCESS" {
|
||||
return "", "", fmt.Errorf("微信下单失败: %s", result["return_msg"])
|
||||
}
|
||||
return result["code_url"], "", nil
|
||||
}
|
||||
|
||||
// verifyWechatNotify 验证微信回调签名,返回 (orderNo, transactionId)
|
||||
func (s *paymentService) verifyWechatNotify(body []byte, cfg WechatConfig) (string, string, error) {
|
||||
result := s.xmlToMap(string(body))
|
||||
if result["return_code"] != "SUCCESS" {
|
||||
return "", "", errors.New("微信回调失败")
|
||||
}
|
||||
sign := s.wechatSign(result, cfg.ApiKey)
|
||||
if sign != result["sign"] {
|
||||
return "", "", errors.New("微信回调签名验证失败")
|
||||
}
|
||||
return result["out_trade_no"], result["transaction_id"], nil
|
||||
}
|
||||
|
||||
func (s *paymentService) wechatSign(params map[string]string, apiKey string) string {
|
||||
keys := make([]string, 0, len(params))
|
||||
for k := range params {
|
||||
if k == "sign" {
|
||||
continue
|
||||
}
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
var pairs []string
|
||||
for _, k := range keys {
|
||||
v := params[k]
|
||||
if v != "" {
|
||||
pairs = append(pairs, k+"="+v)
|
||||
}
|
||||
}
|
||||
pairs = append(pairs, "key="+apiKey)
|
||||
raw := strings.Join(pairs, "&")
|
||||
h := md5.Sum([]byte(raw))
|
||||
return strings.ToUpper(hex.EncodeToString(h[:]))
|
||||
}
|
||||
|
||||
// ==================== 支付宝支付 ====================
|
||||
|
||||
func (s *paymentService) callAlipay(ctx context.Context, order *entity.PaymentOrder, cfg AlipayConfig) (codeUrl, redirectUrl string, err error) {
|
||||
if cfg.AppId == "" || cfg.PrivateKey == "" {
|
||||
return "", "", errors.New("支付宝支付未配置")
|
||||
}
|
||||
|
||||
bizContent := fmt.Sprintf(`{"out_trade_no":"%s","total_amount":"%.2f","subject":"%s"}`, order.OrderNo, float64(order.Amount)/100, order.Subject)
|
||||
|
||||
params := url.Values{}
|
||||
params.Set("app_id", cfg.AppId)
|
||||
params.Set("method", "alipay.trade.precreate")
|
||||
params.Set("format", "JSON")
|
||||
params.Set("charset", "utf-8")
|
||||
params.Set("sign_type", "RSA2")
|
||||
params.Set("timestamp", time.Now().Format("2006-01-02 15:04:05"))
|
||||
params.Set("version", "1.0")
|
||||
params.Set("biz_content", bizContent)
|
||||
params.Set("notify_url", "")
|
||||
|
||||
sign := s.alipaySign(params, cfg.PrivateKey)
|
||||
params.Set("sign", sign)
|
||||
|
||||
resp, err := http.PostForm("https://openapi.alipay.com/gateway.do", params)
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("调用支付宝下单失败: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
b, _ := io.ReadAll(resp.Body)
|
||||
|
||||
var result struct {
|
||||
Response struct {
|
||||
Code string `json:"code"`
|
||||
Msg string `json:"msg"`
|
||||
QrCode string `json:"qr_code"`
|
||||
SubMsg string `json:"sub_msg"`
|
||||
} `json:"alipay_trade_precreate_response"`
|
||||
Sign string `json:"sign"`
|
||||
}
|
||||
if err := json.Unmarshal(b, &result); err != nil {
|
||||
return "", "", errors.New("支付宝返回解析失败")
|
||||
}
|
||||
if result.Response.Code != "10000" {
|
||||
return "", "", fmt.Errorf("支付宝下单失败: %s", result.Response.SubMsg)
|
||||
}
|
||||
return result.Response.QrCode, "", nil
|
||||
}
|
||||
|
||||
func (s *paymentService) verifyAlipayNotify(body []byte, cfg AlipayConfig) (string, string, error) {
|
||||
vals, err := url.ParseQuery(string(body))
|
||||
if err != nil {
|
||||
return "", "", errors.New("支付宝回调解析失败")
|
||||
}
|
||||
if vals.Get("trade_status") != "TRADE_SUCCESS" {
|
||||
return "", "", errors.New("支付宝回调状态非成功")
|
||||
}
|
||||
sign := s.alipaySign(vals, cfg.PublicKey)
|
||||
if sign != vals.Get("sign") {
|
||||
return "", "", errors.New("支付宝回调签名验证失败")
|
||||
}
|
||||
return vals.Get("out_trade_no"), vals.Get("trade_no"), nil
|
||||
}
|
||||
|
||||
func (s *paymentService) alipaySign(params url.Values, privateKey string) string {
|
||||
keys := make([]string, 0, len(params))
|
||||
for k := range params {
|
||||
if k == "sign" || k == "sign_type" {
|
||||
continue
|
||||
}
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
var pairs []string
|
||||
for _, k := range keys {
|
||||
v := params.Get(k)
|
||||
if v != "" {
|
||||
pairs = append(pairs, k+"="+v)
|
||||
}
|
||||
}
|
||||
raw := strings.Join(pairs, "&")
|
||||
h := md5.Sum([]byte(raw + privateKey))
|
||||
return hex.EncodeToString(h[:])
|
||||
}
|
||||
|
||||
// ==================== 工具方法 ====================
|
||||
|
||||
func (s *paymentService) randomStr(n int) string {
|
||||
letters := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||
b := make([]byte, n)
|
||||
for i := range b {
|
||||
b[i] = letters[rand.Intn(len(letters))]
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func (s *paymentService) mapToXML(m map[string]string) string {
|
||||
var xml string
|
||||
xml += "<xml>"
|
||||
keys := make([]string, 0, len(m))
|
||||
for k := range m {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
for _, k := range keys {
|
||||
xml += fmt.Sprintf("<%s><![CDATA[%s]]></%s>", k, m[k], k)
|
||||
}
|
||||
xml += "</xml>"
|
||||
return xml
|
||||
}
|
||||
|
||||
func (s *paymentService) xmlToMap(xmlStr string) map[string]string {
|
||||
result := make(map[string]string)
|
||||
var key, value string
|
||||
inKey := false
|
||||
inValue := false
|
||||
for i := 0; i < len(xmlStr); i++ {
|
||||
c := xmlStr[i]
|
||||
if c == '<' {
|
||||
if i+1 < len(xmlStr) && xmlStr[i+1] == '/' {
|
||||
inKey = false
|
||||
if key != "" && value != "" {
|
||||
result[key] = value
|
||||
key = ""
|
||||
value = ""
|
||||
}
|
||||
continue
|
||||
}
|
||||
if i+1 < len(xmlStr) && xmlStr[i+1] == '!' {
|
||||
continue
|
||||
}
|
||||
if !inKey && !inValue {
|
||||
inKey = true
|
||||
key = ""
|
||||
continue
|
||||
}
|
||||
}
|
||||
if c == '>' {
|
||||
if inKey {
|
||||
inKey = false
|
||||
inValue = true
|
||||
value = ""
|
||||
continue
|
||||
}
|
||||
if inValue {
|
||||
inValue = false
|
||||
continue
|
||||
}
|
||||
}
|
||||
if inKey {
|
||||
key += string(c)
|
||||
} else if inValue {
|
||||
value += string(c)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// InitDefaultPaymentConfig 初始化默认支付配置(空配置)
|
||||
func InitDefaultPaymentConfig() PaymentConfig {
|
||||
return PaymentConfig{
|
||||
Wechat: WechatConfig{},
|
||||
Alipay: AlipayConfig{},
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user