Files
ycc-proxy-server/app/main/api/internal/logic/agent/generatinglinklogic.go

159 lines
4.8 KiB
Go
Raw Normal View History

2025-11-27 13:09:54 +08:00
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
}