feat(camel_oil): 支持Token验证码输入与重新发送功能
- 在CamelOil接口中新增InputVerificationCode和ResendVerificationCode方法 - 扩展Token状态,增加验证码验证失败状态 - 调整Token创建逻辑,初始化状态为验证码已发送 - 删除旧的发送验证码和登录方法,改为统一的验证码输入处理 - 增加验证Token状态后验证码登录逻辑,更新登录Token信息 - 实现重新发送验证码接口,限制状态后允许重发 - API和控制层新增输入验证码与重新发送验证码的请求响应结构与处理逻辑 - Token列表及详情响应中新增LoginToken字段返回登录令牌信息
This commit is contained in:
@@ -30,5 +30,7 @@ type ICamelOilV1 interface {
|
||||
ListTokens(ctx context.Context, req *v1.ListTokensReq) (res *v1.ListTokensRes, err error)
|
||||
UpdateToken(ctx context.Context, req *v1.UpdateTokenReq) (res *v1.UpdateTokenRes, err error)
|
||||
DeleteToken(ctx context.Context, req *v1.DeleteTokenReq) (res *v1.DeleteTokenRes, err error)
|
||||
InputVerificationCode(ctx context.Context, req *v1.InputVerificationCodeReq) (res *v1.InputVerificationCodeRes, err error)
|
||||
ResendVerificationCode(ctx context.Context, req *v1.ResendVerificationCodeReq) (res *v1.ResendVerificationCodeRes, err error)
|
||||
ListCardBindingsByToken(ctx context.Context, req *v1.ListCardBindingsByTokenReq) (res *v1.ListCardBindingsByTokenRes, err error)
|
||||
}
|
||||
|
||||
@@ -2,10 +2,10 @@ package v1
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"kami/api/commonApi"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"kami/api/commonApi"
|
||||
"kami/internal/consts"
|
||||
)
|
||||
|
||||
// ====================================================================================
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
// CreateTokenReq 创建 Token 请求
|
||||
type CreateTokenReq struct {
|
||||
g.Meta `path:"/token/create" tags:"JD V2 Token Management" method:"post" summary:"创建 Token"`
|
||||
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:"充值金额限制"`
|
||||
@@ -35,22 +35,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:"名称"`
|
||||
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:"更新时间"`
|
||||
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:"更新时间"`
|
||||
}
|
||||
|
||||
// GetTokenRes 获取 Token 信息响应
|
||||
@@ -67,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
|
||||
Name string `json:"name" description:"名称"`
|
||||
Status consts.CamelOilTokenStatus `json:"status" description:"状态"`
|
||||
Name string `json:"name" description:"Token名称"`
|
||||
Status int `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"`
|
||||
Name string `json:"name" v:"required" description:"名称"`
|
||||
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:"充值金额限制"`
|
||||
@@ -98,6 +98,29 @@ type DeleteTokenRes struct {
|
||||
Message string `json:"message" description:"信息"`
|
||||
}
|
||||
|
||||
// InputVerificationCodeReq 输入验证码请求
|
||||
type InputVerificationCodeReq struct {
|
||||
g.Meta `path:"/token/input-verification-code" tags:"JD V2 Token Management" method:"post" summary:"输入验证码"`
|
||||
TokenId int64 `json:"tokenId" v:"required" description:"Token ID"`
|
||||
Code string `json:"code" v:"required" description:"验证码"`
|
||||
}
|
||||
|
||||
// InputVerificationCodeRes 输入验证码响应
|
||||
type InputVerificationCodeRes struct {
|
||||
Message string `json:"message" description:"信息"`
|
||||
}
|
||||
|
||||
// ResendVerificationCodeReq 重新发送验证码请求
|
||||
type ResendVerificationCodeReq struct {
|
||||
g.Meta `path:"/token/resend-verification-code" tags:"JD V2 Token Management" method:"post" summary:"重新发送验证码"`
|
||||
TokenId int64 `json:"tokenId" v:"required" description:"Token ID"`
|
||||
}
|
||||
|
||||
// ResendVerificationCodeRes 重新发送验证码响应
|
||||
type ResendVerificationCodeRes struct {
|
||||
Message string `json:"message" description:"信息"`
|
||||
}
|
||||
|
||||
// ====================================================================================
|
||||
// 卡密绑定 API 请求/响应结构
|
||||
// ====================================================================================
|
||||
@@ -133,6 +156,7 @@ func (t TokenInfo) MarshalJSON() ([]byte, error) {
|
||||
Id: t.Id,
|
||||
UserId: t.UserId,
|
||||
Name: t.Name,
|
||||
LoginToken: t.LoginToken,
|
||||
Phone: t.Phone,
|
||||
Status: t.Status,
|
||||
BindCount: t.BindCount,
|
||||
@@ -142,7 +166,6 @@ 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,
|
||||
|
||||
@@ -2,6 +2,7 @@ package consts
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"time"
|
||||
)
|
||||
|
||||
// ====================================================================================
|
||||
@@ -89,7 +90,8 @@ const (
|
||||
CamelOilTokenStatusDisabled CamelOilTokenStatus = 2 // 已禁用
|
||||
CamelOilTokenStatusExpired CamelOilTokenStatus = 3 // 已过期
|
||||
CamelOilTokenStatusLoginFailed CamelOilTokenStatus = 4 // 登录失败
|
||||
CamelOilTokenStatusCodeSent CamelOilTokenStatus = 5 // 验证码已发送待登录
|
||||
CamelOilTokenStatusCodeSent CamelOilTokenStatus = 5 // 验证码已发送
|
||||
CamelOilTokenStatusVerificationFailed CamelOilTokenStatus = 6 // 验证码验证失败
|
||||
)
|
||||
|
||||
// CamelOilTokenStatusText Token状态文本映射
|
||||
@@ -100,6 +102,7 @@ var CamelOilTokenStatusText = map[CamelOilTokenStatus]string{
|
||||
CamelOilTokenStatusExpired: "已过期",
|
||||
CamelOilTokenStatusLoginFailed: "登录失败",
|
||||
CamelOilTokenStatusCodeSent: "验证码已发送",
|
||||
CamelOilTokenStatusVerificationFailed: "验证码验证失败",
|
||||
}
|
||||
|
||||
// ====================================================================================
|
||||
@@ -216,7 +219,7 @@ var CamelOilPrefetchOrderChangeTypeText = map[CamelOilPrefetchOrderChangeType]st
|
||||
|
||||
const (
|
||||
// CamelOilPrefetchOrderExpireDuration 预拉取订单过期时间(小时)
|
||||
CamelOilPrefetchOrderExpireDuration = gtime.M * 5
|
||||
CamelOilPrefetchOrderExpireDuration = time.Hour * 24
|
||||
|
||||
// CamelOilPrefetchOrderLockKey Redis中预拉取订单的分布式锁键名前缀
|
||||
CamelOilPrefetchOrderLockKey = "camel_oil_api:prefetch:order:lock:"
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"github.com/gogf/gf/v2/errors/gcode"
|
||||
v1 "kami/api/camel_oil/v1"
|
||||
"kami/internal/errHandler"
|
||||
"kami/internal/model"
|
||||
"kami/internal/service"
|
||||
)
|
||||
|
||||
@@ -16,13 +15,7 @@ func (c *ControllerV1) CreateToken(ctx context.Context, req *v1.CreateTokenReq)
|
||||
err = errHandler.WrapError(ctx, gcode.CodeInternalError, err, "登录校验失败")
|
||||
return
|
||||
}
|
||||
tokenId, err := service.CamelOil().CreateToken(ctx, &model.CamelOilTokenCreateInput{
|
||||
Name: req.Name,
|
||||
Phone: req.Phone,
|
||||
Remark: req.Remark,
|
||||
RechargeLimitAmount: req.RechargeLimitAmount,
|
||||
RechargeLimitCount: req.RechargeLimitCount,
|
||||
})
|
||||
tokenId, err := service.CamelOil().CreateToken(ctx, req.Name, "", req.Phone, req.Remark, req.RechargeLimitAmount, req.RechargeLimitCount)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gcode"
|
||||
v1 "kami/api/camel_oil/v1"
|
||||
"kami/internal/consts"
|
||||
"kami/internal/errHandler"
|
||||
"kami/internal/service"
|
||||
)
|
||||
@@ -25,8 +24,9 @@ func (c *ControllerV1) GetToken(ctx context.Context, req *v1.GetTokenReq) (res *
|
||||
Id: token.Id,
|
||||
UserId: token.UserId,
|
||||
Name: token.Name,
|
||||
LoginToken: token.LoginToken,
|
||||
Phone: token.Phone,
|
||||
Status: consts.CamelOilTokenStatus(token.Status),
|
||||
Status: token.Status,
|
||||
BindCount: token.BindCount,
|
||||
TotalBindAmount: token.TotalBindAmount.InexactFloat64(),
|
||||
TotalRechargeAmount: token.TotalRechargeAmount.InexactFloat64(),
|
||||
@@ -34,7 +34,6 @@ 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,
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package camel_oil
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gcode"
|
||||
v1 "kami/api/camel_oil/v1"
|
||||
"kami/internal/errHandler"
|
||||
"kami/internal/model"
|
||||
"kami/internal/service"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) InputVerificationCode(ctx context.Context, req *v1.InputVerificationCodeReq) (res *v1.InputVerificationCodeRes, err error) {
|
||||
// 登录验证
|
||||
_, err = service.SysAuth().LoginOnlyLogin(ctx)
|
||||
if err != nil {
|
||||
err = errHandler.WrapError(ctx, gcode.CodeInternalError, err, "登录校验失败")
|
||||
return
|
||||
}
|
||||
|
||||
// 构建输入结构
|
||||
input := &model.CamelOilTokenLoginInput{
|
||||
TokenId: req.TokenId,
|
||||
Code: req.Code,
|
||||
}
|
||||
|
||||
// 调用业务逻辑
|
||||
_, err = service.CamelOil().InputVerificationCode(ctx, input)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &v1.InputVerificationCodeRes{
|
||||
Message: "验证码验证成功",
|
||||
}, nil
|
||||
}
|
||||
@@ -25,7 +25,7 @@ func (c *ControllerV1) ListCardBindingsByToken(ctx context.Context, req *v1.List
|
||||
bindingInfos = append(bindingInfos, v1.CardBindingInfo{
|
||||
Id: binding.Id,
|
||||
TokenId: binding.TokenId,
|
||||
TokenName: "", // 需要通过查询获取,这里暂时留空
|
||||
Name: "", // 需要通过查询获取,这里暂时留空
|
||||
OrderId: binding.OrderId,
|
||||
CardNumber: binding.CardNumber,
|
||||
CardPassword: binding.CardPassword,
|
||||
|
||||
@@ -6,7 +6,6 @@ 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"
|
||||
)
|
||||
@@ -21,7 +20,7 @@ func (c *ControllerV1) ListTokens(ctx context.Context, req *v1.ListTokensReq) (r
|
||||
// 调用服务层方法,它会根据当前用户类型自动筛选数据
|
||||
// 管理员:可以查看所有token(包括用户创建和管理员创建的)
|
||||
// 普通用户:只能查看自己创建的token
|
||||
tokens, total, err := service.CamelOil().ListTokensWithPagination(ctx, req.CommonPageReq, req.Name, int(req.Status))
|
||||
tokens, total, err := service.CamelOil().ListTokensWithPagination(ctx, req.CommonPageReq, req.Name, req.Status)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -31,8 +30,9 @@ func (c *ControllerV1) ListTokens(ctx context.Context, req *v1.ListTokensReq) (r
|
||||
Id: token.Id,
|
||||
UserId: token.UserId,
|
||||
Name: token.Name,
|
||||
LoginToken: token.LoginToken,
|
||||
Phone: token.Phone,
|
||||
Status: consts.CamelOilTokenStatus(token.Status),
|
||||
Status: token.Status,
|
||||
BindCount: token.BindCount,
|
||||
TotalBindAmount: token.TotalBindAmount.InexactFloat64(),
|
||||
TotalRechargeAmount: token.TotalRechargeAmount.InexactFloat64(),
|
||||
@@ -40,7 +40,6 @@ 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,
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package camel_oil
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gcode"
|
||||
v1 "kami/api/camel_oil/v1"
|
||||
"kami/internal/errHandler"
|
||||
"kami/internal/service"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) ResendVerificationCode(ctx context.Context, req *v1.ResendVerificationCodeReq) (res *v1.ResendVerificationCodeRes, err error) {
|
||||
_, err = service.SysAuth().LoginOnlyLogin(ctx)
|
||||
if err != nil {
|
||||
err = errHandler.WrapError(ctx, gcode.CodeInternalError, err, "登录校验失败")
|
||||
return
|
||||
}
|
||||
|
||||
err = service.CamelOil().ResendVerificationCode(ctx, req.TokenId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &v1.ResendVerificationCodeRes{
|
||||
Message: "验证码重新发送成功",
|
||||
}, nil
|
||||
}
|
||||
@@ -28,7 +28,7 @@ import (
|
||||
// ====================================================================================
|
||||
|
||||
// CreateToken 创建 Token
|
||||
func (s *sCamelOil) CreateToken(ctx context.Context, input *model.CamelOilTokenCreateInput) (tokenId int64, err error) {
|
||||
func (s *sCamelOil) CreateToken(ctx context.Context, tokenName string, tokenValue string, phone string, remark string, rechargeLimitAmount float64, rechargeLimitCount int) (tokenId int64, err error) {
|
||||
m := dao.V1CamelOilToken.Ctx(ctx).DB(config.GetDatabaseV1())
|
||||
|
||||
// 获取当前用户信息
|
||||
@@ -45,19 +45,19 @@ func (s *sCamelOil) CreateToken(ctx context.Context, input *model.CamelOilTokenC
|
||||
}
|
||||
|
||||
// 将 float64 转换为 decimal.Decimal 存储到数据库
|
||||
rechargeLimitAmountDecimal := decimal.NewFromFloat(input.RechargeLimitAmount)
|
||||
rechargeLimitAmountDecimal := decimal.NewFromFloat(rechargeLimitAmount)
|
||||
|
||||
result, err := m.Insert(&do.V1CamelOilToken{
|
||||
UserId: userId,
|
||||
Name: input.Name,
|
||||
Phone: input.Phone,
|
||||
Status: int(consts.CamelOilTokenStatusPendingVerification), // 待验证码状态
|
||||
Name: tokenName,
|
||||
Phone: phone,
|
||||
Status: int(consts.CamelOilTokenStatusCodeSent),
|
||||
BindCount: 0,
|
||||
TotalBindAmount: decimal.Zero,
|
||||
TotalRechargeAmount: decimal.Zero,
|
||||
RechargeLimitAmount: rechargeLimitAmountDecimal,
|
||||
RechargeLimitCount: input.RechargeLimitCount,
|
||||
Remark: input.Remark,
|
||||
RechargeLimitCount: rechargeLimitCount,
|
||||
Remark: remark,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
@@ -65,14 +65,7 @@ func (s *sCamelOil) CreateToken(ctx context.Context, input *model.CamelOilTokenC
|
||||
}
|
||||
|
||||
tokenId, _ = result.LastInsertId()
|
||||
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)
|
||||
}
|
||||
}()
|
||||
glog.Infof(ctx, "Token创建成功: tokenId=%d, tokenName=%s, phone=%s, 充值金额限制=%.2f, 充值次数限制=%d", tokenId, tokenName, phone, rechargeLimitAmount, rechargeLimitCount)
|
||||
|
||||
return tokenId, nil
|
||||
}
|
||||
@@ -496,38 +489,10 @@ 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) {
|
||||
// InputVerificationCode 输入验证码
|
||||
func (s *sCamelOil) InputVerificationCode(ctx context.Context, req *model.CamelOilTokenLoginInput) (string, error) {
|
||||
// 获取 Token 信息
|
||||
token, err := s.GetTokenInfo(ctx, input.TokenId)
|
||||
token, err := s.GetTokenInfo(ctx, req.TokenId)
|
||||
if err != nil {
|
||||
return "", gerror.Wrap(err, "查询Token信息失败")
|
||||
}
|
||||
@@ -536,24 +501,24 @@ func (s *sCamelOil) LoginToken(ctx context.Context, input *model.CamelOilTokenLo
|
||||
return "", gerror.New("Token不存在")
|
||||
}
|
||||
|
||||
// 检查状态是否已登录
|
||||
if token.Status == int(consts.CamelOilTokenStatusAvailable) {
|
||||
return "", gerror.New("Token已登录")
|
||||
// 检查 Token 状态,只有验证码已发送状态的 Token 才能输入验证码
|
||||
if token.Status != int(consts.CamelOilTokenStatusCodeSent) {
|
||||
return "", gerror.New("Token状态不允许输入验证码")
|
||||
}
|
||||
|
||||
client := camel_oil_api.NewClient(ctx)
|
||||
|
||||
// 从 Redis 获取验证码(这里简化处理,直接使用传入的验证码)
|
||||
loginToken, err := client.LoginWithCaptcha(ctx, token.Phone, input.Code)
|
||||
// 使用验证码登录
|
||||
loginToken, err := client.LoginWithCaptcha(ctx, token.Phone, req.Code)
|
||||
if err != nil {
|
||||
// 更新状态为登录失败
|
||||
s.UpdateTokenStatus(ctx, input.TokenId, consts.CamelOilTokenStatusLoginFailed, "登录失败")
|
||||
return "", gerror.Wrap(err, "登录失败")
|
||||
// 更新状态为验证码验证失败
|
||||
s.UpdateTokenStatus(ctx, req.TokenId, consts.CamelOilTokenStatusVerificationFailed, "验证码验证失败")
|
||||
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{
|
||||
_, err = m.Where(dao.V1CamelOilToken.Columns().Id, req.TokenId).Update(&do.V1CamelOilToken{
|
||||
LoginToken: loginToken,
|
||||
LoginTokenExpiresAt: gtime.Now().Add(24 * 3600 * time.Second), // 24小时后过期
|
||||
LastLoginAt: gtime.Now(),
|
||||
@@ -565,14 +530,14 @@ func (s *sCamelOil) LoginToken(ctx context.Context, input *model.CamelOilTokenLo
|
||||
return "", gerror.Wrap(err, "更新Token登录信息失败")
|
||||
}
|
||||
|
||||
glog.Infof(ctx, "Token登录成功: tokenId=%d, phone=%s", input.TokenId, token.Phone)
|
||||
glog.Infof(ctx, "验证码验证成功,Token登录: tokenId=%d, phone=%s", req.TokenId, token.Phone)
|
||||
return loginToken, nil
|
||||
}
|
||||
|
||||
// ResendVerificationCode 重发验证码
|
||||
func (s *sCamelOil) ResendVerificationCode(ctx context.Context, input *model.CamelOilTokenResendCodeInput) error {
|
||||
// ResendVerificationCode 重新发送验证码
|
||||
func (s *sCamelOil) ResendVerificationCode(ctx context.Context, tokenId int64) error {
|
||||
// 获取 Token 信息
|
||||
token, err := s.GetTokenInfo(ctx, input.TokenId)
|
||||
token, err := s.GetTokenInfo(ctx, tokenId)
|
||||
if err != nil {
|
||||
return gerror.Wrap(err, "查询Token信息失败")
|
||||
}
|
||||
@@ -581,22 +546,42 @@ func (s *sCamelOil) ResendVerificationCode(ctx context.Context, input *model.Cam
|
||||
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失败")
|
||||
// 检查 Token 状态,只有特定状态的 Token 才能重新发送验证码
|
||||
allowedStatuses := []int{
|
||||
int(consts.CamelOilTokenStatusPendingVerification), // 待验证码
|
||||
int(consts.CamelOilTokenStatusCodeSent), // 验证码已发送
|
||||
int(consts.CamelOilTokenStatusVerificationFailed), // 验证码验证失败
|
||||
int(consts.CamelOilTokenStatusLoginFailed), // 登录失败
|
||||
}
|
||||
|
||||
return tokens, nil
|
||||
statusAllowed := false
|
||||
for _, status := range allowedStatuses {
|
||||
if token.Status == status {
|
||||
statusAllowed = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !statusAllowed {
|
||||
return gerror.New("Token状态不允许重新发送验证码")
|
||||
}
|
||||
|
||||
client := camel_oil_api.NewClient(ctx)
|
||||
|
||||
// 发送验证码
|
||||
_, err = client.SendCaptcha(ctx, token.Phone)
|
||||
if err != nil {
|
||||
// 更新状态为登录失败
|
||||
s.UpdateTokenStatus(ctx, tokenId, consts.CamelOilTokenStatusLoginFailed, "发送验证码失败")
|
||||
return gerror.Wrap(err, "发送验证码失败")
|
||||
}
|
||||
|
||||
// 更新 Token 状态为验证码已发送
|
||||
err = s.UpdateTokenStatus(ctx, tokenId, consts.CamelOilTokenStatusCodeSent, "重新发送验证码成功")
|
||||
if err != nil {
|
||||
return gerror.Wrap(err, "更新Token状态失败")
|
||||
}
|
||||
|
||||
glog.Infof(ctx, "验证码重新发送成功: tokenId=%d, phone=%s", tokenId, token.Phone)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -42,3 +42,37 @@ type CamelOilTokenLoginInput struct {
|
||||
type CamelOilTokenResendCodeInput 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:"充值次数限制"`
|
||||
}
|
||||
|
||||
// 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"`
|
||||
}
|
||||
|
||||
@@ -73,15 +73,6 @@ 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 提交订单并返回支付宝支付链接
|
||||
@@ -125,7 +116,7 @@ type (
|
||||
// GetCamelOilSettings 获取骆驼模块设置的辅助函数
|
||||
GetCamelOilSettings(ctx context.Context) (*v1.CamelOilSettings, error)
|
||||
// CreateToken 创建 Token
|
||||
CreateToken(ctx context.Context, input *model.CamelOilTokenCreateInput) (tokenId int64, err error)
|
||||
CreateToken(ctx context.Context, tokenName string, tokenValue string, phone string, remark string, rechargeLimitAmount float64, rechargeLimitCount int) (tokenId int64, err error)
|
||||
// GetTokenInfo 获取 Token 信息
|
||||
GetTokenInfo(ctx context.Context, tokenId int64) (token *entity.V1CamelOilToken, err error)
|
||||
// ListTokens 列出所有可用的 Token
|
||||
@@ -152,14 +143,10 @@ 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)
|
||||
// InputVerificationCode 输入验证码
|
||||
InputVerificationCode(ctx context.Context, req *model.CamelOilTokenLoginInput) (string, error)
|
||||
// ResendVerificationCode 重新发送验证码
|
||||
ResendVerificationCode(ctx context.Context, tokenId int64) error
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user