feat(camel_oil): 新增Token自动登录与验证码管理功能
- 新增Token状态:待验证码、登录失败、验证码已发送等多种状态 - 修改Token模型及数据库结构,新增登录token及过期时间字段 - 创建Token时,默认状态为待验证码,异步发送验证码 - 实现Token登录接口,支持验证码登录并更新登录token信息 - 支持重发验证码接口及获取需登录Token列表接口 - 添加Token自动登录定时任务,自动发送验证码和重试登录 - 优化账号列表查询,默认按状态升序排列,搜索支持模糊匹配 - 调整API和服务接口,统一Token名称和状态相关字段命名 - 修正绑定卡密接口使用登录token替代旧token值登录 - 新增Token管理相关单元测试用例,覆盖新增功能逻辑
This commit is contained in:
@@ -2,11 +2,10 @@ package v1
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"kami/api/commonApi"
|
||||
"kami/utility/utils"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"kami/api/commonApi"
|
||||
"kami/internal/consts"
|
||||
)
|
||||
|
||||
// ====================================================================================
|
||||
@@ -16,9 +15,8 @@ import (
|
||||
// CreateTokenReq 创建 Token 请求
|
||||
type CreateTokenReq struct {
|
||||
g.Meta `path:"/token/create" tags:"JD V2 Token Management" method:"post" summary:"创建 Token"`
|
||||
TokenName string `json:"tokenName" v:"required" description:"Token名称"`
|
||||
TokenValue string `json:"tokenValue" v:"required" description:"Token值"`
|
||||
Phone string `json:"phone" description:"绑定的手机号"`
|
||||
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:"充值次数限制"`
|
||||
@@ -37,22 +35,22 @@ type GetTokenReq struct {
|
||||
|
||||
// TokenInfo Token 信息
|
||||
type TokenInfo struct {
|
||||
Id int64 `json:"id" description:"Token ID"`
|
||||
UserId string `json:"userId" description:"用户ID,空字符串表示管理员创建"`
|
||||
TokenName string `json:"tokenName" description:"Token名称"`
|
||||
TokenValue string `json:"tokenValue" 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:"名称"`
|
||||
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:"最后使用时间"`
|
||||
LastLoginAt *gtime.Time `json:"lastLoginAt" description:"最后登录时间"`
|
||||
Remark string `json:"remark" description:"备注"`
|
||||
CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"`
|
||||
UpdatedAt *gtime.Time `json:"updatedAt" description:"更新时间"`
|
||||
}
|
||||
|
||||
// GetTokenRes 获取 Token 信息响应
|
||||
@@ -69,15 +67,15 @@ type ListTokensRes struct {
|
||||
type ListTokensReq struct {
|
||||
g.Meta `path:"/token/list" tags:"JD V2 Token Management" method:"get" summary:"列出 Token"`
|
||||
commonApi.CommonPageReq
|
||||
TokenName string `json:"tokenName" description:"Token名称"`
|
||||
Status int `json:"status" description:"状态"`
|
||||
Name string `json:"name" description:"名称"`
|
||||
Status consts.CamelOilTokenStatus `json:"status" description:"状态"`
|
||||
}
|
||||
|
||||
// UpdateTokenReq 修改 Token 请求
|
||||
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"`
|
||||
TokenName string `json:"tokenName" v:"required" description:"Token名称"`
|
||||
Name string `json:"name" v:"required" description:"名称"`
|
||||
Phone string `json:"phone" description:"绑定的手机号"`
|
||||
Remark string `json:"remark" description:"备注"`
|
||||
RechargeLimitAmount float64 `json:"rechargeLimitAmount" v:"required" description:"充值金额限制"`
|
||||
@@ -108,7 +106,7 @@ type DeleteTokenRes struct {
|
||||
type CardBindingInfo struct {
|
||||
Id int64 `json:"id" description:"绑定记录ID"`
|
||||
TokenId int64 `json:"tokenId" description:"Token ID"`
|
||||
TokenName string `json:"tokenName" description:"Token名称"`
|
||||
Name string `json:"name" description:"Token名称"`
|
||||
OrderId int64 `json:"orderId" description:"订单ID"`
|
||||
CardNumber string `json:"cardNumber" description:"卡号"`
|
||||
CardPassword string `json:"cardPassword" description:"卡密"`
|
||||
@@ -134,8 +132,7 @@ func (t TokenInfo) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(Alias{
|
||||
Id: t.Id,
|
||||
UserId: t.UserId,
|
||||
TokenName: t.TokenName,
|
||||
TokenValue: utils.MaskTokenValue(t.TokenValue),
|
||||
Name: t.Name,
|
||||
Phone: t.Phone,
|
||||
Status: t.Status,
|
||||
BindCount: t.BindCount,
|
||||
@@ -145,6 +142,7 @@ func (t TokenInfo) MarshalJSON() ([]byte, error) {
|
||||
RechargeLimitCount: t.RechargeLimitCount,
|
||||
LastBindAt: t.LastBindAt,
|
||||
LastUsedAt: t.LastUsedAt,
|
||||
LastLoginAt: t.LastLoginAt,
|
||||
Remark: t.Remark,
|
||||
CreatedAt: t.CreatedAt,
|
||||
UpdatedAt: t.UpdatedAt,
|
||||
|
||||
@@ -84,16 +84,22 @@ var CamelOilCallbackStatusText = map[CamelOilNotifyStatus]string{
|
||||
type CamelOilTokenStatus int
|
||||
|
||||
const (
|
||||
CamelOilTokenStatusAvailable CamelOilTokenStatus = 1 // 可用
|
||||
CamelOilTokenStatusDisabled CamelOilTokenStatus = 2 // 已禁用
|
||||
CamelOilTokenStatusExpired CamelOilTokenStatus = 3 // 已过期
|
||||
CamelOilTokenStatusPendingVerification CamelOilTokenStatus = 0 // 待验证码
|
||||
CamelOilTokenStatusAvailable CamelOilTokenStatus = 1 // 已登录/可用
|
||||
CamelOilTokenStatusDisabled CamelOilTokenStatus = 2 // 已禁用
|
||||
CamelOilTokenStatusExpired CamelOilTokenStatus = 3 // 已过期
|
||||
CamelOilTokenStatusLoginFailed CamelOilTokenStatus = 4 // 登录失败
|
||||
CamelOilTokenStatusCodeSent CamelOilTokenStatus = 5 // 验证码已发送待登录
|
||||
)
|
||||
|
||||
// CamelOilTokenStatusText Token状态文本映射
|
||||
var CamelOilTokenStatusText = map[CamelOilTokenStatus]string{
|
||||
CamelOilTokenStatusAvailable: "可用",
|
||||
CamelOilTokenStatusDisabled: "已禁用",
|
||||
CamelOilTokenStatusExpired: "已过期",
|
||||
CamelOilTokenStatusPendingVerification: "待验证码",
|
||||
CamelOilTokenStatusAvailable: "已登录",
|
||||
CamelOilTokenStatusDisabled: "已禁用",
|
||||
CamelOilTokenStatusExpired: "已过期",
|
||||
CamelOilTokenStatusLoginFailed: "登录失败",
|
||||
CamelOilTokenStatusCodeSent: "验证码已发送",
|
||||
}
|
||||
|
||||
// ====================================================================================
|
||||
|
||||
@@ -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) CreateToken(ctx context.Context, req *v1.CreateTokenReq)
|
||||
err = errHandler.WrapError(ctx, gcode.CodeInternalError, err, "登录校验失败")
|
||||
return
|
||||
}
|
||||
tokenId, err := service.CamelOil().CreateToken(ctx, req.TokenName, req.TokenValue, req.Phone, req.Remark, req.RechargeLimitAmount, req.RechargeLimitCount)
|
||||
tokenId, err := service.CamelOil().CreateToken(ctx, &model.CamelOilTokenCreateInput{
|
||||
Name: req.Name,
|
||||
Phone: req.Phone,
|
||||
Remark: req.Remark,
|
||||
RechargeLimitAmount: req.RechargeLimitAmount,
|
||||
RechargeLimitCount: req.RechargeLimitCount,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -5,9 +5,9 @@ import (
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gcode"
|
||||
v1 "kami/api/camel_oil/v1"
|
||||
"kami/internal/consts"
|
||||
"kami/internal/errHandler"
|
||||
"kami/internal/service"
|
||||
"kami/utility/utils"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) GetToken(ctx context.Context, req *v1.GetTokenReq) (res *v1.GetTokenRes, err error) {
|
||||
@@ -24,10 +24,9 @@ func (c *ControllerV1) GetToken(ctx context.Context, req *v1.GetTokenReq) (res *
|
||||
Token: v1.TokenInfo{
|
||||
Id: token.Id,
|
||||
UserId: token.UserId,
|
||||
TokenName: token.TokenName,
|
||||
TokenValue: utils.MaskTokenValue(token.TokenValue),
|
||||
Name: token.Name,
|
||||
Phone: token.Phone,
|
||||
Status: token.Status,
|
||||
Status: consts.CamelOilTokenStatus(token.Status),
|
||||
BindCount: token.BindCount,
|
||||
TotalBindAmount: token.TotalBindAmount.InexactFloat64(),
|
||||
TotalRechargeAmount: token.TotalRechargeAmount.InexactFloat64(),
|
||||
@@ -35,6 +34,7 @@ func (c *ControllerV1) GetToken(ctx context.Context, req *v1.GetTokenReq) (res *
|
||||
RechargeLimitCount: token.RechargeLimitCount,
|
||||
LastBindAt: token.LastBindAt,
|
||||
LastUsedAt: token.LastUsedAt,
|
||||
LastLoginAt: token.LastLoginAt,
|
||||
Remark: token.Remark,
|
||||
CreatedAt: token.CreatedAt,
|
||||
UpdatedAt: token.UpdatedAt,
|
||||
|
||||
@@ -6,9 +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/service"
|
||||
"kami/utility/utils"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) ListTokens(ctx context.Context, req *v1.ListTokensReq) (res *v1.ListTokensRes, err error) {
|
||||
@@ -21,7 +21,7 @@ func (c *ControllerV1) ListTokens(ctx context.Context, req *v1.ListTokensReq) (r
|
||||
// 调用服务层方法,它会根据当前用户类型自动筛选数据
|
||||
// 管理员:可以查看所有token(包括用户创建和管理员创建的)
|
||||
// 普通用户:只能查看自己创建的token
|
||||
tokens, total, err := service.CamelOil().ListTokensWithPagination(ctx, req.CommonPageReq, req.TokenName, req.Status)
|
||||
tokens, total, err := service.CamelOil().ListTokensWithPagination(ctx, req.CommonPageReq, req.Name, int(req.Status))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -30,10 +30,9 @@ func (c *ControllerV1) ListTokens(ctx context.Context, req *v1.ListTokensReq) (r
|
||||
tokenInfos = append(tokenInfos, v1.TokenInfo{
|
||||
Id: token.Id,
|
||||
UserId: token.UserId,
|
||||
TokenName: token.TokenName,
|
||||
TokenValue: utils.MaskTokenValue(token.TokenValue),
|
||||
Name: token.Name,
|
||||
Phone: token.Phone,
|
||||
Status: token.Status,
|
||||
Status: consts.CamelOilTokenStatus(token.Status),
|
||||
BindCount: token.BindCount,
|
||||
TotalBindAmount: token.TotalBindAmount.InexactFloat64(),
|
||||
TotalRechargeAmount: token.TotalRechargeAmount.InexactFloat64(),
|
||||
@@ -41,6 +40,7 @@ func (c *ControllerV1) ListTokens(ctx context.Context, req *v1.ListTokensReq) (r
|
||||
RechargeLimitCount: token.RechargeLimitCount,
|
||||
LastBindAt: token.LastBindAt,
|
||||
LastUsedAt: token.LastUsedAt,
|
||||
LastLoginAt: token.LastLoginAt,
|
||||
Remark: token.Remark,
|
||||
CreatedAt: token.CreatedAt,
|
||||
UpdatedAt: token.UpdatedAt,
|
||||
|
||||
@@ -15,7 +15,7 @@ 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.TokenName, req.Phone, req.Remark, req.RechargeLimitAmount, req.RechargeLimitCount)
|
||||
err = service.CamelOil().UpdateTokenInfo(ctx, req.TokenId, req.Name, req.Phone, req.Remark, req.RechargeLimitAmount, req.RechargeLimitCount)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -23,10 +23,12 @@ type V1CamelOilTokenDao struct {
|
||||
type V1CamelOilTokenColumns struct {
|
||||
Id string // 主键ID
|
||||
UserId string // 用户ID,空字符串表示管理员创建
|
||||
TokenName string // Token名称/标识
|
||||
TokenValue string // Token具体值
|
||||
Name string // 名称
|
||||
Phone string // 绑定的手机号
|
||||
Status string // 状态:1可用 2已禁用 3已过期
|
||||
Status string // 状态:0待验证码 1可用 2已禁用 3已过期 4登录失败
|
||||
LoginToken string // 登录后获取的token
|
||||
LoginTokenExpiresAt string // 登录token过期时间
|
||||
LastLoginAt string // 最后登录时间
|
||||
BindCount string // 已绑定卡密数量
|
||||
TotalBindAmount string // 累计绑定金额
|
||||
LastBindAt string // 最后绑定时间
|
||||
@@ -44,10 +46,12 @@ type V1CamelOilTokenColumns struct {
|
||||
var v1CamelOilTokenColumns = V1CamelOilTokenColumns{
|
||||
Id: "id",
|
||||
UserId: "user_id",
|
||||
TokenName: "token_name",
|
||||
TokenValue: "token_value",
|
||||
Name: "name",
|
||||
Phone: "phone",
|
||||
Status: "status",
|
||||
LoginToken: "login_token",
|
||||
LoginTokenExpiresAt: "login_token_expires_at",
|
||||
LastLoginAt: "last_login_at",
|
||||
BindCount: "bind_count",
|
||||
TotalBindAmount: "total_bind_amount",
|
||||
LastBindAt: "last_bind_at",
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"kami/internal/model/do"
|
||||
"kami/internal/model/entity"
|
||||
"kami/utility/config"
|
||||
"kami/utility/utils"
|
||||
)
|
||||
|
||||
// ====================================================================================
|
||||
@@ -137,8 +138,7 @@ func (s *sCamelOil) ListAccounts(ctx context.Context, status int, current, pageS
|
||||
|
||||
// ListAccount 查询账号列表(API版本)
|
||||
func (s *sCamelOil) ListAccount(ctx context.Context, req *v1.ListAccountReq) (res *v1.ListAccountRes, err error) {
|
||||
m := dao.V1CamelOilAccount.Ctx(ctx).DB(config.GetDatabaseV1())
|
||||
|
||||
m := dao.V1CamelOilAccount.Ctx(ctx).DB(config.GetDatabaseV1()).OrderAsc(dao.V1CamelOilAccount.Columns().Status)
|
||||
// 构建查询条件
|
||||
if req.Status > 0 {
|
||||
m = m.Where(dao.V1CamelOilAccount.Columns().Status, int(req.Status))
|
||||
@@ -146,7 +146,7 @@ func (s *sCamelOil) ListAccount(ctx context.Context, req *v1.ListAccountReq) (re
|
||||
if req.Keyword != "" {
|
||||
// 基于账号ID、账号名称或手机号搜索
|
||||
m = m.Where("(id LIKE ? OR account_name LIKE ? OR phone LIKE ?)",
|
||||
"%"+req.Keyword+"%", "%"+req.Keyword+"%", "%"+req.Keyword+"%")
|
||||
utils.OrmLike(req.Keyword), utils.OrmLike(req.Keyword), utils.OrmLike(req.Keyword))
|
||||
}
|
||||
|
||||
// 查询总数
|
||||
@@ -157,7 +157,7 @@ func (s *sCamelOil) ListAccount(ctx context.Context, req *v1.ListAccountReq) (re
|
||||
|
||||
// 分页查询
|
||||
var accounts []*entity.V1CamelOilAccount
|
||||
err = m.Page(req.Current, req.PageSize).OrderDesc(dao.V1CamelOilAccount.Columns().CreatedAt).Scan(&accounts)
|
||||
err = m.Page(req.Current, req.PageSize).Scan(&accounts)
|
||||
if err != nil {
|
||||
return nil, gerror.Wrap(err, "查询账号列表失败")
|
||||
}
|
||||
|
||||
10
internal/logic/camel_oil/account_test.go
Normal file
10
internal/logic/camel_oil/account_test.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package camel_oil
|
||||
|
||||
import (
|
||||
v1 "kami/api/camel_oil/v1"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_sCamelOil_ListAccount(t *testing.T) {
|
||||
(&sCamelOil{}).ListAccount(t.Context(), &v1.ListAccountReq{Keyword: "12345", Status: 2})
|
||||
}
|
||||
@@ -405,3 +405,157 @@ func (s *sCamelOil) CronCleanExpiredPrefetchOrders(ctx context.Context) (cleaned
|
||||
glog.Infof(ctx, "清理过期预拉取订单完成,清理数量: %d", cleanedCount)
|
||||
return cleanedCount, nil
|
||||
}
|
||||
|
||||
// CronTokenLoginTask Token 自动登录定时任务 - 由cron调度器定期调用
|
||||
// 流程:检查需要发送验证码或重新登录的 Token,自动处理登录流程
|
||||
func (s *sCamelOil) CronTokenLoginTask(ctx context.Context) error {
|
||||
glog.Info(ctx, "开始执行 Token 自动登录任务")
|
||||
|
||||
// 1. 处理需要发送验证码的 Token(登录状态为 3:验证码待获取)
|
||||
needCodeTokens, err := s.GetTokensNeedingCode(ctx)
|
||||
if err != nil {
|
||||
glog.Errorf(ctx, "查询需要验证码的 Token 失败: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
if len(needCodeTokens) > 0 {
|
||||
glog.Infof(ctx, "查询到 %d 个需要验证码的 Token", len(needCodeTokens))
|
||||
|
||||
codeSuccessCount := 0
|
||||
codeFailCount := 0
|
||||
|
||||
for _, token := range needCodeTokens {
|
||||
// 检查是否需要重试(避免频繁请求)
|
||||
if token.UpdatedAt != nil && gtime.Now().Sub(token.UpdatedAt) < time.Minute*5 {
|
||||
continue
|
||||
}
|
||||
|
||||
err := s.SendVerificationCode(ctx, token.Id, token.Phone)
|
||||
if err != nil {
|
||||
glog.Errorf(ctx, "发送验证码失败,Token ID: %d, 错误: %v", token.Id, err)
|
||||
codeFailCount++
|
||||
} else {
|
||||
codeSuccessCount++
|
||||
}
|
||||
}
|
||||
|
||||
glog.Infof(ctx, "验证码发送完成: 成功=%d, 失败=%d", codeSuccessCount, codeFailCount)
|
||||
}
|
||||
|
||||
// 2. 处理登录失败的 Token(登录状态为 2:登录失败)
|
||||
failedTokens, err := s.GetFailedLoginTokens(ctx)
|
||||
if err != nil {
|
||||
glog.Errorf(ctx, "查询登录失败的 Token 失败: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
if len(failedTokens) > 0 {
|
||||
glog.Infof(ctx, "查询到 %d 个登录失败的 Token", len(failedTokens))
|
||||
|
||||
retrySuccessCount := 0
|
||||
retryFailCount := 0
|
||||
|
||||
for _, token := range failedTokens {
|
||||
// 检查是否需要重试(避免频繁重试,间隔至少30分钟)
|
||||
if token.UpdatedAt != nil && gtime.Now().Sub(token.UpdatedAt) < time.Minute*30 {
|
||||
continue
|
||||
}
|
||||
|
||||
// 重置状态并发送验证码
|
||||
err := s.SendVerificationCode(ctx, token.Id, token.Phone)
|
||||
if err != nil {
|
||||
glog.Errorf(ctx, "重试发送验证码失败,Token ID: %d, 错误: %v", token.Id, err)
|
||||
retryFailCount++
|
||||
} else {
|
||||
retrySuccessCount++
|
||||
}
|
||||
}
|
||||
|
||||
glog.Infof(ctx, "登录失败 Token 重试完成: 成功=%d, 失败=%d", retrySuccessCount, retryFailCount)
|
||||
}
|
||||
|
||||
// 3. 清理过期的 Token(登录 token 过期的)
|
||||
expiredCount, err := s.CleanExpiredLoginTokens(ctx)
|
||||
if err != nil {
|
||||
glog.Errorf(ctx, "清理过期登录 Token 失败: %v", err)
|
||||
} else if expiredCount > 0 {
|
||||
glog.Infof(ctx, "清理过期登录 Token 完成,清理数量: %d", expiredCount)
|
||||
}
|
||||
|
||||
glog.Info(ctx, "Token 自动登录任务完成")
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetTokensNeedingCode 获取需要发送验证码的 Token(状态为待验证码)
|
||||
func (s *sCamelOil) GetTokensNeedingCode(ctx context.Context) ([]*entity.V1CamelOilToken, error) {
|
||||
m := dao.V1CamelOilToken.Ctx(ctx).DB(config.GetDatabaseV1())
|
||||
|
||||
var tokens []*entity.V1CamelOilToken
|
||||
|
||||
// 获取状态为待验证码的 Token
|
||||
err := m.Where(dao.V1CamelOilToken.Columns().Status, int(consts.CamelOilTokenStatusPendingVerification)).
|
||||
Scan(&tokens)
|
||||
|
||||
if err != nil {
|
||||
return nil, gerror.Wrap(err, "查询需要验证码的 Token 失败")
|
||||
}
|
||||
|
||||
return tokens, nil
|
||||
}
|
||||
|
||||
// GetFailedLoginTokens 获取登录失败的 Token(状态为登录失败)
|
||||
func (s *sCamelOil) GetFailedLoginTokens(ctx context.Context) ([]*entity.V1CamelOilToken, error) {
|
||||
m := dao.V1CamelOilToken.Ctx(ctx).DB(config.GetDatabaseV1())
|
||||
|
||||
var tokens []*entity.V1CamelOilToken
|
||||
|
||||
// 获取状态为登录失败的 Token
|
||||
err := m.Where(dao.V1CamelOilToken.Columns().Status, int(consts.CamelOilTokenStatusLoginFailed)).
|
||||
Scan(&tokens)
|
||||
|
||||
if err != nil {
|
||||
return nil, gerror.Wrap(err, "查询登录失败的 Token 失败")
|
||||
}
|
||||
|
||||
return tokens, nil
|
||||
}
|
||||
|
||||
// CleanExpiredLoginTokens 清理登录 token 过期的 Token
|
||||
func (s *sCamelOil) CleanExpiredLoginTokens(ctx context.Context) (cleanedCount int, err error) {
|
||||
m := dao.V1CamelOilToken.Ctx(ctx).DB(config.GetDatabaseV1())
|
||||
|
||||
// 查询登录 token 已过期但状态仍为可用的 Token
|
||||
var expiredTokens []*entity.V1CamelOilToken
|
||||
err = m.Where(dao.V1CamelOilToken.Columns().Status, int(consts.CamelOilTokenStatusAvailable)).
|
||||
WhereNotNull(dao.V1CamelOilToken.Columns().LoginTokenExpiresAt).
|
||||
WhereLT(dao.V1CamelOilToken.Columns().LoginTokenExpiresAt, gtime.Now()).
|
||||
Scan(&expiredTokens)
|
||||
|
||||
if err != nil {
|
||||
return 0, gerror.Wrap(err, "查询过期登录 Token 失败")
|
||||
}
|
||||
|
||||
if len(expiredTokens) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// 将这些 Token 标记为需要重新登录
|
||||
for _, token := range expiredTokens {
|
||||
_, err = m.Where(dao.V1CamelOilToken.Columns().Id, token.Id).
|
||||
Update(&do.V1CamelOilToken{
|
||||
Status: int(consts.CamelOilTokenStatusPendingVerification), // 待验证码状态
|
||||
LoginToken: "", // 清空登录 token
|
||||
LoginTokenExpiresAt: nil, // 清空过期时间
|
||||
UpdatedAt: gtime.Now(),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
glog.Warningf(ctx, "标记过期 Token 为待验证码失败,ID=%d: %v", token.Id, err)
|
||||
continue
|
||||
}
|
||||
|
||||
cleanedCount++
|
||||
}
|
||||
|
||||
return cleanedCount, nil
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package camel_oil
|
||||
import (
|
||||
"context"
|
||||
"kami/internal/model"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/errors/gcode"
|
||||
@@ -27,7 +28,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, input *model.CamelOilTokenCreateInput) (tokenId int64, err error) {
|
||||
m := dao.V1CamelOilToken.Ctx(ctx).DB(config.GetDatabaseV1())
|
||||
|
||||
// 获取当前用户信息
|
||||
@@ -44,20 +45,19 @@ func (s *sCamelOil) CreateToken(ctx context.Context, tokenName string, tokenValu
|
||||
}
|
||||
|
||||
// 将 float64 转换为 decimal.Decimal 存储到数据库
|
||||
rechargeLimitAmountDecimal := decimal.NewFromFloat(rechargeLimitAmount)
|
||||
rechargeLimitAmountDecimal := decimal.NewFromFloat(input.RechargeLimitAmount)
|
||||
|
||||
result, err := m.Insert(&do.V1CamelOilToken{
|
||||
UserId: userId,
|
||||
TokenName: tokenName,
|
||||
TokenValue: tokenValue,
|
||||
Phone: phone,
|
||||
Status: int(consts.CamelOilTokenStatusAvailable),
|
||||
Name: input.Name,
|
||||
Phone: input.Phone,
|
||||
Status: int(consts.CamelOilTokenStatusPendingVerification), // 待验证码状态
|
||||
BindCount: 0,
|
||||
TotalBindAmount: decimal.Zero,
|
||||
TotalRechargeAmount: decimal.Zero,
|
||||
RechargeLimitAmount: rechargeLimitAmountDecimal,
|
||||
RechargeLimitCount: rechargeLimitCount,
|
||||
Remark: remark,
|
||||
RechargeLimitCount: input.RechargeLimitCount,
|
||||
Remark: input.Remark,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
@@ -65,7 +65,14 @@ 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, name=%s, phone=%s, 充值金额限制=%.2f, 充值次数限制=%d", tokenId, input.Name, input.Phone, input.RechargeLimitAmount, input.RechargeLimitCount)
|
||||
|
||||
// 异步发送验证码
|
||||
go func() {
|
||||
if err := s.SendVerificationCode(ctx, tokenId, input.Phone); err != nil {
|
||||
glog.Errorf(ctx, "发送验证码失败: tokenId=%d, phone=%s, error=%v", tokenId, input.Phone, err)
|
||||
}
|
||||
}()
|
||||
|
||||
return tokenId, nil
|
||||
}
|
||||
@@ -131,7 +138,7 @@ func (s *sCamelOil) ListTokensWithPagination(ctx context.Context, pageReq common
|
||||
|
||||
// 添加查询条件
|
||||
if tokenName != "" {
|
||||
query = query.WhereLike(dao.V1CamelOilToken.Columns().TokenName, "%"+tokenName+"%")
|
||||
query = query.WhereLike(dao.V1CamelOilToken.Columns().Name, "%"+tokenName+"%")
|
||||
}
|
||||
|
||||
if status > 0 {
|
||||
@@ -163,7 +170,7 @@ func (s *sCamelOil) UpdateToken(ctx context.Context, tokenId int64, tokenName st
|
||||
m := dao.V1CamelOilToken.Ctx(ctx).DB(config.GetDatabaseV1())
|
||||
|
||||
_, err := m.Where(dao.V1CamelOilToken.Columns().Id, tokenId).Update(&do.V1CamelOilToken{
|
||||
TokenName: tokenName,
|
||||
Name: tokenName,
|
||||
Status: status,
|
||||
Remark: remark,
|
||||
UpdatedAt: gtime.Now(),
|
||||
@@ -206,7 +213,7 @@ func (s *sCamelOil) UpdateTokenInfo(ctx context.Context, tokenId int64, tokenNam
|
||||
rechargeLimitAmountDecimal := decimal.NewFromFloat(rechargeLimitAmount)
|
||||
|
||||
_, err = m.Where(dao.V1CamelOilToken.Columns().Id, tokenId).Update(&do.V1CamelOilToken{
|
||||
TokenName: tokenName,
|
||||
Name: tokenName,
|
||||
Phone: phone,
|
||||
Remark: remark,
|
||||
RechargeLimitAmount: rechargeLimitAmountDecimal,
|
||||
@@ -334,8 +341,8 @@ func (s *sCamelOil) BindCardToToken(ctx context.Context, orderId int64, cardNumb
|
||||
}
|
||||
}
|
||||
|
||||
// 4.2 调用绑卡接口(使用选中 Token 的 TokenValue)
|
||||
rechargeErrType, rechargeErr := camel_oil_api.NewClient(ctx).RechargeCard(ctx, selectedToken.TokenValue, selectedToken.Phone, cardPassword)
|
||||
// 4.2 调用绑卡接口(使用选中 Token 的 LoginToken)
|
||||
rechargeErrType, rechargeErr := camel_oil_api.NewClient(ctx).RechargeCard(ctx, selectedToken.LoginToken, selectedToken.Phone, cardPassword)
|
||||
if rechargeErr != nil {
|
||||
switch rechargeErrType {
|
||||
case camel_oil_api.RechargeCardErrorCode:
|
||||
@@ -488,3 +495,108 @@ func (s *sCamelOil) CalculateTotalBindingAmount(ctx context.Context) (totalAmoun
|
||||
|
||||
return result.Total, nil
|
||||
}
|
||||
|
||||
// ====================================================================================
|
||||
// 验证码和登录相关方法
|
||||
// ====================================================================================
|
||||
|
||||
// SendVerificationCode 发送验证码
|
||||
func (s *sCamelOil) SendVerificationCode(ctx context.Context, tokenId int64, phone string) error {
|
||||
client := camel_oil_api.NewClient(ctx)
|
||||
|
||||
success, err := client.SendCaptcha(ctx, phone)
|
||||
if err != nil {
|
||||
// 更新状态为登录失败
|
||||
s.UpdateTokenStatus(ctx, tokenId, consts.CamelOilTokenStatusLoginFailed, "发送验证码失败")
|
||||
return gerror.Wrap(err, "发送验证码失败")
|
||||
}
|
||||
|
||||
if !success {
|
||||
// 更新状态为登录失败
|
||||
s.UpdateTokenStatus(ctx, tokenId, consts.CamelOilTokenStatusLoginFailed, "发送验证码失败")
|
||||
return gerror.New("发送验证码失败")
|
||||
}
|
||||
|
||||
// 更新状态为验证码已发送
|
||||
s.UpdateTokenStatus(ctx, tokenId, consts.CamelOilTokenStatusCodeSent, "验证码已发送")
|
||||
|
||||
glog.Infof(ctx, "验证码发送成功: tokenId=%d, phone=%s", tokenId, phone)
|
||||
return nil
|
||||
}
|
||||
|
||||
// LoginToken 使用验证码登录 Token
|
||||
func (s *sCamelOil) LoginToken(ctx context.Context, input *model.CamelOilTokenLoginInput) (string, error) {
|
||||
// 获取 Token 信息
|
||||
token, err := s.GetTokenInfo(ctx, input.TokenId)
|
||||
if err != nil {
|
||||
return "", gerror.Wrap(err, "查询Token信息失败")
|
||||
}
|
||||
|
||||
if token == nil {
|
||||
return "", gerror.New("Token不存在")
|
||||
}
|
||||
|
||||
// 检查状态是否已登录
|
||||
if token.Status == int(consts.CamelOilTokenStatusAvailable) {
|
||||
return "", gerror.New("Token已登录")
|
||||
}
|
||||
|
||||
client := camel_oil_api.NewClient(ctx)
|
||||
|
||||
// 从 Redis 获取验证码(这里简化处理,直接使用传入的验证码)
|
||||
loginToken, err := client.LoginWithCaptcha(ctx, token.Phone, input.Code)
|
||||
if err != nil {
|
||||
// 更新状态为登录失败
|
||||
s.UpdateTokenStatus(ctx, input.TokenId, consts.CamelOilTokenStatusLoginFailed, "登录失败")
|
||||
return "", gerror.Wrap(err, "登录失败")
|
||||
}
|
||||
|
||||
// 更新 Token 信息
|
||||
m := dao.V1CamelOilToken.Ctx(ctx).DB(config.GetDatabaseV1())
|
||||
_, err = m.Where(dao.V1CamelOilToken.Columns().Id, input.TokenId).Update(&do.V1CamelOilToken{
|
||||
LoginToken: loginToken,
|
||||
LoginTokenExpiresAt: gtime.Now().Add(24 * 3600 * time.Second), // 24小时后过期
|
||||
LastLoginAt: gtime.Now(),
|
||||
Status: int(consts.CamelOilTokenStatusAvailable), // 可用状态
|
||||
UpdatedAt: gtime.Now(),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return "", gerror.Wrap(err, "更新Token登录信息失败")
|
||||
}
|
||||
|
||||
glog.Infof(ctx, "Token登录成功: tokenId=%d, phone=%s", input.TokenId, token.Phone)
|
||||
return loginToken, nil
|
||||
}
|
||||
|
||||
// ResendVerificationCode 重发验证码
|
||||
func (s *sCamelOil) ResendVerificationCode(ctx context.Context, input *model.CamelOilTokenResendCodeInput) error {
|
||||
// 获取 Token 信息
|
||||
token, err := s.GetTokenInfo(ctx, input.TokenId)
|
||||
if err != nil {
|
||||
return gerror.Wrap(err, "查询Token信息失败")
|
||||
}
|
||||
|
||||
if token == nil {
|
||||
return gerror.New("Token不存在")
|
||||
}
|
||||
|
||||
return s.SendVerificationCode(ctx, input.TokenId, token.Phone)
|
||||
}
|
||||
|
||||
// GetTokensForLogin 获取需要登录的 Token(定时任务使用)
|
||||
func (s *sCamelOil) GetTokensForLogin(ctx context.Context) ([]*entity.V1CamelOilToken, error) {
|
||||
m := dao.V1CamelOilToken.Ctx(ctx).DB(config.GetDatabaseV1())
|
||||
|
||||
var tokens []*entity.V1CamelOilToken
|
||||
|
||||
// 获取待验证码状态的 Token
|
||||
err := m.Where(dao.V1CamelOilToken.Columns().Status, int(consts.CamelOilTokenStatusPendingVerification)).
|
||||
Scan(&tokens)
|
||||
|
||||
if err != nil {
|
||||
return nil, gerror.Wrap(err, "查询待登录Token失败")
|
||||
}
|
||||
|
||||
return tokens, nil
|
||||
}
|
||||
|
||||
@@ -8,3 +8,37 @@ type PrefetchOrderResult struct {
|
||||
AccountName string // 账号名称
|
||||
Amount float64 // 订单金额
|
||||
}
|
||||
|
||||
// ====================================================================================
|
||||
// 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:"充值次数限制"`
|
||||
}
|
||||
|
||||
// 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 重发验证码输入结构
|
||||
type CamelOilTokenResendCodeInput struct {
|
||||
TokenId int64 `json:"tokenId" v:"required" description:"Token ID"`
|
||||
}
|
||||
|
||||
@@ -14,10 +14,12 @@ type V1CamelOilToken struct {
|
||||
g.Meta `orm:"table:camel_oil_token, do:true"`
|
||||
Id any // 主键ID
|
||||
UserId any // 用户ID,空字符串表示管理员创建
|
||||
TokenName any // Token名称/标识
|
||||
TokenValue any // Token具体值
|
||||
Name any // 名称
|
||||
Phone any // 绑定的手机号
|
||||
Status any // 状态:1可用 2已禁用 3已过期
|
||||
Status any // 状态:0待验证码 1可用 2已禁用 3已过期 4登录失败
|
||||
LoginToken any // 登录后获取的token
|
||||
LoginTokenExpiresAt *gtime.Time // 登录token过期时间
|
||||
LastLoginAt *gtime.Time // 最后登录时间
|
||||
BindCount any // 已绑定卡密数量
|
||||
TotalBindAmount any // 累计绑定金额
|
||||
LastBindAt *gtime.Time // 最后绑定时间
|
||||
|
||||
@@ -11,21 +11,23 @@ import (
|
||||
|
||||
// V1CamelOilToken is the golang structure for table v1camel_oil_token.
|
||||
type V1CamelOilToken struct {
|
||||
Id int64 `json:"id" orm:"id" description:"主键ID"`
|
||||
UserId string `json:"userId" orm:"user_id" description:"用户ID,空字符串表示管理员创建"`
|
||||
TokenName string `json:"tokenName" orm:"token_name" description:"Token名称/标识"`
|
||||
TokenValue string `json:"tokenValue" orm:"token_value" description:"Token具体值"`
|
||||
Phone string `json:"phone" orm:"phone" description:"绑定的手机号"`
|
||||
Status int `json:"status" orm:"status" description:"状态:1可用 2已禁用 3已过期"`
|
||||
BindCount int `json:"bindCount" orm:"bind_count" description:"已绑定卡密数量"`
|
||||
TotalBindAmount decimal.Decimal `json:"totalBindAmount" orm:"total_bind_amount" description:"累计绑定金额"`
|
||||
LastBindAt *gtime.Time `json:"lastBindAt" orm:"last_bind_at" description:"最后绑定时间"`
|
||||
LastUsedAt *gtime.Time `json:"lastUsedAt" orm:"last_used_at" description:"最后使用时间"`
|
||||
Remark string `json:"remark" orm:"remark" description:"备注"`
|
||||
CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:"创建时间"`
|
||||
UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:"更新时间"`
|
||||
DeletedAt *gtime.Time `json:"deletedAt" orm:"deleted_at" description:"删除时间(软删除)"`
|
||||
RechargeLimitAmount decimal.Decimal `json:"rechargeLimitAmount" orm:"recharge_limit_amount" description:"充值金额限制"`
|
||||
RechargeLimitCount int `json:"rechargeLimitCount" orm:"recharge_limit_count" description:"充值次数限制"`
|
||||
TotalRechargeAmount decimal.Decimal `json:"totalRechargeAmount" orm:"total_recharge_amount" description:"总充值金额"`
|
||||
Id int64 `json:"id" orm:"id" description:"主键ID"`
|
||||
UserId string `json:"userId" orm:"user_id" description:"用户ID,空字符串表示管理员创建"`
|
||||
Name string `json:"name" orm:"name" description:"名称"`
|
||||
Phone string `json:"phone" orm:"phone" description:"绑定的手机号"`
|
||||
Status int `json:"status" orm:"status" description:"状态:0待验证码 1可用 2已禁用 3已过期 4登录失败"`
|
||||
LoginToken string `json:"loginToken" orm:"login_token" description:"登录后获取的token"`
|
||||
LoginTokenExpiresAt *gtime.Time `json:"loginTokenExpiresAt" orm:"login_token_expires_at" description:"登录token过期时间"`
|
||||
LastLoginAt *gtime.Time `json:"lastLoginAt" orm:"last_login_at" description:"最后登录时间"`
|
||||
BindCount int `json:"bindCount" orm:"bind_count" description:"已绑定卡密数量"`
|
||||
TotalBindAmount decimal.Decimal `json:"totalBindAmount" orm:"total_bind_amount" description:"累计绑定金额"`
|
||||
LastBindAt *gtime.Time `json:"lastBindAt" orm:"last_bind_at" description:"最后绑定时间"`
|
||||
LastUsedAt *gtime.Time `json:"lastUsedAt" orm:"last_used_at" description:"最后使用时间"`
|
||||
Remark string `json:"remark" orm:"remark" description:"备注"`
|
||||
CreatedAt *gtime.Time `json:"createdAt" orm:"created_at" description:"创建时间"`
|
||||
UpdatedAt *gtime.Time `json:"updatedAt" orm:"updated_at" description:"更新时间"`
|
||||
DeletedAt *gtime.Time `json:"deletedAt" orm:"deleted_at" description:"删除时间(软删除)"`
|
||||
RechargeLimitAmount decimal.Decimal `json:"rechargeLimitAmount" orm:"recharge_limit_amount" description:"充值金额限制"`
|
||||
RechargeLimitCount int `json:"rechargeLimitCount" orm:"recharge_limit_count" description:"充值次数限制"`
|
||||
TotalRechargeAmount decimal.Decimal `json:"totalRechargeAmount" orm:"total_recharge_amount" description:"总充值金额"`
|
||||
}
|
||||
|
||||
@@ -73,6 +73,15 @@ type (
|
||||
CronCardBindingTask(ctx context.Context) error
|
||||
// CronCleanExpiredPrefetchOrders 清理过期的预拉取订单
|
||||
CronCleanExpiredPrefetchOrders(ctx context.Context) (cleanedCount int, err error)
|
||||
// CronTokenLoginTask Token 自动登录定时任务 - 由cron调度器定期调用
|
||||
// 流程:检查需要发送验证码或重新登录的 Token,自动处理登录流程
|
||||
CronTokenLoginTask(ctx context.Context) error
|
||||
// GetTokensNeedingCode 获取需要发送验证码的 Token(状态为待验证码)
|
||||
GetTokensNeedingCode(ctx context.Context) ([]*entity.V1CamelOilToken, error)
|
||||
// GetFailedLoginTokens 获取登录失败的 Token(状态为登录失败)
|
||||
GetFailedLoginTokens(ctx context.Context) ([]*entity.V1CamelOilToken, error)
|
||||
// CleanExpiredLoginTokens 清理登录 token 过期的 Token
|
||||
CleanExpiredLoginTokens(ctx context.Context) (cleanedCount int, err error)
|
||||
// UpdateOrderStatus 更新订单状态并记录历史
|
||||
UpdateOrderStatus(ctx context.Context, orderId int64, newStatus consts.CamelOilOrderStatus, operationType consts.CamelOilOrderChangeType, rawData string, description string) (err error)
|
||||
// SubmitOrder 提交订单并返回支付宝支付链接
|
||||
@@ -116,7 +125,7 @@ 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, input *model.CamelOilTokenCreateInput) (tokenId int64, err error)
|
||||
// GetTokenInfo 获取 Token 信息
|
||||
GetTokenInfo(ctx context.Context, tokenId int64) (token *entity.V1CamelOilToken, err error)
|
||||
// ListTokens 列出所有可用的 Token
|
||||
@@ -143,6 +152,14 @@ type (
|
||||
GetTokenBindingStats(ctx context.Context, tokenId int64) (bindCount int, totalAmount decimal.Decimal, err error)
|
||||
// CalculateTotalBindingAmount 计算所有 Token 的累计绑定金额
|
||||
CalculateTotalBindingAmount(ctx context.Context) (totalAmount decimal.Decimal, err error)
|
||||
// SendVerificationCode 发送验证码
|
||||
SendVerificationCode(ctx context.Context, tokenId int64, phone string) error
|
||||
// LoginToken 使用验证码登录 Token
|
||||
LoginToken(ctx context.Context, input *model.CamelOilTokenLoginInput) (string, error)
|
||||
// ResendVerificationCode 重发验证码
|
||||
ResendVerificationCode(ctx context.Context, input *model.CamelOilTokenResendCodeInput) error
|
||||
// GetTokensForLogin 获取需要登录的 Token(定时任务使用)
|
||||
GetTokensForLogin(ctx context.Context) ([]*entity.V1CamelOilToken, error)
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user