1
Some checks failed
Build / build (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
build / Build (push) Has been cancelled
GitHub Actions Mirror / mirror_to_gitee (push) Has been cancelled
GitHub Actions Mirror / mirror_to_gitlab (push) Has been cancelled
Issue Close Require / issue-close-require (push) Has been cancelled
Some checks failed
Build / build (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
build / Build (push) Has been cancelled
GitHub Actions Mirror / mirror_to_gitee (push) Has been cancelled
GitHub Actions Mirror / mirror_to_gitlab (push) Has been cancelled
Issue Close Require / issue-close-require (push) Has been cancelled
This commit is contained in:
@ -222,3 +222,29 @@ func (e TmMemberPlatform) GetStatistic(c *gin.Context) {
|
||||
|
||||
e.OK(data, "获取数据成功")
|
||||
}
|
||||
|
||||
// 修改用户-翻译通道字符消耗
|
||||
func (e TmMemberPlatform) ChangeChars(c *gin.Context) {
|
||||
s := service.TmMemberPlatform{}
|
||||
req := dto.TmMemberPlatformChangeCharsReq{}
|
||||
err := e.MakeContext(c).
|
||||
MakeOrm().
|
||||
Bind(&req).
|
||||
MakeService(&s.Service).
|
||||
Errors
|
||||
if err != nil {
|
||||
e.Logger.Error(err)
|
||||
e.Error(500, err, err.Error())
|
||||
return
|
||||
}
|
||||
req.SetUpdateBy(user.GetUserId(c))
|
||||
p := actions.GetPermissionFromContext(c)
|
||||
|
||||
err = s.ChangeChars(&req, p)
|
||||
if err != nil {
|
||||
e.Error(500, err, fmt.Sprintf("修改用户-翻译通道字符消耗失败,\r\n失败信息 %s", err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
e.OK(nil, "修改成功")
|
||||
}
|
||||
|
||||
131
app/admin/apis/tm_recharge_log.go
Normal file
131
app/admin/apis/tm_recharge_log.go
Normal file
@ -0,0 +1,131 @@
|
||||
package apis
|
||||
|
||||
import (
|
||||
"go-admin/app/admin/service"
|
||||
"go-admin/app/admin/service/dto"
|
||||
"go-admin/common/actions"
|
||||
"go-admin/common/statuscode"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gin-gonic/gin/binding"
|
||||
"github.com/go-admin-team/go-admin-core/sdk/api"
|
||||
"github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth/user"
|
||||
)
|
||||
|
||||
type TmRechargeLog struct {
|
||||
api.Api
|
||||
}
|
||||
|
||||
// GetPage 分页查询
|
||||
func (e TmRechargeLog) GetPage(c *gin.Context) {
|
||||
s := service.TmRechargeLog{}
|
||||
req := dto.TmRechargeLogGetPageReq{}
|
||||
err := e.MakeContext(c).
|
||||
MakeOrm().
|
||||
Bind(&req).
|
||||
MakeService(&s.Service).
|
||||
Errors
|
||||
|
||||
if err != nil {
|
||||
e.Error(500, err, "")
|
||||
return
|
||||
}
|
||||
|
||||
p := actions.GetPermissionFromContext(c)
|
||||
datas := make([]dto.TmRechargeLogResp, 0)
|
||||
var count int64
|
||||
|
||||
err = s.GetPage(&req, p, &datas, &count)
|
||||
|
||||
if err != nil {
|
||||
e.Error(500, err, "")
|
||||
return
|
||||
}
|
||||
|
||||
e.PageOK(datas, int(count), req.GetPageIndex(), req.GetPageSize(), "")
|
||||
}
|
||||
|
||||
// 创建充值订单
|
||||
func (e TmRechargeLog) CreateOrder(c *gin.Context) {
|
||||
req := dto.TmRechargeCreateOrderReq{}
|
||||
s := service.TmRechargeLog{}
|
||||
err := e.MakeContext(c).
|
||||
MakeOrm().
|
||||
Bind(&req).
|
||||
MakeService(&s.Service).
|
||||
Errors
|
||||
|
||||
if err != nil {
|
||||
e.Error(500, nil, statuscode.ErrorMessage[statuscode.ServerError])
|
||||
return
|
||||
}
|
||||
|
||||
apiKey := c.GetString("apiKey")
|
||||
|
||||
code := s.CreateOrder(&req, apiKey)
|
||||
if code != statuscode.Success {
|
||||
e.OK(code, statuscode.ErrorMessage[code])
|
||||
return
|
||||
}
|
||||
|
||||
e.OK(nil, "success")
|
||||
}
|
||||
|
||||
// 后台充值
|
||||
func (e TmRechargeLog) ManagerRecharge(c *gin.Context) {
|
||||
req := dto.TmRechargeCreateOrderReq{}
|
||||
s := service.TmRechargeLog{}
|
||||
err := e.MakeContext(c).
|
||||
MakeOrm().
|
||||
Bind(&req).
|
||||
MakeService(&s.Service).
|
||||
Errors
|
||||
|
||||
if err != nil {
|
||||
e.Error(500, err, "")
|
||||
return
|
||||
}
|
||||
|
||||
if err := req.Validate(); err != nil {
|
||||
e.Error(500, err, "")
|
||||
return
|
||||
}
|
||||
|
||||
req.SetCreateBy(user.GetUserId(c))
|
||||
p := actions.GetPermissionFromContext(c)
|
||||
|
||||
err = s.ManagerRecharge(&req, p)
|
||||
if err != nil {
|
||||
e.Error(500, err, "")
|
||||
return
|
||||
}
|
||||
|
||||
e.OK(nil, "充值成功")
|
||||
}
|
||||
|
||||
// 获取即将过期充值记录
|
||||
func (e TmMember) GetMemberAdvent(c *gin.Context) {
|
||||
s := service.TmRechargeLog{}
|
||||
req := dto.TmRechargeLogFrontReq{}
|
||||
err := e.MakeContext(c).
|
||||
MakeOrm().
|
||||
Bind(&req, binding.Query, binding.Form).
|
||||
MakeService(&s.Service).
|
||||
Errors
|
||||
|
||||
if err != nil {
|
||||
e.Logger.Errorf("获取即将过期充值记录失败:", err)
|
||||
e.Error(statuscode.ServerError, nil, statuscode.ErrorMessage[statuscode.ServerError])
|
||||
}
|
||||
|
||||
userId := user.GetUserId(c)
|
||||
datas := []dto.TmRechargeLogFrontResp{}
|
||||
|
||||
code := s.GetMemberAdvent(&req, &datas, userId)
|
||||
if code != statuscode.Success {
|
||||
e.Error(code, nil, statuscode.ErrorMessage[code])
|
||||
return
|
||||
}
|
||||
|
||||
e.OK(datas, "success")
|
||||
}
|
||||
@ -42,7 +42,7 @@ func (e *Translate) Translate(c *gin.Context) {
|
||||
|
||||
if code != statuscode.Success {
|
||||
e.Logger.Error(err)
|
||||
e.Error(code, nil, statuscode.ErrorMessage[code])
|
||||
e.OK(code, statuscode.ErrorMessage[code])
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@ -10,6 +10,7 @@ type TmMemberPlatform struct {
|
||||
MemberId int `json:"memberId" gorm:"type:bigint;comment:用户id"`
|
||||
RemainingCharacter int `json:"remainingCharacter" gorm:"type:bigint;comment:剩余字符数"`
|
||||
TotalCharacter int `json:"totalCharacter" gorm:"type:bigint;comment:总字符数"`
|
||||
UseCharacter int `json:"useCharacter" gorm:"type:bigint;comment:已用字符数"`
|
||||
PlatformId int `json:"platformId" gorm:"type:bigint;comment:平台id"`
|
||||
PlatformKey string `json:"platformKey" gorm:"type:varchar(50);comment:平台key"`
|
||||
Status int `json:"status" gorm:"type:tinyint;comment:状态 1-启用 2-禁用"`
|
||||
|
||||
@ -1,14 +1,28 @@
|
||||
package models
|
||||
|
||||
import "go-admin/common/models"
|
||||
import (
|
||||
"go-admin/common/models"
|
||||
"time"
|
||||
|
||||
"github.com/shopspring/decimal"
|
||||
)
|
||||
|
||||
type TmRechargeLog struct {
|
||||
models.Model
|
||||
|
||||
UserId int `json:"userId" gorm:"column:user_id;type:bigint;not null;comment:用户id"`
|
||||
MemberId int `json:"memberId" gorm:"column:member_id;type:bigint;not null;comment:翻译用户id"`
|
||||
Status int `json:"status" gorm:"column:status;type:tinyint;not null;comment:状态 1-正常 2-作废"`
|
||||
TotalChars int `json:"totalChars" gorm:"column:total_chars;type:bigint;not null;comment:充值字符数"`
|
||||
Type int `json:"type" gorm:"column:type;type:tinyint;not null;comment:类型 1-充值 2-后台充值 3-赠送"`
|
||||
OrderNo string `json:"orderNo" gorm:"column:order_no;type:varchar(36);not null;comment:订单号"`
|
||||
UserId int `json:"userId" gorm:"column:user_id;type:bigint;not null;comment:用户id"`
|
||||
MemberId int `json:"memberId" gorm:"column:member_id;type:bigint;not null;comment:翻译用户id"`
|
||||
PlatformId int `json:"platformId" gorm:"column:platform_id;type:bigint;not null;comment:平台id"`
|
||||
Status int `json:"status" gorm:"column:status;type:tinyint;not null;comment:状态 1-待支付 2-已支付 3-已取消 4-申请退款 5-已退款 6-已过期"`
|
||||
TotalChars int `json:"totalChars" gorm:"column:total_chars;type:bigint;not null;comment:充值字符数"`
|
||||
TxHash string `json:"txHash" gorm:"column:tx_hash;type:varchar(64);comment:交易hash"`
|
||||
Amount decimal.Decimal `json:"amount" gorm:"column:amount;type:decimal(10,6);not null;comment:充值金额U"`
|
||||
ReceiveChannel string `json:"receiveChannel" gorm:"column:receive_channel;type:varchar(100);not null;comment:充值渠道"`
|
||||
ReceiveAddress string `json:"receiveAddress" gorm:"column:receive_address;type:varchar(100);not null;comment:充值地址"`
|
||||
PayTime *time.Time `json:"payTime" gorm:"column:pay_time;type:datetime;comment:支付时间"`
|
||||
ExpireAt time.Time `json:"expireAt" gorm:"column:expire_at;type:datetime;not null;comment:过期时间"`
|
||||
models.ModelTime
|
||||
models.ControlBy
|
||||
}
|
||||
|
||||
@ -16,6 +16,7 @@ func init() {
|
||||
// registerTmMemberRouter
|
||||
func registerTmMemberRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) {
|
||||
api := apis.TmMember{}
|
||||
rechargeApi := apis.TmRechargeLog{}
|
||||
r := v1.Group("/tm-member").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole())
|
||||
{
|
||||
r.GET("", actions.PermissionAction(), api.GetPage)
|
||||
@ -24,7 +25,8 @@ func registerTmMemberRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddl
|
||||
r.PUT("/:id", actions.PermissionAction(), api.Update)
|
||||
r.DELETE("", api.Delete)
|
||||
|
||||
r.POST("recharge", actions.PermissionAction(), api.Recharge) //字符充值
|
||||
// r.POST("recharge", actions.PermissionAction(), api.Recharge) //字符充值
|
||||
r.POST("manager-recharge", actions.PermissionAction(), rechargeApi.ManagerRecharge)
|
||||
r.PUT("status", actions.PermissionAction(), api.ChangeStatus) //状态变更
|
||||
}
|
||||
|
||||
@ -32,5 +34,6 @@ func registerTmMemberRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddl
|
||||
{
|
||||
r2.GET("/api-key", api.GetMyApiKey)
|
||||
r2.GET("platforms", api.GetPlatforms)
|
||||
r2.GET("member-advent", api.GetMemberAdvent) //获取用户即将过期的充值信息
|
||||
}
|
||||
}
|
||||
|
||||
@ -23,6 +23,7 @@ func registerTmMemberPlatformRouter(v1 *gin.RouterGroup, authMiddleware *jwt.Gin
|
||||
r.POST("", api.Insert)
|
||||
r.PUT("/:id", actions.PermissionAction(), api.Update)
|
||||
r.DELETE("", api.Delete)
|
||||
r.POST("/change-chars", actions.PermissionAction(), api.ChangeChars)
|
||||
}
|
||||
|
||||
f2 := v1.Group("/tm-member-platform").Use(authMiddleware.MiddlewareFunc())
|
||||
|
||||
@ -120,21 +120,24 @@ func (s *TmMemberDeleteReq) GetId() interface{} {
|
||||
}
|
||||
|
||||
type TmMemberResp struct {
|
||||
Id int `json:"id"`
|
||||
UserId int `json:"userId"`
|
||||
NickName string `json:"nickName"`
|
||||
UserStatus int `json:"userStatus"`
|
||||
Status int `json:"status"`
|
||||
ApiKey string `json:"apiKey"`
|
||||
TotalChars int `json:"totalChars"`
|
||||
RemainChars int `json:"remainChars"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
Platforms []TmMemberPlatformResp `json:"platforms"`
|
||||
Id int `json:"id"`
|
||||
UserId int `json:"userId"`
|
||||
NickName string `json:"nickName"`
|
||||
UserStatus int `json:"userStatus"`
|
||||
Status int `json:"status"`
|
||||
ApiKey string `json:"apiKey"`
|
||||
TotalChars int `json:"totalChars"`
|
||||
RemainChars int `json:"remainChars"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
Platforms []TmMemberPlatformResp `json:"platforms"`
|
||||
UsedPlatform []TmMemberPlatformResp `json:"usedPlatform"`
|
||||
}
|
||||
|
||||
type TmMemberPlatformResp struct {
|
||||
Name string `json:"name"`
|
||||
RemainChars int `json:"remainChars"`
|
||||
PlatformId int `json:"platformId"`
|
||||
MemberId int `json:"memberId"`
|
||||
Name string `json:"name"`
|
||||
TotalChars int `json:"totalChars"`
|
||||
}
|
||||
|
||||
type TmMemberRechargeReq struct {
|
||||
@ -175,9 +178,11 @@ func (e *TmMemberChangeStatusReq) Validate() error {
|
||||
|
||||
type TmMemberPlatformFrontedResp struct {
|
||||
Id int `json:"id"`
|
||||
PlatformId int `json:"platformId"`
|
||||
Name string `json:"name"`
|
||||
RemainChars int `json:"remainChars"`
|
||||
TotalChars int `json:"totalChars"`
|
||||
UseChars int `json:"useChars"`
|
||||
Price int `json:"price"`
|
||||
ApiKey string `json:"apiKey"`
|
||||
}
|
||||
|
||||
@ -99,3 +99,10 @@ type TmMemberDailyUsageDeleteReq struct {
|
||||
func (s *TmMemberDailyUsageDeleteReq) GetId() interface{} {
|
||||
return s.Ids
|
||||
}
|
||||
|
||||
type TmMemberPlatformGroupData struct {
|
||||
MemberId int `json:"memberId" comment:"用户id"`
|
||||
PlatformId int `json:"platformId" comment:"平台id"`
|
||||
// PlatformKey string `json:"platformKey" comment:"平台key"`
|
||||
Total int `json:"total" comment:"总使用量"`
|
||||
}
|
||||
|
||||
@ -109,3 +109,11 @@ type TmMemberPlatformStatisticItemResp struct {
|
||||
PlatformId int `json:"platformId"`
|
||||
Data []int `json:"data" comment:"数据"`
|
||||
}
|
||||
|
||||
type TmMemberPlatformChangeCharsReq struct {
|
||||
Type int `json:"type" comment:"1-可用字符,2-已使用字符"`
|
||||
MemberId int `json:"memberId" comment:"用户id"`
|
||||
PlatformId int `json:"platformId" comment:"平台id"`
|
||||
ChangeNum int `json:"changeNum" comment:"变更数量"`
|
||||
common.ControlBy
|
||||
}
|
||||
|
||||
165
app/admin/service/dto/tm_recharge_log.go
Normal file
165
app/admin/service/dto/tm_recharge_log.go
Normal file
@ -0,0 +1,165 @@
|
||||
package dto
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"go-admin/app/admin/models"
|
||||
"go-admin/common/dto"
|
||||
common "go-admin/common/models"
|
||||
"time"
|
||||
|
||||
"github.com/shopspring/decimal"
|
||||
)
|
||||
|
||||
type TmRechargeLogGetPageReq struct {
|
||||
dto.Pagination `search:"-"`
|
||||
Type int `form:"type" search:"type:exact;column:type;table:tm_recharge_log"`
|
||||
Status int `form:"status" search:"type:exact;column:status;table:tm_recharge_log"`
|
||||
PlatformId int `form:"platformId" search:"type:exact;column:platform_id;table:tm_recharge_log"`
|
||||
TmRechargeLogOrder
|
||||
}
|
||||
|
||||
type TmRechargeLogOrder struct {
|
||||
Id string `form:"idOrder" search:"type:order;column:id;table:tm_platform"`
|
||||
PayTime string `form:"payTimeOrder" search:"type:order;column:pay_time;table:tm_platform"`
|
||||
}
|
||||
|
||||
func (m *TmRechargeLogGetPageReq) GetNeedSearch() interface{} {
|
||||
return *m
|
||||
}
|
||||
|
||||
type TmRechargeLogInsertReq struct {
|
||||
Id int `json:"-" comment:"平台id"`
|
||||
MemberId int `json:"memberId" comment:"会员id"`
|
||||
PlatformId int `json:"platformId" comment:"平台id"`
|
||||
Amount decimal.Decimal `json:"amount" comment:"充值金额"`
|
||||
TotalChars int `json:"totalChars" comment:"总字数"`
|
||||
ReceiveChannel string `json:"receiveChannel" comment:"充值渠道"`
|
||||
Status int `json:"status" comment:"充值状态"`
|
||||
|
||||
common.ControlBy
|
||||
}
|
||||
|
||||
func (s *TmRechargeLogInsertReq) Generate(model *models.TmPlatform) {
|
||||
if s.Id == 0 {
|
||||
model.Model = common.Model{Id: s.Id}
|
||||
}
|
||||
|
||||
model.CreateBy = s.CreateBy // 添加这而,需要记录是被谁创建的
|
||||
}
|
||||
|
||||
func (s *TmRechargeLogInsertReq) GetId() interface{} {
|
||||
return s.Id
|
||||
}
|
||||
|
||||
type TmRechargeLogListResp struct {
|
||||
Id int `json:"id"`
|
||||
ShowName string `json:"showName"`
|
||||
Code string `json:"code"`
|
||||
Price decimal.Decimal `json:"price"`
|
||||
}
|
||||
|
||||
// TmPlatformGetReq 功能获取请求参数
|
||||
type TmRechargeLogGetReq struct {
|
||||
Id int `uri:"id"`
|
||||
}
|
||||
|
||||
func (s *TmRechargeLogGetReq) GetId() interface{} {
|
||||
return s.Id
|
||||
}
|
||||
|
||||
// TmPlatformDeleteReq 功能删除请求参数
|
||||
type TmRechargeLogDeleteReq struct {
|
||||
Ids []int `json:"ids"`
|
||||
}
|
||||
|
||||
func (s *TmRechargeLogDeleteReq) GetId() interface{} {
|
||||
return s.Ids
|
||||
}
|
||||
|
||||
type TmRechargeLogResp struct {
|
||||
Id int `json:"id"`
|
||||
|
||||
OrderNo string `json:"orderNo"`
|
||||
Type int `json:"type"`
|
||||
MemberId int `json:"memberId"`
|
||||
UserId int `json:"userId"`
|
||||
PlatformId int `json:"platformId"`
|
||||
Amount decimal.Decimal `json:"amount"`
|
||||
TotalChars int `json:"totalChars"`
|
||||
ReceiveChannel string `json:"receiveChannel"`
|
||||
Status int `json:"status"`
|
||||
TxHash string `json:"txHash"`
|
||||
PayTime string `json:"payTime"`
|
||||
CreatedAt string `json:"createdAt"`
|
||||
}
|
||||
|
||||
// 用户充值订单创建请求参数
|
||||
type TmRechargeCreateOrderReq struct {
|
||||
Type int `json:"type" comment:"充值类型 1-用户充值 2-平台充值"`
|
||||
MemberId int `json:"memberId" comment:"会员id"`
|
||||
UserId int `json:"userId" comment:"用户id"`
|
||||
PlatformId int `json:"platformId" comment:"平台id"`
|
||||
TotalChars int `json:"totalChars" comment:"总字数"`
|
||||
ReceiveChannel string `json:"receiveChannel" comment:"充值渠道"`
|
||||
ReceiveAddress string `json:"receiveAddress" comment:"充值地址"`
|
||||
TxHash string `json:"txHash" comment:"交易hash"`
|
||||
Amount decimal.Decimal `json:"amount" comment:"充值金额"`
|
||||
ExpireDays int `json:"expireDays" comment:"过期天数"`
|
||||
common.ControlBy
|
||||
}
|
||||
|
||||
func (e *TmRechargeCreateOrderReq) Validate() error {
|
||||
if e.ExpireDays <= 0 {
|
||||
return errors.New("过期天数必须大于0")
|
||||
}
|
||||
|
||||
if e.MemberId <= 0 {
|
||||
return errors.New("会员不存在")
|
||||
}
|
||||
|
||||
if e.PlatformId <= 0 {
|
||||
return errors.New("平台不存在")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *TmRechargeCreateOrderReq) Generate(model *models.TmRechargeLog) {
|
||||
if model == nil {
|
||||
model = &models.TmRechargeLog{}
|
||||
}
|
||||
|
||||
model.PlatformId = e.PlatformId
|
||||
model.MemberId = e.MemberId
|
||||
model.UserId = e.UserId
|
||||
model.Type = e.Type
|
||||
model.TotalChars = e.TotalChars * 10000
|
||||
model.Amount = e.Amount
|
||||
model.Status = 1
|
||||
model.ReceiveChannel = e.ReceiveChannel
|
||||
model.ReceiveAddress = e.ReceiveAddress
|
||||
model.TxHash = e.TxHash
|
||||
model.CreateBy = e.CreateBy
|
||||
model.CreatedAt = time.Now()
|
||||
}
|
||||
|
||||
// 用户充值订单创建参数
|
||||
type TmRechargeLogInsertOrUpdateReq struct {
|
||||
MemberId int `json:"memberId" comment:"会员id"`
|
||||
PlatformId int `json:"platformId" comment:"平台id"`
|
||||
PlatformKey string `json:"platformKey" comment:"平台key"`
|
||||
RemainCharater int `json:"remainChars" comment:"剩余字数"`
|
||||
}
|
||||
|
||||
type TmRechargeLogFrontReq struct {
|
||||
PlatformId int `json:"platformId" query:"platformId" form:"platformId" comment:"平台id"`
|
||||
}
|
||||
|
||||
type TmRechargeLogFrontResp struct {
|
||||
Id int `json:"id"`
|
||||
OrderNo string `json:"orderNo"`
|
||||
PlatformName string `json:"platformName"`
|
||||
ExpireUnix int64 `json:"expireUnix"`
|
||||
TotalCharater int `json:"totalCharater"`
|
||||
RemainCharater int `json:"remainCharater"`
|
||||
}
|
||||
57
app/admin/service/quota_manager/lua/deduct.lua
Normal file
57
app/admin/service/quota_manager/lua/deduct.lua
Normal file
@ -0,0 +1,57 @@
|
||||
-- KEYS[1] = tm_member_remain_count:{key}:{platformCode}
|
||||
-- ARGV[1] = 当前时间戳(秒)
|
||||
-- ARGV[2] = 扣减数量
|
||||
|
||||
local zset_key = KEYS[1]
|
||||
local now = tonumber(ARGV[1])
|
||||
local deduct = tonumber(ARGV[2])
|
||||
local remain = deduct
|
||||
local result = {}
|
||||
|
||||
|
||||
-- 获取所有过期的 quota_id
|
||||
local expired_quota_ids = redis.call("ZRANGEBYSCORE", zset_key, "-inf", now)
|
||||
for _, quota_id in ipairs(expired_quota_ids) do
|
||||
redis.call("DEL", "quota:" .. quota_id)
|
||||
end
|
||||
|
||||
-- 清理过期额度
|
||||
redis.call("ZREMRANGEBYSCORE", zset_key, "-inf", now)
|
||||
|
||||
local quota_ids = redis.call("ZRANGEBYSCORE", zset_key, now, "+inf")
|
||||
|
||||
for _, quota_id in ipairs(quota_ids) do
|
||||
local quota_key = "quota:" .. quota_id
|
||||
local amount = tonumber(redis.call("HGET", quota_key, "amount") or "0")
|
||||
|
||||
if amount > 0 then
|
||||
local used = 0
|
||||
if amount >= remain then
|
||||
used = remain
|
||||
redis.call("HINCRBY", quota_key, "amount", -remain)
|
||||
remain = 0
|
||||
else
|
||||
used = amount
|
||||
redis.call("HINCRBY", quota_key, "amount", -amount)
|
||||
remain = remain - amount
|
||||
end
|
||||
|
||||
table.insert(result, quota_id .. ":" .. used)
|
||||
|
||||
local new_amount = tonumber(redis.call("HGET", quota_key, "amount") or "0")
|
||||
if new_amount <= 0 then
|
||||
redis.call("DEL", quota_key)
|
||||
redis.call("ZREM", zset_key, quota_id)
|
||||
end
|
||||
|
||||
if remain == 0 then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if remain > 0 then
|
||||
return {}
|
||||
end
|
||||
|
||||
return result
|
||||
21
app/admin/service/quota_manager/lua/refund.lua
Normal file
21
app/admin/service/quota_manager/lua/refund.lua
Normal file
@ -0,0 +1,21 @@
|
||||
-- KEYS[1] = tm_member_remain_count:{key}:{platformCode}
|
||||
-- ARGV = {quota_id_1, amount_1, expire_1, quota_id_2, amount_2, expire_2, ...}
|
||||
|
||||
local zset_key = KEYS[1]
|
||||
local len = table.getn(ARGV)
|
||||
|
||||
for i = 1, len, 3 do
|
||||
local quota_id = ARGV[i]
|
||||
local amount = tonumber(ARGV[i+1])
|
||||
local expire = tonumber(ARGV[i+2])
|
||||
local quota_key = "quota:" .. quota_id
|
||||
|
||||
if redis.call("EXISTS", quota_key) == 0 then
|
||||
redis.call("HSET", quota_key, "amount", amount)
|
||||
redis.call("ZADD", zset_key, expire, quota_id)
|
||||
else
|
||||
redis.call("HINCRBY", quota_key, "amount", amount)
|
||||
end
|
||||
end
|
||||
|
||||
return 1
|
||||
229
app/admin/service/quota_manager/quota_manager.go
Normal file
229
app/admin/service/quota_manager/quota_manager.go
Normal file
@ -0,0 +1,229 @@
|
||||
package quota_manager
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
rediskey "go-admin/common/redis_key"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-redis/redis/v8"
|
||||
)
|
||||
|
||||
type QuotaUsage struct {
|
||||
QuotaID string
|
||||
Used int64
|
||||
Expire int64
|
||||
}
|
||||
|
||||
type QuotaRecharge struct {
|
||||
QuotaID string
|
||||
Amount int64
|
||||
ExpireAt int64
|
||||
}
|
||||
|
||||
type QuotaManager struct {
|
||||
rdb *redis.Client
|
||||
deductLua *redis.Script
|
||||
refundLua *redis.Script
|
||||
zsetKeyPrefix string // "tm_member_remain_count"
|
||||
}
|
||||
|
||||
func NewQuotaManager(rdb *redis.Client) *QuotaManager {
|
||||
deductScript := `
|
||||
-- Lua 脚本内容复制 deduct.lua
|
||||
local zset_key = KEYS[1]
|
||||
local now = tonumber(ARGV[1])
|
||||
local deduct = tonumber(ARGV[2])
|
||||
local remain = deduct
|
||||
local result = {}
|
||||
|
||||
local expired_quota_ids = redis.call("ZRANGEBYSCORE", zset_key, "-inf", now)
|
||||
for _, quota_id in ipairs(expired_quota_ids) do
|
||||
redis.call("DEL", "quota:" .. quota_id)
|
||||
end
|
||||
|
||||
redis.call("ZREMRANGEBYSCORE", zset_key, "-inf", now)
|
||||
|
||||
local quota_ids = redis.call("ZRANGEBYSCORE", zset_key, now, "+inf")
|
||||
|
||||
for _, quota_id in ipairs(quota_ids) do
|
||||
local quota_key = "quota:" .. quota_id
|
||||
local amount = tonumber(redis.call("HGET", quota_key, "amount") or "0")
|
||||
|
||||
if amount > 0 then
|
||||
local used = 0
|
||||
if amount >= remain then
|
||||
used = remain
|
||||
redis.call("HINCRBY", quota_key, "amount", -remain)
|
||||
remain = 0
|
||||
else
|
||||
used = amount
|
||||
redis.call("HINCRBY", quota_key, "amount", -amount)
|
||||
remain = remain - amount
|
||||
end
|
||||
|
||||
table.insert(result, quota_id .. ":" .. used)
|
||||
|
||||
local new_amount = tonumber(redis.call("HGET", quota_key, "amount") or "0")
|
||||
if new_amount <= 0 then
|
||||
redis.call("DEL", quota_key)
|
||||
redis.call("ZREM", zset_key, quota_id)
|
||||
end
|
||||
|
||||
if remain == 0 then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if remain > 0 then
|
||||
return {}
|
||||
end
|
||||
|
||||
return result
|
||||
`
|
||||
refundScript := `
|
||||
-- Lua 脚本内容复制 refund.lua
|
||||
local zset_key = KEYS[1]
|
||||
local len = table.getn(ARGV)
|
||||
|
||||
for i = 1, len, 3 do
|
||||
local quota_id = ARGV[i]
|
||||
local amount = tonumber(ARGV[i+1])
|
||||
local expire = tonumber(ARGV[i+2])
|
||||
local quota_key = "quota:" .. quota_id
|
||||
|
||||
if redis.call("EXISTS", quota_key) == 0 then
|
||||
redis.call("HSET", quota_key, "amount", amount)
|
||||
redis.call("ZADD", zset_key, expire, quota_id)
|
||||
else
|
||||
redis.call("HINCRBY", quota_key, "amount", amount)
|
||||
end
|
||||
end
|
||||
|
||||
return 1
|
||||
`
|
||||
|
||||
return &QuotaManager{
|
||||
rdb: rdb,
|
||||
deductLua: redis.NewScript(deductScript),
|
||||
refundLua: redis.NewScript(refundScript),
|
||||
zsetKeyPrefix: rediskey.TM_MEMBER_REMAIN_COUNT_PURE,
|
||||
}
|
||||
}
|
||||
|
||||
func (q *QuotaManager) zsetKey(userKey, platformCode string) string {
|
||||
return fmt.Sprintf("%s:%s:%s", q.zsetKeyPrefix, userKey, platformCode)
|
||||
}
|
||||
|
||||
// 充值写入
|
||||
func (q *QuotaManager) AddQuota(ctx context.Context, userKey, platformCode string, recharge QuotaRecharge) error {
|
||||
zsetKey := q.zsetKey(userKey, platformCode)
|
||||
quotaKey := fmt.Sprintf("quota:%s", recharge.QuotaID)
|
||||
|
||||
err := q.rdb.HSet(ctx, quotaKey, map[string]interface{}{
|
||||
"amount": recharge.Amount,
|
||||
}).Err()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = q.rdb.ZAdd(ctx, zsetKey, &redis.Z{
|
||||
Score: float64(recharge.ExpireAt),
|
||||
Member: recharge.QuotaID,
|
||||
}).Err()
|
||||
return err
|
||||
}
|
||||
|
||||
// 扣减
|
||||
func (q *QuotaManager) Deduct(ctx context.Context, userKey, platformCode string, deductCount int64) ([]QuotaUsage, error) {
|
||||
zsetKey := q.zsetKey(userKey, platformCode)
|
||||
now := time.Now().Unix()
|
||||
|
||||
res, err := q.deductLua.Run(ctx, q.rdb, []string{zsetKey}, now, deductCount).Result()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
arr, ok := res.([]interface{})
|
||||
if !ok || len(arr) == 0 {
|
||||
return nil, fmt.Errorf("insufficient quota or invalid response")
|
||||
}
|
||||
|
||||
var usages []QuotaUsage
|
||||
for _, v := range arr {
|
||||
s, ok := v.(string)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
parts := strings.Split(s, ":")
|
||||
if len(parts) != 2 {
|
||||
continue
|
||||
}
|
||||
used, _ := strconv.ParseInt(parts[1], 10, 64)
|
||||
usages = append(usages, QuotaUsage{
|
||||
QuotaID: parts[0],
|
||||
Used: used,
|
||||
})
|
||||
}
|
||||
|
||||
for i := range usages {
|
||||
score, err := q.rdb.ZScore(ctx, zsetKey, usages[i].QuotaID).Result()
|
||||
if err == nil {
|
||||
usages[i].Expire = int64(score)
|
||||
}
|
||||
}
|
||||
return usages, nil
|
||||
}
|
||||
|
||||
// 回滚
|
||||
func (q *QuotaManager) Refund(ctx context.Context, userKey, platformCode string, usages []QuotaUsage) error {
|
||||
zsetKey := q.zsetKey(userKey, platformCode)
|
||||
|
||||
var args []interface{}
|
||||
for _, u := range usages {
|
||||
args = append(args, u.QuotaID, u.Used, u.Expire)
|
||||
}
|
||||
|
||||
_, err := q.refundLua.Run(ctx, q.rdb, []string{zsetKey}, args...).Result()
|
||||
return err
|
||||
}
|
||||
|
||||
func (q *QuotaManager) GetTotalRemainingQuota(ctx context.Context, apiKey, platformCode string) (int, error) {
|
||||
zsetKey := q.zsetKey(apiKey, platformCode)
|
||||
|
||||
now := time.Now().Unix()
|
||||
total := 0
|
||||
|
||||
// 获取全部 quotaID 和过期时间
|
||||
zsetEntries, err := q.rdb.ZRangeWithScores(ctx, zsetKey, 0, -1).Result()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
for _, entry := range zsetEntries {
|
||||
expireAt := int64(entry.Score)
|
||||
if expireAt <= now {
|
||||
continue // 跳过已过期的 quota
|
||||
}
|
||||
|
||||
quotaID := fmt.Sprintf("%v", entry.Member)
|
||||
quotaKey := fmt.Sprintf("quota:%s", quotaID)
|
||||
|
||||
amountStr, err := q.rdb.HGet(ctx, quotaKey, "amount").Result()
|
||||
if err != nil || amountStr == "" {
|
||||
continue // 不存在或异常
|
||||
}
|
||||
|
||||
amount, err := strconv.Atoi(amountStr)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
total += amount
|
||||
}
|
||||
|
||||
return total, nil
|
||||
}
|
||||
80
app/admin/service/quota_manager/quota_manager_test.go
Normal file
80
app/admin/service/quota_manager/quota_manager_test.go
Normal file
@ -0,0 +1,80 @@
|
||||
package quota_manager
|
||||
|
||||
import (
|
||||
"context"
|
||||
"go-admin/utils/redishelper"
|
||||
"os"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
redisAddr = "localhost:6379"
|
||||
redisPwd = ""
|
||||
redisDB = 1
|
||||
)
|
||||
|
||||
func setupRedis() {
|
||||
redishelper.InitDefaultRedis(redisAddr, redisPwd, redisDB)
|
||||
redishelper.InitLockRedisConn(redisAddr, redisPwd, strconv.Itoa(redisDB))
|
||||
}
|
||||
|
||||
func TestQuotaManager_AddDeductRefund(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
setupRedis()
|
||||
qmgr := NewQuotaManager(redishelper.DefaultRedis.GetClient())
|
||||
|
||||
userKey := "Bw4iSj9Y90ix0e05GrMFp6EuFFTIbE9j"
|
||||
platformCode := "deepl_free"
|
||||
quotaID := "testquota1"
|
||||
expireAt := time.Now().Add(1 * time.Hour).Unix()
|
||||
amount := int64(1000)
|
||||
|
||||
// 充值写入
|
||||
err := qmgr.AddQuota(ctx, userKey, platformCode, QuotaRecharge{
|
||||
QuotaID: quotaID,
|
||||
Amount: amount,
|
||||
ExpireAt: expireAt,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("AddQuota failed: %v", err)
|
||||
}
|
||||
|
||||
// 扣减500
|
||||
usages, err := qmgr.Deduct(ctx, userKey, platformCode, 500)
|
||||
if err != nil {
|
||||
t.Fatalf("Deduct failed: %v", err)
|
||||
}
|
||||
if len(usages) == 0 {
|
||||
t.Fatal("Deduct returned empty usage")
|
||||
}
|
||||
|
||||
if usages[0].Used != 500 {
|
||||
t.Errorf("Expected Used=500, got %d", usages[0].Used)
|
||||
}
|
||||
|
||||
// 回滚500
|
||||
err = qmgr.Refund(ctx, userKey, platformCode, usages)
|
||||
if err != nil {
|
||||
t.Fatalf("Refund failed: %v", err)
|
||||
}
|
||||
|
||||
// 再次扣减1000,确认余额充足
|
||||
usages, err = qmgr.Deduct(ctx, userKey, platformCode, 1000)
|
||||
if err != nil {
|
||||
t.Fatalf("Second Deduct failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// 设置过期时间
|
||||
func TestQuotaManager_Deduct_Refund_WithExpire(t *testing.T) {
|
||||
setupRedis()
|
||||
if err := redishelper.DefaultRedis.ZUpdateScore("tm_member_remain_count:MiyJrgfh3gYhwyDO43fdhHNswm4CeAfn:deepl", 1751436958, "573610499514565142"); err != nil {
|
||||
t.Fatalf("ZUpdateScore failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
@ -82,7 +82,7 @@ func (e *SysUser) Insert(c *dto.SysUserInsertReq) error {
|
||||
e.Orm.Model(role).Where("role_id = ?", c.RoleId).Find(&role)
|
||||
|
||||
if role.RoleId == 0 {
|
||||
err = errors.New("角色不存在")
|
||||
return errors.New("角色不存在")
|
||||
}
|
||||
|
||||
err = e.Orm.Model(&data).Where("username = ?", c.Username).Count(&i).Error
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
@ -9,12 +10,12 @@ import (
|
||||
|
||||
"github.com/bytedance/sonic"
|
||||
"github.com/go-admin-team/go-admin-core/sdk/service"
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/jinzhu/copier"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"go-admin/app/admin/models"
|
||||
"go-admin/app/admin/service/dto"
|
||||
"go-admin/app/admin/service/quota_manager"
|
||||
"go-admin/common/actions"
|
||||
cDto "go-admin/common/dto"
|
||||
rediskey "go-admin/common/redis_key"
|
||||
@ -31,6 +32,7 @@ func (e TmMember) GetUserPlatforms(userId int, resp *[]dto.TmMemberPlatformFront
|
||||
var memberAccount models.TmMember
|
||||
|
||||
if err := e.Orm.Model(&memberAccount).
|
||||
Where("user_id=?", userId).
|
||||
Find(&memberAccount).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
@ -51,8 +53,10 @@ func (e TmMember) GetUserPlatforms(userId int, resp *[]dto.TmMemberPlatformFront
|
||||
|
||||
dataItem.ApiKey = memberAccount.ApiKey
|
||||
dataItem.Name = platform.ShowName
|
||||
dataItem.PlatformId = platform.Id
|
||||
dataItem.Price = int(platform.Price.IntPart())
|
||||
dataItem.RemainChars, _ = e.GetRemainCount(item.PlatformKey, dataItem.ApiKey)
|
||||
dataItem.RemainChars = item.RemainingCharacter
|
||||
dataItem.UseChars = item.UseCharacter
|
||||
|
||||
*resp = append(*resp, dataItem)
|
||||
}
|
||||
@ -82,25 +86,30 @@ func (e *TmMember) GetPage(c *dto.TmMemberGetPageReq, p *actions.DataPermission,
|
||||
}
|
||||
|
||||
userIds := []int{}
|
||||
memberIds := []int{}
|
||||
|
||||
for _, item := range datas {
|
||||
if !utility.ContainsInt(userIds, item.UserId) {
|
||||
userIds = append(userIds, item.UserId)
|
||||
}
|
||||
|
||||
if !utility.ContainsInt(memberIds, item.Id) {
|
||||
memberIds = append(memberIds, item.Id)
|
||||
}
|
||||
}
|
||||
|
||||
memberPlatformService := TmMemberPlatform{Service: e.Service}
|
||||
platformService := TmPlatform{Service: e.Service}
|
||||
userService := SysUser{Service: e.Service}
|
||||
users, _ := userService.GetByIds(userIds)
|
||||
activeList, _ := platformService.GetActiveList()
|
||||
memberPlatforms, _ := memberPlatformService.GetMemberList(memberIds)
|
||||
|
||||
for _, item := range datas {
|
||||
dataItem := dto.TmMemberResp{}
|
||||
copier.Copy(&dataItem, &item)
|
||||
|
||||
// count, _ := e.GetRemainCount(,dataItem.ApiKey)
|
||||
dataItem.ApiKey = utility.DesensitizeGeneric(dataItem.ApiKey, 2, 2, '*')
|
||||
// dataItem.RemainChars = count
|
||||
|
||||
for _, user := range users {
|
||||
if user.UserId == item.UserId {
|
||||
@ -108,14 +117,33 @@ func (e *TmMember) GetPage(c *dto.TmMemberGetPageReq, p *actions.DataPermission,
|
||||
}
|
||||
}
|
||||
|
||||
//剩余字符
|
||||
for _, platform := range activeList {
|
||||
platformItem := dto.TmMemberPlatformResp{}
|
||||
platformItem.PlatformId = platform.Id
|
||||
platformItem.MemberId = item.Id
|
||||
platformItem.Name = platform.Name
|
||||
platformItem.RemainChars, _ = e.GetRemainCount(platform.Code, item.ApiKey)
|
||||
platformItem.TotalChars, _ = e.GetRemainCount(platform.Code, item.ApiKey)
|
||||
|
||||
dataItem.Platforms = append(dataItem.Platforms, platformItem)
|
||||
}
|
||||
|
||||
//已用字符
|
||||
for _, platform := range activeList {
|
||||
platformItem := dto.TmMemberPlatformResp{}
|
||||
platformItem.PlatformId = platform.Id
|
||||
platformItem.MemberId = item.Id
|
||||
platformItem.Name = platform.Name
|
||||
|
||||
for _, memberPlatform := range memberPlatforms {
|
||||
if memberPlatform.PlatformId == platform.Id && memberPlatform.MemberId == item.Id {
|
||||
platformItem.TotalChars = memberPlatform.UseCharacter
|
||||
}
|
||||
}
|
||||
|
||||
dataItem.UsedPlatform = append(dataItem.UsedPlatform, platformItem)
|
||||
}
|
||||
|
||||
*list = append(*list, dataItem)
|
||||
}
|
||||
|
||||
@ -190,13 +218,11 @@ func (e *TmMember) SaveAllCache() error {
|
||||
}
|
||||
for _, item := range list {
|
||||
key := fmt.Sprintf(rediskey.TM_MEMBER_BY_KEY, item.ApiKey)
|
||||
// remainKey := fmt.Sprintf(rediskey.TM_MEMBER_REMAIN_COUNT, item.ApiKey)
|
||||
val, err := sonic.MarshalString(item)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
redishelper.DefaultRedis.SetString(key, val)
|
||||
// redishelper.DefaultRedis.SetString(remainKey, strconv.Itoa(item.RemainChars))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -262,64 +288,101 @@ func (e *TmMember) RemoveByUserIds(userIds []int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// SyncMemberRemain 同步剩余字符
|
||||
// SyncMemberRemain 同步剩余字符(ZSET 多笔充值版)
|
||||
func (e *TmMember) SyncMemberRemain() error {
|
||||
scanKeys, err := redishelper.DefaultRedis.ScanKeys(fmt.Sprintf("%s*", rediskey.TM_MEMBER_REMAIN_COUNT_PURE))
|
||||
|
||||
scanKeys, err := redishelper.DefaultRedis.ScanKeys(fmt.Sprintf("%s:*:*", rediskey.TM_MEMBER_REMAIN_COUNT_PURE))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
members := e.getCacheMembers()
|
||||
dailyUsageService := TmMemberDailyUsage{Service: e.Service}
|
||||
datas := make([]models.TmMemberPlatform, 0)
|
||||
now := time.Now().Unix()
|
||||
|
||||
for _, key := range scanKeys {
|
||||
items := strings.Split(key, ":")
|
||||
apiKey := items[len(items)-2]
|
||||
platform := items[len(items)-1]
|
||||
val, err := redishelper.DefaultRedis.GetString(key)
|
||||
remainCount, err1 := strconv.Atoi(val)
|
||||
|
||||
if err != nil || err1 != nil {
|
||||
e.Log.Errorf("TmMemberService SyncMemberRemain GetString error:%s \r\n err1:%s \r\n", err, err1)
|
||||
if len(items) < 3 {
|
||||
continue
|
||||
}
|
||||
|
||||
apiKey := items[len(items)-2]
|
||||
platform := items[len(items)-1]
|
||||
|
||||
// 清除过期的 quotaID(ZSET + Hash)
|
||||
expiredIDs, err := redishelper.DefaultRedis.ZRangeByScore(key, "-inf", strconv.FormatInt(now, 10))
|
||||
if err == nil && len(expiredIDs) > 0 {
|
||||
for _, quotaID := range expiredIDs {
|
||||
redishelper.DefaultRedis.DeleteString(fmt.Sprintf("quota:%s", quotaID))
|
||||
}
|
||||
redishelper.DefaultRedis.ZRemValues(key, expiredIDs...)
|
||||
}
|
||||
|
||||
// 从 ZSET 获取所有 quota ID(不清理过期,数据库中保留的是理论值)
|
||||
zsetEntries, err := redishelper.DefaultRedis.GetRevRangeScoresSortSet(key)
|
||||
if err != nil {
|
||||
e.Log.Errorf("TmMemberService SyncMemberRemain ZRANGE failed for key %s: %v", key, err)
|
||||
continue
|
||||
}
|
||||
|
||||
totalRemain := 0
|
||||
for _, entry := range zsetEntries {
|
||||
quotaID, ok := entry.Member.(string)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
quotaKey := fmt.Sprintf("quota:%s", quotaID)
|
||||
amountStr, err := redishelper.DefaultRedis.HGetField(quotaKey, "amount")
|
||||
if err != nil || amountStr == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
amount, err := strconv.Atoi(amountStr)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
totalRemain += amount
|
||||
}
|
||||
|
||||
if member := members[apiKey]; member.Id > 0 {
|
||||
item := models.TmMemberPlatform{}
|
||||
item.Id = member.Id
|
||||
item.RemainingCharacter = remainCount
|
||||
item.PlatformKey = platform
|
||||
datas = append(datas, item)
|
||||
memberPlatform := models.TmMemberPlatform{
|
||||
PlatformKey: platform,
|
||||
RemainingCharacter: totalRemain,
|
||||
}
|
||||
memberPlatform.Id = member.Id
|
||||
datas = append(datas, memberPlatform)
|
||||
}
|
||||
}
|
||||
|
||||
// 批量更新数据库(分批,每批最多 1000 条)
|
||||
arrayData := utility.SplitSlice(datas, 1000)
|
||||
for _, dataBatch := range arrayData {
|
||||
|
||||
// 遍历当前批次的所有记录,为每条记录单独执行 UPDATE
|
||||
for _, record := range dataBatch {
|
||||
stmt := `
|
||||
UPDATE tm_member_platform
|
||||
SET
|
||||
remaining_character = ?,
|
||||
updated_at = NOW()
|
||||
WHERE platform_key = ? AND member_id = ?;
|
||||
`
|
||||
UPDATE tm_member_platform
|
||||
SET
|
||||
remaining_character = ?,
|
||||
updated_at = NOW()
|
||||
WHERE platform_key = ? AND member_id = ?;
|
||||
`
|
||||
args := []interface{}{
|
||||
record.RemainingCharacter,
|
||||
record.PlatformKey,
|
||||
record.Id,
|
||||
}
|
||||
|
||||
// 执行单个 UPDATE 语句
|
||||
if err := e.Orm.Exec(stmt, args...).Error; err != nil {
|
||||
// 记录错误,但继续处理批次中的其他记录
|
||||
e.Log.Errorf("TmMemberService SyncMemberRemain single Exec for PlatformKey %s, MemberID %d error: %s \r\n", record.PlatformKey, record.Id, err)
|
||||
e.Log.Errorf("TmMemberService SyncMemberRemain single Exec for PlatformKey %s, MemberID %d error: %s \r\n",
|
||||
record.PlatformKey, record.Id, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 同步每日使用量(不变)
|
||||
dailyUsageService.SyncTotalUse()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -444,24 +507,6 @@ func (e *TmMember) loadSyncData(keys []string, members *map[string]models.TmMemb
|
||||
}
|
||||
}
|
||||
|
||||
// func (e *TmMember) GetMyApiKey(userId int) (dto.TranslateUserInfoResp, error) {
|
||||
// var data models.TmMember
|
||||
// resp := dto.TranslateUserInfoResp{}
|
||||
// if err := e.Orm.Model(&data).Where("user_id = ?", userId).First(&data).Error; err != nil {
|
||||
// e.Log.Errorf("TmMemberService GetMyApiKey error:%s \r\n", err)
|
||||
// return resp, nil
|
||||
// }
|
||||
|
||||
// var err error
|
||||
// resp.UserApiKey = data.ApiKey
|
||||
// resp.RemainChars, err = e.GetRemainCount(data.ApiKey)
|
||||
|
||||
// if err != nil {
|
||||
// e.Log.Errorf("转换类型失败,error:%v", err)
|
||||
// }
|
||||
// return resp, nil
|
||||
// }
|
||||
|
||||
// GetTranslateStatistic 获取翻译统计
|
||||
func (e *TmMember) GetTranslateStatistic(userId int, list *[]dto.TranslateStatisticResp) error {
|
||||
endDate := time.Now().Format("2006-01-02")
|
||||
@ -535,31 +580,24 @@ func (e *TmMember) Recharge(req *dto.TmMemberRechargeReq, p *actions.DataPermiss
|
||||
|
||||
// 获取可用字符数
|
||||
func (e *TmMember) GetRemainCount(platformKey, apiKey string) (int, error) {
|
||||
key := fmt.Sprintf(rediskey.TM_MEMBER_REMAIN_COUNT, apiKey, platformKey)
|
||||
val, err := redishelper.DefaultRedis.GetString(key)
|
||||
result := 0
|
||||
ctx := context.Background()
|
||||
quotaManager := quota_manager.NewQuotaManager(redishelper.DefaultRedis.GetClient())
|
||||
result, err := quotaManager.GetTotalRemainingQuota(ctx, apiKey, platformKey)
|
||||
|
||||
if err != nil && !errors.Is(err, redis.Nil) {
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if val != "" {
|
||||
result, err = strconv.Atoi(val)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
// if result == 0 {
|
||||
// var data models.TmMember
|
||||
|
||||
if result == 0 {
|
||||
var data models.TmMember
|
||||
// if err := e.Orm.Model(&data).Where("api_key = ?", apiKey).First(&data).Error; err != nil {
|
||||
// return 0, err
|
||||
// }
|
||||
|
||||
if err := e.Orm.Model(&data).Where("api_key = ?", apiKey).First(&data).Error; err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
result = data.RemainChars
|
||||
redishelper.DefaultRedis.SetString(key, strconv.Itoa(result))
|
||||
}
|
||||
// result = data.RemainChars
|
||||
// // redishelper.DefaultRedis.SetString(key, strconv.Itoa(result))
|
||||
// }
|
||||
|
||||
return result, nil
|
||||
}
|
||||
@ -578,6 +616,55 @@ func (e *TmMember) DecrBy(platformKey, apiKey string, totalChars int) error {
|
||||
return redishelper.DefaultRedis.DecrBy(remainCountKey, int64(totalChars)).Err()
|
||||
}
|
||||
|
||||
// 增加字符
|
||||
func (e *TmMember) IncyByQuote(ctx context.Context, platformKey, apiKey string, totalChars int, orderNo string, expireAt time.Time) error {
|
||||
quotaManager := quota_manager.NewQuotaManager(redishelper.DefaultRedis.GetClient())
|
||||
rechargeData := quota_manager.QuotaRecharge{
|
||||
QuotaID: orderNo,
|
||||
Amount: int64(totalChars),
|
||||
ExpireAt: expireAt.Unix(),
|
||||
}
|
||||
|
||||
if err := quotaManager.AddQuota(ctx, apiKey, platformKey, rechargeData); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 扣除字符
|
||||
func (e *TmMember) DecrByQuote(ctx context.Context, platformKey, apiKey string, totalChars int) ([]quota_manager.QuotaUsage, error) {
|
||||
quoteManage := quota_manager.NewQuotaManager(redishelper.DefaultRedis.GetClient())
|
||||
|
||||
datas, err := quoteManage.Deduct(ctx, apiKey, platformKey, int64(totalChars))
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return datas, nil
|
||||
}
|
||||
|
||||
// 回滚扣除字符
|
||||
// apiKey 用户翻译密钥
|
||||
// platformKey 平台标识
|
||||
// datas 扣除的字符数据
|
||||
func (e *TmMember) RefundQuote(ctx context.Context, apiKey, platformKey string, datas *[]quota_manager.QuotaUsage) error {
|
||||
quoteManage := quota_manager.NewQuotaManager(redishelper.DefaultRedis.GetClient())
|
||||
if err := quoteManage.Refund(ctx, apiKey, platformKey, *datas); err != nil {
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 设置可用字符数
|
||||
func (e *TmMember) SetChars(platformKey, apiKey string, totalChars int) error {
|
||||
remainCountKey := fmt.Sprintf(rediskey.TM_MEMBER_REMAIN_COUNT, apiKey, platformKey)
|
||||
|
||||
return redishelper.DefaultRedis.SetString(remainCountKey, strconv.Itoa(totalChars))
|
||||
}
|
||||
|
||||
// 根据id获取数据
|
||||
func (e *TmMember) GetById(id int, data *models.TmMember) error {
|
||||
if err := e.Orm.Model(data).Where("id = ?", id).First(data).Error; err != nil {
|
||||
@ -586,6 +673,15 @@ func (e *TmMember) GetById(id int, data *models.TmMember) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 根据userId 获取数据
|
||||
func (e *TmMember) GetByUserId(userId int, data *models.TmMember) error {
|
||||
if err := e.Orm.Model(data).Where("user_id = ?", userId).First(data).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 修改翻译用户状态
|
||||
func (e TmMember) ChangeStatus(req *dto.TmMemberChangeStatusReq, p *actions.DataPermission) error {
|
||||
var err error
|
||||
@ -638,7 +734,6 @@ func (e *TmMember) SyncInsert(req *dto.TmMemberSyncInsertReq, entity *models.TmM
|
||||
platformService := TmPlatform{Service: e.Service}
|
||||
activePlatforms, _ := platformService.GetActiveList()
|
||||
TmMemberPlatforms := make([]models.TmMemberPlatform, 0)
|
||||
|
||||
copier.Copy(entity, req)
|
||||
|
||||
apiKey, err := utility.GenerateBase62Key(32)
|
||||
@ -661,8 +756,8 @@ func (e *TmMember) SyncInsert(req *dto.TmMemberSyncInsertReq, entity *models.TmM
|
||||
PlatformId: platform.Id,
|
||||
PlatformKey: platform.Code,
|
||||
Status: 1,
|
||||
TotalCharacter: 10000,
|
||||
RemainingCharacter: 10000,
|
||||
TotalCharacter: 0,
|
||||
RemainingCharacter: 0,
|
||||
}
|
||||
|
||||
TmMemberPlatforms = append(TmMemberPlatforms, item)
|
||||
@ -672,9 +767,10 @@ func (e *TmMember) SyncInsert(req *dto.TmMemberSyncInsertReq, entity *models.TmM
|
||||
return err
|
||||
}
|
||||
|
||||
for _, platform := range TmMemberPlatforms {
|
||||
e.IncrBy(platform.PlatformKey, entity.ApiKey, platform.RemainingCharacter)
|
||||
}
|
||||
// for _, platform := range TmMemberPlatforms {
|
||||
// // e.IncrBy(platform.PlatformKey, entity.ApiKey, platform.RemainingCharacter)
|
||||
// e.IncyByQuote(ctx,platform.PlatformKey,entity.ApiKey,platform.TotalCharacter,,)
|
||||
// }
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -128,7 +128,7 @@ func (e *TmMemberDailyUsage) GetStatistic(userId int, resp *dto.TmMemberPlatform
|
||||
|
||||
if err := e.Orm.Model(models.TmMemberDailyUsage{}).
|
||||
Joins("JOIN tm_member on tm_member.id=tm_member_daily_usage.member_id").
|
||||
Where("tm_member_daily_usage.date >= ? and tm_member_daily_usage.date <= ?", startTime, endTime).Find(&datas).Error; err != nil {
|
||||
Where("tm_member.user_id =? and tm_member_daily_usage.date >= ? and tm_member_daily_usage.date <= ?", userId, startTime, endTime).Find(&datas).Error; err != nil {
|
||||
e.Log.Error("获取折线图数据失败", err)
|
||||
return nil
|
||||
}
|
||||
@ -178,3 +178,24 @@ func (e *TmMemberDailyUsage) GetStatistic(userId int, resp *dto.TmMemberPlatform
|
||||
resp.Data = respDatas
|
||||
return nil
|
||||
}
|
||||
|
||||
// 同步总使用量
|
||||
func (e *TmMemberDailyUsage) SyncTotalUse() error {
|
||||
var datas []dto.TmMemberPlatformGroupData
|
||||
var data models.TmMemberPlatform
|
||||
|
||||
if err := e.Orm.Model(models.TmMemberDailyUsage{}).
|
||||
Group("member_id, platform_id").
|
||||
Select("member_id, platform_id, sum(use_chars) as total").
|
||||
Find(&datas).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, item := range datas {
|
||||
if err := e.Orm.Model(data).Where("member_id = ? and platform_id = ? ", item.MemberId, item.PlatformId).Update("use_character", item.Total).Error; err != nil {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -16,6 +16,42 @@ type TmMemberPlatform struct {
|
||||
service.Service
|
||||
}
|
||||
|
||||
// 修改用户字符
|
||||
func (e TmMemberPlatform) ChangeChars(req *dto.TmMemberPlatformChangeCharsReq, p *actions.DataPermission) error {
|
||||
var data models.TmMemberPlatform
|
||||
|
||||
switch req.Type {
|
||||
case 1:
|
||||
member := models.TmMember{}
|
||||
memberService := TmMember{Service: e.Service}
|
||||
memberService.GetById(req.MemberId, &member)
|
||||
|
||||
if member.Id == 0 {
|
||||
return errors.New("用户不存在")
|
||||
}
|
||||
|
||||
platformService := TmPlatform{Service: e.Service}
|
||||
platform, err := platformService.GetById(req.PlatformId)
|
||||
|
||||
if err != nil {
|
||||
return errors.New("平台不存在")
|
||||
}
|
||||
|
||||
if err := memberService.SetChars(platform.Code, member.ApiKey, req.ChangeNum); err != nil {
|
||||
return errors.New("设置剩余字符失败")
|
||||
}
|
||||
|
||||
if err := e.Orm.Model(data).Where("member_id =? AND platform_id =?", req.MemberId, req.PlatformId).Update("remaining_character", req.ChangeNum).Error; err != nil {
|
||||
e.Log.Errorf("TmMemberPlatformService ChangeChars error:%s \r\n", err)
|
||||
}
|
||||
case 2:
|
||||
default:
|
||||
return errors.New("修改类型错误")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetPage 获取TmMemberPlatform列表
|
||||
func (e *TmMemberPlatform) GetPage(c *dto.TmMemberPlatformGetPageReq, p *actions.DataPermission, list *[]models.TmMemberPlatform, count *int64) error {
|
||||
var err error
|
||||
@ -107,3 +143,40 @@ func (e *TmMemberPlatform) Remove(d *dto.TmMemberPlatformDeleteReq, p *actions.D
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetMemberList 获取用户列表
|
||||
func (e *TmMemberPlatform) GetMemberList(memberIds []int) ([]models.TmMemberPlatform, error) {
|
||||
result := make([]models.TmMemberPlatform, 0)
|
||||
err := e.Orm.Model(&models.TmMemberPlatform{}).
|
||||
Where("member_id IN (?)", memberIds).
|
||||
Find(&result).Error
|
||||
if err != nil {
|
||||
e.Log.Errorf("Service GetMemberList error:%s \r\n", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// InsertOrUpdateRemainChars 新增或更新用户剩余字符
|
||||
func (e *TmMemberPlatform) GetOrInsert(req *dto.TmRechargeLogInsertOrUpdateReq) (models.TmMemberPlatform, error) {
|
||||
result := models.TmMemberPlatform{}
|
||||
|
||||
e.Orm.Model(result).Where("member_id =? AND platform_id =?", req.MemberId, req.PlatformId).First(&result)
|
||||
|
||||
if result.Id == 0 {
|
||||
result.MemberId = req.MemberId
|
||||
result.PlatformId = req.PlatformId
|
||||
result.PlatformKey = req.PlatformKey
|
||||
result.RemainingCharacter = 0
|
||||
result.TotalCharacter = 0
|
||||
result.Status = 1
|
||||
|
||||
if err := e.Orm.Save(&result).Error; err != nil {
|
||||
e.Log.Errorf("Service InsertOrUpdateRemainChars error:%s \r\n", err)
|
||||
return result, err
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
@ -225,6 +225,17 @@ func (e *TmPlatform) GetByKey(code string) (*models.TmPlatform, error) {
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
// 根据id 获取翻译平台信息
|
||||
func (e *TmPlatform) GetById(id int) (*models.TmPlatform, error) {
|
||||
var result models.TmPlatform
|
||||
err := e.Orm.Model(&result).Where("id = ?", id).Find(&result).Error
|
||||
if err != nil {
|
||||
e.Log.Errorf("db error:%s", err)
|
||||
return nil, err
|
||||
}
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
func (e *TmPlatform) GetActiveList() ([]models.TmPlatform, error) {
|
||||
var list []models.TmPlatform
|
||||
err := e.Orm.Model(&models.TmPlatform{}).Find(&list).Error
|
||||
|
||||
205
app/admin/service/tm_recharge_log.go
Normal file
205
app/admin/service/tm_recharge_log.go
Normal file
@ -0,0 +1,205 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"go-admin/app/admin/models"
|
||||
"go-admin/app/admin/service/dto"
|
||||
"go-admin/app/admin/service/quota_manager"
|
||||
"go-admin/common/actions"
|
||||
cDto "go-admin/common/dto"
|
||||
"go-admin/common/statuscode"
|
||||
"go-admin/utils/redishelper"
|
||||
"go-admin/utils/utility"
|
||||
"sort"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/go-admin-team/go-admin-core/sdk/service"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type TmRechargeLog struct {
|
||||
service.Service
|
||||
}
|
||||
|
||||
// 首页获取即将过期的数据
|
||||
func (e *TmRechargeLog) GetMemberAdvent(req *dto.TmRechargeLogFrontReq, resp *[]dto.TmRechargeLogFrontResp, userId int) int {
|
||||
var datas []models.TmRechargeLog
|
||||
|
||||
if err := e.Orm.Model(&models.TmRechargeLog{}).
|
||||
Where("user_id =? and platform_id =? and expire_at > now() and status =2", userId, req.PlatformId).
|
||||
Find(&datas).Error; err != nil {
|
||||
e.Log.Errorf("TmRechargeLogService GetMemberAdvent error:%s \r\n", err)
|
||||
return statuscode.ServerError
|
||||
}
|
||||
|
||||
for _, item := range datas {
|
||||
respItem := dto.TmRechargeLogFrontResp{}
|
||||
respItem.Id = item.Id
|
||||
respItem.OrderNo = item.OrderNo
|
||||
// respItem.PlatformName=item.PlatformName
|
||||
respItem.TotalCharater = item.TotalChars
|
||||
respItem.ExpireUnix = item.ExpireAt.Unix()
|
||||
count, err := e.GetRemainByOrderNo(item.OrderNo)
|
||||
|
||||
if err != nil {
|
||||
e.Log.Errorf("TmRechargeLogService GetRemainByOrderNo error:%s \r\n", err)
|
||||
continue
|
||||
}
|
||||
|
||||
respItem.RemainCharater = count
|
||||
*resp = append(*resp, respItem)
|
||||
}
|
||||
|
||||
sort.Slice(*resp, func(i, j int) bool {
|
||||
return (*resp)[i].ExpireUnix < (*resp)[j].ExpireUnix
|
||||
})
|
||||
|
||||
return statuscode.Success
|
||||
}
|
||||
|
||||
// 后台充值
|
||||
func (e *TmRechargeLog) ManagerRecharge(req *dto.TmRechargeCreateOrderReq, p *actions.DataPermission) error {
|
||||
ctx := context.Background()
|
||||
var data models.TmRechargeLog
|
||||
member, platform, memberPlatform, code := e.CreateOrderJudge(req)
|
||||
if code != statuscode.Success {
|
||||
return errors.New(statuscode.ErrorMessage[code])
|
||||
}
|
||||
|
||||
req.Generate(&data)
|
||||
now := time.Now()
|
||||
data.OrderNo = utility.GenerateTraceID()
|
||||
data.Type = 2
|
||||
data.Status = 2
|
||||
data.UserId = member.UserId
|
||||
data.ExpireAt = time.Now().AddDate(0, 0, req.ExpireDays)
|
||||
data.PayTime = &now
|
||||
|
||||
rechargeData := quota_manager.QuotaRecharge{
|
||||
QuotaID: data.OrderNo,
|
||||
Amount: int64(data.TotalChars),
|
||||
ExpireAt: data.ExpireAt.Unix(),
|
||||
}
|
||||
qmgr := quota_manager.NewQuotaManager(redishelper.DefaultRedis.GetClient())
|
||||
|
||||
// 事务处理
|
||||
err := e.Orm.Transaction(func(tx *gorm.DB) error {
|
||||
//写入充值记录
|
||||
if err1 := e.Orm.Create(&data).Error; err1 != nil {
|
||||
return err1
|
||||
}
|
||||
|
||||
//更新用户翻译可用字符
|
||||
if err1 := tx.Model(&models.TmMemberPlatform{}).Where("id =?", memberPlatform.Id).Update("remaining_character", data.TotalChars).Error; err1 != nil {
|
||||
return err1
|
||||
}
|
||||
|
||||
//写入可用字符
|
||||
if err1 := qmgr.AddQuota(ctx, member.ApiKey, platform.Code, rechargeData); err1 != nil {
|
||||
return err1
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// 新增充值校验
|
||||
func (e *TmRechargeLog) CreateOrderJudge(req *dto.TmRechargeCreateOrderReq) (models.TmMember, *models.TmPlatform, models.TmMemberPlatform, int) {
|
||||
memberService := TmMember{Service: e.Service}
|
||||
member := models.TmMember{}
|
||||
if err := memberService.GetById(req.MemberId, &member); err != nil {
|
||||
return models.TmMember{}, nil, models.TmMemberPlatform{}, statuscode.NotFindMember
|
||||
}
|
||||
|
||||
if member.ApiKey == "" {
|
||||
return models.TmMember{}, nil, models.TmMemberPlatform{}, statuscode.NotFindApiKey
|
||||
}
|
||||
|
||||
platformService := TmPlatform{Service: e.Service}
|
||||
platform, err := platformService.GetById(req.PlatformId)
|
||||
|
||||
if err != nil {
|
||||
e.Log.Errorf("获取平台信息失败:%s \r\n", err.Error())
|
||||
return models.TmMember{}, nil, models.TmMemberPlatform{}, statuscode.PlatformNotSupport
|
||||
}
|
||||
|
||||
if platform == nil || platform.Id == 0 {
|
||||
return models.TmMember{}, nil, models.TmMemberPlatform{}, statuscode.PlatformNotSupport
|
||||
}
|
||||
|
||||
memberPlatformService := TmMemberPlatform{Service: e.Service}
|
||||
memberPlatform, err := memberPlatformService.GetOrInsert(&dto.TmRechargeLogInsertOrUpdateReq{
|
||||
MemberId: req.MemberId,
|
||||
PlatformId: req.PlatformId,
|
||||
PlatformKey: platform.Code,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return models.TmMember{}, nil, models.TmMemberPlatform{}, statuscode.ServerError
|
||||
}
|
||||
|
||||
if memberPlatform.Status == 2 {
|
||||
return models.TmMember{}, nil, models.TmMemberPlatform{}, statuscode.MemberPlatformNotSupport
|
||||
}
|
||||
return member, platform, memberPlatform, statuscode.Success
|
||||
}
|
||||
|
||||
// 用户发起充值
|
||||
// return code
|
||||
func (e TmRechargeLog) CreateOrder(req *dto.TmRechargeCreateOrderReq, apiKey string) int {
|
||||
// ctx := context.Background()
|
||||
// var data models.TmRechargeLog
|
||||
// member, platform, memberPlatform, code := e.CreateOrderJudge(req)
|
||||
|
||||
// if code != statuscode.Success {
|
||||
// return code
|
||||
// }
|
||||
// req.Generate(&data)
|
||||
// now := time.Now()
|
||||
// data.OrderNo = utility.GenerateTraceID()
|
||||
// data.Type = 1
|
||||
// data.Status = 1
|
||||
// data.UserId = member.UserId
|
||||
// data.ExpireAt = time.Now().AddDate(0, 0, 30)
|
||||
// data.PaymentTime = &now
|
||||
|
||||
return statuscode.Success
|
||||
}
|
||||
|
||||
// 分页查询
|
||||
func (e *TmRechargeLog) GetPage(req *dto.TmRechargeLogGetPageReq, p *actions.DataPermission, datas *[]dto.TmRechargeLogResp, count *int64) error {
|
||||
var err error
|
||||
var data models.TmRechargeLog
|
||||
var list []models.TmRechargeLog
|
||||
|
||||
err = e.Orm.Model(&data).
|
||||
Scopes(
|
||||
cDto.MakeCondition(req.GetNeedSearch()),
|
||||
cDto.Paginate(req.GetPageSize(), req.GetPageIndex()),
|
||||
actions.Permission(data.TableName(), p),
|
||||
).
|
||||
Find(list).Limit(-1).Offset(-1).
|
||||
Count(count).Error
|
||||
if err != nil {
|
||||
e.Log.Errorf("TmPlatformService GetPage error:%s \r\n", err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 根据充值订单号 获取剩余可用字符
|
||||
func (e *TmRechargeLog) GetRemainByOrderNo(orderNo string) (int, error) {
|
||||
key := fmt.Sprintf("quota:%s", orderNo)
|
||||
val, err := redishelper.DefaultRedis.HGetField(key, "amount")
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return strconv.Atoi(val)
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"go-admin/app/admin/models"
|
||||
@ -95,6 +96,7 @@ func (s *TranslatorService) RegisterProvider(name string, provider Translator) {
|
||||
// 翻译校验
|
||||
// return statusCode
|
||||
func (s *TranslatorService) TranslateJudge(req *dto.TranslateReq, apiKey string) (result *dto.TranslateResult, respCode int) {
|
||||
ctx := context.Background()
|
||||
tmMemberService := TmMember{Service: s.Service}
|
||||
tmPlatformAccount := TmPlatformAccount{Service: s.Service}
|
||||
memberInfo, err1 := tmMemberService.GetByKey(apiKey)
|
||||
@ -126,16 +128,23 @@ func (s *TranslatorService) TranslateJudge(req *dto.TranslateReq, apiKey string)
|
||||
return
|
||||
}
|
||||
|
||||
result, err := Translator.providers[req.Platform].Translate(req.Text, req.SourceLang, req.TargetLang)
|
||||
decyDatas, err := tmMemberService.DecrByQuote(ctx, req.Platform, apiKey, count)
|
||||
|
||||
if err != nil {
|
||||
s.Log.Errorf("翻译计数失败:%v", err)
|
||||
return nil, statuscode.ServerError
|
||||
}
|
||||
|
||||
result, err = Translator.providers[req.Platform].Translate(req.Text, req.SourceLang, req.TargetLang)
|
||||
|
||||
if err == nil {
|
||||
err2 := tmMemberService.DecrBy(req.Platform, apiKey, count)
|
||||
// err2 := tmMemberService.DecrBy(req.Platform, apiKey, count)
|
||||
|
||||
if err2 != nil {
|
||||
s.Log.Errorf("翻译计数失败:%v", err2)
|
||||
respCode = statuscode.ServerError
|
||||
return
|
||||
}
|
||||
// if err2 != nil {
|
||||
// s.Log.Errorf("翻译计数失败:%v", err2)
|
||||
// respCode = statuscode.ServerError
|
||||
// return
|
||||
// }
|
||||
|
||||
platformConfigInterface := Translator.config.ProviderConfigs[req.Platform]
|
||||
|
||||
@ -149,6 +158,8 @@ func (s *TranslatorService) TranslateJudge(req *dto.TranslateReq, apiKey string)
|
||||
//每日统计保留三天
|
||||
redishelper.DefaultRedis.Expire(fmt.Sprintf(rediskey.TM_MEMBER_DAILY_COUNT, date, apiKey, req.Platform), 3*24*time.Hour)
|
||||
} else {
|
||||
tmMemberService.RefundQuote(ctx, apiKey, req.Platform, &decyDatas)
|
||||
|
||||
code = statuscode.ServerError
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user