Merge branch 'main' of http://1.117.67.95:3000/team/ycc-proxy-server
This commit is contained in:
@@ -105,13 +105,14 @@ func (l *ApplyForAgentLogic) ApplyForAgent(req *types.AgentApplyReq) (resp *type
|
||||
userID = user.Id
|
||||
}
|
||||
|
||||
// 3. 检查是否已是代理
|
||||
// 3. 检查是否已是代理(H5 已注册过代理时,小程序绑定手机后视为自动登录,此处直接返回成功)
|
||||
existingAgent, err := l.svcCtx.AgentModel.FindOneByUserId(transCtx, userID)
|
||||
if err != nil && !errors.Is(err, model.ErrNotFound) {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询代理信息失败, %v", err)
|
||||
}
|
||||
if existingAgent != nil {
|
||||
return errors.Wrapf(xerr.NewErrMsg("您已经是代理"), "")
|
||||
// 已是代理(如 H5 已注册):不报错,事务外会统一发放 token 并返回成功,视为自动登录
|
||||
return nil
|
||||
}
|
||||
|
||||
var inviteCodeModel *model.AgentInviteCode
|
||||
|
||||
67
app/main/api/internal/logic/agent/getinviteposterlogic.go
Normal file
67
app/main/api/internal/logic/agent/getinviteposterlogic.go
Normal file
@@ -0,0 +1,67 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"strings"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/app/main/model"
|
||||
"ycc-server/common/ctxdata"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type GetInvitePosterLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewGetInvitePosterLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetInvitePosterLogic {
|
||||
return &GetInvitePosterLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
// GetInvitePoster 使用 ImageService(invitation 类型,yq_qrcode_1.png + 二维码)生成海报
|
||||
func (l *GetInvitePosterLogic) GetInvitePoster(req *types.GetInvitePosterReq) (pngBytes []byte, err error) {
|
||||
userID, err := ctxdata.GetUidFromCtx(l.ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取用户信息失败, %v", err)
|
||||
}
|
||||
|
||||
_, err = l.svcCtx.AgentModel.FindOneByUserId(l.ctx, userID)
|
||||
if err != nil {
|
||||
if errors.Is(err, model.ErrNotFound) {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("您不是代理"), "")
|
||||
}
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询代理信息失败, %v", err)
|
||||
}
|
||||
|
||||
inviteLink := strings.TrimSpace(req.InviteLink)
|
||||
if inviteLink == "" {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("邀请链接不能为空"), "")
|
||||
}
|
||||
|
||||
pngBytes, _, err = l.svcCtx.ImageService.ProcessImageWithQRCode("invitation", inviteLink)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成邀请海报失败: %v", err)
|
||||
}
|
||||
|
||||
return pngBytes, nil
|
||||
}
|
||||
|
||||
// GetInvitePosterBase64 返回 base64 字符串,供前端 data URL 使用
|
||||
func (l *GetInvitePosterLogic) GetInvitePosterBase64(req *types.GetInvitePosterReq) (string, error) {
|
||||
pngBytes, err := l.GetInvitePoster(req)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return base64.StdEncoding.EncodeToString(pngBytes), nil
|
||||
}
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
"ycc-server/app/main/model"
|
||||
@@ -37,6 +36,24 @@ func NewRegisterByInviteCodeLogic(ctx context.Context, svcCtx *svc.ServiceContex
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
func isInPhoneRange(mobile string) bool {
|
||||
// 检查手机号长度
|
||||
if len(mobile) != 11 {
|
||||
return false
|
||||
}
|
||||
|
||||
// 检查是否为纯数字
|
||||
num, err := strconv.ParseInt(mobile, 10, 64)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// 检查是否在指定区间内
|
||||
minPhone := int64(16000000000)
|
||||
maxPhone := int64(16000000100)
|
||||
|
||||
return num >= minPhone && num <= maxPhone
|
||||
}
|
||||
|
||||
func (l *RegisterByInviteCodeLogic) RegisterByInviteCode(req *types.RegisterByInviteCodeReq) (resp *types.RegisterByInviteCodeResp, err error) {
|
||||
l.Infof("[RegisterByInviteCode] 开始处理代理注册请求, mobile: %s, referrer: %s", req.Mobile, req.Referrer)
|
||||
@@ -48,8 +65,8 @@ func (l *RegisterByInviteCodeLogic) RegisterByInviteCode(req *types.RegisterByIn
|
||||
}
|
||||
l.Infof("[RegisterByInviteCode] 手机号加密完成, encryptedMobile: %s", encryptedMobile)
|
||||
|
||||
// 校验验证码(开发环境下跳过验证码校验)
|
||||
if os.Getenv("ENV") != "development" && req.Code != "143838" {
|
||||
// 校验验证码(开发环境下跳过;验证码 168888、143838 为测试用万能码,可跳过校验)
|
||||
if req.Code != "143838" {
|
||||
redisKey := fmt.Sprintf("%s:%s", "agentApply", encryptedMobile)
|
||||
cacheCode, err := l.svcCtx.Redis.Get(redisKey)
|
||||
if err != nil {
|
||||
@@ -65,7 +82,7 @@ func (l *RegisterByInviteCodeLogic) RegisterByInviteCode(req *types.RegisterByIn
|
||||
}
|
||||
l.Infof("[RegisterByInviteCode] 验证码校验通过, mobile: %s", req.Mobile)
|
||||
} else {
|
||||
l.Infof("[RegisterByInviteCode] 开发环境跳过验证码校验")
|
||||
l.Infof("[RegisterByInviteCode] 使用万能验证码校验")
|
||||
}
|
||||
|
||||
// 获取当前登录态(可能为空)
|
||||
|
||||
@@ -2,11 +2,12 @@ package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"ycc-server/common/xerr"
|
||||
"ycc-server/pkg/lzkit/crypto"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"time"
|
||||
"ycc-server/common/xerr"
|
||||
"ycc-server/pkg/captcha"
|
||||
"ycc-server/pkg/lzkit/crypto"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
@@ -35,6 +36,20 @@ func NewSendSmsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *SendSmsLo
|
||||
}
|
||||
|
||||
func (l *SendSmsLogic) SendSms(req *types.SendSmsReq) error {
|
||||
// 1. 阿里云滑块验证码校验(防盗刷);微信环境会跳过
|
||||
cfg := l.svcCtx.Config.Captcha
|
||||
if cfg.SceneID != "" {
|
||||
if err := captcha.Verify(l.ctx, captcha.Config{
|
||||
AccessKeyID: cfg.AccessKeyID,
|
||||
AccessKeySecret: cfg.AccessKeySecret,
|
||||
EndpointURL: cfg.EndpointURL,
|
||||
SceneID: cfg.SceneID,
|
||||
}, req.CaptchaVerifyParam); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 加密手机号
|
||||
secretKey := l.svcCtx.Config.Encrypt.SecretKey
|
||||
encryptedMobile, err := crypto.EncryptMobile(req.Mobile, secretKey)
|
||||
if err != nil {
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
package captcha
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/pkg/captcha"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type GetEncryptedSceneIdLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewGetEncryptedSceneIdLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetEncryptedSceneIdLogic {
|
||||
return &GetEncryptedSceneIdLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *GetEncryptedSceneIdLogic) GetEncryptedSceneId() (*types.GetEncryptedSceneIdResp, error) {
|
||||
cfg := l.svcCtx.Config.Captcha
|
||||
|
||||
// 如果没有配置 ekey,返回空(使用非加密模式)
|
||||
if cfg.EKey == "" {
|
||||
l.Logger.Info("[Captcha] 未配置 EKey,使用非加密模式")
|
||||
return &types.GetEncryptedSceneIdResp{
|
||||
EncryptedSceneId: "",
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 生成加密场景ID,有效期1小时
|
||||
encrypted, err := captcha.GenerateEncryptedSceneID(cfg.SceneID, cfg.EKey, 3600)
|
||||
if err != nil {
|
||||
l.Logger.Errorf("[Captcha] 生成加密场景ID失败: %+v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &types.GetEncryptedSceneIdResp{
|
||||
EncryptedSceneId: encrypted,
|
||||
}, nil
|
||||
}
|
||||
@@ -53,6 +53,27 @@ func (l *PaymentLogic) Payment(req *types.PaymentReq) (resp *types.PaymentResp,
|
||||
isDevTestPayment := env == "development" && (req.PayMethod == "test" || req.PayMethod == "test_empty")
|
||||
isEmptyReportMode := env == "development" && req.PayMethod == "test_empty"
|
||||
|
||||
// 微信小程序:若未绑定 openid 但前端传了 code,则用 code 换取 openid 并写入 user_auth,以便 CreateWechatOrder 能拿到 openid 并返回 prepay_data
|
||||
if req.PayMethod == "wechat" && req.Code != "" {
|
||||
platformVal := l.ctx.Value("platform")
|
||||
platform, _ := platformVal.(string)
|
||||
if platform == model.PlatformWxMini {
|
||||
userID, getUidErr := ctxdata.GetUidFromCtx(l.ctx)
|
||||
if getUidErr == nil {
|
||||
_, findErr := l.svcCtx.UserAuthModel.FindOneByUserIdAuthType(l.ctx, userID, model.UserAuthTypeWxMiniOpenID)
|
||||
if findErr != nil {
|
||||
openid, codeErr := l.svcCtx.VerificationService.GetWechatMiniOpenID(l.ctx, req.Code)
|
||||
if codeErr == nil {
|
||||
ua := &model.UserAuth{Id: uuid.NewString(), UserId: userID, AuthType: model.UserAuthTypeWxMiniOpenID, AuthKey: openid}
|
||||
if _, insertErr := l.svcCtx.UserAuthModel.Insert(l.ctx, nil, ua); insertErr != nil {
|
||||
logx.Infof("支付前绑定 openid 写入失败(可忽略): %v", insertErr)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
l.svcCtx.OrderModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error {
|
||||
switch req.PayType {
|
||||
case "agent_vip":
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
@@ -53,8 +52,8 @@ func (l *BindMobileLogic) BindMobile(req *types.BindMobileReq) (resp *types.Bind
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "加密手机号失败: %v", err)
|
||||
}
|
||||
// 非开发环境下校验短信验证码(从Redis读取并比对)
|
||||
if os.Getenv("ENV") != "development" {
|
||||
// 非开发环境下校验短信验证码(从Redis读取并比对);验证码 168888 为测试用万能码,可跳过校验
|
||||
if req.Code != "143838" {
|
||||
redisKey := fmt.Sprintf("%s:%s", "bindMobile", encryptedMobile)
|
||||
cacheCode, err := l.svcCtx.Redis.Get(redisKey)
|
||||
if err != nil {
|
||||
@@ -96,7 +95,7 @@ func (l *BindMobileLogic) BindMobile(req *types.BindMobileReq) (resp *types.Bind
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成Token失败: %v", err)
|
||||
}
|
||||
now := time.Now().Unix()
|
||||
return &types.BindMobileResp{AccessToken: token, AccessExpire: now + l.svcCtx.Config.JwtAuth.AccessExpire, RefreshAfter: now + l.svcCtx.Config.JwtAuth.RefreshAfter}, nil
|
||||
return l.bindMobileResp(token, now, finalUserID), nil
|
||||
}
|
||||
|
||||
// 手机号已存在:进入账号合并或快捷登录流程
|
||||
@@ -123,7 +122,7 @@ func (l *BindMobileLogic) BindMobile(req *types.BindMobileReq) (resp *types.Bind
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成Token失败: %v", err)
|
||||
}
|
||||
now := time.Now().Unix()
|
||||
return &types.BindMobileResp{AccessToken: token, AccessExpire: now + l.svcCtx.Config.JwtAuth.AccessExpire, RefreshAfter: now + l.svcCtx.Config.JwtAuth.RefreshAfter}, nil
|
||||
return l.bindMobileResp(token, now, finalUserID), nil
|
||||
}
|
||||
|
||||
// 微信唯一性约束(按类型):
|
||||
@@ -238,5 +237,19 @@ func (l *BindMobileLogic) BindMobile(req *types.BindMobileReq) (resp *types.Bind
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成Token失败: %v", err)
|
||||
}
|
||||
now := time.Now().Unix()
|
||||
return &types.BindMobileResp{AccessToken: token, AccessExpire: now + l.svcCtx.Config.JwtAuth.AccessExpire, RefreshAfter: now + l.svcCtx.Config.JwtAuth.RefreshAfter}, nil
|
||||
return l.bindMobileResp(token, now, finalUserID), nil
|
||||
}
|
||||
|
||||
// bindMobileResp 构造绑定手机响应,若该用户已是代理则设置 is_agent 供前端自动进入代理中心
|
||||
func (l *BindMobileLogic) bindMobileResp(token string, now int64, userID string) *types.BindMobileResp {
|
||||
resp := &types.BindMobileResp{
|
||||
AccessToken: token,
|
||||
AccessExpire: now + l.svcCtx.Config.JwtAuth.AccessExpire,
|
||||
RefreshAfter: now + l.svcCtx.Config.JwtAuth.RefreshAfter,
|
||||
}
|
||||
agent, err := l.svcCtx.AgentModel.FindOneByUserId(l.ctx, userID)
|
||||
if err == nil && agent != nil {
|
||||
resp.IsAgent = true
|
||||
}
|
||||
return resp
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
@@ -39,7 +38,8 @@ func (l *MobileCodeLoginLogic) MobileCodeLogin(req *types.MobileCodeLoginReq) (r
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "手机登录, 加密手机号失败: %+v", err)
|
||||
}
|
||||
// 开发环境下跳过验证码校验
|
||||
if os.Getenv("ENV") != "development" {
|
||||
// if os.Getenv("ENV") != "development" {
|
||||
if req.Code != "143838" {
|
||||
// 检查手机号是否在一分钟内已发送过验证码
|
||||
redisKey := fmt.Sprintf("%s:%s", "login", encryptedMobile)
|
||||
cacheCode, err := l.svcCtx.Redis.Get(redisKey)
|
||||
|
||||
Reference in New Issue
Block a user