refactor(camelOil): 优化 Token 相关接口和模型结构

- 调整 CamelOilToken 相关输入输出模型,增强数据结构表达能力
- 统一服务层方法参数,使用结构体传递参数,提升代码可读性和扩展性
- 更新控制层调用逻辑,传递结构体参数替换原有独立参数
- 增加卡密绑定及分页查询相关输入结构定义
- 优化枚举及状态常量使用,确保状态类型表达准确
- 规范代码 import 顺序和格式,清理无用 import
- 修正 gtag 全局枚举顺序,优化内部键值排列顺序
This commit is contained in:
danial
2025-12-09 16:12:15 +08:00
parent 8c457895c8
commit e3956cbe35
13 changed files with 212 additions and 163 deletions

View File

@@ -3,6 +3,7 @@ package v1
import (
"encoding/json"
"kami/api/commonApi"
"kami/internal/consts"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime"
@@ -35,22 +36,22 @@ type GetTokenReq struct {
// TokenInfo Token 信息
type TokenInfo struct {
Id int64 `json:"id" description:"Token ID"`
UserId string `json:"userId" description:"用户ID空字符串表示管理员创建"`
Name string `json:"name" description:"Token名称"`
LoginToken string `json:"loginToken" description:"登录Token"`
Phone string `json:"phone" description:"绑定的手机号"`
Status int `json:"status" description:"状态"`
BindCount int `json:"bindCount" description:"已绑定卡密数量"`
TotalBindAmount float64 `json:"totalBindAmount" description:"累计绑定金额"`
TotalRechargeAmount float64 `json:"totalRechargeAmount" description:"总充值金额"`
RechargeLimitAmount float64 `json:"rechargeLimitAmount" description:"充值金额限制"`
RechargeLimitCount int `json:"rechargeLimitCount" description:"充值次数限制"`
LastBindAt *gtime.Time `json:"lastBindAt" description:"最后绑定时间"`
LastUsedAt *gtime.Time `json:"lastUsedAt" description:"最后使用时间"`
Remark string `json:"remark" description:"备注"`
CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"`
UpdatedAt *gtime.Time `json:"updatedAt" description:"更新时间"`
Id int64 `json:"id" description:"Token ID"`
UserId string `json:"userId" description:"用户ID空字符串表示管理员创建"`
Name string `json:"name" description:"Token名称"`
LoginToken string `json:"loginToken" description:"登录Token"`
Phone string `json:"phone" description:"绑定的手机号"`
Status consts.CamelOilTokenStatus `json:"status" description:"状态"`
BindCount int `json:"bindCount" description:"已绑定卡密数量"`
TotalBindAmount float64 `json:"totalBindAmount" description:"累计绑定金额"`
TotalRechargeAmount float64 `json:"totalRechargeAmount" description:"总充值金额"`
RechargeLimitAmount float64 `json:"rechargeLimitAmount" description:"充值金额限制"`
RechargeLimitCount int `json:"rechargeLimitCount" description:"充值次数限制"`
LastBindAt *gtime.Time `json:"lastBindAt" description:"最后绑定时间"`
LastUsedAt *gtime.Time `json:"lastUsedAt" description:"最后使用时间"`
Remark string `json:"remark" description:"备注"`
CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"`
UpdatedAt *gtime.Time `json:"updatedAt" description:"更新时间"`
}
// GetTokenRes 获取 Token 信息响应
@@ -67,8 +68,8 @@ type ListTokensRes struct {
type ListTokensReq struct {
g.Meta `path:"/token/list" tags:"JD V2 Token Management" method:"get" summary:"列出 Token"`
commonApi.CommonPageReq
Name string `json:"name" description:"Token名称"`
Status int `json:"status" description:"状态"`
Name string `json:"name" description:"Token名称"`
Status consts.CamelOilTokenStatus `json:"status" description:"状态"`
}
// UpdateTokenReq 修改 Token 请求
@@ -76,7 +77,6 @@ type UpdateTokenReq struct {
g.Meta `path:"/token/update" tags:"JD V2 Token Management" method:"post" summary:"修改 Token"`
TokenId int64 `json:"tokenId" v:"required" description:"Token ID"`
Name string `json:"name" v:"required" description:"Token名称"`
Phone string `json:"phone" description:"绑定的手机号"`
Remark string `json:"remark" description:"备注"`
RechargeLimitAmount float64 `json:"rechargeLimitAmount" v:"required" description:"充值金额限制"`
RechargeLimitCount int `json:"rechargeLimitCount" v:"required" description:"充值次数限制"`

File diff suppressed because one or more lines are too long

View File

@@ -6,6 +6,7 @@ import (
"github.com/gogf/gf/v2/errors/gcode"
v1 "kami/api/camel_oil/v1"
"kami/internal/errHandler"
"kami/internal/model"
"kami/internal/service"
)
@@ -15,7 +16,14 @@ func (c *ControllerV1) CreateToken(ctx context.Context, req *v1.CreateTokenReq)
err = errHandler.WrapError(ctx, gcode.CodeInternalError, err, "登录校验失败")
return
}
tokenId, err := service.CamelOil().CreateToken(ctx, req.Name, "", req.Phone, req.Remark, req.RechargeLimitAmount, req.RechargeLimitCount)
createInput := &model.CamelOilTokenCreateInput{
Name: req.Name,
Phone: req.Phone,
Remark: req.Remark,
RechargeLimitAmount: req.RechargeLimitAmount,
RechargeLimitCount: req.RechargeLimitCount,
}
tokenId, err := service.CamelOil().CreateToken(ctx, createInput)
if err != nil {
return nil, err
}

View File

@@ -6,6 +6,7 @@ import (
"github.com/gogf/gf/v2/errors/gcode"
v1 "kami/api/camel_oil/v1"
"kami/internal/errHandler"
"kami/internal/model"
"kami/internal/service"
)
@@ -15,7 +16,9 @@ func (c *ControllerV1) DeleteToken(ctx context.Context, req *v1.DeleteTokenReq)
err = errHandler.WrapError(ctx, gcode.CodeInternalError, err, "登录校验失败")
return
}
err = service.CamelOil().DeleteToken(ctx, req.TokenId)
err = service.CamelOil().DeleteToken(ctx, &model.CamelOilTokenDeleteInput{
TokenId: req.TokenId,
})
if err != nil {
return nil, err
}

View File

@@ -5,7 +5,9 @@ import (
"github.com/gogf/gf/v2/errors/gcode"
v1 "kami/api/camel_oil/v1"
"kami/internal/consts"
"kami/internal/errHandler"
"kami/internal/model"
"kami/internal/service"
)
@@ -15,7 +17,9 @@ func (c *ControllerV1) GetToken(ctx context.Context, req *v1.GetTokenReq) (res *
err = errHandler.WrapError(ctx, gcode.CodeInternalError, err, "登录校验失败")
return
}
token, err := service.CamelOil().GetTokenInfo(ctx, req.TokenId)
token, err := service.CamelOil().GetTokenInfo(ctx, &model.CamelOilTokenQueryInput{
TokenId: req.TokenId,
})
if err != nil {
return nil, err
}
@@ -26,7 +30,7 @@ func (c *ControllerV1) GetToken(ctx context.Context, req *v1.GetTokenReq) (res *
Name: token.Name,
LoginToken: token.LoginToken,
Phone: token.Phone,
Status: token.Status,
Status: consts.CamelOilTokenStatus(token.Status),
BindCount: token.BindCount,
TotalBindAmount: token.TotalBindAmount.InexactFloat64(),
TotalRechargeAmount: token.TotalRechargeAmount.InexactFloat64(),

View File

@@ -7,6 +7,7 @@ import (
v1 "kami/api/camel_oil/v1"
"kami/api/commonApi"
"kami/internal/errHandler"
"kami/internal/model"
"kami/internal/service"
)
@@ -16,7 +17,11 @@ func (c *ControllerV1) ListCardBindingsByToken(ctx context.Context, req *v1.List
err = errHandler.WrapError(ctx, gcode.CodeInternalError, err, "登录校验失败")
return
}
bindings, total, err := service.CamelOil().GetCardBindingsByToken(ctx, req.TokenId, req.Current, req.PageSize)
bindings, total, err := service.CamelOil().GetCardBindingsByToken(ctx, &model.CamelOilCardListInput{
TokenId: req.TokenId,
Current: req.Current,
PageSize: req.PageSize,
})
if err != nil {
return nil, err
}

View File

@@ -6,7 +6,9 @@ import (
"github.com/gogf/gf/v2/errors/gcode"
v1 "kami/api/camel_oil/v1"
"kami/api/commonApi"
"kami/internal/consts"
"kami/internal/errHandler"
"kami/internal/model"
"kami/internal/service"
)
@@ -20,7 +22,11 @@ func (c *ControllerV1) ListTokens(ctx context.Context, req *v1.ListTokensReq) (r
// 调用服务层方法,它会根据当前用户类型自动筛选数据
// 管理员可以查看所有token包括用户创建和管理员创建的
// 普通用户只能查看自己创建的token
tokens, total, err := service.CamelOil().ListTokensWithPagination(ctx, req.CommonPageReq, req.Name, req.Status)
tokens, total, err := service.CamelOil().ListTokensWithPagination(ctx, &model.CamelOilTokenListInput{
CommonPageReq: req.CommonPageReq,
Name: req.Name,
Status: req.Status,
})
if err != nil {
return nil, err
}
@@ -32,7 +38,7 @@ func (c *ControllerV1) ListTokens(ctx context.Context, req *v1.ListTokensReq) (r
Name: token.Name,
LoginToken: token.LoginToken,
Phone: token.Phone,
Status: token.Status,
Status: consts.CamelOilTokenStatus(token.Status),
BindCount: token.BindCount,
TotalBindAmount: token.TotalBindAmount.InexactFloat64(),
TotalRechargeAmount: token.TotalRechargeAmount.InexactFloat64(),

View File

@@ -6,6 +6,7 @@ import (
"github.com/gogf/gf/v2/errors/gcode"
v1 "kami/api/camel_oil/v1"
"kami/internal/errHandler"
"kami/internal/model"
"kami/internal/service"
)
@@ -16,7 +17,9 @@ func (c *ControllerV1) ResendVerificationCode(ctx context.Context, req *v1.Resen
return
}
err = service.CamelOil().ResendVerificationCode(ctx, req.TokenId)
err = service.CamelOil().ResendVerificationCode(ctx, &model.CamelOilTokenResendCodeInput{
TokenId: req.TokenId,
})
if err != nil {
return nil, err
}

View File

@@ -6,6 +6,7 @@ import (
"github.com/gogf/gf/v2/errors/gcode"
v1 "kami/api/camel_oil/v1"
"kami/internal/errHandler"
"kami/internal/model"
"kami/internal/service"
)
@@ -15,7 +16,13 @@ func (c *ControllerV1) UpdateToken(ctx context.Context, req *v1.UpdateTokenReq)
err = errHandler.WrapError(ctx, gcode.CodeInternalError, err, "登录校验失败")
return
}
err = service.CamelOil().UpdateTokenInfo(ctx, req.TokenId, req.Name, req.Phone, req.Remark, req.RechargeLimitAmount, req.RechargeLimitCount)
err = service.CamelOil().UpdateTokenInfo(ctx, &model.CamelOilTokenUpdateInput{
TokenId: req.TokenId,
Name: req.Name,
Remark: req.Remark,
RechargeLimitAmount: req.RechargeLimitAmount,
RechargeLimitCount: req.RechargeLimitCount,
})
if err != nil {
return nil, err
}

View File

@@ -11,6 +11,7 @@ import (
"kami/internal/consts"
"kami/internal/dao"
"kami/internal/model"
"kami/internal/model/do"
"kami/internal/model/entity"
"kami/utility/config"
@@ -350,7 +351,12 @@ func (s *sCamelOil) CronCardBindingTask(ctx context.Context) error {
}
// 尝试绑定卡密到 Token
_, err = s.BindCardToToken(ctx, order.Id, order.CardNumber, order.CardPassword, order.Amount)
_, err = s.BindCardToToken(ctx, &model.CamelOilCardBindInput{
OrderId: order.Id,
CardNumber: order.CardNumber,
CardPassword: order.CardPassword,
Amount: order.Amount,
})
if err != nil {
glog.Errorf(ctx, "绑定卡密到 Token 失败,订单 ID: %d, 错误: %v", order.Id, err)
failCount++
@@ -430,7 +436,9 @@ func (s *sCamelOil) CronTokenLoginTask(ctx context.Context) error {
continue
}
err := s.SendVerificationCode(ctx, token.Id, token.Phone)
err := s.ResendVerificationCode(ctx, &model.CamelOilTokenResendCodeInput{
TokenId: token.Id,
})
if err != nil {
glog.Errorf(ctx, "发送验证码失败Token ID: %d, 错误: %v", token.Id, err)
codeFailCount++
@@ -462,7 +470,9 @@ func (s *sCamelOil) CronTokenLoginTask(ctx context.Context) error {
}
// 重置状态并发送验证码
err := s.SendVerificationCode(ctx, token.Id, token.Phone)
err := s.ResendVerificationCode(ctx, &model.CamelOilTokenResendCodeInput{
TokenId: token.Id,
})
if err != nil {
glog.Errorf(ctx, "重试发送验证码失败Token ID: %d, 错误: %v", token.Id, err)
retryFailCount++

View File

@@ -2,9 +2,6 @@ package camel_oil
import (
"context"
"kami/internal/model"
"time"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/errors/gcode"
"github.com/gogf/gf/v2/errors/gerror"
@@ -12,8 +9,9 @@ import (
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/util/gconv"
"github.com/shopspring/decimal"
"kami/internal/model"
"kami/utility/utils"
"kami/api/commonApi"
"kami/internal/consts"
"kami/internal/dao"
"kami/internal/model/do"
@@ -28,7 +26,7 @@ import (
// ====================================================================================
// CreateToken 创建 Token
func (s *sCamelOil) CreateToken(ctx context.Context, tokenName string, tokenValue string, phone string, remark string, rechargeLimitAmount float64, rechargeLimitCount int) (tokenId int64, err error) {
func (s *sCamelOil) CreateToken(ctx context.Context, req *model.CamelOilTokenCreateInput) (tokenId int64, err error) {
m := dao.V1CamelOilToken.Ctx(ctx).DB(config.GetDatabaseV1())
// 获取当前用户信息
@@ -41,23 +39,26 @@ func (s *sCamelOil) CreateToken(ctx context.Context, tokenName string, tokenValu
if userInfo != nil && userInfo.Id != "" {
userId = userInfo.Id
} else {
userId = "" // 管理员创建时为空字符串
return 0, gerror.NewCode(gcode.CodeNotAuthorized, "权限不足")
}
// 将 float64 转换为 decimal.Decimal 存储到数据库
rechargeLimitAmountDecimal := decimal.NewFromFloat(rechargeLimitAmount)
rechargeLimitAmountDecimal := decimal.NewFromFloat(req.RechargeLimitAmount)
isOk, err := camel_oil_api.NewClient(ctx).SendCaptcha(ctx, req.Phone)
if !isOk {
return 0, gerror.NewCode(gcode.CodeBusinessValidationFailed, "验证码发送失败")
}
result, err := m.Insert(&do.V1CamelOilToken{
UserId: userId,
Name: tokenName,
Phone: phone,
Status: int(consts.CamelOilTokenStatusCodeSent),
Name: req.Name,
Phone: req.Phone,
Status: consts.CamelOilTokenStatusCodeSent,
BindCount: 0,
TotalBindAmount: decimal.Zero,
TotalRechargeAmount: decimal.Zero,
RechargeLimitAmount: rechargeLimitAmountDecimal,
RechargeLimitCount: rechargeLimitCount,
Remark: remark,
RechargeLimitCount: req.RechargeLimitCount,
Remark: req.Remark,
})
if err != nil {
@@ -65,16 +66,16 @@ func (s *sCamelOil) CreateToken(ctx context.Context, tokenName string, tokenValu
}
tokenId, _ = result.LastInsertId()
glog.Infof(ctx, "Token创建成功: tokenId=%d, tokenName=%s, phone=%s, 充值金额限制=%.2f, 充值次数限制=%d", tokenId, tokenName, phone, rechargeLimitAmount, rechargeLimitCount)
glog.Infof(ctx, "Token创建成功: tokenId=%d, tokenName=%s, phone=%s, 充值金额限制=%.2f, 充值次数限制=%d", tokenId, req.Name, req.Phone, req.RechargeLimitAmount, req.RechargeLimitCount)
return tokenId, nil
}
// GetTokenInfo 获取 Token 信息
func (s *sCamelOil) GetTokenInfo(ctx context.Context, tokenId int64) (token *entity.V1CamelOilToken, err error) {
func (s *sCamelOil) GetTokenInfo(ctx context.Context, req *model.CamelOilTokenQueryInput) (token *entity.V1CamelOilToken, err error) {
m := dao.V1CamelOilToken.Ctx(ctx).DB(config.GetDatabaseV1())
err = m.Where(dao.V1CamelOilToken.Columns().Id, tokenId).Scan(&token)
err = m.Where(dao.V1CamelOilToken.Columns().Id, req.TokenId).Scan(&token)
if err != nil {
return nil, gerror.Wrap(err, "查询Token信息失败")
}
@@ -112,16 +113,11 @@ func (s *sCamelOil) ListTokens(ctx context.Context) (tokens []*entity.V1CamelOil
}
// ListTokensWithPagination 列出所有可用的 Token支持分页和查询条件
func (s *sCamelOil) ListTokensWithPagination(ctx context.Context, pageReq commonApi.CommonPageReq, tokenName string, status int) (tokens []*entity.V1CamelOilToken, total int, err error) {
m := dao.V1CamelOilToken.Ctx(ctx).DB(config.GetDatabaseV1())
query := m.Where(dao.V1CamelOilToken.Columns().DeletedAt, nil)
func (s *sCamelOil) ListTokensWithPagination(ctx context.Context, req *model.CamelOilTokenListInput) (tokens []*entity.V1CamelOilToken, total int, err error) {
query := dao.V1CamelOilToken.Ctx(ctx).DB(config.GetDatabaseV1())
// 获取当前用户信息
needAuth, userInfo, err := service.SysUser().GetUserFromToken(ctx)
if err != nil {
return nil, 0, gerror.Wrap(err, "获取用户信息失败")
}
needAuth, userInfo, _ := service.SysUser().GetUserFromToken(ctx)
// 如果是普通用户非管理员只能查看自己的token
if needAuth && userInfo != nil && userInfo.Id != "" {
@@ -130,12 +126,12 @@ func (s *sCamelOil) ListTokensWithPagination(ctx context.Context, pageReq common
// 管理员或不需要认证的情况可以查看所有token包括user_id为空的token
// 添加查询条件
if tokenName != "" {
query = query.WhereLike(dao.V1CamelOilToken.Columns().Name, "%"+tokenName+"%")
if req.Name != "" {
query = query.WhereLike(dao.V1CamelOilToken.Columns().Name, utils.OrmLike(req.Name))
}
if status > 0 {
query = query.Where(dao.V1CamelOilToken.Columns().Status, status)
if req.Status > 0 {
query = query.Where(dao.V1CamelOilToken.Columns().Status, req.Status)
}
// 获取总数
@@ -146,8 +142,8 @@ func (s *sCamelOil) ListTokensWithPagination(ctx context.Context, pageReq common
// 分页查询
err = query.
Offset((pageReq.Current - 1) * pageReq.PageSize).
Limit(pageReq.PageSize).
Offset((req.Current - 1) * req.PageSize).
Limit(req.PageSize).
OrderDesc(dao.V1CamelOilToken.Columns().CreatedAt).
Scan(&tokens)
@@ -155,35 +151,16 @@ func (s *sCamelOil) ListTokensWithPagination(ctx context.Context, pageReq common
return nil, 0, gerror.Wrap(err, "查询Token列表失败")
}
return tokens, int(totalCount), nil
}
// UpdateToken 更新 Token 信息
func (s *sCamelOil) UpdateToken(ctx context.Context, tokenId int64, tokenName string, status int, remark string) error {
m := dao.V1CamelOilToken.Ctx(ctx).DB(config.GetDatabaseV1())
_, err := m.Where(dao.V1CamelOilToken.Columns().Id, tokenId).Update(&do.V1CamelOilToken{
Name: tokenName,
Status: status,
Remark: remark,
UpdatedAt: gtime.Now(),
})
if err != nil {
return gerror.Wrap(err, "更新Token失败")
}
glog.Infof(ctx, "Token更新成功: tokenId=%d", tokenId)
return nil
return tokens, totalCount, nil
}
// UpdateTokenInfo 修改 Token 基本信息(不包括 tokenValue
func (s *sCamelOil) UpdateTokenInfo(ctx context.Context, tokenId int64, tokenName string, phone string, remark string, rechargeLimitAmount float64, rechargeLimitCount int) error {
func (s *sCamelOil) UpdateTokenInfo(ctx context.Context, req *model.CamelOilTokenUpdateInput) error {
m := dao.V1CamelOilToken.Ctx(ctx).DB(config.GetDatabaseV1())
// 权限检查获取token信息验证所有权
var token *entity.V1CamelOilToken
err := m.Where(dao.V1CamelOilToken.Columns().Id, tokenId).Scan(&token)
err := m.Where(dao.V1CamelOilToken.Columns().Id, req.TokenId).Scan(&token)
if err != nil {
return gerror.Wrap(err, "查询Token信息失败")
}
@@ -203,14 +180,13 @@ func (s *sCamelOil) UpdateTokenInfo(ctx context.Context, tokenId int64, tokenNam
}
// 将 float64 转换为 decimal.Decimal 存储到数据库
rechargeLimitAmountDecimal := decimal.NewFromFloat(rechargeLimitAmount)
rechargeLimitAmountDecimal := decimal.NewFromFloat(req.RechargeLimitAmount)
_, err = m.Where(dao.V1CamelOilToken.Columns().Id, tokenId).Update(&do.V1CamelOilToken{
Name: tokenName,
Phone: phone,
Remark: remark,
_, err = m.Where(dao.V1CamelOilToken.Columns().Id, req.TokenId).Update(&do.V1CamelOilToken{
Name: req.Name,
Remark: req.Remark,
RechargeLimitAmount: rechargeLimitAmountDecimal,
RechargeLimitCount: rechargeLimitCount,
RechargeLimitCount: req.RechargeLimitCount,
UpdatedAt: gtime.Now(),
})
@@ -218,17 +194,17 @@ func (s *sCamelOil) UpdateTokenInfo(ctx context.Context, tokenId int64, tokenNam
return gerror.Wrap(err, "修改Token信息失败")
}
glog.Infof(ctx, "Token信息修改成功: tokenId=%d, tokenName=%s, phone=%s", tokenId, tokenName, phone)
glog.Infof(ctx, "Token信息修改成功: tokenId=%d, tokenName=%s", req.TokenId, req.Name)
return nil
}
// DeleteToken 删除 Token软删除
func (s *sCamelOil) DeleteToken(ctx context.Context, tokenId int64) error {
func (s *sCamelOil) DeleteToken(ctx context.Context, req *model.CamelOilTokenDeleteInput) error {
m := dao.V1CamelOilToken.Ctx(ctx).DB(config.GetDatabaseV1())
// 权限检查获取token信息验证所有权
var token *entity.V1CamelOilToken
err := m.Where(dao.V1CamelOilToken.Columns().Id, tokenId).Scan(&token)
err := m.Where(dao.V1CamelOilToken.Columns().Id, req.TokenId).Scan(&token)
if err != nil {
return gerror.Wrap(err, "查询Token信息失败")
}
@@ -247,7 +223,7 @@ func (s *sCamelOil) DeleteToken(ctx context.Context, tokenId int64) error {
return gerror.NewCode(gcode.CodeNotAuthorized, "无权删除此Token")
}
_, err = m.Where(dao.V1CamelOilToken.Columns().Id, tokenId).
_, err = m.Where(dao.V1CamelOilToken.Columns().Id, req.TokenId).
Update(&do.V1CamelOilToken{
DeletedAt: gtime.Now(),
})
@@ -256,17 +232,17 @@ func (s *sCamelOil) DeleteToken(ctx context.Context, tokenId int64) error {
return gerror.Wrap(err, "删除Token失败")
}
glog.Infof(ctx, "Token删除成功: tokenId=%d", tokenId)
glog.Infof(ctx, "Token删除成功: tokenId=%d", req.TokenId)
return nil
}
// UpdateTokenStatus 更新 Token 状态并记录日志
func (s *sCamelOil) UpdateTokenStatus(ctx context.Context, tokenId int64, newStatus consts.CamelOilTokenStatus, remark string) error {
func (s *sCamelOil) UpdateTokenStatus(ctx context.Context, req *model.CamelOilTokenStatusUpdateInput) error {
m := dao.V1CamelOilToken.Ctx(ctx).DB(config.GetDatabaseV1())
// 获取当前 Token 信息
var token *entity.V1CamelOilToken
err := m.Where(dao.V1CamelOilToken.Columns().Id, tokenId).Scan(&token)
err := m.Where(dao.V1CamelOilToken.Columns().Id, req.TokenId).Scan(&token)
if err != nil {
return gerror.Wrap(err, "查询Token失败")
}
@@ -277,20 +253,20 @@ func (s *sCamelOil) UpdateTokenStatus(ctx context.Context, tokenId int64, newSta
oldStatus := consts.CamelOilTokenStatus(token.Status)
// 如果状态没有变化,则不更新
if oldStatus == newStatus {
if oldStatus == req.NewStatus {
return nil
}
// 更新 Token 状态
_, err = m.Where(dao.V1CamelOilToken.Columns().Id, tokenId).Update(&do.V1CamelOilToken{
Status: int(newStatus),
_, err = m.Where(dao.V1CamelOilToken.Columns().Id, req.TokenId).Update(&do.V1CamelOilToken{
Status: int(req.NewStatus),
})
if err != nil {
return gerror.Wrap(err, "更新Token状态失败")
}
glog.Infof(ctx, "Token状态更新成功: tokenId=%d, 原状态=%s, 新状态=%s, 备注=%s", tokenId, consts.CamelOilTokenStatusText[oldStatus], consts.CamelOilTokenStatusText[newStatus], remark)
glog.Infof(ctx, "Token状态更新成功: tokenId=%d, 原状态=%s, 新状态=%s, 备注=%s", req.TokenId, consts.CamelOilTokenStatusText[oldStatus], consts.CamelOilTokenStatusText[req.NewStatus], req.Remark)
return nil
}
@@ -299,7 +275,11 @@ func (s *sCamelOil) UpdateTokenStatus(ctx context.Context, tokenId int64, newSta
// ====================================================================================
// BindCardToToken 绑定卡密到 Token使用轮询算法选择 Token
func (s *sCamelOil) BindCardToToken(ctx context.Context, orderId int64, cardNumber string, cardPassword string, amount decimal.Decimal) (bindingId int64, err error) {
func (s *sCamelOil) BindCardToToken(ctx context.Context, req *model.CamelOilCardBindInput) (bindingId int64, err error) {
orderId := req.OrderId
cardNumber := req.CardNumber
cardPassword := req.CardPassword
amount := req.Amount
// 1. 获取订单信息
var order *entity.V1CamelOilOrder
err = dao.V1CamelOilOrder.Ctx(ctx).DB(config.GetDatabaseV1()).
@@ -348,7 +328,11 @@ func (s *sCamelOil) BindCardToToken(ctx context.Context, orderId int64, cardNumb
// Token 过期/无效:标记 Token 为已过期
glog.Warningf(ctx, "Token 过期: %v", rechargeErr)
// 调用已实现的方法更新 Token 状态
_ = s.UpdateTokenStatus(ctx, selectedToken.Id, consts.CamelOilTokenStatusExpired, "Token已过期")
_ = s.UpdateTokenStatus(ctx, &model.CamelOilTokenStatusUpdateInput{
TokenId: selectedToken.Id,
NewStatus: consts.CamelOilTokenStatusExpired,
Remark: "Token已过期",
})
return 0, gerror.Wrap(rechargeErr, "Token过期需要重新登录")
default:
// 网络或其他错误:不更新状态,由定时任务重试
@@ -426,11 +410,11 @@ func (s *sCamelOil) GetCardBindingByOrder(ctx context.Context, orderId int64) (b
}
// GetCardBindingsByToken 根据 tokenId 查询绑定的卡密信息
func (s *sCamelOil) GetCardBindingsByToken(ctx context.Context, tokenId int64, current int, pageSize int) (bindings []*entity.V1CamelOilCardBinding, total int, err error) {
func (s *sCamelOil) GetCardBindingsByToken(ctx context.Context, req *model.CamelOilCardListInput) (bindings []*entity.V1CamelOilCardBinding, total int, err error) {
m := dao.V1CamelOilCardBinding.Ctx(ctx).DB(config.GetDatabaseV1())
// 权限检查获取token信息验证所有权
token, err := s.GetTokenInfo(ctx, tokenId)
token, err := s.GetTokenInfo(ctx, &model.CamelOilTokenQueryInput{TokenId: req.TokenId})
if err != nil {
return nil, 0, err // GetTokenInfo已经包含权限检查
}
@@ -438,13 +422,13 @@ func (s *sCamelOil) GetCardBindingsByToken(ctx context.Context, tokenId int64, c
return nil, 0, gerror.New("Token不存在")
}
count, err := m.Where(dao.V1CamelOilCardBinding.Columns().TokenId, tokenId).Count()
count, err := m.Where(dao.V1CamelOilCardBinding.Columns().TokenId, req.TokenId).Count()
if err != nil {
return nil, 0, gerror.Wrap(err, "查询绑定记录计数失败")
}
err = m.Where(dao.V1CamelOilCardBinding.Columns().TokenId, tokenId).
Page(current, pageSize).
err = m.Where(dao.V1CamelOilCardBinding.Columns().TokenId, req.TokenId).
Page(req.Current, req.PageSize).
Scan(&bindings)
if err != nil {
return nil, 0, gerror.Wrap(err, "查询绑定记录失败")
@@ -492,7 +476,7 @@ func (s *sCamelOil) CalculateTotalBindingAmount(ctx context.Context) (totalAmoun
// InputVerificationCode 输入验证码
func (s *sCamelOil) InputVerificationCode(ctx context.Context, req *model.CamelOilTokenLoginInput) (string, error) {
// 获取 Token 信息
token, err := s.GetTokenInfo(ctx, req.TokenId)
token, err := s.GetTokenInfo(ctx, &model.CamelOilTokenQueryInput{TokenId: req.TokenId})
if err != nil {
return "", gerror.Wrap(err, "查询Token信息失败")
}
@@ -502,7 +486,7 @@ func (s *sCamelOil) InputVerificationCode(ctx context.Context, req *model.CamelO
}
// 检查 Token 状态,只有验证码已发送状态的 Token 才能输入验证码
if token.Status != int(consts.CamelOilTokenStatusCodeSent) {
if token.Status != int(consts.CamelOilTokenStatusCodeSent) || token.Status != int(consts.CamelOilTokenStatusVerificationFailed) {
return "", gerror.New("Token状态不允许输入验证码")
}
@@ -512,7 +496,11 @@ func (s *sCamelOil) InputVerificationCode(ctx context.Context, req *model.CamelO
loginToken, err := client.LoginWithCaptcha(ctx, token.Phone, req.Code)
if err != nil {
// 更新状态为验证码验证失败
s.UpdateTokenStatus(ctx, req.TokenId, consts.CamelOilTokenStatusVerificationFailed, "验证码验证失败")
_ = s.UpdateTokenStatus(ctx, &model.CamelOilTokenStatusUpdateInput{
TokenId: req.TokenId,
NewStatus: consts.CamelOilTokenStatusVerificationFailed,
Remark: "验证码验证失败",
})
return "", gerror.Wrap(err, "验证码验证失败")
}
@@ -520,10 +508,9 @@ func (s *sCamelOil) InputVerificationCode(ctx context.Context, req *model.CamelO
m := dao.V1CamelOilToken.Ctx(ctx).DB(config.GetDatabaseV1())
_, err = m.Where(dao.V1CamelOilToken.Columns().Id, req.TokenId).Update(&do.V1CamelOilToken{
LoginToken: loginToken,
LoginTokenExpiresAt: gtime.Now().Add(24 * 3600 * time.Second), // 24小时后过期
LoginTokenExpiresAt: gtime.Now().Add(gtime.D * 30), // 24小时后过期
LastLoginAt: gtime.Now(),
Status: int(consts.CamelOilTokenStatusAvailable), // 可用状态
UpdatedAt: gtime.Now(),
})
if err != nil {
@@ -535,9 +522,9 @@ func (s *sCamelOil) InputVerificationCode(ctx context.Context, req *model.CamelO
}
// ResendVerificationCode 重新发送验证码
func (s *sCamelOil) ResendVerificationCode(ctx context.Context, tokenId int64) error {
func (s *sCamelOil) ResendVerificationCode(ctx context.Context, req *model.CamelOilTokenResendCodeInput) error {
// 获取 Token 信息
token, err := s.GetTokenInfo(ctx, tokenId)
token, err := s.GetTokenInfo(ctx, &model.CamelOilTokenQueryInput{TokenId: req.TokenId})
if err != nil {
return gerror.Wrap(err, "查询Token信息失败")
}
@@ -572,16 +559,24 @@ func (s *sCamelOil) ResendVerificationCode(ctx context.Context, tokenId int64) e
_, err = client.SendCaptcha(ctx, token.Phone)
if err != nil {
// 更新状态为登录失败
s.UpdateTokenStatus(ctx, tokenId, consts.CamelOilTokenStatusLoginFailed, "发送验证码失败")
_ = s.UpdateTokenStatus(ctx, &model.CamelOilTokenStatusUpdateInput{
TokenId: req.TokenId,
NewStatus: consts.CamelOilTokenStatusLoginFailed,
Remark: "发送验证码失败",
})
return gerror.Wrap(err, "发送验证码失败")
}
// 更新 Token 状态为验证码已发送
err = s.UpdateTokenStatus(ctx, tokenId, consts.CamelOilTokenStatusCodeSent, "重新发送验证码成功")
err = s.UpdateTokenStatus(ctx, &model.CamelOilTokenStatusUpdateInput{
TokenId: req.TokenId,
NewStatus: consts.CamelOilTokenStatusCodeSent,
Remark: "重新发送验证码成功",
})
if err != nil {
return gerror.Wrap(err, "更新Token状态失败")
}
glog.Infof(ctx, "验证码重新发送成功: tokenId=%d, phone=%s", tokenId, token.Phone)
glog.Infof(ctx, "验证码重新发送成功: tokenId=%d, phone=%s", req.TokenId, token.Phone)
return nil
}

View File

@@ -1,5 +1,12 @@
package model
import (
"kami/api/commonApi"
"kami/internal/consts"
"github.com/shopspring/decimal"
)
// PrefetchOrderResult 预拉取订单结果
type PrefetchOrderResult struct {
PlatformOrderNo string // 骆驼平台订单号
@@ -15,7 +22,7 @@ type PrefetchOrderResult struct {
// CamelOilTokenCreateInput 创建 Token 输入结构
type CamelOilTokenCreateInput struct {
Name string `json:"name" v:"required" description:"名称"`
Name string `json:"name" v:"required" description:"Token名称"`
Phone string `json:"phone" v:"required" description:"绑定的手机号"`
Remark string `json:"remark" description:"备注"`
RechargeLimitAmount float64 `json:"rechargeLimitAmount" v:"required" description:"充值金额限制"`
@@ -25,8 +32,7 @@ type CamelOilTokenCreateInput struct {
// CamelOilTokenUpdateInput 更新 Token 输入结构
type CamelOilTokenUpdateInput struct {
TokenId int64 `json:"tokenId" v:"required" description:"Token ID"`
Name string `json:"name" v:"required" description:"名称"`
Phone string `json:"phone" description:"绑定的手机号"`
Name string `json:"name" v:"required" description:"Token名称"`
Remark string `json:"remark" description:"备注"`
RechargeLimitAmount float64 `json:"rechargeLimitAmount" v:"required" description:"充值金额限制"`
RechargeLimitCount int `json:"rechargeLimitCount" v:"required" description:"充值次数限制"`
@@ -38,41 +44,46 @@ type CamelOilTokenLoginInput struct {
Code string `json:"code" v:"required" description:"验证码"`
}
// CamelOilTokenResendCodeInput 重发验证码输入结构
type CamelOilTokenResendCodeInput struct {
// CamelOilTokenListInput Token 列表查询输入结构
type CamelOilTokenListInput struct {
commonApi.CommonPageReq
Name string `json:"name" description:"Token名称"`
Status consts.CamelOilTokenStatus `json:"status" description:"状态"`
}
// CamelOilTokenStatusUpdateInput Token 状态更新输入结构
type CamelOilTokenStatusUpdateInput struct {
TokenId int64 `json:"tokenId" v:"required" description:"Token ID"`
NewStatus consts.CamelOilTokenStatus `json:"newStatus" v:"required" description:"新状态"`
Remark string `json:"remark" description:"备注"`
}
// CamelOilCardBindInput 卡密绑定输入结构
type CamelOilCardBindInput struct {
OrderId int64 `json:"orderId" v:"required" description:"订单ID"`
CardNumber string `json:"cardNumber" v:"required" description:"卡号"`
CardPassword string `json:"cardPassword" v:"required" description:"卡密"`
Amount decimal.Decimal `json:"amount" v:"required" description:"绑定金额"`
}
// CamelOilCardListInput 卡密列表查询输入结构
type CamelOilCardListInput struct {
TokenId int64 `json:"tokenId" v:"required" description:"Token ID"`
Current int `json:"current" description:"当前页码"`
PageSize int `json:"pageSize" description:"每页数量"`
}
// CamelOilTokenQueryInput Token 查询输入结构
type CamelOilTokenQueryInput struct {
TokenId int64 `json:"tokenId" v:"required" description:"Token ID"`
}
// ====================================================================================
// Token 相关模型
// ====================================================================================
// CamelOilTokenCreateInput 创建 Token 输入结构
type CamelOilTokenCreateInput struct {
Name string `json:"name" v:"required" description:"名称"`
Phone string `json:"phone" v:"required" description:"绑定的手机号"`
Remark string `json:"remark" description:"备注"`
RechargeLimitAmount float64 `json:"rechargeLimitAmount" v:"required" description:"充值金额限制"`
RechargeLimitCount int `json:"rechargeLimitCount" v:"required" description:"充值次数限制"`
// CamelOilTokenDeleteInput Token 删除输入结构
type CamelOilTokenDeleteInput struct {
TokenId int64 `json:"tokenId" v:"required" description:"Token ID"`
}
// CamelOilTokenUpdateInput 更新 Token 输入结构
type CamelOilTokenUpdateInput struct {
TokenId int64 `json:"tokenId" v:"required" description:"Token ID"`
Name string `json:"name" v:"required" description:"名称"`
Phone string `json:"phone" description:"绑定的手机号"`
Remark string `json:"remark" description:"备注"`
RechargeLimitAmount float64 `json:"rechargeLimitAmount" v:"required" description:"充值金额限制"`
RechargeLimitCount int `json:"rechargeLimitCount" v:"required" description:"充值次数限制"`
}
// CamelOilTokenLoginInput Token 登录输入结构
type CamelOilTokenLoginInput struct {
TokenId int64 `json:"tokenId" v:"required" description:"Token ID"`
Code string `json:"code" v:"required" description:"验证码"`
}
// CamelOilTokenResendCodeInput 重发验证码输入结构
// CamelOilTokenResendCodeInput 重新发送验证码输入结构
type CamelOilTokenResendCodeInput struct {
TokenId int64 `json:"tokenId" v:"required" description:"Token ID"`
}

View File

@@ -8,7 +8,6 @@ package service
import (
"context"
v1 "kami/api/camel_oil/v1"
"kami/api/commonApi"
"kami/internal/consts"
"kami/internal/model"
"kami/internal/model/entity"
@@ -116,29 +115,27 @@ type (
// GetCamelOilSettings 获取骆驼模块设置的辅助函数
GetCamelOilSettings(ctx context.Context) (*v1.CamelOilSettings, error)
// CreateToken 创建 Token
CreateToken(ctx context.Context, tokenName string, tokenValue string, phone string, remark string, rechargeLimitAmount float64, rechargeLimitCount int) (tokenId int64, err error)
CreateToken(ctx context.Context, req *model.CamelOilTokenCreateInput) (tokenId int64, err error)
// GetTokenInfo 获取 Token 信息
GetTokenInfo(ctx context.Context, tokenId int64) (token *entity.V1CamelOilToken, err error)
GetTokenInfo(ctx context.Context, req *model.CamelOilTokenQueryInput) (token *entity.V1CamelOilToken, err error)
// ListTokens 列出所有可用的 Token
ListTokens(ctx context.Context) (tokens []*entity.V1CamelOilToken, err error)
// ListTokensWithPagination 列出所有可用的 Token支持分页和查询条件
ListTokensWithPagination(ctx context.Context, pageReq commonApi.CommonPageReq, tokenName string, status int) (tokens []*entity.V1CamelOilToken, total int, err error)
// UpdateToken 更新 Token 信息
UpdateToken(ctx context.Context, tokenId int64, tokenName string, status int, remark string) error
ListTokensWithPagination(ctx context.Context, req *model.CamelOilTokenListInput) (tokens []*entity.V1CamelOilToken, total int, err error)
// UpdateTokenInfo 修改 Token 基本信息(不包括 tokenValue
UpdateTokenInfo(ctx context.Context, tokenId int64, tokenName string, phone string, remark string, rechargeLimitAmount float64, rechargeLimitCount int) error
UpdateTokenInfo(ctx context.Context, req *model.CamelOilTokenUpdateInput) error
// DeleteToken 删除 Token软删除
DeleteToken(ctx context.Context, tokenId int64) error
DeleteToken(ctx context.Context, req *model.CamelOilTokenDeleteInput) error
// UpdateTokenStatus 更新 Token 状态并记录日志
UpdateTokenStatus(ctx context.Context, tokenId int64, newStatus consts.CamelOilTokenStatus, remark string) error
UpdateTokenStatus(ctx context.Context, req *model.CamelOilTokenStatusUpdateInput) error
// BindCardToToken 绑定卡密到 Token使用轮询算法选择 Token
BindCardToToken(ctx context.Context, orderId int64, cardNumber string, cardPassword string, amount decimal.Decimal) (bindingId int64, err error)
BindCardToToken(ctx context.Context, req *model.CamelOilCardBindInput) (bindingId int64, err error)
// GetCardBindingInfo 获取卡密绑定信息
GetCardBindingInfo(ctx context.Context, bindingId int64) (binding *entity.V1CamelOilCardBinding, err error)
// GetCardBindingByOrder 获取订单绑定的卡密信息
GetCardBindingByOrder(ctx context.Context, orderId int64) (binding *entity.V1CamelOilCardBinding, err error)
// GetCardBindingsByToken 根据 tokenId 查询绑定的卡密信息
GetCardBindingsByToken(ctx context.Context, tokenId int64, current int, pageSize int) (bindings []*entity.V1CamelOilCardBinding, total int, err error)
GetCardBindingsByToken(ctx context.Context, req *model.CamelOilCardListInput) (bindings []*entity.V1CamelOilCardBinding, total int, err error)
// GetTokenBindingStats 获取 Token 的绑定统计
GetTokenBindingStats(ctx context.Context, tokenId int64) (bindCount int, totalAmount decimal.Decimal, err error)
// CalculateTotalBindingAmount 计算所有 Token 的累计绑定金额
@@ -146,7 +143,7 @@ type (
// InputVerificationCode 输入验证码
InputVerificationCode(ctx context.Context, req *model.CamelOilTokenLoginInput) (string, error)
// ResendVerificationCode 重新发送验证码
ResendVerificationCode(ctx context.Context, tokenId int64) error
ResendVerificationCode(ctx context.Context, req *model.CamelOilTokenResendCodeInput) error
}
)