package agent import ( "context" "encoding/hex" "encoding/json" "strconv" "ycc-server/app/main/model" "ycc-server/common/ctxdata" "ycc-server/common/globalkey" "ycc-server/common/xerr" "ycc-server/pkg/lzkit/crypto" "github.com/Masterminds/squirrel" "github.com/pkg/errors" "ycc-server/app/main/api/internal/svc" "ycc-server/app/main/api/internal/types" "github.com/zeromicro/go-zero/core/logx" ) type GeneratingLinkLogic struct { logx.Logger ctx context.Context svcCtx *svc.ServiceContext } func NewGeneratingLinkLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GeneratingLinkLogic { return &GeneratingLinkLogic{ Logger: logx.WithContext(ctx), ctx: ctx, svcCtx: svcCtx, } } func (l *GeneratingLinkLogic) GeneratingLink(req *types.AgentGeneratingLinkReq) (resp *types.AgentGeneratingLinkResp, err error) { userID, err := ctxdata.GetUidFromCtx(l.ctx) if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成推广链接失败, %v", err) } // 1. 获取代理信息 agentModel, 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) } // 2. 获取系统配置 basePrice, err := l.getConfigFloat("base_price") if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取基础底价配置失败, %v", err) } systemMaxPrice, err := l.getConfigFloat("system_max_price") if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取系统价格上限配置失败, %v", err) } // 4. 计算实际底价(基础底价 + 等级加成) levelBonus := l.getLevelBonus(agentModel.Level) actualBasePrice := basePrice + float64(levelBonus) // 5. 验证设定价格范围 if req.SetPrice < actualBasePrice || req.SetPrice > systemMaxPrice { return nil, errors.Wrapf(xerr.NewErrMsg("设定价格必须在 %.2f 到 %.2f 之间"), "设定价格必须在 %.2f 到 %.2f 之间", actualBasePrice, systemMaxPrice) } // 6. 检查是否已存在相同的链接(同一代理、同一产品、同一价格) builder := l.svcCtx.AgentLinkModel.SelectBuilder().Where(squirrel.And{ squirrel.Eq{"agent_id": agentModel.Id}, squirrel.Eq{"product_id": req.ProductId}, squirrel.Eq{"set_price": req.SetPrice}, squirrel.Eq{"del_state": globalkey.DelStateNo}, }) existingLinks, err := l.svcCtx.AgentLinkModel.FindAll(l.ctx, builder, "") if err != nil && !errors.Is(err, model.ErrNotFound) { return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询推广链接失败, %v", err) } if len(existingLinks) > 0 { // 已存在,直接返回 return &types.AgentGeneratingLinkResp{ LinkIdentifier: existingLinks[0].LinkIdentifier, }, nil } // 7. 生成推广链接标识 var agentIdentifier types.AgentIdentifier agentIdentifier.AgentID = agentModel.Id agentIdentifier.ProductID = req.ProductId agentIdentifier.SetPrice = req.SetPrice agentIdentifierByte, err := json.Marshal(agentIdentifier) if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "序列化标识失败, %v", err) } // 8. 加密链接标识 secretKey := l.svcCtx.Config.Encrypt.SecretKey key, decodeErr := hex.DecodeString(secretKey) if decodeErr != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取AES密钥失败: %+v", decodeErr) } encrypted, err := crypto.AesEncryptURL(agentIdentifierByte, key) if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "加密链接标识失败, %v", err) } // 9. 保存推广链接 agentLink := &model.AgentLink{ AgentId: agentModel.Id, UserId: userID, ProductId: req.ProductId, LinkIdentifier: encrypted, SetPrice: req.SetPrice, ActualBasePrice: actualBasePrice, } _, err = l.svcCtx.AgentLinkModel.Insert(l.ctx, nil, agentLink) if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "保存推广链接失败, %v", err) } return &types.AgentGeneratingLinkResp{ LinkIdentifier: encrypted, }, nil } // getLevelBonus 获取等级加成 func (l *GeneratingLinkLogic) getLevelBonus(level int64) int64 { switch level { case 1: // 普通 return 6 case 2: // 黄金 return 3 case 3: // 钻石 return 0 default: return 0 } } // getConfigFloat 获取配置值(浮点数) func (l *GeneratingLinkLogic) getConfigFloat(configKey string) (float64, error) { config, err := l.svcCtx.AgentConfigModel.FindOneByConfigKey(l.ctx, configKey) if err != nil { return 0, err } value, err := strconv.ParseFloat(config.ConfigValue, 64) if err != nil { return 0, errors.Wrapf(err, "解析配置值失败, key: %s, value: %s", configKey, config.ConfigValue) } return value, nil }