v1.1
This commit is contained in:
@@ -11,6 +11,7 @@ import (
|
||||
"ycc-server/common/globalkey"
|
||||
"ycc-server/pkg/lzkit/lzUtils"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
@@ -205,20 +206,21 @@ func (s *AgentService) calculatePriceCost(setPrice, priceThreshold, priceFeeRate
|
||||
// giveAgentCommission 发放代理佣金
|
||||
// orderPrice: 订单单价,用于判断是否需要冻结
|
||||
// 返回:freezeTaskId(如果有冻结任务),error
|
||||
func (s *AgentService) giveAgentCommission(ctx context.Context, session sqlx.Session, agentId, orderId, productId int64, amount float64, orderPrice float64) (int64, error) {
|
||||
func (s *AgentService) giveAgentCommission(ctx context.Context, session sqlx.Session, agentId, orderId, productId string, amount float64, orderPrice float64) (string, error) {
|
||||
// 1. 创建佣金记录
|
||||
commission := &model.AgentCommission{
|
||||
Id: uuid.NewString(),
|
||||
AgentId: agentId,
|
||||
OrderId: orderId,
|
||||
ProductId: productId,
|
||||
Amount: amount,
|
||||
Status: 1, // 已发放
|
||||
}
|
||||
commissionResult, err := s.AgentCommissionModel.Insert(ctx, session, commission)
|
||||
_, err := s.AgentCommissionModel.Insert(ctx, session, commission)
|
||||
if err != nil {
|
||||
return 0, errors.Wrapf(err, "创建佣金记录失败")
|
||||
return "", errors.Wrapf(err, "创建佣金记录失败")
|
||||
}
|
||||
commissionId, _ := commissionResult.LastInsertId()
|
||||
commissionId := commission.Id
|
||||
|
||||
// 2. 判断是否需要冻结
|
||||
// 2.1 获取冻结阈值配置(默认100元)
|
||||
@@ -231,7 +233,7 @@ func (s *AgentService) giveAgentCommission(ctx context.Context, session sqlx.Ses
|
||||
|
||||
// 2.2 判断订单单价是否达到冻结阈值
|
||||
freezeAmount := 0.0
|
||||
var freezeTaskId int64 = 0
|
||||
var freezeTaskId string = ""
|
||||
if orderPrice >= freezeThreshold {
|
||||
// 2.3 获取冻结比例配置(默认10%)
|
||||
freezeRatio, err := s.getConfigFloat(ctx, "commission_freeze_ratio")
|
||||
@@ -266,6 +268,7 @@ func (s *AgentService) giveAgentCommission(ctx context.Context, session sqlx.Ses
|
||||
|
||||
// 创建冻结任务记录
|
||||
freezeTask := &model.AgentFreezeTask{
|
||||
Id: uuid.NewString(),
|
||||
AgentId: agentId,
|
||||
OrderId: orderId,
|
||||
CommissionId: commissionId,
|
||||
@@ -277,18 +280,18 @@ func (s *AgentService) giveAgentCommission(ctx context.Context, session sqlx.Ses
|
||||
UnfreezeTime: unfreezeTime,
|
||||
Remark: lzUtils.StringToNullString(fmt.Sprintf("订单单价%.2f元,冻结比例%.2f%%,解冻天数%d天", orderPrice, freezeRatio*100, unfreezeDays)),
|
||||
}
|
||||
freezeTaskResult, err := s.AgentFreezeTaskModel.Insert(ctx, session, freezeTask)
|
||||
_, err = s.AgentFreezeTaskModel.Insert(ctx, session, freezeTask)
|
||||
if err != nil {
|
||||
return 0, errors.Wrapf(err, "创建冻结任务失败")
|
||||
return "", errors.Wrapf(err, "创建冻结任务失败")
|
||||
}
|
||||
freezeTaskId, _ = freezeTaskResult.LastInsertId()
|
||||
freezeTaskId = freezeTask.Id
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 更新钱包余额
|
||||
wallet, err := s.AgentWalletModel.FindOneByAgentId(ctx, agentId)
|
||||
if err != nil {
|
||||
return 0, errors.Wrapf(err, "查询钱包失败, agentId: %d", agentId)
|
||||
return "", errors.Wrapf(err, "查询钱包失败, agentId: %s", agentId)
|
||||
}
|
||||
|
||||
// 实际到账金额 = 佣金金额 - 冻结金额
|
||||
@@ -298,14 +301,14 @@ func (s *AgentService) giveAgentCommission(ctx context.Context, session sqlx.Ses
|
||||
wallet.FrozenBalance += freezeAmount
|
||||
wallet.TotalEarnings += amount // 累计收益包含冻结部分
|
||||
if err := s.AgentWalletModel.UpdateWithVersion(ctx, session, wallet); err != nil {
|
||||
return 0, errors.Wrapf(err, "更新钱包失败")
|
||||
return "", errors.Wrapf(err, "更新钱包失败")
|
||||
}
|
||||
|
||||
return freezeTaskId, nil
|
||||
}
|
||||
|
||||
// distributeLevelBonus 分配等级加成返佣给上级链
|
||||
func (s *AgentService) distributeLevelBonus(ctx context.Context, session sqlx.Session, agent *model.Agent, orderId, productId int64, levelBonus float64, levelBonusInt int64) error {
|
||||
func (s *AgentService) distributeLevelBonus(ctx context.Context, session sqlx.Session, agent *model.Agent, orderId, productId string, levelBonus float64, levelBonusInt int64) error {
|
||||
// 钻石代理:等级加成为0,无返佣分配
|
||||
if agent.Level == 3 {
|
||||
return nil
|
||||
@@ -377,7 +380,7 @@ func (s *AgentService) distributeLevelBonus(ctx context.Context, session sqlx.Se
|
||||
// 注意:findDiamondParent 和 findGoldParent 会自动跳过中间的所有普通代理,
|
||||
//
|
||||
// 直接向上查找到第一个钻石或黄金代理
|
||||
func (s *AgentService) distributeNormalAgentBonus(ctx context.Context, session sqlx.Session, agent *model.Agent, orderId, productId int64, amount float64, levelBonusInt int64) error {
|
||||
func (s *AgentService) distributeNormalAgentBonus(ctx context.Context, session sqlx.Session, agent *model.Agent, orderId, productId string, amount float64, levelBonusInt int64) error {
|
||||
// 1. 查找直接上级
|
||||
parent, err := s.findDirectParent(ctx, agent.Id)
|
||||
if err != nil && !errors.Is(err, model.ErrNotFound) {
|
||||
@@ -626,18 +629,19 @@ func (s *AgentService) getRebateConfigFloat(ctx context.Context, configKey strin
|
||||
}
|
||||
|
||||
// giveRebate 发放返佣
|
||||
func (s *AgentService) giveRebate(ctx context.Context, session sqlx.Session, agentId, sourceAgentId, orderId, productId int64, amount float64, levelBonus int64, rebateType int64) error {
|
||||
// 1. 创建返佣记录
|
||||
rebate := &model.AgentRebate{
|
||||
AgentId: agentId,
|
||||
SourceAgentId: sourceAgentId,
|
||||
OrderId: orderId,
|
||||
ProductId: productId,
|
||||
RebateType: rebateType,
|
||||
LevelBonus: float64(levelBonus), // 等级加成金额
|
||||
RebateAmount: amount,
|
||||
Status: 1, // 已发放
|
||||
}
|
||||
func (s *AgentService) giveRebate(ctx context.Context, session sqlx.Session, agentId, sourceAgentId, orderId, productId string, amount float64, levelBonus int64, rebateType int64) error {
|
||||
// 1. 创建返佣记录
|
||||
rebate := &model.AgentRebate{
|
||||
Id: uuid.NewString(),
|
||||
AgentId: agentId,
|
||||
SourceAgentId: sourceAgentId,
|
||||
OrderId: orderId,
|
||||
ProductId: productId,
|
||||
RebateType: rebateType,
|
||||
LevelBonus: float64(levelBonus), // 等级加成金额
|
||||
RebateAmount: amount,
|
||||
Status: 1, // 已发放
|
||||
}
|
||||
if _, err := s.AgentRebateModel.Insert(ctx, session, rebate); err != nil {
|
||||
return errors.Wrapf(err, "创建返佣记录失败")
|
||||
}
|
||||
@@ -658,12 +662,12 @@ func (s *AgentService) giveRebate(ctx context.Context, session sqlx.Session, age
|
||||
}
|
||||
|
||||
// FindDirectParent 查找直接上级(公开方法)
|
||||
func (s *AgentService) FindDirectParent(ctx context.Context, agentId int64) (*model.Agent, error) {
|
||||
func (s *AgentService) FindDirectParent(ctx context.Context, agentId string) (*model.Agent, error) {
|
||||
return s.findDirectParent(ctx, agentId)
|
||||
}
|
||||
|
||||
// findDirectParent 查找直接上级
|
||||
func (s *AgentService) findDirectParent(ctx context.Context, agentId int64) (*model.Agent, error) {
|
||||
func (s *AgentService) findDirectParent(ctx context.Context, agentId string) (*model.Agent, error) {
|
||||
// 查找关系类型为1(直接关系)的上级
|
||||
builder := s.AgentRelationModel.SelectBuilder()
|
||||
builder = builder.Where("child_id = ? AND relation_type = ? AND del_state = ?", agentId, 1, globalkey.DelStateNo)
|
||||
@@ -692,7 +696,7 @@ func (s *AgentService) findDirectParent(ctx context.Context, agentId int64) (*mo
|
||||
// - 普通 -> 普通 -> 钻石:会找到钻石(跳过中间的普通代理)
|
||||
// - 普通 -> 黄金 -> 钻石:会找到钻石(跳过黄金代理)
|
||||
// - 普通 -> 普通 -> 黄金:返回 ErrNotFound(没有钻石)
|
||||
func (s *AgentService) findDiamondParent(ctx context.Context, agentId int64) (*model.Agent, error) {
|
||||
func (s *AgentService) findDiamondParent(ctx context.Context, agentId string) (*model.Agent, error) {
|
||||
currentId := agentId
|
||||
maxDepth := 100 // 防止无限循环
|
||||
depth := 0
|
||||
@@ -732,7 +736,7 @@ func (s *AgentService) findDiamondParent(ctx context.Context, agentId int64) (*m
|
||||
// - 普通 -> 普通 -> 黄金:会找到黄金(跳过中间的普通代理)
|
||||
// - 普通 -> 黄金:会找到黄金
|
||||
// - 普通 -> 普通 -> 钻石:返回 ErrNotFound(跳过钻石,继续查找黄金,但找不到)
|
||||
func (s *AgentService) findGoldParent(ctx context.Context, agentId int64) (*model.Agent, error) {
|
||||
func (s *AgentService) findGoldParent(ctx context.Context, agentId string) (*model.Agent, error) {
|
||||
currentId := agentId
|
||||
maxDepth := 100 // 防止无限循环
|
||||
depth := 0
|
||||
@@ -784,7 +788,7 @@ func (s *AgentService) getConfigInt(ctx context.Context, configKey string) (int6
|
||||
}
|
||||
|
||||
// ProcessUpgrade 处理代理升级
|
||||
func (s *AgentService) ProcessUpgrade(ctx context.Context, agentId, toLevel int64, upgradeType int64, upgradeFee, rebateAmount float64, orderNo string, operatorAgentId int64) error {
|
||||
func (s *AgentService) ProcessUpgrade(ctx context.Context, agentId string, toLevel int64, upgradeType int64, upgradeFee, rebateAmount float64, orderNo string, operatorAgentId string) error {
|
||||
return s.AgentWalletModel.Trans(ctx, func(transCtx context.Context, session sqlx.Session) error {
|
||||
// 1. 获取代理信息
|
||||
agent, err := s.AgentModel.FindOne(transCtx, agentId)
|
||||
@@ -820,7 +824,7 @@ func (s *AgentService) ProcessUpgrade(ctx context.Context, agentId, toLevel int6
|
||||
if needDetach {
|
||||
// 脱离前先获取原直接上级及其上级的信息(用于后续重新连接)
|
||||
oldParent, oldParentErr := s.findDirectParent(transCtx, agentId)
|
||||
var grandparentId int64 = 0
|
||||
var grandparentId string = ""
|
||||
if oldParentErr == nil && oldParent != nil {
|
||||
// 查找原上级的上级
|
||||
grandparent, grandparentErr := s.findDirectParent(transCtx, oldParent.Id)
|
||||
@@ -835,7 +839,7 @@ func (s *AgentService) ProcessUpgrade(ctx context.Context, agentId, toLevel int6
|
||||
}
|
||||
|
||||
// 脱离后,尝试连接到原上级的上级
|
||||
if grandparentId > 0 {
|
||||
if grandparentId != "" {
|
||||
if err := s.reconnectToGrandparent(transCtx, session, agentId, toLevel, grandparentId); err != nil {
|
||||
return errors.Wrapf(err, "重新连接上级关系失败")
|
||||
}
|
||||
@@ -844,7 +848,7 @@ func (s *AgentService) ProcessUpgrade(ctx context.Context, agentId, toLevel int6
|
||||
|
||||
// 5. 如果升级为钻石,独立成新团队
|
||||
if toLevel == 3 {
|
||||
agent.TeamLeaderId = sql.NullInt64{Int64: agentId, Valid: true}
|
||||
agent.TeamLeaderId = sql.NullString{String: agentId, Valid: true}
|
||||
// 更新所有下级的团队首领
|
||||
if err := s.updateChildrenTeamLeader(transCtx, session, agentId, agentId); err != nil {
|
||||
return errors.Wrapf(err, "更新下级团队首领失败")
|
||||
@@ -855,8 +859,8 @@ func (s *AgentService) ProcessUpgrade(ctx context.Context, agentId, toLevel int6
|
||||
if err != nil && !errors.Is(err, model.ErrNotFound) {
|
||||
return errors.Wrapf(err, "查找团队首领失败")
|
||||
}
|
||||
if teamLeaderId > 0 {
|
||||
agent.TeamLeaderId = sql.NullInt64{Int64: teamLeaderId, Valid: true}
|
||||
if teamLeaderId != "" {
|
||||
agent.TeamLeaderId = sql.NullString{String: teamLeaderId, Valid: true}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -899,7 +903,7 @@ func (s *AgentService) needDetachFromParent(ctx context.Context, agent *model.Ag
|
||||
}
|
||||
|
||||
// detachFromParent 脱离直接上级关系
|
||||
func (s *AgentService) detachFromParent(ctx context.Context, session sqlx.Session, agentId int64) error {
|
||||
func (s *AgentService) detachFromParent(ctx context.Context, session sqlx.Session, agentId string) error {
|
||||
// 查找直接关系
|
||||
builder := s.AgentRelationModel.SelectBuilder().
|
||||
Where("child_id = ? AND relation_type = ? AND del_state = ?", agentId, 1, globalkey.DelStateNo)
|
||||
@@ -926,7 +930,7 @@ func (s *AgentService) detachFromParent(ctx context.Context, session sqlx.Sessio
|
||||
}
|
||||
|
||||
// reconnectToGrandparent 重新连接到原上级的上级(如果存在且符合条件)
|
||||
func (s *AgentService) reconnectToGrandparent(ctx context.Context, session sqlx.Session, agentId int64, newLevel int64, grandparentId int64) error {
|
||||
func (s *AgentService) reconnectToGrandparent(ctx context.Context, session sqlx.Session, agentId string, newLevel int64, grandparentId string) error {
|
||||
// 获取原上级的上级信息
|
||||
grandparent, err := s.AgentModel.FindOne(ctx, grandparentId)
|
||||
if err != nil {
|
||||
@@ -967,11 +971,12 @@ func (s *AgentService) reconnectToGrandparent(ctx context.Context, session sqlx.
|
||||
}
|
||||
|
||||
// 创建新的关系连接到原上级的上级
|
||||
relation := &model.AgentRelation{
|
||||
ParentId: grandparent.Id,
|
||||
ChildId: agentId,
|
||||
RelationType: 1, // 直接关系
|
||||
}
|
||||
relation := &model.AgentRelation{
|
||||
Id: uuid.NewString(),
|
||||
ParentId: grandparent.Id,
|
||||
ChildId: agentId,
|
||||
RelationType: 1, // 直接关系
|
||||
}
|
||||
if _, err := s.AgentRelationModel.Insert(ctx, session, relation); err != nil {
|
||||
return errors.Wrapf(err, "创建新关系失败")
|
||||
}
|
||||
@@ -980,10 +985,10 @@ func (s *AgentService) reconnectToGrandparent(ctx context.Context, session sqlx.
|
||||
}
|
||||
|
||||
// updateChildrenTeamLeader 更新所有下级的团队首领
|
||||
func (s *AgentService) updateChildrenTeamLeader(ctx context.Context, session sqlx.Session, agentId, teamLeaderId int64) error {
|
||||
func (s *AgentService) updateChildrenTeamLeader(ctx context.Context, session sqlx.Session, agentId, teamLeaderId string) error {
|
||||
// 递归更新所有下级
|
||||
var updateChildren func(int64) error
|
||||
updateChildren = func(parentId int64) error {
|
||||
var updateChildren func(string) error
|
||||
updateChildren = func(parentId string) error {
|
||||
// 查找直接下级
|
||||
builder := s.AgentRelationModel.SelectBuilder().
|
||||
Where("parent_id = ? AND relation_type = ? AND del_state = ?", parentId, 1, globalkey.DelStateNo)
|
||||
@@ -998,9 +1003,9 @@ func (s *AgentService) updateChildrenTeamLeader(ctx context.Context, session sql
|
||||
continue
|
||||
}
|
||||
|
||||
child.TeamLeaderId = sql.NullInt64{Int64: teamLeaderId, Valid: true}
|
||||
child.TeamLeaderId = sql.NullString{String: teamLeaderId, Valid: true}
|
||||
if err := s.AgentModel.UpdateWithVersion(ctx, session, child); err != nil {
|
||||
return errors.Wrapf(err, "更新下级团队首领失败, childId: %d", child.Id)
|
||||
return errors.Wrapf(err, "更新下级团队首领失败, childId: %s", child.Id)
|
||||
}
|
||||
|
||||
// 递归更新下级的下级
|
||||
@@ -1016,24 +1021,24 @@ func (s *AgentService) updateChildrenTeamLeader(ctx context.Context, session sql
|
||||
}
|
||||
|
||||
// findTeamLeaderId 查找团队首领ID(钻石代理)
|
||||
func (s *AgentService) findTeamLeaderId(ctx context.Context, agentId int64) (int64, error) {
|
||||
func (s *AgentService) findTeamLeaderId(ctx context.Context, agentId string) (string, error) {
|
||||
diamondParent, err := s.findDiamondParent(ctx, agentId)
|
||||
if err != nil {
|
||||
if errors.Is(err, model.ErrNotFound) {
|
||||
return 0, nil
|
||||
return "", nil
|
||||
}
|
||||
return 0, err
|
||||
return "", err
|
||||
}
|
||||
return diamondParent.Id, nil
|
||||
}
|
||||
|
||||
// giveRebateForUpgrade 发放升级返佣
|
||||
// 注意:升级返佣信息记录在 agent_upgrade 表中(rebate_agent_id 和 rebate_amount),不需要在 agent_rebate 表中创建记录
|
||||
func (s *AgentService) giveRebateForUpgrade(ctx context.Context, session sqlx.Session, parentAgentId, upgradeAgentId int64, amount float64, orderNo string) error {
|
||||
func (s *AgentService) giveRebateForUpgrade(ctx context.Context, session sqlx.Session, parentAgentId, upgradeAgentId string, amount float64, orderNo string) error {
|
||||
// 更新钱包余额
|
||||
wallet, err := s.AgentWalletModel.FindOneByAgentId(ctx, parentAgentId)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "查询钱包失败, agentId: %d", parentAgentId)
|
||||
return errors.Wrapf(err, "查询钱包失败, agentId: %s", parentAgentId)
|
||||
}
|
||||
|
||||
wallet.Balance += amount
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
"context"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"ycc-server/app/main/model"
|
||||
"ycc-server/app/main/model"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"github.com/zeromicro/go-zero/rest"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"github.com/zeromicro/go-zero/rest"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type ApiRegistryService struct {
|
||||
@@ -26,27 +27,27 @@ func NewApiRegistryService(adminApiModel model.AdminApiModel) *ApiRegistryServic
|
||||
// RegisterAllApis 自动注册所有API到数据库
|
||||
func (s *ApiRegistryService) RegisterAllApis(ctx context.Context, routes []rest.Route) error {
|
||||
logx.Infof("开始注册API,共 %d 个路由", len(routes))
|
||||
|
||||
|
||||
registeredCount := 0
|
||||
skippedCount := 0
|
||||
|
||||
|
||||
for _, route := range routes {
|
||||
// 跳过不需要权限控制的API
|
||||
if s.shouldSkipApi(route.Path) {
|
||||
skippedCount++
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
// 解析API信息
|
||||
apiInfo := s.parseRouteToApi(route)
|
||||
|
||||
|
||||
// 检查是否已存在
|
||||
existing, err := s.adminApiModel.FindOneByApiCode(ctx, apiInfo.ApiCode)
|
||||
if err != nil && !errors.Is(err, model.ErrNotFound) {
|
||||
logx.Errorf("查询API失败: %v, apiCode: %s", err, apiInfo.ApiCode)
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
// 如果不存在则插入
|
||||
if existing == nil {
|
||||
_, err = s.adminApiModel.Insert(ctx, nil, apiInfo)
|
||||
@@ -63,7 +64,7 @@ func (s *ApiRegistryService) RegisterAllApis(ctx context.Context, routes []rest.
|
||||
existing.Method = apiInfo.Method
|
||||
existing.Url = apiInfo.Url
|
||||
existing.Description = apiInfo.Description
|
||||
|
||||
|
||||
_, err = s.adminApiModel.Update(ctx, nil, existing)
|
||||
if err != nil {
|
||||
logx.Errorf("更新API失败: %v, apiCode: %s", err, apiInfo.ApiCode)
|
||||
@@ -73,7 +74,7 @@ func (s *ApiRegistryService) RegisterAllApis(ctx context.Context, routes []rest.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
logx.Infof("API注册完成,新增: %d, 跳过: %d", registeredCount, skippedCount)
|
||||
return nil
|
||||
}
|
||||
@@ -94,13 +95,13 @@ func (s *ApiRegistryService) shouldSkipApi(path string) bool {
|
||||
"/api/v1/authorization/", // 授权接口
|
||||
"/health", // 健康检查
|
||||
}
|
||||
|
||||
|
||||
for _, skipPath := range skipPaths {
|
||||
if strings.HasPrefix(path, skipPath) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -108,33 +109,34 @@ func (s *ApiRegistryService) shouldSkipApi(path string) bool {
|
||||
func (s *ApiRegistryService) parseRouteToApi(route rest.Route) *model.AdminApi {
|
||||
// 生成API编码
|
||||
apiCode := s.generateApiCode(route.Method, route.Path)
|
||||
|
||||
|
||||
// 生成API名称
|
||||
apiName := s.generateApiName(route.Path)
|
||||
|
||||
|
||||
// 生成描述
|
||||
description := s.generateDescription(route.Method, route.Path)
|
||||
|
||||
return &model.AdminApi{
|
||||
ApiName: apiName,
|
||||
ApiCode: apiCode,
|
||||
Method: route.Method,
|
||||
Url: route.Path,
|
||||
Status: 1, // 默认启用
|
||||
Description: description,
|
||||
}
|
||||
|
||||
return &model.AdminApi{
|
||||
Id: uuid.NewString(),
|
||||
ApiName: apiName,
|
||||
ApiCode: apiCode,
|
||||
Method: route.Method,
|
||||
Url: route.Path,
|
||||
Status: 1, // 默认启用
|
||||
Description: description,
|
||||
}
|
||||
}
|
||||
|
||||
// generateApiCode 生成API编码
|
||||
func (s *ApiRegistryService) generateApiCode(method, path string) string {
|
||||
// 移除路径参数,如 :id
|
||||
cleanPath := regexp.MustCompile(`/:[\w]+`).ReplaceAllString(path, "")
|
||||
|
||||
|
||||
// 转换为小写并替换特殊字符
|
||||
apiCode := strings.ToLower(method) + "_" + strings.ReplaceAll(cleanPath, "/", "_")
|
||||
apiCode = strings.TrimPrefix(apiCode, "_")
|
||||
apiCode = strings.TrimSuffix(apiCode, "_")
|
||||
|
||||
|
||||
return apiCode
|
||||
}
|
||||
|
||||
@@ -145,52 +147,52 @@ func (s *ApiRegistryService) generateApiName(path string) string {
|
||||
if len(parts) < 3 {
|
||||
return path
|
||||
}
|
||||
|
||||
|
||||
// 获取模块名和操作名
|
||||
module := parts[len(parts)-2]
|
||||
action := parts[len(parts)-1]
|
||||
|
||||
|
||||
// 转换为中文描述
|
||||
moduleMap := map[string]string{
|
||||
"agent": "代理管理",
|
||||
"auth": "认证管理",
|
||||
"feature": "功能管理",
|
||||
"menu": "菜单管理",
|
||||
"notification": "通知管理",
|
||||
"order": "订单管理",
|
||||
"agent": "代理管理",
|
||||
"auth": "认证管理",
|
||||
"feature": "功能管理",
|
||||
"menu": "菜单管理",
|
||||
"notification": "通知管理",
|
||||
"order": "订单管理",
|
||||
"platform_user": "平台用户",
|
||||
"product": "产品管理",
|
||||
"query": "查询管理",
|
||||
"role": "角色管理",
|
||||
"user": "用户管理",
|
||||
"product": "产品管理",
|
||||
"query": "查询管理",
|
||||
"role": "角色管理",
|
||||
"user": "用户管理",
|
||||
}
|
||||
|
||||
|
||||
actionMap := map[string]string{
|
||||
"list": "列表",
|
||||
"create": "创建",
|
||||
"update": "更新",
|
||||
"delete": "删除",
|
||||
"detail": "详情",
|
||||
"login": "登录",
|
||||
"config": "配置",
|
||||
"example": "示例",
|
||||
"refund": "退款",
|
||||
"link": "链接",
|
||||
"stats": "统计",
|
||||
"cleanup": "清理",
|
||||
"record": "记录",
|
||||
"list": "列表",
|
||||
"create": "创建",
|
||||
"update": "更新",
|
||||
"delete": "删除",
|
||||
"detail": "详情",
|
||||
"login": "登录",
|
||||
"config": "配置",
|
||||
"example": "示例",
|
||||
"refund": "退款",
|
||||
"link": "链接",
|
||||
"stats": "统计",
|
||||
"cleanup": "清理",
|
||||
"record": "记录",
|
||||
}
|
||||
|
||||
|
||||
moduleName := moduleMap[module]
|
||||
if moduleName == "" {
|
||||
moduleName = module
|
||||
}
|
||||
|
||||
|
||||
actionName := actionMap[action]
|
||||
if actionName == "" {
|
||||
actionName = action
|
||||
}
|
||||
|
||||
|
||||
return fmt.Sprintf("%s-%s", moduleName, actionName)
|
||||
}
|
||||
|
||||
@@ -202,14 +204,14 @@ func (s *ApiRegistryService) generateDescription(method, path string) string {
|
||||
"PUT": "更新",
|
||||
"DELETE": "删除",
|
||||
}
|
||||
|
||||
|
||||
methodDesc := methodMap[method]
|
||||
if methodDesc == "" {
|
||||
methodDesc = method
|
||||
}
|
||||
|
||||
|
||||
apiName := s.generateApiName(path)
|
||||
|
||||
|
||||
return fmt.Sprintf("%s%s", methodDesc, apiName)
|
||||
}
|
||||
|
||||
|
||||
@@ -58,26 +58,26 @@ type APIResponseData struct {
|
||||
}
|
||||
|
||||
// ProcessRequests 处理请求
|
||||
func (a *ApiRequestService) ProcessRequests(params []byte, productID int64) ([]byte, error) {
|
||||
func (a *ApiRequestService) ProcessRequests(params []byte, productID string) ([]byte, error) {
|
||||
var ctx, cancel = context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
build := a.productFeatureModel.SelectBuilder().Where(squirrel.Eq{
|
||||
"product_id": productID,
|
||||
})
|
||||
build := a.productFeatureModel.SelectBuilder().Where(squirrel.Eq{
|
||||
"product_id": productID,
|
||||
})
|
||||
productFeatureList, findProductFeatureErr := a.productFeatureModel.FindAll(ctx, build, "")
|
||||
if findProductFeatureErr != nil {
|
||||
return nil, findProductFeatureErr
|
||||
}
|
||||
var featureIDs []int64
|
||||
isImportantMap := make(map[int64]int64, len(productFeatureList))
|
||||
var featureIDs []string
|
||||
isImportantMap := make(map[string]int64, len(productFeatureList))
|
||||
for _, pf := range productFeatureList {
|
||||
featureIDs = append(featureIDs, pf.FeatureId)
|
||||
isImportantMap[pf.FeatureId] = pf.IsImportant
|
||||
featureIDs = append(featureIDs, pf.FeatureId)
|
||||
isImportantMap[pf.FeatureId] = pf.IsImportant
|
||||
}
|
||||
if len(featureIDs) == 0 {
|
||||
return nil, errors.New("featureIDs 是空的")
|
||||
}
|
||||
builder := a.featureModel.SelectBuilder().Where(squirrel.Eq{"id": featureIDs})
|
||||
builder := a.featureModel.SelectBuilder().Where(squirrel.Eq{"id": featureIDs})
|
||||
featureList, findFeatureErr := a.featureModel.FindAll(ctx, builder, "")
|
||||
if findFeatureErr != nil {
|
||||
return nil, findFeatureErr
|
||||
@@ -114,7 +114,7 @@ func (a *ApiRequestService) ProcessRequests(params []byte, productID int64) ([]b
|
||||
preprocessErr error
|
||||
)
|
||||
// 若 isImportantMap[feature.ID] == 1,则表示需要在出错时重试
|
||||
isImportant := isImportantMap[feature.Id] == 1
|
||||
isImportant := isImportantMap[feature.Id] == 1
|
||||
tryCount := 0
|
||||
for {
|
||||
tryCount++
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
"ycc-server/app/main/api/internal/config"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/hibiken/asynq"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
@@ -31,14 +31,14 @@ func NewAsynqService(c config.Config) *AsynqService {
|
||||
func (s *AsynqService) Close() error {
|
||||
return s.client.Close()
|
||||
}
|
||||
func (s *AsynqService) SendQueryTask(orderID int64) error {
|
||||
func (s *AsynqService) SendQueryTask(orderID string) error {
|
||||
// 准备任务的 payload
|
||||
payload := types.MsgPaySuccessQueryPayload{
|
||||
OrderID: orderID,
|
||||
}
|
||||
payloadBytes, err := json.Marshal(payload)
|
||||
if err != nil {
|
||||
logx.Errorf("发送异步任务失败 (无法编码 payload): %v, 订单号: %d", err, orderID)
|
||||
logx.Errorf("发送异步任务失败 (无法编码 payload): %v, 订单号: %s", err, orderID)
|
||||
return err // 直接返回错误,避免继续执行
|
||||
}
|
||||
|
||||
@@ -51,24 +51,24 @@ func (s *AsynqService) SendQueryTask(orderID int64) error {
|
||||
// 将任务加入队列并获取任务信息
|
||||
info, err := s.client.Enqueue(task)
|
||||
if err != nil {
|
||||
logx.Errorf("发送异步任务失败 (加入队列失败): %+v, 订单号: %d", err, orderID)
|
||||
logx.Errorf("发送异步任务失败 (加入队列失败): %+v, 订单号: %s", err, orderID)
|
||||
return err
|
||||
}
|
||||
|
||||
// 记录成功日志,带上任务 ID 和队列信息
|
||||
logx.Infof("发送异步任务成功,任务ID: %s, 队列: %s, 订单号: %d", info.ID, info.Queue, orderID)
|
||||
logx.Infof("发送异步任务成功,任务ID: %s, 队列: %s, 订单号: %s", info.ID, info.Queue, orderID)
|
||||
return nil
|
||||
}
|
||||
|
||||
// SendAgentProcessTask 发送代理处理任务
|
||||
func (s *AsynqService) SendAgentProcessTask(orderID int64) error {
|
||||
func (s *AsynqService) SendAgentProcessTask(orderID string) error {
|
||||
// 准备任务的 payload
|
||||
payload := types.MsgAgentProcessPayload{
|
||||
OrderID: orderID,
|
||||
}
|
||||
payloadBytes, err := json.Marshal(payload)
|
||||
if err != nil {
|
||||
logx.Errorf("发送代理处理任务失败 (无法编码 payload): %v, 订单号: %d", err, orderID)
|
||||
logx.Errorf("发送代理处理任务失败 (无法编码 payload): %v, 订单号: %s", err, orderID)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -81,31 +81,31 @@ func (s *AsynqService) SendAgentProcessTask(orderID int64) error {
|
||||
// 将任务加入队列并获取任务信息
|
||||
info, err := s.client.Enqueue(task)
|
||||
if err != nil {
|
||||
logx.Errorf("发送代理处理任务失败 (加入队列失败): %+v, 订单号: %d", err, orderID)
|
||||
logx.Errorf("发送代理处理任务失败 (加入队列失败): %+v, 订单号: %s", err, orderID)
|
||||
return err
|
||||
}
|
||||
|
||||
// 记录成功日志,带上任务 ID 和队列信息
|
||||
logx.Infof("发送代理处理任务成功,任务ID: %s, 队列: %s, 订单号: %d", info.ID, info.Queue, orderID)
|
||||
logx.Infof("发送代理处理任务成功,任务ID: %s, 队列: %s, 订单号: %s", info.ID, info.Queue, orderID)
|
||||
return nil
|
||||
}
|
||||
|
||||
// SendUnfreezeTask 发送解冻任务(延迟执行)
|
||||
func (s *AsynqService) SendUnfreezeTask(freezeTaskId int64, processAt time.Time) error {
|
||||
func (s *AsynqService) SendUnfreezeTask(freezeTaskId string, processAt time.Time) error {
|
||||
// 准备任务的 payload
|
||||
payload := types.MsgUnfreezeCommissionPayload{
|
||||
FreezeTaskId: freezeTaskId,
|
||||
}
|
||||
payloadBytes, err := json.Marshal(payload)
|
||||
if err != nil {
|
||||
logx.Errorf("发送解冻任务失败 (无法编码 payload): %v, 冻结任务ID: %d", err, freezeTaskId)
|
||||
logx.Errorf("发送解冻任务失败 (无法编码 payload): %v, 冻结任务ID: %s", err, freezeTaskId)
|
||||
return err
|
||||
}
|
||||
|
||||
options := []asynq.Option{
|
||||
asynq.MaxRetry(5), // 设置最大重试次数
|
||||
asynq.ProcessAt(processAt), // 延迟到指定时间执行
|
||||
asynq.Queue("critical"), // 使用关键队列
|
||||
asynq.MaxRetry(5), // 设置最大重试次数
|
||||
asynq.ProcessAt(processAt), // 延迟到指定时间执行
|
||||
asynq.Queue("critical"), // 使用关键队列
|
||||
}
|
||||
// 创建任务
|
||||
task := asynq.NewTask(types.MsgUnfreezeCommission, payloadBytes, options...)
|
||||
@@ -113,11 +113,11 @@ func (s *AsynqService) SendUnfreezeTask(freezeTaskId int64, processAt time.Time)
|
||||
// 将任务加入队列并获取任务信息
|
||||
info, err := s.client.Enqueue(task)
|
||||
if err != nil {
|
||||
logx.Errorf("发送解冻任务失败 (加入队列失败): %+v, 冻结任务ID: %d", err, freezeTaskId)
|
||||
logx.Errorf("发送解冻任务失败 (加入队列失败): %+v, 冻结任务ID: %s", err, freezeTaskId)
|
||||
return err
|
||||
}
|
||||
|
||||
// 记录成功日志,带上任务 ID 和队列信息
|
||||
logx.Infof("发送解冻任务成功,任务ID: %s, 队列: %s, 冻结任务ID: %d, 执行时间: %v", info.ID, info.Queue, freezeTaskId, processAt)
|
||||
logx.Infof("发送解冻任务成功,任务ID: %s, 队列: %s, 冻结任务ID: %s, 执行时间: %v", info.ID, info.Queue, freezeTaskId, processAt)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"ycc-server/app/main/api/internal/config"
|
||||
"ycc-server/app/main/model"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/jung-kurt/gofpdf"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
@@ -36,9 +37,9 @@ func NewAuthorizationService(c config.Config, authDocModel model.AuthorizationDo
|
||||
// GenerateAuthorizationDocument 生成授权书PDF
|
||||
func (s *AuthorizationService) GenerateAuthorizationDocument(
|
||||
ctx context.Context,
|
||||
userID int64,
|
||||
orderID int64,
|
||||
queryID int64,
|
||||
userID string,
|
||||
orderID string,
|
||||
queryID string,
|
||||
userInfo map[string]interface{},
|
||||
) (*model.AuthorizationDocument, error) {
|
||||
// 1. 生成PDF内容
|
||||
@@ -56,7 +57,7 @@ func (s *AuthorizationService) GenerateAuthorizationDocument(
|
||||
}
|
||||
|
||||
// 3. 生成文件名和路径
|
||||
fileName := fmt.Sprintf("auth_%d_%d_%s.pdf", userID, orderID, time.Now().Format("20060102_150405"))
|
||||
fileName := fmt.Sprintf("auth_%s_%s_%s.pdf", userID, orderID, time.Now().Format("20060102_150405"))
|
||||
filePath := filepath.Join(dirPath, fileName)
|
||||
// 只存储相对路径,不包含域名
|
||||
relativePath := fmt.Sprintf("%s/%s/%s", year, month, fileName)
|
||||
@@ -68,6 +69,7 @@ func (s *AuthorizationService) GenerateAuthorizationDocument(
|
||||
|
||||
// 5. 保存到数据库
|
||||
authDoc := &model.AuthorizationDocument{
|
||||
Id: uuid.NewString(),
|
||||
UserId: userID,
|
||||
OrderId: orderID,
|
||||
QueryId: queryID,
|
||||
@@ -80,15 +82,14 @@ func (s *AuthorizationService) GenerateAuthorizationDocument(
|
||||
ExpireTime: sql.NullTime{Valid: false}, // 永久保留,不设置过期时间
|
||||
}
|
||||
|
||||
result, err := s.authDocModel.Insert(ctx, nil, authDoc)
|
||||
_, err = s.authDocModel.Insert(ctx, nil, authDoc)
|
||||
if err != nil {
|
||||
// 如果数据库保存失败,删除已创建的文件
|
||||
os.Remove(filePath)
|
||||
return nil, errors.Wrapf(err, "保存授权书记录失败")
|
||||
}
|
||||
|
||||
authDoc.Id, _ = result.LastInsertId()
|
||||
logx.Infof("授权书生成成功: userID=%d, orderID=%d, filePath=%s", userID, orderID, filePath)
|
||||
logx.Infof("授权书生成成功: userID=%s, orderID=%s, filePath=%s", userID, orderID, filePath)
|
||||
|
||||
return authDoc, nil
|
||||
}
|
||||
|
||||
@@ -2,12 +2,12 @@ package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"ycc-server/app/main/api/internal/config"
|
||||
"ycc-server/app/main/model"
|
||||
"ycc-server/common/ctxdata"
|
||||
jwtx "ycc-server/common/jwt"
|
||||
"ycc-server/common/xerr"
|
||||
"database/sql"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/pkg/errors"
|
||||
@@ -18,17 +18,15 @@ type UserService struct {
|
||||
Config *config.Config
|
||||
userModel model.UserModel
|
||||
userAuthModel model.UserAuthModel
|
||||
userTempModel model.UserTempModel
|
||||
agentModel model.AgentModel
|
||||
}
|
||||
|
||||
// NewUserService 创建UserService实例
|
||||
func NewUserService(config *config.Config, userModel model.UserModel, userAuthModel model.UserAuthModel, userTempModel model.UserTempModel, agentModel model.AgentModel) *UserService {
|
||||
func NewUserService(config *config.Config, userModel model.UserModel, userAuthModel model.UserAuthModel, agentModel model.AgentModel) *UserService {
|
||||
return &UserService{
|
||||
Config: config,
|
||||
userModel: userModel,
|
||||
userAuthModel: userAuthModel,
|
||||
userTempModel: userTempModel,
|
||||
agentModel: agentModel,
|
||||
}
|
||||
}
|
||||
@@ -40,51 +38,42 @@ func (s *UserService) GenerateUUIDUserId(ctx context.Context) (string, error) {
|
||||
}
|
||||
|
||||
// RegisterUUIDUser 注册UUID用户,返回用户ID
|
||||
func (s *UserService) RegisterUUIDUser(ctx context.Context) (int64, error) {
|
||||
func (s *UserService) RegisterUUIDUser(ctx context.Context) (string, error) {
|
||||
// 生成UUID
|
||||
uuidStr, err := s.GenerateUUIDUserId(ctx)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
return "", err
|
||||
}
|
||||
|
||||
var userId int64
|
||||
var userId string
|
||||
err = s.userModel.Trans(ctx, func(ctx context.Context, session sqlx.Session) error {
|
||||
// 创建用户记录
|
||||
user := &model.User{}
|
||||
result, err := s.userModel.Insert(ctx, session, user)
|
||||
if err != nil {
|
||||
return err
|
||||
user := &model.User{Id: uuid.NewString()}
|
||||
if _, userInsertErr := s.userModel.Insert(ctx, session, user); userInsertErr != nil {
|
||||
return userInsertErr
|
||||
}
|
||||
userId, err = result.LastInsertId()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 创建用户认证记录
|
||||
userAuth := &model.UserAuth{
|
||||
UserId: userId,
|
||||
AuthType: model.UserAuthTypeUUID,
|
||||
AuthKey: uuidStr,
|
||||
}
|
||||
_, err = s.userAuthModel.Insert(ctx, session, userAuth)
|
||||
return err
|
||||
userId = user.Id
|
||||
userAuth := &model.UserAuth{Id: uuid.NewString(), UserId: userId, AuthType: model.UserAuthTypeUUID, AuthKey: uuidStr}
|
||||
_, userAuthInsertErr := s.userAuthModel.Insert(ctx, session, userAuth)
|
||||
return userAuthInsertErr
|
||||
})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
return "", err
|
||||
}
|
||||
|
||||
return userId, nil
|
||||
}
|
||||
|
||||
// generalUserToken 生成用户token
|
||||
func (s *UserService) GeneralUserToken(ctx context.Context, userID int64, userType int64) (string, error) {
|
||||
// GeneralUserToken 生成用户token
|
||||
func (s *UserService) GeneralUserToken(ctx context.Context, userID string, userType int64) (string, error) {
|
||||
platform, err := ctxdata.GetPlatformFromCtx(ctx)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var isAgent int64
|
||||
var agentID int64
|
||||
var agentID string
|
||||
var authType string
|
||||
var authKey string
|
||||
if userType == model.UserTypeNormal {
|
||||
agent, err := s.agentModel.FindOneByUserId(ctx, userID)
|
||||
if err != nil && !errors.Is(err, model.ErrNotFound) {
|
||||
@@ -94,13 +83,17 @@ func (s *UserService) GeneralUserToken(ctx context.Context, userID int64, userTy
|
||||
agentID = agent.Id
|
||||
isAgent = model.AgentStatusYes
|
||||
}
|
||||
} else {
|
||||
userTemp, err := s.userTempModel.FindOne(ctx, userID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
userAuth, err := s.userAuthModel.FindOneByUserIdAuthType(ctx, userID, model.UserAuthTypeMobile)
|
||||
if err == nil && userAuth != nil {
|
||||
authType = userAuth.AuthType
|
||||
authKey = userAuth.AuthKey
|
||||
}
|
||||
if userTemp != nil {
|
||||
userID = userTemp.Id
|
||||
} else {
|
||||
platAuthType := s.getAuthTypeByPlatform(platform)
|
||||
ua, err := s.userAuthModel.FindOneByUserIdAuthType(ctx, userID, platAuthType)
|
||||
if err == nil && ua != nil {
|
||||
authType = ua.AuthType
|
||||
authKey = ua.AuthKey
|
||||
}
|
||||
}
|
||||
token, generaErr := jwtx.GenerateJwtToken(jwtx.JwtClaims{
|
||||
@@ -109,95 +102,93 @@ func (s *UserService) GeneralUserToken(ctx context.Context, userID int64, userTy
|
||||
Platform: platform,
|
||||
UserType: userType,
|
||||
IsAgent: isAgent,
|
||||
AuthType: authType,
|
||||
AuthKey: authKey,
|
||||
}, s.Config.JwtAuth.AccessSecret, s.Config.JwtAuth.AccessExpire)
|
||||
if generaErr != nil {
|
||||
return "", errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "更新token, 生成token失败 : %d", userID)
|
||||
return "", errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "更新token, 生成token失败 : %s", userID)
|
||||
}
|
||||
return token, nil
|
||||
}
|
||||
|
||||
func (s *UserService) getAuthTypeByPlatform(platform string) string {
|
||||
switch platform {
|
||||
case model.PlatformWxMini:
|
||||
return model.UserAuthTypeWxMiniOpenID
|
||||
case model.PlatformWxH5:
|
||||
return model.UserAuthTypeWxh5OpenID
|
||||
case model.PlatformH5, model.PlatformApp:
|
||||
return model.UserAuthTypeUUID
|
||||
default:
|
||||
return model.UserAuthTypeUUID
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterUser 注册用户,返回用户ID
|
||||
// 传入手机号,自动注册,如果ctx存在临时用户则临时用户转为正式用户
|
||||
func (s *UserService) RegisterUser(ctx context.Context, mobile string) (int64, error) {
|
||||
func (s *UserService) RegisterUser(ctx context.Context, mobile string) (string, error) {
|
||||
claims, err := ctxdata.GetClaimsFromCtx(ctx)
|
||||
if err != nil && !errors.Is(err, ctxdata.ErrNoInCtx) {
|
||||
return 0, err
|
||||
return "", err
|
||||
}
|
||||
user, err := s.userModel.FindOneByMobile(ctx, sql.NullString{String: mobile, Valid: true})
|
||||
if err != nil && !errors.Is(err, model.ErrNotFound) {
|
||||
return 0, err
|
||||
return "", err
|
||||
}
|
||||
if user != nil {
|
||||
return 0, errors.New("用户已注册")
|
||||
return "", errors.New("用户已注册")
|
||||
}
|
||||
// 普通注册
|
||||
if claims == nil {
|
||||
var userId int64
|
||||
var userId string
|
||||
err = s.userModel.Trans(ctx, func(ctx context.Context, session sqlx.Session) error {
|
||||
user := &model.User{
|
||||
Mobile: sql.NullString{String: mobile, Valid: true},
|
||||
user := &model.User{Id: uuid.NewString(), Mobile: sql.NullString{String: mobile, Valid: true}}
|
||||
if _, userInsertErr := s.userModel.Insert(ctx, session, user); userInsertErr != nil {
|
||||
return userInsertErr
|
||||
}
|
||||
result, err := s.userModel.Insert(ctx, session, user)
|
||||
if err != nil {
|
||||
return err
|
||||
userId = user.Id
|
||||
_, userAuthInsertErr := s.userAuthModel.Insert(ctx, session, &model.UserAuth{Id: uuid.NewString(), UserId: userId, AuthType: model.UserAuthTypeMobile, AuthKey: mobile})
|
||||
if userAuthInsertErr != nil {
|
||||
return userAuthInsertErr
|
||||
}
|
||||
userId, err = result.LastInsertId()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.userAuthModel.Insert(ctx, session, &model.UserAuth{
|
||||
UserId: userId,
|
||||
AuthType: model.UserAuthTypeMobile,
|
||||
AuthKey: mobile,
|
||||
})
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
return "", err
|
||||
}
|
||||
return userId, nil
|
||||
}
|
||||
|
||||
// 双重判断是否已经注册
|
||||
if claims.UserType == model.UserTypeNormal {
|
||||
return 0, errors.New("用户已注册")
|
||||
return "", errors.New("用户已注册")
|
||||
}
|
||||
var userId int64
|
||||
var userId string
|
||||
// 临时转正式注册
|
||||
err = s.userModel.Trans(ctx, func(ctx context.Context, session sqlx.Session) error {
|
||||
user := &model.User{
|
||||
Mobile: sql.NullString{String: mobile, Valid: true},
|
||||
user := &model.User{Id: uuid.NewString(), Mobile: sql.NullString{String: mobile, Valid: true}}
|
||||
if _, userInsertErr := s.userModel.Insert(ctx, session, user); userInsertErr != nil {
|
||||
return userInsertErr
|
||||
}
|
||||
result, err := s.userModel.Insert(ctx, session, user)
|
||||
if err != nil {
|
||||
return err
|
||||
userId = user.Id
|
||||
_, userAuthInsertErr := s.userAuthModel.Insert(ctx, session, &model.UserAuth{Id: uuid.NewString(), UserId: userId, AuthType: model.UserAuthTypeMobile, AuthKey: mobile})
|
||||
if userAuthInsertErr != nil {
|
||||
return userAuthInsertErr
|
||||
}
|
||||
userId, err = result.LastInsertId()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = s.userAuthModel.Insert(ctx, session, &model.UserAuth{
|
||||
UserId: userId,
|
||||
AuthType: model.UserAuthTypeMobile,
|
||||
AuthKey: mobile,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = s.TempUserBindUser(ctx, session, userId)
|
||||
if err != nil {
|
||||
return err
|
||||
tempUserBindErr := s.TempUserBindUser(ctx, session, userId)
|
||||
if tempUserBindErr != nil {
|
||||
return tempUserBindErr
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
return "", err
|
||||
}
|
||||
return userId, nil
|
||||
}
|
||||
|
||||
// TempUserBindUser 临时用户绑定用户
|
||||
func (s *UserService) TempUserBindUser(ctx context.Context, session sqlx.Session, normalUserID int64) error {
|
||||
func (s *UserService) TempUserBindUser(ctx context.Context, session sqlx.Session, normalUserID string) error {
|
||||
claims, err := ctxdata.GetClaimsFromCtx(ctx)
|
||||
if err != nil && !errors.Is(err, ctxdata.ErrNoInCtx) {
|
||||
return err
|
||||
@@ -207,38 +198,17 @@ func (s *UserService) TempUserBindUser(ctx context.Context, session sqlx.Session
|
||||
return errors.New("无临时用户")
|
||||
}
|
||||
|
||||
// 使用事务上下文查询临时用户
|
||||
userTemp, err := s.userTempModel.FindOne(ctx, claims.UserId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 检查是否已经注册过
|
||||
userAuth, err := s.userAuthModel.FindOneByAuthTypeAuthKey(ctx, userTemp.AuthType, userTemp.AuthKey)
|
||||
existingAuth, err := s.userAuthModel.FindOneByAuthTypeAuthKey(ctx, claims.AuthType, claims.AuthKey)
|
||||
if err != nil && !errors.Is(err, model.ErrNotFound) {
|
||||
return err
|
||||
}
|
||||
if userAuth != nil {
|
||||
if existingAuth != nil {
|
||||
return errors.New("临时用户已注册")
|
||||
}
|
||||
|
||||
if session == nil {
|
||||
err := s.userAuthModel.Trans(ctx, func(ctx context.Context, session sqlx.Session) error {
|
||||
_, err = s.userAuthModel.Insert(ctx, session, &model.UserAuth{
|
||||
UserId: normalUserID,
|
||||
AuthType: userTemp.AuthType,
|
||||
AuthKey: userTemp.AuthKey,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 重新获取最新的userTemp数据,确保版本号是最新的
|
||||
latestUserTemp, err := s.userTempModel.FindOne(ctx, claims.UserId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = s.userTempModel.DeleteSoft(ctx, session, latestUserTemp)
|
||||
_, err = s.userAuthModel.Insert(ctx, session, &model.UserAuth{Id: uuid.NewString(), UserId: normalUserID, AuthType: claims.AuthType, AuthKey: claims.AuthKey})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -249,48 +219,10 @@ func (s *UserService) TempUserBindUser(ctx context.Context, session sqlx.Session
|
||||
}
|
||||
return nil
|
||||
} else {
|
||||
_, err = s.userAuthModel.Insert(ctx, session, &model.UserAuth{
|
||||
UserId: normalUserID,
|
||||
AuthType: userTemp.AuthType,
|
||||
AuthKey: userTemp.AuthKey,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 重新获取最新的userTemp数据,确保版本号是最新的
|
||||
latestUserTemp, err := s.userTempModel.FindOne(ctx, claims.UserId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = s.userTempModel.DeleteSoft(ctx, session, latestUserTemp)
|
||||
_, err = s.userAuthModel.Insert(ctx, session, &model.UserAuth{Id: uuid.NewString(), UserId: normalUserID, AuthType: claims.AuthType, AuthKey: claims.AuthKey})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// _bak_RegisterUUIDUser 注册UUID用户,返回用户ID
|
||||
func (s *UserService) _bak_RegisterUUIDUser(ctx context.Context) error {
|
||||
// 生成UUID
|
||||
uuidStr, err := s.GenerateUUIDUserId(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = s.userTempModel.Trans(ctx, func(ctx context.Context, session sqlx.Session) error {
|
||||
// 创建用户临时记录
|
||||
userTemp := &model.UserTemp{
|
||||
AuthType: model.UserAuthTypeUUID,
|
||||
AuthKey: uuidStr,
|
||||
}
|
||||
_, err := s.userTempModel.Insert(ctx, session, userTemp)
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"ycc-server/app/main/api/internal/config"
|
||||
tianyuanapi "ycc-server/app/main/api/internal/service/tianyuanapi_sdk"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"ycc-server/app/main/api/internal/config"
|
||||
tianyuanapi "ycc-server/app/main/api/internal/service/tianyuanapi_sdk"
|
||||
|
||||
"github.com/tidwall/gjson"
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
type VerificationService struct {
|
||||
c config.Config
|
||||
@@ -150,3 +153,55 @@ func (r *VerificationService) ThreeFactorVerification(request ThreeFactorVerific
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
// GetWechatH5OpenID 通过code获取微信H5 OpenID
|
||||
func (r *VerificationService) GetWechatH5OpenID(ctx context.Context, code string) (string, error) {
|
||||
appID := r.c.WechatH5.AppID
|
||||
appSecret := r.c.WechatH5.AppSecret
|
||||
url := fmt.Sprintf("https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code", appID, appSecret, code)
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
var data struct {
|
||||
Openid string `json:"openid"`
|
||||
}
|
||||
if err := json.Unmarshal(body, &data); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if data.Openid == "" {
|
||||
return "", fmt.Errorf("openid为空")
|
||||
}
|
||||
return data.Openid, nil
|
||||
}
|
||||
|
||||
// GetWechatMiniOpenID 通过code获取微信小程序 OpenID
|
||||
func (r *VerificationService) GetWechatMiniOpenID(ctx context.Context, code string) (string, error) {
|
||||
appID := r.c.WechatMini.AppID
|
||||
appSecret := r.c.WechatMini.AppSecret
|
||||
url := fmt.Sprintf("https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code", appID, appSecret, code)
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
var data struct {
|
||||
Openid string `json:"openid"`
|
||||
}
|
||||
if err := json.Unmarshal(body, &data); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if data.Openid == "" {
|
||||
return "", fmt.Errorf("openid为空")
|
||||
}
|
||||
return data.Openid, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user