first commit
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
package admin_agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminAuditAgentLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminAuditAgentLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminAuditAgentLogic {
|
||||
return &AdminAuditAgentLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminAuditAgentLogic) AdminAuditAgent(req *types.AdminAuditAgentReq) (resp *types.AdminAuditAgentResp, err error) {
|
||||
// todo: add your logic here and delete this line
|
||||
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package admin_agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"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 AdminAuditRealNameLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminAuditRealNameLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminAuditRealNameLogic {
|
||||
return &AdminAuditRealNameLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
// AdminAuditRealName 实名认证审核(已废弃:实名认证改为三要素核验,无需审核)
|
||||
func (l *AdminAuditRealNameLogic) AdminAuditRealName(req *types.AdminAuditRealNameReq) (resp *types.AdminAuditRealNameResp, err error) {
|
||||
// 该接口已废弃,实名认证现在通过三要素核验自动完成,无需人工审核
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("该接口已废弃,实名认证改为三要素核验,无需审核"), "")
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
package admin_agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"time"
|
||||
"ycc-server/common/globalkey"
|
||||
"ycc-server/common/xerr"
|
||||
"ycc-server/pkg/lzkit/lzUtils"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminAuditWithdrawalLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminAuditWithdrawalLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminAuditWithdrawalLogic {
|
||||
return &AdminAuditWithdrawalLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminAuditWithdrawalLogic) AdminAuditWithdrawal(req *types.AdminAuditWithdrawalReq) (resp *types.AdminAuditWithdrawalResp, err error) {
|
||||
// 1. 查询提现记录
|
||||
withdrawal, err := l.svcCtx.AgentWithdrawalModel.FindOne(l.ctx, req.WithdrawalId)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询提现记录失败, %v", err)
|
||||
}
|
||||
|
||||
// 3. 检查状态(必须是待审核状态)
|
||||
if withdrawal.Status != 1 {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("该提现记录已处理"), "")
|
||||
}
|
||||
|
||||
// 4. 使用事务处理审核
|
||||
err = l.svcCtx.AgentWithdrawalModel.Trans(l.ctx, func(transCtx context.Context, session sqlx.Session) error {
|
||||
if req.Status == 2 { // 审核通过
|
||||
// 4.1 更新提现记录状态为提现中
|
||||
withdrawal.Status = 4 // 提现中
|
||||
withdrawal.Remark = sql.NullString{String: req.Remark, Valid: true}
|
||||
if err := l.svcCtx.AgentWithdrawalModel.UpdateWithVersion(transCtx, session, withdrawal); err != nil {
|
||||
return errors.Wrapf(err, "更新提现记录失败")
|
||||
}
|
||||
|
||||
// 4.2 调用支付宝转账接口
|
||||
outBizNo := withdrawal.WithdrawNo
|
||||
transferResp, err := l.svcCtx.AlipayService.AliTransfer(transCtx, withdrawal.PayeeAccount, withdrawal.PayeeName, withdrawal.ActualAmount, "代理提现", outBizNo)
|
||||
if err != nil {
|
||||
// 转账失败,更新状态为失败
|
||||
withdrawal.Status = 6 // 提现失败
|
||||
withdrawal.Remark = sql.NullString{String: fmt.Sprintf("转账失败: %v", err), Valid: true}
|
||||
l.svcCtx.AgentWithdrawalModel.UpdateWithVersion(transCtx, session, withdrawal)
|
||||
|
||||
// 解冻余额
|
||||
wallet, err := l.svcCtx.AgentWalletModel.FindOneByAgentId(transCtx, withdrawal.AgentId)
|
||||
if err == nil {
|
||||
wallet.FrozenBalance -= withdrawal.Amount
|
||||
wallet.Balance += withdrawal.Amount
|
||||
l.svcCtx.AgentWalletModel.UpdateWithVersion(transCtx, session, wallet)
|
||||
}
|
||||
|
||||
return errors.Wrapf(err, "支付宝转账失败")
|
||||
}
|
||||
|
||||
// 4.3 根据转账结果更新状态
|
||||
switch transferResp.Status {
|
||||
case "SUCCESS":
|
||||
// 转账成功
|
||||
withdrawal.Status = 5 // 提现成功
|
||||
if err := l.svcCtx.AgentWithdrawalModel.UpdateWithVersion(transCtx, session, withdrawal); err != nil {
|
||||
return errors.Wrapf(err, "更新提现记录失败")
|
||||
}
|
||||
|
||||
// 更新钱包(解冻并扣除)
|
||||
wallet, err := l.svcCtx.AgentWalletModel.FindOneByAgentId(transCtx, withdrawal.AgentId)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "查询钱包失败")
|
||||
}
|
||||
wallet.FrozenBalance -= withdrawal.Amount
|
||||
wallet.WithdrawnAmount += withdrawal.Amount
|
||||
if err := l.svcCtx.AgentWalletModel.UpdateWithVersion(transCtx, session, wallet); err != nil {
|
||||
return errors.Wrapf(err, "更新钱包失败")
|
||||
}
|
||||
|
||||
// 更新扣税记录状态
|
||||
taxBuilder := l.svcCtx.AgentWithdrawalTaxModel.SelectBuilder().
|
||||
Where("withdrawal_id = ? AND del_state = ?", withdrawal.Id, globalkey.DelStateNo)
|
||||
taxRecords, err := l.svcCtx.AgentWithdrawalTaxModel.FindAll(transCtx, taxBuilder, "")
|
||||
if err == nil && len(taxRecords) > 0 {
|
||||
taxRecord := taxRecords[0]
|
||||
taxRecord.TaxStatus = 2 // 已扣税
|
||||
taxRecord.TaxTime = lzUtils.TimeToNullTime(time.Now())
|
||||
l.svcCtx.AgentWithdrawalTaxModel.UpdateWithVersion(transCtx, session, taxRecord)
|
||||
}
|
||||
|
||||
case "FAIL":
|
||||
// 转账失败
|
||||
withdrawal.Status = 6 // 提现失败
|
||||
errorMsg := l.mapAlipayError(transferResp.SubCode)
|
||||
withdrawal.Remark = sql.NullString{String: errorMsg, Valid: true}
|
||||
if err := l.svcCtx.AgentWithdrawalModel.UpdateWithVersion(transCtx, session, withdrawal); err != nil {
|
||||
return errors.Wrapf(err, "更新提现记录失败")
|
||||
}
|
||||
|
||||
// 解冻余额
|
||||
wallet, err := l.svcCtx.AgentWalletModel.FindOneByAgentId(transCtx, withdrawal.AgentId)
|
||||
if err == nil {
|
||||
wallet.FrozenBalance -= withdrawal.Amount
|
||||
wallet.Balance += withdrawal.Amount
|
||||
l.svcCtx.AgentWalletModel.UpdateWithVersion(transCtx, session, wallet)
|
||||
}
|
||||
|
||||
case "DEALING":
|
||||
// 处理中,保持提现中状态,后续通过轮询更新
|
||||
// 状态已经是4(提现中),无需更新
|
||||
}
|
||||
|
||||
} else if req.Status == 3 { // 审核拒绝
|
||||
// 4.1 更新提现记录状态为拒绝
|
||||
withdrawal.Status = 3 // 审核拒绝
|
||||
withdrawal.Remark = sql.NullString{String: req.Remark, Valid: true}
|
||||
if err := l.svcCtx.AgentWithdrawalModel.UpdateWithVersion(transCtx, session, withdrawal); err != nil {
|
||||
return errors.Wrapf(err, "更新提现记录失败")
|
||||
}
|
||||
|
||||
// 4.2 解冻余额
|
||||
wallet, err := l.svcCtx.AgentWalletModel.FindOneByAgentId(transCtx, withdrawal.AgentId)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "查询钱包失败")
|
||||
}
|
||||
wallet.FrozenBalance -= withdrawal.Amount
|
||||
wallet.Balance += withdrawal.Amount
|
||||
if err := l.svcCtx.AgentWalletModel.UpdateWithVersion(transCtx, session, wallet); err != nil {
|
||||
return errors.Wrapf(err, "更新钱包失败")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &types.AdminAuditWithdrawalResp{
|
||||
Success: true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// mapAlipayError 映射支付宝错误码
|
||||
func (l *AdminAuditWithdrawalLogic) mapAlipayError(code string) string {
|
||||
errorMapping := map[string]string{
|
||||
"PAYEE_USERINFO_ERROR": "收款方姓名或信息不匹配",
|
||||
"PAYEE_CARD_INFO_ERROR": "收款支付宝账号及户名不一致",
|
||||
"PAYEE_IDENTITY_NOT_MATCH": "收款方身份信息不匹配",
|
||||
"PAYEE_USER_IS_INST": "收款方为金融机构,不能使用提现功能",
|
||||
"PAYEE_USER_TYPE_ERROR": "该支付宝账号类型不支持提现",
|
||||
}
|
||||
if msg, ok := errorMapping[code]; ok {
|
||||
return msg
|
||||
}
|
||||
return "系统错误,请联系客服"
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
package admin_agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"time"
|
||||
"ycc-server/app/main/model"
|
||||
"ycc-server/common/tool"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminGenerateDiamondInviteCodeLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminGenerateDiamondInviteCodeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminGenerateDiamondInviteCodeLogic {
|
||||
return &AdminGenerateDiamondInviteCodeLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminGenerateDiamondInviteCodeLogic) AdminGenerateDiamondInviteCode(req *types.AdminGenerateDiamondInviteCodeReq) (resp *types.AdminGenerateDiamondInviteCodeResp, err error) {
|
||||
// 1. 验证生成数量
|
||||
if req.Count <= 0 || req.Count > 100 {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("生成数量必须在1-100之间"), "")
|
||||
}
|
||||
|
||||
// 2. 生成钻石邀请码(平台发放,agent_id为NULL,target_level为3)
|
||||
codes := make([]string, 0, req.Count)
|
||||
var expireTime sql.NullTime
|
||||
if req.ExpireDays > 0 {
|
||||
expireTime = sql.NullTime{
|
||||
Time: time.Now().AddDate(0, 0, int(req.ExpireDays)),
|
||||
Valid: true,
|
||||
}
|
||||
}
|
||||
|
||||
err = l.svcCtx.AgentInviteCodeModel.Trans(l.ctx, func(transCtx context.Context, session sqlx.Session) error {
|
||||
for i := int64(0); i < req.Count; i++ {
|
||||
// 生成8位随机邀请码(大小写字母+数字)
|
||||
var code string
|
||||
maxRetries := 10 // 最大重试次数
|
||||
for retry := 0; retry < maxRetries; retry++ {
|
||||
code = tool.Krand(8, tool.KC_RAND_KIND_ALL)
|
||||
// 检查邀请码是否已存在
|
||||
_, err := l.svcCtx.AgentInviteCodeModel.FindOneByCode(transCtx, code)
|
||||
if err != nil {
|
||||
if errors.Is(err, model.ErrNotFound) {
|
||||
// 邀请码不存在,可以使用
|
||||
break
|
||||
}
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "检查邀请码失败, %v", err)
|
||||
}
|
||||
// 邀请码已存在,继续生成
|
||||
if retry == maxRetries-1 {
|
||||
return errors.Wrapf(xerr.NewErrMsg("生成邀请码失败,请重试"), "")
|
||||
}
|
||||
}
|
||||
|
||||
// 创建邀请码记录(平台发放的钻石邀请码)
|
||||
inviteCode := &model.AgentInviteCode{
|
||||
Code: code,
|
||||
AgentId: sql.NullInt64{Valid: false}, // NULL表示平台发放
|
||||
TargetLevel: 3, // 钻石代理
|
||||
Status: 0, // 未使用
|
||||
ExpireTime: expireTime,
|
||||
Remark: sql.NullString{String: req.Remark, Valid: req.Remark != ""},
|
||||
}
|
||||
|
||||
_, err := l.svcCtx.AgentInviteCodeModel.Insert(transCtx, session, inviteCode)
|
||||
if err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "创建邀请码失败, %v", err)
|
||||
}
|
||||
|
||||
codes = append(codes, code)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &types.AdminGenerateDiamondInviteCodeResp{
|
||||
Codes: codes,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package admin_agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
|
||||
"github.com/Masterminds/squirrel"
|
||||
"github.com/jinzhu/copier"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminGetAgentCommissionListLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminGetAgentCommissionListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminGetAgentCommissionListLogic {
|
||||
return &AdminGetAgentCommissionListLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminGetAgentCommissionListLogic) AdminGetAgentCommissionList(req *types.AdminGetAgentCommissionListReq) (resp *types.AdminGetAgentCommissionListResp, err error) {
|
||||
builder := l.svcCtx.AgentCommissionModel.SelectBuilder()
|
||||
if req.AgentId != nil {
|
||||
builder = builder.Where(squirrel.Eq{"agent_id": *req.AgentId})
|
||||
}
|
||||
if req.Status != nil {
|
||||
builder = builder.Where(squirrel.Eq{"status": *req.Status})
|
||||
}
|
||||
// 产品名称筛选功能已移除,如需可按product_id筛选
|
||||
|
||||
list, total, err := l.svcCtx.AgentCommissionModel.FindPageListByPageWithTotal(l.ctx, builder, req.Page, req.PageSize, "create_time DESC")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 批量查product_name
|
||||
productIds := make(map[int64]struct{})
|
||||
for _, v := range list {
|
||||
productIds[v.ProductId] = struct{}{}
|
||||
}
|
||||
productNameMap := make(map[int64]string)
|
||||
if len(productIds) > 0 {
|
||||
ids := make([]int64, 0, len(productIds))
|
||||
for id := range productIds {
|
||||
ids = append(ids, id)
|
||||
}
|
||||
builder := l.svcCtx.ProductModel.SelectBuilder().Where(squirrel.Eq{"id": ids})
|
||||
products, _ := l.svcCtx.ProductModel.FindAll(l.ctx, builder, "")
|
||||
for _, p := range products {
|
||||
productNameMap[p.Id] = p.ProductName
|
||||
}
|
||||
}
|
||||
|
||||
items := make([]types.AgentCommissionListItem, 0, len(list))
|
||||
for _, v := range list {
|
||||
item := types.AgentCommissionListItem{}
|
||||
_ = copier.Copy(&item, v)
|
||||
item.ProductName = productNameMap[v.ProductId]
|
||||
item.CreateTime = v.CreateTime.Format("2006-01-02 15:04:05")
|
||||
items = append(items, item)
|
||||
}
|
||||
resp = &types.AdminGetAgentCommissionListResp{
|
||||
Total: total,
|
||||
Items: items,
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package admin_agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminGetAgentConfigLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminGetAgentConfigLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminGetAgentConfigLogic {
|
||||
return &AdminGetAgentConfigLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminGetAgentConfigLogic) AdminGetAgentConfig() (resp *types.AdminGetAgentConfigResp, err error) {
|
||||
// 获取配置值的辅助函数
|
||||
getConfigFloat := func(key string) float64 {
|
||||
config, err := l.svcCtx.AgentConfigModel.FindOneByConfigKey(l.ctx, key)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
value, _ := strconv.ParseFloat(config.ConfigValue, 64)
|
||||
return value
|
||||
}
|
||||
|
||||
// 获取等级加成配置
|
||||
level1Bonus := getConfigFloat("level_1_bonus")
|
||||
level2Bonus := getConfigFloat("level_2_bonus")
|
||||
level3Bonus := getConfigFloat("level_3_bonus")
|
||||
|
||||
// 获取升级费用配置
|
||||
upgradeToGoldFee := getConfigFloat("upgrade_to_gold_fee")
|
||||
upgradeToDiamondFee := getConfigFloat("upgrade_to_diamond_fee")
|
||||
|
||||
// 获取升级返佣配置
|
||||
upgradeToGoldRebate := getConfigFloat("upgrade_to_gold_rebate")
|
||||
upgradeToDiamondRebate := getConfigFloat("upgrade_to_diamond_rebate")
|
||||
|
||||
return &types.AdminGetAgentConfigResp{
|
||||
BasePrice: getConfigFloat("base_price"),
|
||||
SystemMaxPrice: getConfigFloat("system_max_price"),
|
||||
PriceThreshold: getConfigFloat("price_threshold"),
|
||||
PriceFeeRate: getConfigFloat("price_fee_rate"),
|
||||
LevelBonus: types.LevelBonusConfig{
|
||||
Normal: int64(level1Bonus),
|
||||
Gold: int64(level2Bonus),
|
||||
Diamond: int64(level3Bonus),
|
||||
},
|
||||
UpgradeFee: types.UpgradeFeeConfig{
|
||||
NormalToGold: upgradeToGoldFee,
|
||||
NormalToDiamond: upgradeToDiamondFee,
|
||||
GoldToDiamond: upgradeToDiamondFee - upgradeToGoldFee,
|
||||
},
|
||||
UpgradeRebate: types.UpgradeRebateConfig{
|
||||
NormalToGoldRebate: upgradeToGoldRebate,
|
||||
ToDiamondRebate: upgradeToDiamondRebate,
|
||||
},
|
||||
TaxRate: getConfigFloat("tax_rate"),
|
||||
TaxExemptionAmount: getConfigFloat("tax_exemption_amount"),
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package admin_agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
|
||||
"github.com/Masterminds/squirrel"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminGetAgentLinkListLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminGetAgentLinkListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminGetAgentLinkListLogic {
|
||||
return &AdminGetAgentLinkListLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminGetAgentLinkListLogic) AdminGetAgentLinkList(req *types.AdminGetAgentLinkListReq) (resp *types.AdminGetAgentLinkListResp, err error) {
|
||||
builder := l.svcCtx.AgentLinkModel.SelectBuilder()
|
||||
if req.AgentId != nil {
|
||||
builder = builder.Where("agent_id = ?", *req.AgentId)
|
||||
}
|
||||
if req.LinkIdentifier != nil && *req.LinkIdentifier != "" {
|
||||
builder = builder.Where("link_identifier = ?", *req.LinkIdentifier)
|
||||
}
|
||||
|
||||
// 如果传入ProductId,添加筛选条件
|
||||
if req.ProductId != nil {
|
||||
builder = builder.Where("product_id = ?", *req.ProductId)
|
||||
}
|
||||
|
||||
links, total, err := l.svcCtx.AgentLinkModel.FindPageListByPageWithTotal(l.ctx, builder, req.Page, req.PageSize, "id DESC")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 批量查product_id->name,避免N+1
|
||||
productIdSet := make(map[int64]struct{})
|
||||
for _, link := range links {
|
||||
productIdSet[link.ProductId] = struct{}{}
|
||||
}
|
||||
productIdList := make([]int64, 0, len(productIdSet))
|
||||
for id := range productIdSet {
|
||||
productIdList = append(productIdList, id)
|
||||
}
|
||||
productNameMap := make(map[int64]string)
|
||||
if len(productIdList) > 0 {
|
||||
products, _ := l.svcCtx.ProductModel.FindAll(l.ctx, l.svcCtx.ProductModel.SelectBuilder().Where(squirrel.Eq{"id": productIdList}), "")
|
||||
for _, p := range products {
|
||||
productNameMap[p.Id] = p.ProductName
|
||||
}
|
||||
}
|
||||
|
||||
items := make([]types.AgentLinkListItem, 0, len(links))
|
||||
for _, link := range links {
|
||||
items = append(items, types.AgentLinkListItem{
|
||||
Id: link.Id,
|
||||
AgentId: link.AgentId,
|
||||
ProductId: link.ProductId,
|
||||
ProductName: productNameMap[link.ProductId],
|
||||
SetPrice: link.SetPrice,
|
||||
ActualBasePrice: link.ActualBasePrice,
|
||||
LinkIdentifier: link.LinkIdentifier,
|
||||
CreateTime: link.CreateTime.Format("2006-01-02 15:04:05"),
|
||||
})
|
||||
}
|
||||
|
||||
resp = &types.AdminGetAgentLinkListResp{
|
||||
Total: total,
|
||||
Items: items,
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
package admin_agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/common/xerr"
|
||||
"ycc-server/pkg/lzkit/crypto"
|
||||
|
||||
"github.com/Masterminds/squirrel"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminGetAgentListLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminGetAgentListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminGetAgentListLogic {
|
||||
return &AdminGetAgentListLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminGetAgentListLogic) AdminGetAgentList(req *types.AdminGetAgentListReq) (resp *types.AdminGetAgentListResp, err error) {
|
||||
builder := l.svcCtx.AgentModel.SelectBuilder()
|
||||
|
||||
// 如果传入TeamLeaderId,则查找该团队首领下的所有代理
|
||||
if req.TeamLeaderId != nil {
|
||||
builder = builder.Where(squirrel.Eq{"team_leader_id": *req.TeamLeaderId})
|
||||
}
|
||||
if req.Level != nil {
|
||||
builder = builder.Where(squirrel.Eq{"level": *req.Level})
|
||||
}
|
||||
if req.Mobile != nil && *req.Mobile != "" {
|
||||
// 加密手机号进行查询
|
||||
encryptedMobile, err := crypto.EncryptMobile(*req.Mobile, l.svcCtx.Config.Encrypt.SecretKey)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "加密手机号失败: %v", err)
|
||||
}
|
||||
builder = builder.Where(squirrel.Eq{"mobile": encryptedMobile})
|
||||
}
|
||||
if req.Region != nil && *req.Region != "" {
|
||||
// 注意:region字段现在是可选的,查询时需要处理NULL值
|
||||
// 如果region字段是NULL,使用IS NULL查询;否则使用等值查询
|
||||
// 这里简化处理,直接使用等值查询(如果数据库中有NULL值,需要特殊处理)
|
||||
builder = builder.Where(squirrel.Eq{"region": *req.Region})
|
||||
}
|
||||
|
||||
agents, total, err := l.svcCtx.AgentModel.FindPageListByPageWithTotal(l.ctx, builder, req.Page, req.PageSize, "id DESC")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
items := make([]types.AgentListItem, 0, len(agents))
|
||||
|
||||
for _, agent := range agents {
|
||||
// 获取等级名称
|
||||
levelName := ""
|
||||
switch agent.Level {
|
||||
case 1:
|
||||
levelName = "普通"
|
||||
case 2:
|
||||
levelName = "黄金"
|
||||
case 3:
|
||||
levelName = "钻石"
|
||||
}
|
||||
|
||||
agent.Mobile, err = crypto.DecryptMobile(agent.Mobile, l.svcCtx.Config.Encrypt.SecretKey)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取代理信息, 解密手机号失败: %v", err)
|
||||
}
|
||||
|
||||
// 查询钱包信息
|
||||
wallet, _ := l.svcCtx.AgentWalletModel.FindOneByAgentId(l.ctx, agent.Id)
|
||||
|
||||
// 查询实名认证信息
|
||||
realNameInfo, _ := l.svcCtx.AgentRealNameModel.FindOneByAgentId(l.ctx, agent.Id)
|
||||
isRealName := false
|
||||
if realNameInfo != nil && realNameInfo.VerifyTime.Valid {
|
||||
isRealName = true // verify_time不为空表示已通过三要素核验
|
||||
}
|
||||
|
||||
wechatId := ""
|
||||
if agent.WechatId.Valid {
|
||||
wechatId = agent.WechatId.String
|
||||
}
|
||||
teamLeaderId := int64(0)
|
||||
if agent.TeamLeaderId.Valid {
|
||||
teamLeaderId = agent.TeamLeaderId.Int64
|
||||
}
|
||||
|
||||
// 获取区域
|
||||
region := ""
|
||||
if agent.Region.Valid {
|
||||
region = agent.Region.String
|
||||
}
|
||||
|
||||
item := types.AgentListItem{
|
||||
Id: agent.Id,
|
||||
UserId: agent.UserId,
|
||||
Level: agent.Level,
|
||||
LevelName: levelName,
|
||||
Region: region,
|
||||
Mobile: agent.Mobile,
|
||||
WechatId: wechatId,
|
||||
TeamLeaderId: teamLeaderId,
|
||||
Balance: 0,
|
||||
TotalEarnings: 0,
|
||||
FrozenBalance: 0,
|
||||
WithdrawnAmount: 0,
|
||||
IsRealName: isRealName,
|
||||
CreateTime: agent.CreateTime.Format("2006-01-02 15:04:05"),
|
||||
}
|
||||
|
||||
if wallet != nil {
|
||||
item.Balance = wallet.Balance
|
||||
item.TotalEarnings = wallet.TotalEarnings
|
||||
item.FrozenBalance = wallet.FrozenBalance
|
||||
item.WithdrawnAmount = wallet.WithdrawnAmount
|
||||
}
|
||||
|
||||
items = append(items, item)
|
||||
}
|
||||
|
||||
resp = &types.AdminGetAgentListResp{
|
||||
Total: total,
|
||||
Items: items,
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
package admin_agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"ycc-server/common/globalkey"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"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 AdminGetAgentOrderListLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminGetAgentOrderListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminGetAgentOrderListLogic {
|
||||
return &AdminGetAgentOrderListLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminGetAgentOrderListLogic) AdminGetAgentOrderList(req *types.AdminGetAgentOrderListReq) (resp *types.AdminGetAgentOrderListResp, err error) {
|
||||
builder := l.svcCtx.AgentOrderModel.SelectBuilder().
|
||||
Where("del_state = ?", globalkey.DelStateNo)
|
||||
|
||||
if req.AgentId != nil {
|
||||
builder = builder.Where("agent_id = ?", *req.AgentId)
|
||||
}
|
||||
if req.OrderId != nil {
|
||||
builder = builder.Where("order_id = ?", *req.OrderId)
|
||||
}
|
||||
if req.ProcessStatus != nil {
|
||||
builder = builder.Where("process_status = ?", *req.ProcessStatus)
|
||||
}
|
||||
|
||||
// 分页查询
|
||||
page := req.Page
|
||||
if page <= 0 {
|
||||
page = 1
|
||||
}
|
||||
pageSize := req.PageSize
|
||||
if pageSize <= 0 {
|
||||
pageSize = 20
|
||||
}
|
||||
|
||||
orders, total, err := l.svcCtx.AgentOrderModel.FindPageListByPageWithTotal(l.ctx, builder, page, pageSize, "create_time DESC")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询代理订单列表失败, %v", err)
|
||||
}
|
||||
|
||||
// 批量查询产品名称
|
||||
productIdSet := make(map[int64]struct{})
|
||||
for _, order := range orders {
|
||||
productIdSet[order.ProductId] = struct{}{}
|
||||
}
|
||||
productIdList := make([]int64, 0, len(productIdSet))
|
||||
for id := range productIdSet {
|
||||
productIdList = append(productIdList, id)
|
||||
}
|
||||
productNameMap := make(map[int64]string)
|
||||
if len(productIdList) > 0 {
|
||||
products, _ := l.svcCtx.ProductModel.FindAll(l.ctx, l.svcCtx.ProductModel.SelectBuilder().Where(squirrel.Eq{"id": productIdList}), "")
|
||||
for _, p := range products {
|
||||
productNameMap[p.Id] = p.ProductName
|
||||
}
|
||||
}
|
||||
|
||||
// 组装响应
|
||||
items := make([]types.AgentOrderListItem, 0, len(orders))
|
||||
for _, order := range orders {
|
||||
items = append(items, types.AgentOrderListItem{
|
||||
Id: order.Id,
|
||||
AgentId: order.AgentId,
|
||||
OrderId: order.OrderId,
|
||||
ProductId: order.ProductId,
|
||||
ProductName: productNameMap[order.ProductId],
|
||||
OrderAmount: order.OrderAmount,
|
||||
SetPrice: order.SetPrice,
|
||||
ActualBasePrice: order.ActualBasePrice,
|
||||
PriceCost: order.PriceCost,
|
||||
AgentProfit: order.AgentProfit,
|
||||
ProcessStatus: order.ProcessStatus,
|
||||
CreateTime: order.CreateTime.Format("2006-01-02 15:04:05"),
|
||||
})
|
||||
}
|
||||
|
||||
return &types.AdminGetAgentOrderListResp{
|
||||
Total: total,
|
||||
Items: items,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package admin_agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"ycc-server/common/globalkey"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"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 AdminGetAgentProductConfigListLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminGetAgentProductConfigListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminGetAgentProductConfigListLogic {
|
||||
return &AdminGetAgentProductConfigListLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminGetAgentProductConfigListLogic) AdminGetAgentProductConfigList(req *types.AdminGetAgentProductConfigListReq) (resp *types.AdminGetAgentProductConfigListResp, err error) {
|
||||
builder := l.svcCtx.AgentProductConfigModel.SelectBuilder().
|
||||
Where("del_state = ?", globalkey.DelStateNo)
|
||||
|
||||
if req.ProductId != nil {
|
||||
builder = builder.Where("product_id = ?", *req.ProductId)
|
||||
}
|
||||
|
||||
// 分页查询
|
||||
page := req.Page
|
||||
if page <= 0 {
|
||||
page = 1
|
||||
}
|
||||
pageSize := req.PageSize
|
||||
if pageSize <= 0 {
|
||||
pageSize = 20
|
||||
}
|
||||
|
||||
configs, total, err := l.svcCtx.AgentProductConfigModel.FindPageListByPageWithTotal(l.ctx, builder, page, pageSize, "id DESC")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询产品配置列表失败, %v", err)
|
||||
}
|
||||
|
||||
// 组装响应
|
||||
items := make([]types.AgentProductConfigItem, 0, len(configs))
|
||||
for _, config := range configs {
|
||||
priceThreshold := 0.0
|
||||
if config.PriceThreshold.Valid {
|
||||
priceThreshold = config.PriceThreshold.Float64
|
||||
}
|
||||
|
||||
priceFeeRate := 0.0
|
||||
if config.PriceFeeRate.Valid {
|
||||
priceFeeRate = config.PriceFeeRate.Float64
|
||||
}
|
||||
|
||||
items = append(items, types.AgentProductConfigItem{
|
||||
Id: config.Id,
|
||||
ProductId: config.ProductId,
|
||||
ProductName: config.ProductName,
|
||||
BasePrice: config.BasePrice,
|
||||
PriceRangeMin: config.BasePrice, // 最低定价等于基础底价
|
||||
PriceRangeMax: config.SystemMaxPrice,
|
||||
PriceThreshold: priceThreshold,
|
||||
PriceFeeRate: priceFeeRate,
|
||||
CreateTime: config.CreateTime.Format("2006-01-02 15:04:05"),
|
||||
})
|
||||
}
|
||||
|
||||
return &types.AdminGetAgentProductConfigListResp{
|
||||
Total: total,
|
||||
Items: items,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
package admin_agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"ycc-server/common/globalkey"
|
||||
"ycc-server/common/xerr"
|
||||
"ycc-server/pkg/lzkit/crypto"
|
||||
|
||||
"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 AdminGetAgentRealNameListLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminGetAgentRealNameListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminGetAgentRealNameListLogic {
|
||||
return &AdminGetAgentRealNameListLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminGetAgentRealNameListLogic) AdminGetAgentRealNameList(req *types.AdminGetAgentRealNameListReq) (resp *types.AdminGetAgentRealNameListResp, err error) {
|
||||
builder := l.svcCtx.AgentRealNameModel.SelectBuilder().
|
||||
Where("del_state = ?", globalkey.DelStateNo)
|
||||
|
||||
if req.AgentId != nil {
|
||||
builder = builder.Where("agent_id = ?", *req.AgentId)
|
||||
}
|
||||
if req.Status != nil {
|
||||
// 根据状态过滤:1=未验证(verify_time为NULL),2=已通过(verify_time不为NULL)
|
||||
switch *req.Status {
|
||||
case 1: // 未验证
|
||||
builder = builder.Where("verify_time IS NULL")
|
||||
case 2: // 已通过
|
||||
builder = builder.Where("verify_time IS NOT NULL")
|
||||
}
|
||||
}
|
||||
|
||||
// 分页查询
|
||||
page := req.Page
|
||||
if page <= 0 {
|
||||
page = 1
|
||||
}
|
||||
pageSize := req.PageSize
|
||||
if pageSize <= 0 {
|
||||
pageSize = 20
|
||||
}
|
||||
|
||||
realNames, total, err := l.svcCtx.AgentRealNameModel.FindPageListByPageWithTotal(l.ctx, builder, page, pageSize, "create_time DESC")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询实名认证列表失败, %v", err)
|
||||
}
|
||||
|
||||
// 组装响应
|
||||
items := make([]types.AgentRealNameListItem, 0, len(realNames))
|
||||
for _, realName := range realNames {
|
||||
// 解密手机号(仅显示部分)
|
||||
mobile := ""
|
||||
if realName.Mobile != "" {
|
||||
decrypted, err := crypto.DecryptMobile(realName.Mobile, l.svcCtx.Config.Encrypt.SecretKey)
|
||||
if err == nil {
|
||||
mobile = decrypted
|
||||
}
|
||||
}
|
||||
|
||||
// 解密身份证号(仅显示部分)
|
||||
idCard := ""
|
||||
if realName.IdCard != "" {
|
||||
decrypted, err := crypto.DecryptIDCard(realName.IdCard, []byte(l.svcCtx.Config.Encrypt.SecretKey))
|
||||
if err == nil {
|
||||
// 脱敏显示
|
||||
if len(decrypted) > 10 {
|
||||
idCard = decrypted[:3] + "***********" + decrypted[len(decrypted)-4:]
|
||||
} else {
|
||||
idCard = decrypted
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 根据verify_time判断状态:NULL=未验证(1),不为NULL=已通过(2)
|
||||
statusInt := int64(1) // 默认未验证
|
||||
verifyTime := ""
|
||||
if realName.VerifyTime.Valid {
|
||||
statusInt = 2 // 已通过
|
||||
verifyTime = realName.VerifyTime.Time.Format("2006-01-02 15:04:05")
|
||||
}
|
||||
|
||||
item := types.AgentRealNameListItem{
|
||||
Id: realName.Id,
|
||||
AgentId: realName.AgentId,
|
||||
Name: realName.Name,
|
||||
IdCard: idCard,
|
||||
Mobile: mobile,
|
||||
Status: statusInt,
|
||||
CreateTime: realName.CreateTime.Format("2006-01-02 15:04:05"),
|
||||
}
|
||||
// TODO: 重新生成接口后,取消注释下面的代码
|
||||
item.VerifyTime = verifyTime
|
||||
items = append(items, item)
|
||||
}
|
||||
|
||||
return &types.AdminGetAgentRealNameListResp{
|
||||
Total: total,
|
||||
Items: items,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package admin_agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"ycc-server/common/globalkey"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"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 AdminGetAgentRebateListLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminGetAgentRebateListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminGetAgentRebateListLogic {
|
||||
return &AdminGetAgentRebateListLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminGetAgentRebateListLogic) AdminGetAgentRebateList(req *types.AdminGetAgentRebateListReq) (resp *types.AdminGetAgentRebateListResp, err error) {
|
||||
builder := l.svcCtx.AgentRebateModel.SelectBuilder().
|
||||
Where("del_state = ?", globalkey.DelStateNo)
|
||||
|
||||
if req.AgentId != nil {
|
||||
builder = builder.Where("agent_id = ?", *req.AgentId)
|
||||
}
|
||||
if req.SourceAgentId != nil {
|
||||
builder = builder.Where("source_agent_id = ?", *req.SourceAgentId)
|
||||
}
|
||||
if req.RebateType != nil {
|
||||
builder = builder.Where("rebate_type = ?", *req.RebateType)
|
||||
}
|
||||
|
||||
// 分页查询
|
||||
page := req.Page
|
||||
if page <= 0 {
|
||||
page = 1
|
||||
}
|
||||
pageSize := req.PageSize
|
||||
if pageSize <= 0 {
|
||||
pageSize = 20
|
||||
}
|
||||
|
||||
rebates, total, err := l.svcCtx.AgentRebateModel.FindPageListByPageWithTotal(l.ctx, builder, page, pageSize, "create_time DESC")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询返佣列表失败, %v", err)
|
||||
}
|
||||
|
||||
// 批量查询产品名称
|
||||
productIdSet := make(map[int64]struct{})
|
||||
for _, rebate := range rebates {
|
||||
productIdSet[rebate.ProductId] = struct{}{}
|
||||
}
|
||||
productIdList := make([]int64, 0, len(productIdSet))
|
||||
for id := range productIdSet {
|
||||
productIdList = append(productIdList, id)
|
||||
}
|
||||
productNameMap := make(map[int64]string)
|
||||
if len(productIdList) > 0 {
|
||||
products, _ := l.svcCtx.ProductModel.FindAll(l.ctx, l.svcCtx.ProductModel.SelectBuilder().Where(squirrel.Eq{"id": productIdList}), "")
|
||||
for _, p := range products {
|
||||
productNameMap[p.Id] = p.ProductName
|
||||
}
|
||||
}
|
||||
|
||||
// 组装响应
|
||||
items := make([]types.AgentRebateListItem, 0, len(rebates))
|
||||
for _, rebate := range rebates {
|
||||
items = append(items, types.AgentRebateListItem{
|
||||
Id: rebate.Id,
|
||||
AgentId: rebate.AgentId,
|
||||
SourceAgentId: rebate.SourceAgentId,
|
||||
OrderId: rebate.OrderId,
|
||||
RebateType: rebate.RebateType,
|
||||
Amount: rebate.RebateAmount,
|
||||
CreateTime: rebate.CreateTime.Format("2006-01-02 15:04:05"),
|
||||
})
|
||||
}
|
||||
|
||||
return &types.AdminGetAgentRebateListResp{
|
||||
Total: total,
|
||||
Items: items,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package admin_agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"ycc-server/common/globalkey"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"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 AdminGetAgentUpgradeListLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminGetAgentUpgradeListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminGetAgentUpgradeListLogic {
|
||||
return &AdminGetAgentUpgradeListLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminGetAgentUpgradeListLogic) AdminGetAgentUpgradeList(req *types.AdminGetAgentUpgradeListReq) (resp *types.AdminGetAgentUpgradeListResp, err error) {
|
||||
builder := l.svcCtx.AgentUpgradeModel.SelectBuilder().
|
||||
Where("del_state = ?", globalkey.DelStateNo)
|
||||
|
||||
if req.AgentId != nil {
|
||||
builder = builder.Where("agent_id = ?", *req.AgentId)
|
||||
}
|
||||
if req.UpgradeType != nil {
|
||||
builder = builder.Where("upgrade_type = ?", *req.UpgradeType)
|
||||
}
|
||||
if req.Status != nil {
|
||||
builder = builder.Where("status = ?", *req.Status)
|
||||
}
|
||||
|
||||
// 分页查询
|
||||
page := req.Page
|
||||
if page <= 0 {
|
||||
page = 1
|
||||
}
|
||||
pageSize := req.PageSize
|
||||
if pageSize <= 0 {
|
||||
pageSize = 20
|
||||
}
|
||||
|
||||
upgrades, total, err := l.svcCtx.AgentUpgradeModel.FindPageListByPageWithTotal(l.ctx, builder, page, pageSize, "create_time DESC")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询升级记录列表失败, %v", err)
|
||||
}
|
||||
|
||||
// 组装响应
|
||||
items := make([]types.AgentUpgradeListItem, 0, len(upgrades))
|
||||
for _, upgrade := range upgrades {
|
||||
items = append(items, types.AgentUpgradeListItem{
|
||||
Id: upgrade.Id,
|
||||
AgentId: upgrade.AgentId,
|
||||
FromLevel: upgrade.FromLevel,
|
||||
ToLevel: upgrade.ToLevel,
|
||||
UpgradeType: upgrade.UpgradeType,
|
||||
UpgradeFee: upgrade.UpgradeFee,
|
||||
RebateAmount: upgrade.RebateAmount,
|
||||
Status: upgrade.Status,
|
||||
CreateTime: upgrade.CreateTime.Format("2006-01-02 15:04:05"),
|
||||
})
|
||||
}
|
||||
|
||||
return &types.AdminGetAgentUpgradeListResp{
|
||||
Total: total,
|
||||
Items: items,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package admin_agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
|
||||
"github.com/Masterminds/squirrel"
|
||||
"github.com/jinzhu/copier"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminGetAgentWithdrawalListLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminGetAgentWithdrawalListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminGetAgentWithdrawalListLogic {
|
||||
return &AdminGetAgentWithdrawalListLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminGetAgentWithdrawalListLogic) AdminGetAgentWithdrawalList(req *types.AdminGetAgentWithdrawalListReq) (resp *types.AdminGetAgentWithdrawalListResp, err error) {
|
||||
builder := l.svcCtx.AgentWithdrawalModel.SelectBuilder()
|
||||
if req.AgentId != nil {
|
||||
builder = builder.Where(squirrel.Eq{"agent_id": *req.AgentId})
|
||||
}
|
||||
if req.Status != nil {
|
||||
builder = builder.Where(squirrel.Eq{"status": *req.Status})
|
||||
}
|
||||
if req.WithdrawNo != nil && *req.WithdrawNo != "" {
|
||||
builder = builder.Where(squirrel.Eq{"withdraw_no": *req.WithdrawNo})
|
||||
}
|
||||
list, total, err := l.svcCtx.AgentWithdrawalModel.FindPageListByPageWithTotal(l.ctx, builder, req.Page, req.PageSize, "create_time DESC")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items := make([]types.AgentWithdrawalListItem, 0, len(list))
|
||||
for _, v := range list {
|
||||
item := types.AgentWithdrawalListItem{}
|
||||
_ = copier.Copy(&item, v)
|
||||
item.Remark = ""
|
||||
if v.Remark.Valid {
|
||||
item.Remark = v.Remark.String
|
||||
}
|
||||
item.CreateTime = v.CreateTime.Format("2006-01-02 15:04:05")
|
||||
items = append(items, item)
|
||||
}
|
||||
resp = &types.AdminGetAgentWithdrawalListResp{
|
||||
Total: total,
|
||||
Items: items,
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
package admin_agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"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 AdminGetInviteCodeListLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminGetInviteCodeListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminGetInviteCodeListLogic {
|
||||
return &AdminGetInviteCodeListLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminGetInviteCodeListLogic) AdminGetInviteCodeList(req *types.AdminGetInviteCodeListReq) (resp *types.AdminGetInviteCodeListResp, err error) {
|
||||
// 1. 构建查询条件
|
||||
builder := l.svcCtx.AgentInviteCodeModel.SelectBuilder().
|
||||
Where("del_state = ?", globalkey.DelStateNo)
|
||||
|
||||
if req.Code != nil && *req.Code != "" {
|
||||
builder = builder.Where("code = ?", *req.Code)
|
||||
}
|
||||
if req.AgentId != nil {
|
||||
if *req.AgentId == 0 {
|
||||
// agent_id = 0 表示查询平台发放的邀请码(agent_id为NULL)
|
||||
builder = builder.Where("agent_id IS NULL")
|
||||
} else {
|
||||
builder = builder.Where("agent_id = ?", *req.AgentId)
|
||||
}
|
||||
}
|
||||
if req.TargetLevel != nil {
|
||||
builder = builder.Where("target_level = ?", *req.TargetLevel)
|
||||
}
|
||||
if req.Status != nil {
|
||||
builder = builder.Where("status = ?", *req.Status)
|
||||
}
|
||||
|
||||
// 2. 分页查询
|
||||
list, total, err := l.svcCtx.AgentInviteCodeModel.FindPageListByPageWithTotal(l.ctx, builder, req.Page, req.PageSize, "create_time DESC")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询邀请码列表失败, %v", err)
|
||||
}
|
||||
|
||||
// 3. 批量查询代理信息(用于显示代理手机号)
|
||||
agentIds := make(map[int64]struct{})
|
||||
for _, v := range list {
|
||||
if v.AgentId.Valid && v.AgentId.Int64 > 0 {
|
||||
agentIds[v.AgentId.Int64] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
agentMobileMap := make(map[int64]string)
|
||||
if len(agentIds) > 0 {
|
||||
agentIdList := make([]int64, 0, len(agentIds))
|
||||
for id := range agentIds {
|
||||
agentIdList = append(agentIdList, id)
|
||||
}
|
||||
agents, _ := l.svcCtx.AgentModel.FindAll(l.ctx, l.svcCtx.AgentModel.SelectBuilder().Where(squirrel.Eq{"id": agentIdList}), "")
|
||||
secretKey := l.svcCtx.Config.Encrypt.SecretKey
|
||||
for _, agent := range agents {
|
||||
mobile, decErr := crypto.DecryptMobile(agent.Mobile, secretKey)
|
||||
if decErr == nil {
|
||||
agentMobileMap[agent.Id] = mobile
|
||||
} else {
|
||||
l.Logger.Errorf("解密代理手机号失败: %v", decErr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 格式化返回数据
|
||||
items := make([]types.InviteCodeListItem, 0, len(list))
|
||||
for _, v := range list {
|
||||
item := types.InviteCodeListItem{
|
||||
Id: v.Id,
|
||||
Code: v.Code,
|
||||
AgentId: 0,
|
||||
AgentMobile: "",
|
||||
TargetLevel: v.TargetLevel,
|
||||
Status: v.Status,
|
||||
CreateTime: v.CreateTime.Format("2006-01-02 15:04:05"),
|
||||
}
|
||||
|
||||
if v.AgentId.Valid {
|
||||
item.AgentId = v.AgentId.Int64
|
||||
item.AgentMobile = agentMobileMap[v.AgentId.Int64]
|
||||
}
|
||||
|
||||
if v.UsedUserId.Valid {
|
||||
item.UsedUserId = v.UsedUserId.Int64
|
||||
}
|
||||
if v.UsedAgentId.Valid {
|
||||
item.UsedAgentId = v.UsedAgentId.Int64
|
||||
}
|
||||
if v.UsedTime.Valid {
|
||||
item.UsedTime = v.UsedTime.Time.Format("2006-01-02 15:04:05")
|
||||
}
|
||||
if v.ExpireTime.Valid {
|
||||
item.ExpireTime = v.ExpireTime.Time.Format("2006-01-02 15:04:05")
|
||||
}
|
||||
if v.Remark.Valid {
|
||||
item.Remark = v.Remark.String
|
||||
}
|
||||
|
||||
items = append(items, item)
|
||||
}
|
||||
|
||||
return &types.AdminGetInviteCodeListResp{
|
||||
Total: total,
|
||||
Items: items,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package admin_agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"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 AdminUpdateAgentConfigLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminUpdateAgentConfigLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminUpdateAgentConfigLogic {
|
||||
return &AdminUpdateAgentConfigLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminUpdateAgentConfigLogic) AdminUpdateAgentConfig(req *types.AdminUpdateAgentConfigReq) (resp *types.AdminUpdateAgentConfigResp, err error) {
|
||||
// 更新配置的辅助函数
|
||||
updateConfig := func(key string, value *float64) error {
|
||||
if value == nil {
|
||||
return nil
|
||||
}
|
||||
config, err := l.svcCtx.AgentConfigModel.FindOneByConfigKey(l.ctx, key)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "查询配置失败, key: %s", key)
|
||||
}
|
||||
config.ConfigValue = strconv.FormatFloat(*value, 'f', -1, 64)
|
||||
return l.svcCtx.AgentConfigModel.UpdateWithVersion(l.ctx, nil, config)
|
||||
}
|
||||
|
||||
// 更新各个配置项
|
||||
if err := updateConfig("base_price", req.BasePrice); err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新基础底价失败, %v", err)
|
||||
}
|
||||
if err := updateConfig("system_max_price", req.SystemMaxPrice); err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新系统价格上限失败, %v", err)
|
||||
}
|
||||
if err := updateConfig("price_threshold", req.PriceThreshold); err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新提价标准阈值失败, %v", err)
|
||||
}
|
||||
if err := updateConfig("price_fee_rate", req.PriceFeeRate); err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新提价手续费比例失败, %v", err)
|
||||
}
|
||||
if err := updateConfig("tax_rate", req.TaxRate); err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新税率失败, %v", err)
|
||||
}
|
||||
if err := updateConfig("tax_exemption_amount", req.TaxExemptionAmount); err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新免税额度失败, %v", err)
|
||||
}
|
||||
|
||||
return &types.AdminUpdateAgentConfigResp{
|
||||
Success: true,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package admin_agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"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 AdminUpdateAgentProductConfigLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminUpdateAgentProductConfigLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminUpdateAgentProductConfigLogic {
|
||||
return &AdminUpdateAgentProductConfigLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminUpdateAgentProductConfigLogic) AdminUpdateAgentProductConfig(req *types.AdminUpdateAgentProductConfigReq) (resp *types.AdminUpdateAgentProductConfigResp, err error) {
|
||||
// 查询配置
|
||||
config, err := l.svcCtx.AgentProductConfigModel.FindOne(l.ctx, req.Id)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询产品配置失败, %v", err)
|
||||
}
|
||||
|
||||
// 更新配置字段
|
||||
config.BasePrice = req.BasePrice
|
||||
config.SystemMaxPrice = req.PriceRangeMax
|
||||
config.PriceThreshold = sql.NullFloat64{Float64: req.PriceThreshold, Valid: true}
|
||||
config.PriceFeeRate = sql.NullFloat64{Float64: req.PriceFeeRate, Valid: true}
|
||||
|
||||
// 更新配置
|
||||
if err := l.svcCtx.AgentProductConfigModel.UpdateWithVersion(l.ctx, nil, config); err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新产品配置失败, %v", err)
|
||||
}
|
||||
|
||||
return &types.AdminUpdateAgentProductConfigResp{
|
||||
Success: true,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package admin_api
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/app/main/model"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminBatchUpdateApiStatusLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminBatchUpdateApiStatusLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminBatchUpdateApiStatusLogic {
|
||||
return &AdminBatchUpdateApiStatusLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminBatchUpdateApiStatusLogic) AdminBatchUpdateApiStatus(req *types.AdminBatchUpdateApiStatusReq) (resp *types.AdminBatchUpdateApiStatusResp, err error) {
|
||||
// 1. 参数验证
|
||||
if len(req.Ids) == 0 {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.PARAM_VERIFICATION_ERROR),
|
||||
"API ID列表不能为空")
|
||||
}
|
||||
if req.Status != 0 && req.Status != 1 {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.PARAM_VERIFICATION_ERROR),
|
||||
"状态值无效, status: %d", req.Status)
|
||||
}
|
||||
|
||||
// 2. 批量更新API状态
|
||||
successCount := 0
|
||||
for _, id := range req.Ids {
|
||||
if id <= 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// 查询API是否存在
|
||||
api, err := l.svcCtx.AdminApiModel.FindOne(l.ctx, id)
|
||||
if err != nil {
|
||||
if errors.Is(err, model.ErrNotFound) {
|
||||
continue // 跳过不存在的API
|
||||
}
|
||||
logx.Errorf("查询API失败, err: %v, id: %d", err, id)
|
||||
continue
|
||||
}
|
||||
|
||||
// 更新状态
|
||||
api.Status = req.Status
|
||||
_, err = l.svcCtx.AdminApiModel.Update(l.ctx, nil, api)
|
||||
if err != nil {
|
||||
logx.Errorf("更新API状态失败, err: %v, id: %d", err, id)
|
||||
continue
|
||||
}
|
||||
|
||||
successCount++
|
||||
}
|
||||
|
||||
// 3. 返回结果
|
||||
return &types.AdminBatchUpdateApiStatusResp{Success: true}, nil
|
||||
}
|
||||
78
app/main/api/internal/logic/admin_api/admincreateapilogic.go
Normal file
78
app/main/api/internal/logic/admin_api/admincreateapilogic.go
Normal file
@@ -0,0 +1,78 @@
|
||||
package admin_api
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/app/main/model"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminCreateApiLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminCreateApiLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminCreateApiLogic {
|
||||
return &AdminCreateApiLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminCreateApiLogic) AdminCreateApi(req *types.AdminCreateApiReq) (resp *types.AdminCreateApiResp, err error) {
|
||||
// 1. 参数验证
|
||||
if req.ApiName == "" {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.PARAM_VERIFICATION_ERROR),
|
||||
"API名称不能为空")
|
||||
}
|
||||
if req.ApiCode == "" {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.PARAM_VERIFICATION_ERROR),
|
||||
"API编码不能为空")
|
||||
}
|
||||
if req.Method == "" {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.PARAM_VERIFICATION_ERROR),
|
||||
"请求方法不能为空")
|
||||
}
|
||||
if req.Url == "" {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.PARAM_VERIFICATION_ERROR),
|
||||
"API路径不能为空")
|
||||
}
|
||||
|
||||
// 2. 检查API编码是否已存在
|
||||
existing, err := l.svcCtx.AdminApiModel.FindOneByApiCode(l.ctx, req.ApiCode)
|
||||
if err != nil && !errors.Is(err, model.ErrNotFound) {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
|
||||
"查询API失败, err: %v, apiCode: %s", err, req.ApiCode)
|
||||
}
|
||||
if existing != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.PARAM_VERIFICATION_ERROR),
|
||||
"API编码已存在: %s", req.ApiCode)
|
||||
}
|
||||
|
||||
// 3. 创建API记录
|
||||
apiData := &model.AdminApi{
|
||||
ApiName: req.ApiName,
|
||||
ApiCode: req.ApiCode,
|
||||
Method: req.Method,
|
||||
Url: req.Url,
|
||||
Status: req.Status,
|
||||
Description: req.Description,
|
||||
}
|
||||
|
||||
result, err := l.svcCtx.AdminApiModel.Insert(l.ctx, nil, apiData)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
|
||||
"创建API失败, err: %v", err)
|
||||
}
|
||||
|
||||
// 4. 返回结果
|
||||
apiId, _ := result.LastInsertId()
|
||||
return &types.AdminCreateApiResp{Id: apiId}, nil
|
||||
}
|
||||
68
app/main/api/internal/logic/admin_api/admindeleteapilogic.go
Normal file
68
app/main/api/internal/logic/admin_api/admindeleteapilogic.go
Normal file
@@ -0,0 +1,68 @@
|
||||
package admin_api
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/app/main/model"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminDeleteApiLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminDeleteApiLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminDeleteApiLogic {
|
||||
return &AdminDeleteApiLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminDeleteApiLogic) AdminDeleteApi(req *types.AdminDeleteApiReq) (resp *types.AdminDeleteApiResp, err error) {
|
||||
// 1. 参数验证
|
||||
if req.Id <= 0 {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.PARAM_VERIFICATION_ERROR),
|
||||
"API ID必须大于0, id: %d", req.Id)
|
||||
}
|
||||
|
||||
// 2. 查询API是否存在
|
||||
api, err := l.svcCtx.AdminApiModel.FindOne(l.ctx, req.Id)
|
||||
if err != nil {
|
||||
if errors.Is(err, model.ErrNotFound) {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
|
||||
"API不存在, id: %d", req.Id)
|
||||
}
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
|
||||
"查询API失败, err: %v, id: %d", err, req.Id)
|
||||
}
|
||||
|
||||
// 3. 检查是否有角色关联该API
|
||||
roleApiBuilder := l.svcCtx.AdminRoleApiModel.SelectBuilder().Where("api_id = ?", req.Id)
|
||||
roleApis, err := l.svcCtx.AdminRoleApiModel.FindAll(l.ctx, roleApiBuilder, "")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
|
||||
"查询角色API关联失败, err: %v, apiId: %d", err, req.Id)
|
||||
}
|
||||
if len(roleApis) > 0 {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.PARAM_VERIFICATION_ERROR),
|
||||
"该API已被角色使用,无法删除, apiId: %d", req.Id)
|
||||
}
|
||||
|
||||
// 4. 执行软删除
|
||||
err = l.svcCtx.AdminApiModel.DeleteSoft(l.ctx, nil, api)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
|
||||
"删除API失败, err: %v, id: %d", err, req.Id)
|
||||
}
|
||||
|
||||
// 5. 返回结果
|
||||
return &types.AdminDeleteApiResp{Success: true}, nil
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package admin_api
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/app/main/model"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminGetApiDetailLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminGetApiDetailLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminGetApiDetailLogic {
|
||||
return &AdminGetApiDetailLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminGetApiDetailLogic) AdminGetApiDetail(req *types.AdminGetApiDetailReq) (resp *types.AdminGetApiDetailResp, err error) {
|
||||
// 1. 参数验证
|
||||
if req.Id <= 0 {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.PARAM_VERIFICATION_ERROR),
|
||||
"API ID必须大于0, id: %d", req.Id)
|
||||
}
|
||||
|
||||
// 2. 查询API详情
|
||||
api, err := l.svcCtx.AdminApiModel.FindOne(l.ctx, req.Id)
|
||||
if err != nil {
|
||||
if errors.Is(err, model.ErrNotFound) {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
|
||||
"API不存在, id: %d", req.Id)
|
||||
}
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
|
||||
"查询API详情失败, err: %v, id: %d", err, req.Id)
|
||||
}
|
||||
|
||||
// 3. 返回结果
|
||||
return &types.AdminGetApiDetailResp{
|
||||
AdminApiInfo: types.AdminApiInfo{
|
||||
Id: api.Id,
|
||||
ApiName: api.ApiName,
|
||||
ApiCode: api.ApiCode,
|
||||
Method: api.Method,
|
||||
Url: api.Url,
|
||||
Status: api.Status,
|
||||
Description: api.Description,
|
||||
CreateTime: api.CreateTime.Format("2006-01-02 15:04:05"),
|
||||
UpdateTime: api.UpdateTime.Format("2006-01-02 15:04:05"),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package admin_api
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminGetApiListLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminGetApiListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminGetApiListLogic {
|
||||
return &AdminGetApiListLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminGetApiListLogic) AdminGetApiList(req *types.AdminGetApiListReq) (resp *types.AdminGetApiListResp, err error) {
|
||||
// 1. 参数验证
|
||||
if req.Page <= 0 {
|
||||
req.Page = 1
|
||||
}
|
||||
if req.PageSize <= 0 {
|
||||
req.PageSize = 20
|
||||
}
|
||||
if req.PageSize > 100 {
|
||||
req.PageSize = 100
|
||||
}
|
||||
|
||||
// 2. 构建查询条件
|
||||
builder := l.svcCtx.AdminApiModel.SelectBuilder()
|
||||
|
||||
// 添加搜索条件
|
||||
if req.ApiName != "" {
|
||||
builder = builder.Where("api_name LIKE ?", "%"+req.ApiName+"%")
|
||||
}
|
||||
if req.Method != "" {
|
||||
builder = builder.Where("method = ?", req.Method)
|
||||
}
|
||||
if req.Status > 0 {
|
||||
builder = builder.Where("status = ?", req.Status)
|
||||
}
|
||||
|
||||
// 3. 查询总数
|
||||
total, err := l.svcCtx.AdminApiModel.FindCount(l.ctx, builder, "id")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
|
||||
"查询API总数失败, err: %v", err)
|
||||
}
|
||||
|
||||
// 4. 查询列表
|
||||
apis, err := l.svcCtx.AdminApiModel.FindPageListByPage(l.ctx, builder, req.Page, req.PageSize, "id DESC")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
|
||||
"查询API列表失败, err: %v", err)
|
||||
}
|
||||
|
||||
// 5. 转换数据格式
|
||||
var apiList []types.AdminApiInfo
|
||||
for _, api := range apis {
|
||||
apiList = append(apiList, types.AdminApiInfo{
|
||||
Id: api.Id,
|
||||
ApiName: api.ApiName,
|
||||
ApiCode: api.ApiCode,
|
||||
Method: api.Method,
|
||||
Url: api.Url,
|
||||
Status: api.Status,
|
||||
Description: api.Description,
|
||||
CreateTime: api.CreateTime.Format("2006-01-02 15:04:05"),
|
||||
UpdateTime: api.UpdateTime.Format("2006-01-02 15:04:05"),
|
||||
})
|
||||
}
|
||||
|
||||
// 6. 返回结果
|
||||
return &types.AdminGetApiListResp{
|
||||
Items: apiList,
|
||||
Total: total,
|
||||
}, nil
|
||||
}
|
||||
92
app/main/api/internal/logic/admin_api/adminupdateapilogic.go
Normal file
92
app/main/api/internal/logic/admin_api/adminupdateapilogic.go
Normal file
@@ -0,0 +1,92 @@
|
||||
package admin_api
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/app/main/model"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminUpdateApiLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminUpdateApiLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminUpdateApiLogic {
|
||||
return &AdminUpdateApiLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminUpdateApiLogic) AdminUpdateApi(req *types.AdminUpdateApiReq) (resp *types.AdminUpdateApiResp, err error) {
|
||||
// 1. 参数验证
|
||||
if req.Id <= 0 {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.PARAM_VERIFICATION_ERROR),
|
||||
"API ID必须大于0, id: %d", req.Id)
|
||||
}
|
||||
if req.ApiName == "" {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.PARAM_VERIFICATION_ERROR),
|
||||
"API名称不能为空")
|
||||
}
|
||||
if req.ApiCode == "" {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.PARAM_VERIFICATION_ERROR),
|
||||
"API编码不能为空")
|
||||
}
|
||||
if req.Method == "" {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.PARAM_VERIFICATION_ERROR),
|
||||
"请求方法不能为空")
|
||||
}
|
||||
if req.Url == "" {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.PARAM_VERIFICATION_ERROR),
|
||||
"API路径不能为空")
|
||||
}
|
||||
|
||||
// 2. 查询API是否存在
|
||||
api, err := l.svcCtx.AdminApiModel.FindOne(l.ctx, req.Id)
|
||||
if err != nil {
|
||||
if errors.Is(err, model.ErrNotFound) {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
|
||||
"API不存在, id: %d", req.Id)
|
||||
}
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
|
||||
"查询API失败, err: %v, id: %d", err, req.Id)
|
||||
}
|
||||
|
||||
// 3. 检查API编码是否被其他记录使用
|
||||
if api.ApiCode != req.ApiCode {
|
||||
existing, err := l.svcCtx.AdminApiModel.FindOneByApiCode(l.ctx, req.ApiCode)
|
||||
if err != nil && !errors.Is(err, model.ErrNotFound) {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
|
||||
"查询API失败, err: %v, apiCode: %s", err, req.ApiCode)
|
||||
}
|
||||
if existing != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.PARAM_VERIFICATION_ERROR),
|
||||
"API编码已存在: %s", req.ApiCode)
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 更新API信息
|
||||
api.ApiName = req.ApiName
|
||||
api.ApiCode = req.ApiCode
|
||||
api.Method = req.Method
|
||||
api.Url = req.Url
|
||||
api.Status = req.Status
|
||||
api.Description = req.Description
|
||||
|
||||
_, err = l.svcCtx.AdminApiModel.Update(l.ctx, nil, api)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
|
||||
"更新API失败, err: %v, id: %d", err, req.Id)
|
||||
}
|
||||
|
||||
// 5. 返回结果
|
||||
return &types.AdminUpdateApiResp{Success: true}, nil
|
||||
}
|
||||
93
app/main/api/internal/logic/admin_auth/adminloginlogic.go
Normal file
93
app/main/api/internal/logic/admin_auth/adminloginlogic.go
Normal file
@@ -0,0 +1,93 @@
|
||||
package admin_auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/app/main/model"
|
||||
jwtx "ycc-server/common/jwt"
|
||||
"ycc-server/common/xerr"
|
||||
"ycc-server/pkg/lzkit/crypto"
|
||||
|
||||
"github.com/Masterminds/squirrel"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminLoginLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminLoginLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminLoginLogic {
|
||||
return &AdminLoginLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminLoginLogic) AdminLogin(req *types.AdminLoginReq) (resp *types.AdminLoginResp, err error) {
|
||||
// 1. 验证验证码
|
||||
if !req.Captcha {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("验证码错误"), "用户登录, 验证码错误, 验证码: %v", req.Captcha)
|
||||
}
|
||||
|
||||
// 2. 验证用户名和密码
|
||||
user, err := l.svcCtx.AdminUserModel.FindOneByUsername(l.ctx, req.Username)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("用户名或密码错误"), "用户登录, 用户名或密码错误, 用户名: %s", req.Username)
|
||||
}
|
||||
|
||||
// 3. 验证密码
|
||||
if !crypto.PasswordVerify(req.Password, user.Password) {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("用户名或密码错误"), "用户登录, 用户名或密码错误, 用户名: %s", req.Username)
|
||||
}
|
||||
|
||||
// 4. 获取权限
|
||||
adminUserRoleBuilder := l.svcCtx.AdminUserRoleModel.SelectBuilder().Where(squirrel.Eq{"user_id": user.Id})
|
||||
permissions, err := l.svcCtx.AdminUserRoleModel.FindAll(l.ctx, adminUserRoleBuilder, "role_id DESC")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("获取权限失败"), "用户登录, 获取权限失败, 用户名: %s", req.Username)
|
||||
}
|
||||
|
||||
// 获取角色ID数组
|
||||
roleIds := make([]int64, 0)
|
||||
for _, permission := range permissions {
|
||||
roleIds = append(roleIds, permission.RoleId)
|
||||
}
|
||||
|
||||
// 获取角色名称
|
||||
roles := make([]string, 0)
|
||||
for _, roleId := range roleIds {
|
||||
role, err := l.svcCtx.AdminRoleModel.FindOne(l.ctx, roleId)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
roles = append(roles, role.RoleCode)
|
||||
}
|
||||
|
||||
// 5. 生成token
|
||||
refreshToken := l.svcCtx.Config.AdminConfig.RefreshAfter
|
||||
expiresAt := l.svcCtx.Config.AdminConfig.AccessExpire
|
||||
claims := jwtx.JwtClaims{
|
||||
UserId: user.Id,
|
||||
AgentId: 0,
|
||||
Platform: model.PlatformAdmin,
|
||||
UserType: model.UserTypeAdmin,
|
||||
IsAgent: model.AgentStatusNo,
|
||||
}
|
||||
token, err := jwtx.GenerateJwtToken(claims, l.svcCtx.Config.AdminConfig.AccessSecret, expiresAt)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("生成token失败"), "用户登录, 生成token失败, 用户名: %s", req.Username)
|
||||
}
|
||||
|
||||
return &types.AdminLoginResp{
|
||||
AccessToken: token,
|
||||
AccessExpire: expiresAt,
|
||||
RefreshAfter: refreshToken,
|
||||
Roles: roles,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package admin_feature
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/app/main/model"
|
||||
"ycc-server/common/xerr"
|
||||
"ycc-server/pkg/lzkit/crypto"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminConfigFeatureExampleLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminConfigFeatureExampleLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminConfigFeatureExampleLogic {
|
||||
return &AdminConfigFeatureExampleLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminConfigFeatureExampleLogic) AdminConfigFeatureExample(req *types.AdminConfigFeatureExampleReq) (resp *types.AdminConfigFeatureExampleResp, err error) {
|
||||
// 1. 验证功能是否存在
|
||||
feature, err := l.svcCtx.FeatureModel.FindOne(l.ctx, req.FeatureId)
|
||||
if err != nil && !errors.Is(err, model.ErrNotFound) {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
|
||||
"查询功能失败, featureId: %d, err: %v", req.FeatureId, err)
|
||||
}
|
||||
if feature == nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.REUQEST_PARAM_ERROR),
|
||||
"功能不存在, featureId: %d", req.FeatureId)
|
||||
}
|
||||
|
||||
// 2. 检查是否已存在示例数据
|
||||
existingExample, err := l.svcCtx.ExampleModel.FindOneByFeatureId(l.ctx, req.FeatureId)
|
||||
if err != nil && !errors.Is(err, model.ErrNotFound) {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
|
||||
"查询示例数据失败, featureId: %d, err: %v", req.FeatureId, err)
|
||||
}
|
||||
|
||||
// 3. 加密示例数据
|
||||
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)
|
||||
}
|
||||
|
||||
encryptedData, aesEncryptErr := crypto.AesEncrypt([]byte(req.Data), key)
|
||||
if aesEncryptErr != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR),
|
||||
"加密示例数据失败: %v", aesEncryptErr)
|
||||
}
|
||||
|
||||
// 4. 准备示例数据
|
||||
exampleData := &model.Example{
|
||||
ApiId: feature.ApiId,
|
||||
FeatureId: req.FeatureId,
|
||||
Content: encryptedData,
|
||||
}
|
||||
|
||||
// 4. 根据是否存在决定新增或更新
|
||||
if existingExample == nil {
|
||||
// 新增示例数据
|
||||
_, err = l.svcCtx.ExampleModel.Insert(l.ctx, nil, exampleData)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
|
||||
"创建示例数据失败, featureId: %d, err: %v", req.FeatureId, err)
|
||||
}
|
||||
} else {
|
||||
// 更新示例数据
|
||||
exampleData.Id = existingExample.Id
|
||||
exampleData.Version = existingExample.Version
|
||||
_, err = l.svcCtx.ExampleModel.Update(l.ctx, nil, exampleData)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
|
||||
"更新示例数据失败, featureId: %d, err: %v", req.FeatureId, err)
|
||||
}
|
||||
}
|
||||
|
||||
// 5. 返回成功结果
|
||||
return &types.AdminConfigFeatureExampleResp{Success: true}, nil
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package admin_feature
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/app/main/model"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminCreateFeatureLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminCreateFeatureLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminCreateFeatureLogic {
|
||||
return &AdminCreateFeatureLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminCreateFeatureLogic) AdminCreateFeature(req *types.AdminCreateFeatureReq) (resp *types.AdminCreateFeatureResp, err error) {
|
||||
// 1. 数据转换
|
||||
data := &model.Feature{
|
||||
ApiId: req.ApiId,
|
||||
Name: req.Name,
|
||||
}
|
||||
|
||||
// 2. 数据库操作
|
||||
result, err := l.svcCtx.FeatureModel.Insert(l.ctx, nil, data)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
|
||||
"创建功能失败, err: %v, req: %+v", err, req)
|
||||
}
|
||||
|
||||
// 3. 返回结果
|
||||
id, _ := result.LastInsertId()
|
||||
return &types.AdminCreateFeatureResp{Id: id}, nil
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package admin_feature
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminDeleteFeatureLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminDeleteFeatureLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminDeleteFeatureLogic {
|
||||
return &AdminDeleteFeatureLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminDeleteFeatureLogic) AdminDeleteFeature(req *types.AdminDeleteFeatureReq) (resp *types.AdminDeleteFeatureResp, err error) {
|
||||
// 1. 查询记录是否存在
|
||||
record, err := l.svcCtx.FeatureModel.FindOne(l.ctx, req.Id)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
|
||||
"查找功能失败, err: %v, id: %d", err, req.Id)
|
||||
}
|
||||
|
||||
// 2. 执行软删除
|
||||
err = l.svcCtx.FeatureModel.DeleteSoft(l.ctx, nil, record)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
|
||||
"删除功能失败, err: %v, id: %d", err, req.Id)
|
||||
}
|
||||
|
||||
// 3. 返回结果
|
||||
return &types.AdminDeleteFeatureResp{Success: true}, nil
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package admin_feature
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminGetFeatureDetailLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminGetFeatureDetailLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminGetFeatureDetailLogic {
|
||||
return &AdminGetFeatureDetailLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminGetFeatureDetailLogic) AdminGetFeatureDetail(req *types.AdminGetFeatureDetailReq) (resp *types.AdminGetFeatureDetailResp, err error) {
|
||||
// 1. 查询记录
|
||||
record, err := l.svcCtx.FeatureModel.FindOne(l.ctx, req.Id)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
|
||||
"查找功能失败, err: %v, id: %d", err, req.Id)
|
||||
}
|
||||
|
||||
// 2. 构建响应
|
||||
resp = &types.AdminGetFeatureDetailResp{
|
||||
Id: record.Id,
|
||||
ApiId: record.ApiId,
|
||||
Name: record.Name,
|
||||
CreateTime: record.CreateTime.Format("2006-01-02 15:04:05"),
|
||||
UpdateTime: record.UpdateTime.Format("2006-01-02 15:04:05"),
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package admin_feature
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/app/main/model"
|
||||
"ycc-server/common/xerr"
|
||||
"ycc-server/pkg/lzkit/crypto"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminGetFeatureExampleLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminGetFeatureExampleLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminGetFeatureExampleLogic {
|
||||
return &AdminGetFeatureExampleLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminGetFeatureExampleLogic) AdminGetFeatureExample(req *types.AdminGetFeatureExampleReq) (resp *types.AdminGetFeatureExampleResp, err error) {
|
||||
// 1. 查询示例数据
|
||||
example, err := l.svcCtx.ExampleModel.FindOneByFeatureId(l.ctx, req.FeatureId)
|
||||
if err != nil {
|
||||
if errors.Is(err, model.ErrNotFound) {
|
||||
// 示例数据不存在,返回空数据
|
||||
return &types.AdminGetFeatureExampleResp{
|
||||
Id: 0,
|
||||
FeatureId: req.FeatureId,
|
||||
ApiId: "",
|
||||
Data: "",
|
||||
CreateTime: "",
|
||||
UpdateTime: "",
|
||||
}, nil
|
||||
}
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
|
||||
"查询示例数据失败, featureId: %d, err: %v", req.FeatureId, err)
|
||||
}
|
||||
|
||||
// 2. 获取解密密钥
|
||||
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)
|
||||
}
|
||||
|
||||
// 3. 解密示例数据
|
||||
var decryptedData string
|
||||
if example.Content == "000" {
|
||||
// 特殊值,直接返回
|
||||
decryptedData = example.Content
|
||||
} else {
|
||||
// 解密数据
|
||||
decryptedBytes, decryptErr := crypto.AesDecrypt(example.Content, key)
|
||||
if decryptErr != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR),
|
||||
"解密示例数据失败: %v", decryptErr)
|
||||
}
|
||||
decryptedData = string(decryptedBytes)
|
||||
}
|
||||
|
||||
// 4. 返回解密后的数据
|
||||
return &types.AdminGetFeatureExampleResp{
|
||||
Id: example.Id,
|
||||
FeatureId: example.FeatureId,
|
||||
ApiId: example.ApiId,
|
||||
Data: decryptedData,
|
||||
CreateTime: example.CreateTime.Format("2006-01-02 15:04:05"),
|
||||
UpdateTime: example.UpdateTime.Format("2006-01-02 15:04:05"),
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package admin_feature
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminGetFeatureListLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminGetFeatureListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminGetFeatureListLogic {
|
||||
return &AdminGetFeatureListLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminGetFeatureListLogic) AdminGetFeatureList(req *types.AdminGetFeatureListReq) (resp *types.AdminGetFeatureListResp, err error) {
|
||||
// 1. 构建查询条件
|
||||
builder := l.svcCtx.FeatureModel.SelectBuilder()
|
||||
|
||||
// 2. 添加查询条件
|
||||
if req.ApiId != nil && *req.ApiId != "" {
|
||||
builder = builder.Where("api_id LIKE ?", "%"+*req.ApiId+"%")
|
||||
}
|
||||
if req.Name != nil && *req.Name != "" {
|
||||
builder = builder.Where("name LIKE ?", "%"+*req.Name+"%")
|
||||
}
|
||||
|
||||
// 3. 执行分页查询
|
||||
list, total, err := l.svcCtx.FeatureModel.FindPageListByPageWithTotal(
|
||||
l.ctx, builder, req.Page, req.PageSize, "id DESC")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
|
||||
"查询功能列表失败, err: %v, req: %+v", err, req)
|
||||
}
|
||||
|
||||
// 4. 构建响应列表
|
||||
items := make([]types.FeatureListItem, 0, len(list))
|
||||
for _, item := range list {
|
||||
listItem := types.FeatureListItem{
|
||||
Id: item.Id,
|
||||
ApiId: item.ApiId,
|
||||
Name: item.Name,
|
||||
CreateTime: item.CreateTime.Format("2006-01-02 15:04:05"),
|
||||
UpdateTime: item.UpdateTime.Format("2006-01-02 15:04:05"),
|
||||
}
|
||||
items = append(items, listItem)
|
||||
}
|
||||
|
||||
// 5. 返回结果
|
||||
return &types.AdminGetFeatureListResp{
|
||||
Total: total,
|
||||
Items: items,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package admin_feature
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminUpdateFeatureLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminUpdateFeatureLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminUpdateFeatureLogic {
|
||||
return &AdminUpdateFeatureLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminUpdateFeatureLogic) AdminUpdateFeature(req *types.AdminUpdateFeatureReq) (resp *types.AdminUpdateFeatureResp, err error) {
|
||||
// 1. 参数验证
|
||||
if req.Id <= 0 {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.PARAM_VERIFICATION_ERROR),
|
||||
"功能ID必须大于0, id: %d", req.Id)
|
||||
}
|
||||
|
||||
// 2. 查询记录是否存在
|
||||
record, err := l.svcCtx.FeatureModel.FindOne(l.ctx, req.Id)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
|
||||
"查找功能失败, err: %v, id: %d", err, req.Id)
|
||||
}
|
||||
|
||||
// 3. 直接更新record的字段(只更新非空字段)
|
||||
if req.ApiId != nil && *req.ApiId != "" {
|
||||
record.ApiId = *req.ApiId
|
||||
}
|
||||
if req.Name != nil && *req.Name != "" {
|
||||
record.Name = *req.Name
|
||||
}
|
||||
|
||||
// 4. 执行更新操作
|
||||
err = l.svcCtx.FeatureModel.UpdateWithVersion(l.ctx, nil, record)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
|
||||
"更新功能失败, err: %v, id: %d", err, req.Id)
|
||||
}
|
||||
|
||||
// 5. 返回成功结果
|
||||
return &types.AdminUpdateFeatureResp{Success: true}, nil
|
||||
}
|
||||
97
app/main/api/internal/logic/admin_menu/createmenulogic.go
Normal file
97
app/main/api/internal/logic/admin_menu/createmenulogic.go
Normal file
@@ -0,0 +1,97 @@
|
||||
package admin_menu
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/app/main/model"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type CreateMenuLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewCreateMenuLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateMenuLogic {
|
||||
return &CreateMenuLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *CreateMenuLogic) CreateMenu(req *types.CreateMenuReq) (resp *types.CreateMenuResp, err error) {
|
||||
// 1. 参数验证
|
||||
if req.Name == "" {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("菜单名称不能为空"), "菜单名称不能为空")
|
||||
}
|
||||
if req.Type == "menu" && req.Component == "" {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("组件路径不能为空"), "组件路径不能为空")
|
||||
}
|
||||
|
||||
// 2. 检查名称和路径是否重复
|
||||
exists, err := l.svcCtx.AdminMenuModel.FindOneByNamePath(l.ctx, req.Name, req.Path)
|
||||
if err != nil && !errors.Is(err, model.ErrNotFound) {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询菜单失败, err: %v", err)
|
||||
}
|
||||
if exists != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("菜单名称或路径已存在"), "菜单名称或路径已存在")
|
||||
}
|
||||
|
||||
// 3. 检查父菜单是否存在(如果不是根菜单)
|
||||
if req.Pid > 0 {
|
||||
parentMenu, err := l.svcCtx.AdminMenuModel.FindOne(l.ctx, req.Pid)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询父菜单失败, id: %d, err: %v", req.Pid, err)
|
||||
}
|
||||
if parentMenu == nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "父菜单不存在, id: %d", req.Pid)
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 将类型标签转换为值
|
||||
typeValue, err := l.svcCtx.DictService.GetDictValue(l.ctx, "admin_menu_type", req.Type)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "菜单类型无效: %v", err)
|
||||
}
|
||||
|
||||
// 5. 创建菜单记录
|
||||
menu := &model.AdminMenu{
|
||||
Pid: req.Pid,
|
||||
Name: req.Name,
|
||||
Path: req.Path,
|
||||
Component: req.Component,
|
||||
Redirect: sql.NullString{String: req.Redirect, Valid: req.Redirect != ""},
|
||||
Status: req.Status,
|
||||
Type: typeValue,
|
||||
Sort: req.Sort,
|
||||
CreateTime: time.Now(),
|
||||
UpdateTime: time.Now(),
|
||||
}
|
||||
|
||||
// 将Meta转换为JSON字符串
|
||||
metaJson, err := json.Marshal(req.Meta)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "Meta数据格式错误: %v", err)
|
||||
}
|
||||
menu.Meta = string(metaJson)
|
||||
|
||||
// 6. 保存到数据库
|
||||
_, err = l.svcCtx.AdminMenuModel.Insert(l.ctx, nil, menu)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "创建菜单失败, err: %v", err)
|
||||
}
|
||||
|
||||
return &types.CreateMenuResp{
|
||||
Id: menu.Id,
|
||||
}, nil
|
||||
}
|
||||
75
app/main/api/internal/logic/admin_menu/deletemenulogic.go
Normal file
75
app/main/api/internal/logic/admin_menu/deletemenulogic.go
Normal file
@@ -0,0 +1,75 @@
|
||||
package admin_menu
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type DeleteMenuLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewDeleteMenuLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DeleteMenuLogic {
|
||||
return &DeleteMenuLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *DeleteMenuLogic) DeleteMenu(req *types.DeleteMenuReq) (resp *types.DeleteMenuResp, err error) {
|
||||
// 1. 参数验证
|
||||
if req.Id <= 0 {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.PARAM_VERIFICATION_ERROR),
|
||||
"菜单ID必须大于0, id: %d", req.Id)
|
||||
}
|
||||
|
||||
// 2. 查询菜单是否存在
|
||||
menu, err := l.svcCtx.AdminMenuModel.FindOne(l.ctx, req.Id)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
|
||||
"查找菜单失败, err: %v, id: %d", err, req.Id)
|
||||
}
|
||||
|
||||
// 3. 检查是否有子菜单
|
||||
childMenuBuilder := l.svcCtx.AdminMenuModel.SelectBuilder().Where("pid = ?", req.Id)
|
||||
childMenus, err := l.svcCtx.AdminMenuModel.FindAll(l.ctx, childMenuBuilder, "")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
|
||||
"查询子菜单失败, err: %v, parent_id: %d", err, req.Id)
|
||||
}
|
||||
if len(childMenus) > 0 {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("该菜单下还有子菜单,无法删除"),
|
||||
"该菜单下还有子菜单,无法删除, id: %d", req.Id)
|
||||
}
|
||||
|
||||
// 4. 检查是否有角色关联该菜单
|
||||
roleMenuBuilder := l.svcCtx.AdminRoleMenuModel.SelectBuilder().Where("menu_id = ?", req.Id)
|
||||
roleMenus, err := l.svcCtx.AdminRoleMenuModel.FindAll(l.ctx, roleMenuBuilder, "")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
|
||||
"查询角色菜单关联失败, err: %v, menu_id: %d", err, req.Id)
|
||||
}
|
||||
if len(roleMenus) > 0 {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("该菜单已被角色使用,无法删除"),
|
||||
"该菜单已被角色使用,无法删除, id: %d", req.Id)
|
||||
}
|
||||
|
||||
// 5. 执行软删除
|
||||
err = l.svcCtx.AdminMenuModel.DeleteSoft(l.ctx, nil, menu)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
|
||||
"删除菜单失败, err: %v, id: %d", err, req.Id)
|
||||
}
|
||||
|
||||
// 6. 返回成功结果
|
||||
return &types.DeleteMenuResp{Success: true}, nil
|
||||
}
|
||||
250
app/main/api/internal/logic/admin_menu/getmenualllogic.go
Normal file
250
app/main/api/internal/logic/admin_menu/getmenualllogic.go
Normal file
@@ -0,0 +1,250 @@
|
||||
package admin_menu
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sort"
|
||||
"strconv"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/common/ctxdata"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"github.com/Masterminds/squirrel"
|
||||
"github.com/bytedance/sonic"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/samber/lo"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"github.com/zeromicro/go-zero/core/mr"
|
||||
)
|
||||
|
||||
type GetMenuAllLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewGetMenuAllLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetMenuAllLogic {
|
||||
return &GetMenuAllLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *GetMenuAllLogic) GetMenuAll(req *types.GetMenuAllReq) (resp *[]types.GetMenuAllResp, err error) {
|
||||
userId, err := ctxdata.GetUidFromCtx(l.ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取用户ID失败, %+v", err)
|
||||
}
|
||||
|
||||
// 使用MapReduceVoid并发获取用户角色
|
||||
var roleIds []int64
|
||||
var permissions []*struct {
|
||||
RoleId int64
|
||||
}
|
||||
|
||||
type UserRoleResult struct {
|
||||
RoleId int64
|
||||
}
|
||||
|
||||
err = mr.MapReduceVoid(
|
||||
func(source chan<- interface{}) {
|
||||
adminUserRoleBuilder := l.svcCtx.AdminUserRoleModel.SelectBuilder().Where(squirrel.Eq{"user_id": userId})
|
||||
source <- adminUserRoleBuilder
|
||||
},
|
||||
func(item interface{}, writer mr.Writer[*UserRoleResult], cancel func(error)) {
|
||||
builder := item.(squirrel.SelectBuilder)
|
||||
result, err := l.svcCtx.AdminUserRoleModel.FindAll(l.ctx, builder, "role_id DESC")
|
||||
if err != nil {
|
||||
cancel(errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取用户角色信息失败, %+v", err))
|
||||
return
|
||||
}
|
||||
|
||||
for _, r := range result {
|
||||
writer.Write(&UserRoleResult{RoleId: r.RoleId})
|
||||
}
|
||||
},
|
||||
func(pipe <-chan *UserRoleResult, cancel func(error)) {
|
||||
for item := range pipe {
|
||||
permissions = append(permissions, &struct{ RoleId int64 }{RoleId: item.RoleId})
|
||||
}
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, permission := range permissions {
|
||||
roleIds = append(roleIds, permission.RoleId)
|
||||
}
|
||||
|
||||
// 使用MapReduceVoid并发获取角色菜单
|
||||
var menuIds []int64
|
||||
var roleMenus []*struct {
|
||||
MenuId int64
|
||||
}
|
||||
|
||||
type RoleMenuResult struct {
|
||||
MenuId int64
|
||||
}
|
||||
|
||||
err = mr.MapReduceVoid(
|
||||
func(source chan<- interface{}) {
|
||||
getRoleMenuBuilder := l.svcCtx.AdminRoleMenuModel.SelectBuilder().Where(squirrel.Eq{"role_id": roleIds})
|
||||
source <- getRoleMenuBuilder
|
||||
},
|
||||
func(item interface{}, writer mr.Writer[*RoleMenuResult], cancel func(error)) {
|
||||
builder := item.(squirrel.SelectBuilder)
|
||||
result, err := l.svcCtx.AdminRoleMenuModel.FindAll(l.ctx, builder, "id DESC")
|
||||
if err != nil {
|
||||
cancel(errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取角色菜单信息失败, %+v", err))
|
||||
return
|
||||
}
|
||||
|
||||
for _, r := range result {
|
||||
writer.Write(&RoleMenuResult{MenuId: r.MenuId})
|
||||
}
|
||||
},
|
||||
func(pipe <-chan *RoleMenuResult, cancel func(error)) {
|
||||
for item := range pipe {
|
||||
roleMenus = append(roleMenus, &struct{ MenuId int64 }{MenuId: item.MenuId})
|
||||
}
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, roleMenu := range roleMenus {
|
||||
menuIds = append(menuIds, roleMenu.MenuId)
|
||||
}
|
||||
|
||||
// 使用MapReduceVoid并发获取菜单
|
||||
type AdminMenuStruct struct {
|
||||
Id int64
|
||||
Pid int64
|
||||
Name string
|
||||
Path string
|
||||
Component string
|
||||
Redirect struct {
|
||||
String string
|
||||
Valid bool
|
||||
}
|
||||
Meta string
|
||||
Sort int64
|
||||
Type int64
|
||||
Status int64
|
||||
}
|
||||
|
||||
var menus []*AdminMenuStruct
|
||||
|
||||
err = mr.MapReduceVoid(
|
||||
func(source chan<- interface{}) {
|
||||
adminMenuBuilder := l.svcCtx.AdminMenuModel.SelectBuilder().Where(squirrel.Eq{"id": menuIds})
|
||||
source <- adminMenuBuilder
|
||||
},
|
||||
func(item interface{}, writer mr.Writer[*AdminMenuStruct], cancel func(error)) {
|
||||
builder := item.(squirrel.SelectBuilder)
|
||||
result, err := l.svcCtx.AdminMenuModel.FindAll(l.ctx, builder, "sort ASC")
|
||||
if err != nil {
|
||||
cancel(errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取菜单信息失败, %+v", err))
|
||||
return
|
||||
}
|
||||
|
||||
for _, r := range result {
|
||||
menu := &AdminMenuStruct{
|
||||
Id: r.Id,
|
||||
Pid: r.Pid,
|
||||
Name: r.Name,
|
||||
Path: r.Path,
|
||||
Component: r.Component,
|
||||
Redirect: r.Redirect,
|
||||
Meta: r.Meta,
|
||||
Sort: r.Sort,
|
||||
Type: r.Type,
|
||||
Status: r.Status,
|
||||
}
|
||||
writer.Write(menu)
|
||||
}
|
||||
},
|
||||
func(pipe <-chan *AdminMenuStruct, cancel func(error)) {
|
||||
for item := range pipe {
|
||||
menus = append(menus, item)
|
||||
}
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 转换为types.Menu结构并存储到映射表
|
||||
menuMap := make(map[string]types.GetMenuAllResp)
|
||||
for _, menu := range menus {
|
||||
// 只处理状态正常的菜单
|
||||
if menu.Status != 1 {
|
||||
continue
|
||||
}
|
||||
|
||||
meta := make(map[string]interface{})
|
||||
err = sonic.Unmarshal([]byte(menu.Meta), &meta)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "解析菜单Meta信息失败, %+v", err)
|
||||
}
|
||||
|
||||
redirect := func() string {
|
||||
if menu.Redirect.Valid {
|
||||
return menu.Redirect.String
|
||||
}
|
||||
return ""
|
||||
}()
|
||||
|
||||
menuId := strconv.FormatInt(menu.Id, 10)
|
||||
menuMap[menuId] = types.GetMenuAllResp{
|
||||
Name: menu.Name,
|
||||
Path: menu.Path,
|
||||
Redirect: redirect,
|
||||
Component: menu.Component,
|
||||
Sort: menu.Sort,
|
||||
Meta: meta,
|
||||
Children: make([]types.GetMenuAllResp, 0),
|
||||
}
|
||||
}
|
||||
|
||||
// 按ParentId将菜单分组
|
||||
menuGroups := lo.GroupBy(menus, func(item *AdminMenuStruct) int64 {
|
||||
return item.Pid
|
||||
})
|
||||
|
||||
// 递归构建菜单树
|
||||
var buildMenuTree func(parentId int64) []types.GetMenuAllResp
|
||||
buildMenuTree = func(parentId int64) []types.GetMenuAllResp {
|
||||
children := make([]types.GetMenuAllResp, 0)
|
||||
|
||||
childMenus, ok := menuGroups[parentId]
|
||||
if !ok {
|
||||
return children
|
||||
}
|
||||
|
||||
// 按Sort排序
|
||||
sort.Slice(childMenus, func(i, j int) bool {
|
||||
return childMenus[i].Sort < childMenus[j].Sort
|
||||
})
|
||||
|
||||
for _, childMenu := range childMenus {
|
||||
menuId := strconv.FormatInt(childMenu.Id, 10)
|
||||
if menu, exists := menuMap[menuId]; exists && childMenu.Status == 1 {
|
||||
// 递归构建子菜单
|
||||
menu.Children = buildMenuTree(childMenu.Id)
|
||||
children = append(children, menu)
|
||||
}
|
||||
}
|
||||
|
||||
return children
|
||||
}
|
||||
|
||||
// 从根菜单开始构建(ParentId为0的是根菜单)
|
||||
menuTree := buildMenuTree(0)
|
||||
|
||||
return &menuTree, nil
|
||||
}
|
||||
30
app/main/api/internal/logic/admin_menu/getmenudetaillogic.go
Normal file
30
app/main/api/internal/logic/admin_menu/getmenudetaillogic.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package admin_menu
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type GetMenuDetailLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewGetMenuDetailLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetMenuDetailLogic {
|
||||
return &GetMenuDetailLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *GetMenuDetailLogic) GetMenuDetail(req *types.GetMenuDetailReq) (resp *types.GetMenuDetailResp, err error) {
|
||||
// todo: add your logic here and delete this line
|
||||
|
||||
return
|
||||
}
|
||||
109
app/main/api/internal/logic/admin_menu/getmenulistlogic.go
Normal file
109
app/main/api/internal/logic/admin_menu/getmenulistlogic.go
Normal file
@@ -0,0 +1,109 @@
|
||||
package admin_menu
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type GetMenuListLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewGetMenuListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetMenuListLogic {
|
||||
return &GetMenuListLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *GetMenuListLogic) GetMenuList(req *types.GetMenuListReq) (resp []types.MenuListItem, err error) {
|
||||
// 构建查询条件
|
||||
builder := l.svcCtx.AdminMenuModel.SelectBuilder()
|
||||
|
||||
// 添加筛选条件
|
||||
if len(req.Name) > 0 {
|
||||
builder = builder.Where("name LIKE ?", "%"+req.Name+"%")
|
||||
}
|
||||
if len(req.Path) > 0 {
|
||||
builder = builder.Where("path LIKE ?", "%"+req.Path+"%")
|
||||
}
|
||||
if req.Status != -1 {
|
||||
builder = builder.Where("status = ?", req.Status)
|
||||
}
|
||||
if req.Type != "" {
|
||||
builder = builder.Where("type = ?", req.Type)
|
||||
}
|
||||
|
||||
// 排序但不分页,获取所有符合条件的菜单
|
||||
builder = builder.OrderBy("sort ASC")
|
||||
|
||||
// 获取所有菜单
|
||||
menus, err := l.svcCtx.AdminMenuModel.FindAll(l.ctx, builder, "id ASC")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询菜单失败, err: %v", err)
|
||||
}
|
||||
|
||||
// 将菜单按ID存入map
|
||||
menuMap := make(map[int64]types.MenuListItem)
|
||||
for _, menu := range menus {
|
||||
var meta map[string]interface{}
|
||||
err := json.Unmarshal([]byte(menu.Meta), &meta)
|
||||
if err != nil {
|
||||
logx.Errorf("解析Meta字段失败: %v", err)
|
||||
meta = make(map[string]interface{})
|
||||
}
|
||||
menuType, err := l.svcCtx.DictService.GetDictLabel(l.ctx, "admin_menu_type", menu.Type)
|
||||
if err != nil {
|
||||
logx.Errorf("获取菜单类型失败: %v", err)
|
||||
menuType = ""
|
||||
}
|
||||
item := types.MenuListItem{
|
||||
Id: menu.Id,
|
||||
Pid: menu.Pid,
|
||||
Name: menu.Name,
|
||||
Path: menu.Path,
|
||||
Component: menu.Component,
|
||||
Redirect: menu.Redirect.String,
|
||||
Meta: meta,
|
||||
Status: menu.Status,
|
||||
Type: menuType,
|
||||
Sort: menu.Sort,
|
||||
CreateTime: menu.CreateTime.Format("2006-01-02 15:04:05"),
|
||||
Children: make([]types.MenuListItem, 0),
|
||||
}
|
||||
menuMap[menu.Id] = item
|
||||
}
|
||||
|
||||
// 构建父子关系
|
||||
for _, menu := range menus {
|
||||
if menu.Pid > 0 {
|
||||
// 找到父菜单
|
||||
if parent, exists := menuMap[menu.Pid]; exists {
|
||||
// 添加当前菜单到父菜单的子菜单列表
|
||||
children := append(parent.Children, menuMap[menu.Id])
|
||||
parent.Children = children
|
||||
menuMap[menu.Pid] = parent
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 提取顶级菜单(ParentId为0)到响应列表
|
||||
result := make([]types.MenuListItem, 0)
|
||||
for _, menu := range menus {
|
||||
if menu.Pid == 0 {
|
||||
result = append(result, menuMap[menu.Id])
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
96
app/main/api/internal/logic/admin_menu/updatemenulogic.go
Normal file
96
app/main/api/internal/logic/admin_menu/updatemenulogic.go
Normal file
@@ -0,0 +1,96 @@
|
||||
package admin_menu
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/app/main/model"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type UpdateMenuLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewUpdateMenuLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateMenuLogic {
|
||||
return &UpdateMenuLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *UpdateMenuLogic) UpdateMenu(req *types.UpdateMenuReq) (resp *types.UpdateMenuResp, err error) {
|
||||
// 1. 检查菜单是否存在
|
||||
menu, err := l.svcCtx.AdminMenuModel.FindOne(l.ctx, req.Id)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询菜单失败, id: %d, err: %v", req.Id, err)
|
||||
}
|
||||
if menu == nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "菜单不存在, id: %d", req.Id)
|
||||
}
|
||||
|
||||
// 2. 将类型标签转换为值
|
||||
typeValue, err := l.svcCtx.DictService.GetDictValue(l.ctx, "admin_menu_type", req.Type)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "菜单类型无效: %v", err)
|
||||
}
|
||||
|
||||
// 3. 检查父菜单是否存在(如果不是根菜单)
|
||||
if req.Pid > 0 {
|
||||
parentMenu, err := l.svcCtx.AdminMenuModel.FindOne(l.ctx, req.Pid)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询父菜单失败, id: %d, err: %v", req.Pid, err)
|
||||
}
|
||||
if parentMenu == nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "父菜单不存在, id: %d", req.Pid)
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 检查名称和路径是否重复
|
||||
if req.Name != menu.Name || req.Path != menu.Path {
|
||||
exists, err := l.svcCtx.AdminMenuModel.FindOneByNamePath(l.ctx, req.Name, req.Path)
|
||||
if err != nil && !errors.Is(err, model.ErrNotFound) {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询菜单失败, err: %v", err)
|
||||
}
|
||||
if exists != nil && exists.Id != req.Id {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("菜单名称或路径已存在"), "菜单名称或路径已存在")
|
||||
}
|
||||
}
|
||||
|
||||
// 5. 更新菜单信息
|
||||
|
||||
menu.Pid = req.Pid
|
||||
menu.Name = req.Name
|
||||
menu.Path = req.Path
|
||||
menu.Component = req.Component
|
||||
menu.Redirect = sql.NullString{String: req.Redirect, Valid: req.Redirect != ""}
|
||||
menu.Status = req.Status
|
||||
menu.Type = typeValue
|
||||
menu.Sort = req.Sort
|
||||
|
||||
// 将Meta转换为JSON字符串
|
||||
metaJson, err := json.Marshal(req.Meta)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "Meta数据格式错误: %v", err)
|
||||
}
|
||||
menu.Meta = string(metaJson)
|
||||
|
||||
// 6. 保存更新
|
||||
_, err = l.svcCtx.AdminMenuModel.Update(l.ctx, nil, menu)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新菜单失败, err: %v", err)
|
||||
}
|
||||
|
||||
return &types.UpdateMenuResp{
|
||||
Success: true,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package admin_notification
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"time"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/app/main/model"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminCreateNotificationLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminCreateNotificationLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminCreateNotificationLogic {
|
||||
return &AdminCreateNotificationLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminCreateNotificationLogic) AdminCreateNotification(req *types.AdminCreateNotificationReq) (resp *types.AdminCreateNotificationResp, err error) {
|
||||
startDate, _ := time.Parse("2006-01-02", req.StartDate)
|
||||
endDate, _ := time.Parse("2006-01-02", req.EndDate)
|
||||
data := &model.GlobalNotifications{
|
||||
Title: req.Title,
|
||||
Content: req.Content,
|
||||
NotificationPage: req.NotificationPage,
|
||||
StartDate: sql.NullTime{Time: startDate, Valid: req.StartDate != ""},
|
||||
EndDate: sql.NullTime{Time: endDate, Valid: req.EndDate != ""},
|
||||
StartTime: req.StartTime,
|
||||
EndTime: req.EndTime,
|
||||
Status: req.Status,
|
||||
}
|
||||
result, err := l.svcCtx.GlobalNotificationsModel.Insert(l.ctx, nil, data)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "创建通知失败, err: %v, req: %+v", err, req)
|
||||
}
|
||||
id, _ := result.LastInsertId()
|
||||
return &types.AdminCreateNotificationResp{Id: id}, nil
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package admin_notification
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminDeleteNotificationLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminDeleteNotificationLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminDeleteNotificationLogic {
|
||||
return &AdminDeleteNotificationLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminDeleteNotificationLogic) AdminDeleteNotification(req *types.AdminDeleteNotificationReq) (resp *types.AdminDeleteNotificationResp, err error) {
|
||||
notification, err := l.svcCtx.GlobalNotificationsModel.FindOne(l.ctx, req.Id)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查找通知失败, err: %v, id: %d", err, req.Id)
|
||||
}
|
||||
err = l.svcCtx.GlobalNotificationsModel.DeleteSoft(l.ctx, nil, notification)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "删除通知失败, err: %v, id: %d", err, req.Id)
|
||||
}
|
||||
return &types.AdminDeleteNotificationResp{Success: true}, nil
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package admin_notification
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminGetNotificationDetailLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminGetNotificationDetailLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminGetNotificationDetailLogic {
|
||||
return &AdminGetNotificationDetailLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminGetNotificationDetailLogic) AdminGetNotificationDetail(req *types.AdminGetNotificationDetailReq) (resp *types.AdminGetNotificationDetailResp, err error) {
|
||||
notification, err := l.svcCtx.GlobalNotificationsModel.FindOne(l.ctx, req.Id)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查找通知失败, err: %v, id: %d", err, req.Id)
|
||||
}
|
||||
resp = &types.AdminGetNotificationDetailResp{
|
||||
Id: notification.Id,
|
||||
Title: notification.Title,
|
||||
Content: notification.Content,
|
||||
NotificationPage: notification.NotificationPage,
|
||||
StartDate: "",
|
||||
StartTime: notification.StartTime,
|
||||
EndDate: "",
|
||||
EndTime: notification.EndTime,
|
||||
Status: notification.Status,
|
||||
CreateTime: notification.CreateTime.Format("2006-01-02 15:04:05"),
|
||||
UpdateTime: notification.UpdateTime.Format("2006-01-02 15:04:05"),
|
||||
}
|
||||
if notification.StartDate.Valid {
|
||||
resp.StartDate = notification.StartDate.Time.Format("2006-01-02")
|
||||
}
|
||||
if notification.EndDate.Valid {
|
||||
resp.EndDate = notification.EndDate.Time.Format("2006-01-02")
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package admin_notification
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminGetNotificationListLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminGetNotificationListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminGetNotificationListLogic {
|
||||
return &AdminGetNotificationListLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminGetNotificationListLogic) AdminGetNotificationList(req *types.AdminGetNotificationListReq) (resp *types.AdminGetNotificationListResp, err error) {
|
||||
builder := l.svcCtx.GlobalNotificationsModel.SelectBuilder()
|
||||
if req.Title != nil {
|
||||
builder = builder.Where("title LIKE ?", "%"+*req.Title+"%")
|
||||
}
|
||||
if req.NotificationPage != nil {
|
||||
builder = builder.Where("notification_page = ?", *req.NotificationPage)
|
||||
}
|
||||
if req.Status != nil {
|
||||
builder = builder.Where("status = ?", *req.Status)
|
||||
}
|
||||
if req.StartDate != nil {
|
||||
if t, err := time.Parse("2006-01-02", *req.StartDate); err == nil {
|
||||
builder = builder.Where("start_date >= ?", t)
|
||||
}
|
||||
}
|
||||
if req.EndDate != nil {
|
||||
if t, err := time.Parse("2006-01-02", *req.EndDate); err == nil {
|
||||
builder = builder.Where("end_date <= ?", t)
|
||||
}
|
||||
}
|
||||
list, total, err := l.svcCtx.GlobalNotificationsModel.FindPageListByPageWithTotal(l.ctx, builder, req.Page, req.PageSize, "id DESC")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询通知列表失败, err: %v, req: %+v", err, req)
|
||||
}
|
||||
items := make([]types.NotificationListItem, 0, len(list))
|
||||
for _, n := range list {
|
||||
item := types.NotificationListItem{
|
||||
Id: n.Id,
|
||||
Title: n.Title,
|
||||
NotificationPage: n.NotificationPage,
|
||||
Content: n.Content,
|
||||
StartDate: "",
|
||||
StartTime: n.StartTime,
|
||||
EndDate: "",
|
||||
EndTime: n.EndTime,
|
||||
Status: n.Status,
|
||||
CreateTime: n.CreateTime.Format("2006-01-02 15:04:05"),
|
||||
UpdateTime: n.UpdateTime.Format("2006-01-02 15:04:05"),
|
||||
}
|
||||
if n.StartDate.Valid {
|
||||
item.StartDate = n.StartDate.Time.Format("2006-01-02")
|
||||
}
|
||||
if n.EndDate.Valid {
|
||||
item.EndDate = n.EndDate.Time.Format("2006-01-02")
|
||||
}
|
||||
items = append(items, item)
|
||||
}
|
||||
resp = &types.AdminGetNotificationListResp{
|
||||
Total: total,
|
||||
Items: items,
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package admin_notification
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"time"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminUpdateNotificationLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminUpdateNotificationLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminUpdateNotificationLogic {
|
||||
return &AdminUpdateNotificationLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminUpdateNotificationLogic) AdminUpdateNotification(req *types.AdminUpdateNotificationReq) (resp *types.AdminUpdateNotificationResp, err error) {
|
||||
notification, err := l.svcCtx.GlobalNotificationsModel.FindOne(l.ctx, req.Id)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查找通知失败, err: %v, id: %d", err, req.Id)
|
||||
}
|
||||
if req.StartDate != nil {
|
||||
startDate, _ := time.Parse("2006-01-02", *req.StartDate)
|
||||
notification.StartDate = sql.NullTime{Time: startDate, Valid: true}
|
||||
}
|
||||
if req.EndDate != nil {
|
||||
endDate, _ := time.Parse("2006-01-02", *req.EndDate)
|
||||
notification.EndDate = sql.NullTime{Time: endDate, Valid: true}
|
||||
}
|
||||
if req.Title != nil {
|
||||
notification.Title = *req.Title
|
||||
}
|
||||
if req.Content != nil {
|
||||
notification.Content = *req.Content
|
||||
}
|
||||
if req.NotificationPage != nil {
|
||||
notification.NotificationPage = *req.NotificationPage
|
||||
}
|
||||
if req.StartTime != nil {
|
||||
notification.StartTime = *req.StartTime
|
||||
}
|
||||
if req.EndTime != nil {
|
||||
notification.EndTime = *req.EndTime
|
||||
}
|
||||
if req.Status != nil {
|
||||
notification.Status = *req.Status
|
||||
}
|
||||
_, err = l.svcCtx.GlobalNotificationsModel.Update(l.ctx, nil, notification)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新通知失败, err: %v, req: %+v", err, req)
|
||||
}
|
||||
return &types.AdminUpdateNotificationResp{Success: true}, nil
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package admin_order
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/app/main/model"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
)
|
||||
|
||||
type AdminCreateOrderLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminCreateOrderLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminCreateOrderLogic {
|
||||
return &AdminCreateOrderLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminCreateOrderLogic) AdminCreateOrder(req *types.AdminCreateOrderReq) (resp *types.AdminCreateOrderResp, err error) {
|
||||
// 生成订单号
|
||||
orderNo := fmt.Sprintf("%dADMIN", time.Now().UnixNano())
|
||||
|
||||
// 根据产品名称查询产品ID
|
||||
builder := l.svcCtx.ProductModel.SelectBuilder()
|
||||
builder = builder.Where("product_name = ? AND del_state = ?", req.ProductName, 0)
|
||||
products, err := l.svcCtx.ProductModel.FindAll(l.ctx, builder, "")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "AdminCreateOrder, 查询产品失败 err: %v", err)
|
||||
}
|
||||
if len(products) == 0 {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg(fmt.Sprintf("产品不存在: %s", req.ProductName)), "AdminCreateOrder, 查询产品失败 err: %v", err)
|
||||
}
|
||||
product := products[0]
|
||||
|
||||
// 创建订单对象
|
||||
order := &model.Order{
|
||||
OrderNo: orderNo,
|
||||
PlatformOrderId: sql.NullString{String: req.PlatformOrderId, Valid: req.PlatformOrderId != ""},
|
||||
ProductId: product.Id,
|
||||
PaymentPlatform: req.PaymentPlatform,
|
||||
PaymentScene: req.PaymentScene,
|
||||
Amount: req.Amount,
|
||||
Status: req.Status,
|
||||
}
|
||||
|
||||
// 使用事务处理订单创建
|
||||
var orderId int64
|
||||
err = l.svcCtx.OrderModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error {
|
||||
// 插入订单
|
||||
result, err := l.svcCtx.OrderModel.Insert(ctx, session, order)
|
||||
if err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "AdminCreateOrder, 创建订单失败 err: %v", err)
|
||||
}
|
||||
|
||||
// 获取订单ID
|
||||
orderId, err = result.LastInsertId()
|
||||
if err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "AdminCreateOrder, 获取订单ID失败 err: %v", err)
|
||||
}
|
||||
|
||||
// 如果是推广订单,创建推广订单记录
|
||||
if req.IsPromotion == 1 {
|
||||
promotionOrder := &model.AdminPromotionOrder{
|
||||
OrderId: orderId,
|
||||
Version: 1,
|
||||
CreateTime: time.Now(),
|
||||
UpdateTime: time.Now(),
|
||||
}
|
||||
_, err = l.svcCtx.AdminPromotionOrderModel.Insert(ctx, session, promotionOrder)
|
||||
if err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "AdminCreateOrder, 创建推广订单失败 err: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &types.AdminCreateOrderResp{
|
||||
Id: orderId,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package admin_order
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
)
|
||||
|
||||
type AdminDeleteOrderLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminDeleteOrderLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminDeleteOrderLogic {
|
||||
return &AdminDeleteOrderLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminDeleteOrderLogic) AdminDeleteOrder(req *types.AdminDeleteOrderReq) (resp *types.AdminDeleteOrderResp, err error) {
|
||||
// 获取订单信息
|
||||
order, err := l.svcCtx.OrderModel.FindOne(l.ctx, req.Id)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "AdminDeleteOrder, 查询订单失败 err: %v", err)
|
||||
}
|
||||
|
||||
// 使用事务删除订单
|
||||
err = l.svcCtx.OrderModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error {
|
||||
// 软删除订单
|
||||
err := l.svcCtx.OrderModel.DeleteSoft(ctx, session, order)
|
||||
if err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "AdminDeleteOrder, 删除订单失败 err: %v", err)
|
||||
}
|
||||
|
||||
// 删除关联的推广订单记录
|
||||
promotionOrder, err := l.svcCtx.AdminPromotionOrderModel.FindOneByOrderId(ctx, order.Id)
|
||||
if err == nil && promotionOrder != nil {
|
||||
err = l.svcCtx.AdminPromotionOrderModel.DeleteSoft(ctx, session, promotionOrder)
|
||||
if err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "AdminDeleteOrder, 删除推广订单失败 err: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &types.AdminDeleteOrderResp{
|
||||
Success: true,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
package admin_order
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/app/main/model"
|
||||
"ycc-server/common/globalkey"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminGetOrderDetailLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminGetOrderDetailLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminGetOrderDetailLogic {
|
||||
return &AdminGetOrderDetailLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminGetOrderDetailLogic) AdminGetOrderDetail(req *types.AdminGetOrderDetailReq) (resp *types.AdminGetOrderDetailResp, err error) {
|
||||
// 获取订单信息
|
||||
order, err := l.svcCtx.OrderModel.FindOne(l.ctx, req.Id)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "AdminGetOrderDetail, 查询订单失败 err: %v", err)
|
||||
}
|
||||
|
||||
// 获取产品信息
|
||||
product, err := l.svcCtx.ProductModel.FindOne(l.ctx, order.ProductId)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "AdminGetOrderDetail, 查询产品失败 err: %v", err)
|
||||
}
|
||||
|
||||
// 判断是否为推广订单
|
||||
var isPromotion int64
|
||||
promotionOrder, err := l.svcCtx.AdminPromotionOrderModel.FindOneByOrderId(l.ctx, order.Id)
|
||||
if err == nil && promotionOrder != nil {
|
||||
isPromotion = 1
|
||||
}
|
||||
|
||||
// 判断是否为代理订单并获取代理处理状态
|
||||
var isAgentOrder bool
|
||||
var agentProcessStatus string
|
||||
|
||||
agentOrder, err := l.svcCtx.AgentOrderModel.FindOneByOrderId(l.ctx, order.Id)
|
||||
if err == nil && agentOrder != nil {
|
||||
isAgentOrder = true
|
||||
|
||||
// 查询代理佣金记录
|
||||
commissions, err := l.svcCtx.AgentCommissionModel.FindAll(l.ctx,
|
||||
l.svcCtx.AgentCommissionModel.SelectBuilder().Where("order_id = ?", order.Id), "")
|
||||
if err != nil && !errors.Is(err, model.ErrNotFound) {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "AdminGetOrderDetail, 查询代理佣金失败 err: %v", err)
|
||||
}
|
||||
|
||||
if len(commissions) > 0 {
|
||||
agentProcessStatus = "success"
|
||||
} else {
|
||||
// 检查订单状态,如果是已支付但无佣金记录,则为待处理或失败
|
||||
if order.Status == "paid" {
|
||||
agentProcessStatus = "pending"
|
||||
} else {
|
||||
agentProcessStatus = "failed"
|
||||
}
|
||||
}
|
||||
} else {
|
||||
isAgentOrder = false
|
||||
agentProcessStatus = "not_agent"
|
||||
}
|
||||
|
||||
// 获取查询状态
|
||||
var queryState string
|
||||
builder := l.svcCtx.QueryModel.SelectBuilder().Where("order_id = ?", order.Id).Columns("query_state")
|
||||
queries, err := l.svcCtx.QueryModel.FindAll(l.ctx, builder, "")
|
||||
if err != nil && !errors.Is(err, model.ErrNotFound) {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "AdminGetOrderDetail, 查询查询状态失败 err: %v", err)
|
||||
}
|
||||
|
||||
if len(queries) > 0 {
|
||||
queryState = queries[0].QueryState
|
||||
} else {
|
||||
// 查询清理日志
|
||||
cleanupBuilder := l.svcCtx.QueryCleanupDetailModel.SelectBuilder().
|
||||
Where("order_id = ?", order.Id).
|
||||
Where("del_state = ?", globalkey.DelStateNo).
|
||||
OrderBy("create_time DESC").
|
||||
Limit(1)
|
||||
cleanupDetails, err := l.svcCtx.QueryCleanupDetailModel.FindAll(l.ctx, cleanupBuilder, "")
|
||||
if err != nil && !errors.Is(err, model.ErrNotFound) {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "AdminGetOrderDetail, 查询清理日志失败 err: %v", err)
|
||||
}
|
||||
|
||||
if len(cleanupDetails) > 0 {
|
||||
queryState = model.QueryStateCleaned
|
||||
} else {
|
||||
queryState = ""
|
||||
}
|
||||
}
|
||||
|
||||
// 构建响应
|
||||
resp = &types.AdminGetOrderDetailResp{
|
||||
Id: order.Id,
|
||||
OrderNo: order.OrderNo,
|
||||
PlatformOrderId: order.PlatformOrderId.String,
|
||||
ProductName: product.ProductName,
|
||||
PaymentPlatform: order.PaymentPlatform,
|
||||
PaymentScene: order.PaymentScene,
|
||||
Amount: order.Amount,
|
||||
Status: order.Status,
|
||||
CreateTime: order.CreateTime.Format("2006-01-02 15:04:05"),
|
||||
UpdateTime: order.UpdateTime.Format("2006-01-02 15:04:05"),
|
||||
IsPromotion: isPromotion,
|
||||
QueryState: queryState,
|
||||
IsAgentOrder: isAgentOrder,
|
||||
AgentProcessStatus: agentProcessStatus,
|
||||
}
|
||||
|
||||
// 处理可选字段
|
||||
if order.PayTime.Valid {
|
||||
resp.PayTime = order.PayTime.Time.Format("2006-01-02 15:04:05")
|
||||
}
|
||||
if order.RefundTime.Valid {
|
||||
resp.RefundTime = order.RefundTime.Time.Format("2006-01-02 15:04:05")
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
@@ -0,0 +1,295 @@
|
||||
package admin_order
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/app/main/model"
|
||||
"ycc-server/common/globalkey"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"github.com/Masterminds/squirrel"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"github.com/zeromicro/go-zero/core/mr"
|
||||
)
|
||||
|
||||
type AdminGetOrderListLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminGetOrderListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminGetOrderListLogic {
|
||||
return &AdminGetOrderListLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminGetOrderListLogic) AdminGetOrderList(req *types.AdminGetOrderListReq) (resp *types.AdminGetOrderListResp, err error) {
|
||||
// 构建查询条件
|
||||
builder := l.svcCtx.OrderModel.SelectBuilder()
|
||||
if req.OrderNo != "" {
|
||||
builder = builder.Where("order_no = ?", req.OrderNo)
|
||||
}
|
||||
if req.PlatformOrderId != "" {
|
||||
builder = builder.Where("platform_order_id = ?", req.PlatformOrderId)
|
||||
}
|
||||
if req.ProductName != "" {
|
||||
builder = builder.Where("product_id IN (SELECT id FROM product WHERE product_name LIKE ?)", "%"+req.ProductName+"%")
|
||||
}
|
||||
if req.PaymentPlatform != "" {
|
||||
builder = builder.Where("payment_platform = ?", req.PaymentPlatform)
|
||||
}
|
||||
if req.PaymentScene != "" {
|
||||
builder = builder.Where("payment_scene = ?", req.PaymentScene)
|
||||
}
|
||||
if req.Amount > 0 {
|
||||
builder = builder.Where("amount = ?", req.Amount)
|
||||
}
|
||||
if req.Status != "" {
|
||||
builder = builder.Where("status = ?", req.Status)
|
||||
}
|
||||
if req.IsPromotion != -1 {
|
||||
builder = builder.Where("id IN (SELECT order_id FROM admin_promotion_order WHERE del_state = 0)")
|
||||
}
|
||||
// 时间范围查询
|
||||
if req.CreateTimeStart != "" {
|
||||
builder = builder.Where("create_time >= ?", req.CreateTimeStart)
|
||||
}
|
||||
if req.CreateTimeEnd != "" {
|
||||
builder = builder.Where("create_time <= ?", req.CreateTimeEnd)
|
||||
}
|
||||
if req.PayTimeStart != "" {
|
||||
builder = builder.Where("pay_time >= ?", req.PayTimeStart)
|
||||
}
|
||||
if req.PayTimeEnd != "" {
|
||||
builder = builder.Where("pay_time <= ?", req.PayTimeEnd)
|
||||
}
|
||||
if req.RefundTimeStart != "" {
|
||||
builder = builder.Where("refund_time >= ?", req.RefundTimeStart)
|
||||
}
|
||||
if req.RefundTimeEnd != "" {
|
||||
builder = builder.Where("refund_time <= ?", req.RefundTimeEnd)
|
||||
}
|
||||
|
||||
// 并发获取总数和列表
|
||||
var total int64
|
||||
var orders []*model.Order
|
||||
err = mr.Finish(func() error {
|
||||
var err error
|
||||
total, err = l.svcCtx.OrderModel.FindCount(l.ctx, builder, "id")
|
||||
if err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "AdminGetOrderList, 查询订单总数失败 err: %v", err)
|
||||
}
|
||||
return nil
|
||||
}, func() error {
|
||||
var err error
|
||||
orders, err = l.svcCtx.OrderModel.FindPageListByPage(l.ctx, builder, req.Page, req.PageSize, "id DESC")
|
||||
if err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "AdminGetOrderList, 查询订单列表失败 err: %v", err)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 并发获取产品信息和查询状态
|
||||
productMap := make(map[int64]string)
|
||||
queryStateMap := make(map[int64]string)
|
||||
agentOrderMap := make(map[int64]bool) // 代理订单映射
|
||||
agentProcessStatusMap := make(map[int64]string) // 代理处理状态映射
|
||||
|
||||
var mu sync.Mutex
|
||||
|
||||
// 批量获取查询状态
|
||||
if len(orders) > 0 {
|
||||
orderIds := make([]int64, 0, len(orders))
|
||||
for _, order := range orders {
|
||||
orderIds = append(orderIds, order.Id)
|
||||
}
|
||||
|
||||
// 1. 先查询当前查询状态
|
||||
builder := l.svcCtx.QueryModel.SelectBuilder().
|
||||
Where(squirrel.Eq{"order_id": orderIds}).
|
||||
Columns("order_id", "query_state")
|
||||
queries, err := l.svcCtx.QueryModel.FindAll(l.ctx, builder, "")
|
||||
if err != nil && !errors.Is(err, model.ErrNotFound) {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "AdminGetOrderList, 批量查询查询状态失败 err: %v", err)
|
||||
}
|
||||
|
||||
// 2. 记录已找到查询状态的订单ID
|
||||
foundOrderIds := make(map[int64]bool)
|
||||
for _, query := range queries {
|
||||
queryStateMap[query.OrderId] = query.QueryState
|
||||
foundOrderIds[query.OrderId] = true
|
||||
}
|
||||
|
||||
// 3. 查找未找到查询状态的订单是否在清理日志中
|
||||
notFoundOrderIds := make([]int64, 0)
|
||||
for _, orderId := range orderIds {
|
||||
if !foundOrderIds[orderId] {
|
||||
notFoundOrderIds = append(notFoundOrderIds, orderId)
|
||||
}
|
||||
}
|
||||
|
||||
if len(notFoundOrderIds) > 0 {
|
||||
// 查询清理日志
|
||||
cleanupBuilder := l.svcCtx.QueryCleanupDetailModel.SelectBuilder().
|
||||
Where(squirrel.Eq{"order_id": notFoundOrderIds}).
|
||||
Where("del_state = ?", globalkey.DelStateNo).
|
||||
OrderBy("create_time DESC")
|
||||
cleanupDetails, err := l.svcCtx.QueryCleanupDetailModel.FindAll(l.ctx, cleanupBuilder, "")
|
||||
if err != nil && !errors.Is(err, model.ErrNotFound) {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "AdminGetOrderList, 查询清理日志失败 err: %v", err)
|
||||
}
|
||||
|
||||
// 记录已清理的订单状态
|
||||
for _, detail := range cleanupDetails {
|
||||
if _, exists := queryStateMap[detail.OrderId]; !exists {
|
||||
queryStateMap[detail.OrderId] = model.QueryStateCleaned // 使用常量标记为已清除状态
|
||||
}
|
||||
}
|
||||
|
||||
// 对于既没有查询状态也没有清理记录的订单,不设置状态(保持为空字符串)
|
||||
for _, orderId := range notFoundOrderIds {
|
||||
if _, exists := queryStateMap[orderId]; !exists {
|
||||
queryStateMap[orderId] = "" // 未知状态保持为空字符串
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 批量获取代理订单状态
|
||||
agentOrders, err := l.svcCtx.AgentOrderModel.FindAll(l.ctx,
|
||||
l.svcCtx.AgentOrderModel.SelectBuilder().Where(squirrel.Eq{"order_id": orderIds}), "")
|
||||
if err != nil && !errors.Is(err, model.ErrNotFound) {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "AdminGetOrderList, 批量查询代理订单失败 err: %v", err)
|
||||
}
|
||||
|
||||
// 记录代理订单
|
||||
for _, agentOrder := range agentOrders {
|
||||
agentOrderMap[agentOrder.OrderId] = true
|
||||
}
|
||||
|
||||
// 对于代理订单,查询代理处理状态
|
||||
if len(agentOrders) > 0 {
|
||||
agentOrderIds := make([]int64, 0, len(agentOrders))
|
||||
for _, agentOrder := range agentOrders {
|
||||
agentOrderIds = append(agentOrderIds, agentOrder.OrderId)
|
||||
}
|
||||
|
||||
// 查询代理佣金记录
|
||||
commissions, err := l.svcCtx.AgentCommissionModel.FindAll(l.ctx,
|
||||
l.svcCtx.AgentCommissionModel.SelectBuilder().Where(squirrel.Eq{"order_id": agentOrderIds}), "")
|
||||
if err != nil && !errors.Is(err, model.ErrNotFound) {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "AdminGetOrderList, 批量查询代理佣金失败 err: %v", err)
|
||||
}
|
||||
|
||||
// 记录有佣金记录的订单为处理成功
|
||||
processedOrderIds := make(map[int64]bool)
|
||||
for _, commission := range commissions {
|
||||
processedOrderIds[commission.OrderId] = true
|
||||
}
|
||||
|
||||
// 创建订单状态映射,避免重复查找
|
||||
orderStatusMap := make(map[int64]string)
|
||||
for _, order := range orders {
|
||||
orderStatusMap[order.Id] = order.Status
|
||||
}
|
||||
|
||||
// 设置代理处理状态
|
||||
for _, agentOrder := range agentOrders {
|
||||
orderId := agentOrder.OrderId
|
||||
if processedOrderIds[orderId] {
|
||||
agentProcessStatusMap[orderId] = "success"
|
||||
} else {
|
||||
// 检查订单状态,如果是已支付但无佣金记录,则为待处理或失败
|
||||
if orderStatusMap[orderId] == "paid" {
|
||||
agentProcessStatusMap[orderId] = "pending"
|
||||
} else {
|
||||
agentProcessStatusMap[orderId] = "failed"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 并发获取产品信息
|
||||
err = mr.MapReduceVoid(func(source chan<- interface{}) {
|
||||
for _, order := range orders {
|
||||
source <- order
|
||||
}
|
||||
}, func(item interface{}, writer mr.Writer[struct{}], cancel func(error)) {
|
||||
order := item.(*model.Order)
|
||||
|
||||
// 获取产品信息
|
||||
product, err := l.svcCtx.ProductModel.FindOne(l.ctx, order.ProductId)
|
||||
if err != nil && !errors.Is(err, model.ErrNotFound) {
|
||||
cancel(errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "AdminGetOrderList, 查询产品信息失败 err: %v", err))
|
||||
return
|
||||
}
|
||||
mu.Lock()
|
||||
if product != nil {
|
||||
productMap[product.Id] = product.ProductName
|
||||
} else {
|
||||
productMap[order.ProductId] = "" // 产品不存在时设置为空字符串
|
||||
}
|
||||
mu.Unlock()
|
||||
writer.Write(struct{}{})
|
||||
}, func(pipe <-chan struct{}, cancel func(error)) {
|
||||
for range pipe {
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 构建响应
|
||||
resp = &types.AdminGetOrderListResp{
|
||||
Total: total,
|
||||
Items: make([]types.OrderListItem, 0, len(orders)),
|
||||
}
|
||||
|
||||
for _, order := range orders {
|
||||
item := types.OrderListItem{
|
||||
Id: order.Id,
|
||||
OrderNo: order.OrderNo,
|
||||
PlatformOrderId: order.PlatformOrderId.String,
|
||||
ProductName: productMap[order.ProductId],
|
||||
PaymentPlatform: order.PaymentPlatform,
|
||||
PaymentScene: order.PaymentScene,
|
||||
Amount: order.Amount,
|
||||
Status: order.Status,
|
||||
CreateTime: order.CreateTime.Format("2006-01-02 15:04:05"),
|
||||
QueryState: queryStateMap[order.Id],
|
||||
}
|
||||
if order.PayTime.Valid {
|
||||
item.PayTime = order.PayTime.Time.Format("2006-01-02 15:04:05")
|
||||
}
|
||||
if order.RefundTime.Valid {
|
||||
item.RefundTime = order.RefundTime.Time.Format("2006-01-02 15:04:05")
|
||||
}
|
||||
// 判断是否为推广订单
|
||||
promotionOrder, err := l.svcCtx.AdminPromotionOrderModel.FindOneByOrderId(l.ctx, order.Id)
|
||||
if err == nil && promotionOrder != nil {
|
||||
item.IsPromotion = 1
|
||||
}
|
||||
|
||||
// 设置代理订单相关字段
|
||||
if agentOrderMap[order.Id] {
|
||||
item.IsAgentOrder = true
|
||||
item.AgentProcessStatus = agentProcessStatusMap[order.Id]
|
||||
} else {
|
||||
item.IsAgentOrder = false
|
||||
item.AgentProcessStatus = "not_agent"
|
||||
}
|
||||
resp.Items = append(resp.Items, item)
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
193
app/main/api/internal/logic/admin_order/adminrefundorderlogic.go
Normal file
193
app/main/api/internal/logic/admin_order/adminrefundorderlogic.go
Normal file
@@ -0,0 +1,193 @@
|
||||
package admin_order
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/app/main/model"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
)
|
||||
|
||||
const (
|
||||
PaymentPlatformAlipay = "alipay"
|
||||
PaymentPlatformWechat = "wechat"
|
||||
OrderStatusPaid = "paid"
|
||||
RefundNoPrefix = "refund-"
|
||||
)
|
||||
|
||||
type AdminRefundOrderLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminRefundOrderLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminRefundOrderLogic {
|
||||
return &AdminRefundOrderLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
func (l *AdminRefundOrderLogic) AdminRefundOrder(req *types.AdminRefundOrderReq) (resp *types.AdminRefundOrderResp, err error) {
|
||||
// 获取并验证订单
|
||||
order, err := l.getAndValidateOrder(req.Id, req.RefundAmount)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 根据支付平台处理退款
|
||||
switch order.PaymentPlatform {
|
||||
case PaymentPlatformAlipay:
|
||||
return l.handleAlipayRefund(order, req)
|
||||
case PaymentPlatformWechat:
|
||||
return l.handleWechatRefund(order, req)
|
||||
default:
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("不支持的支付平台"), "AdminRefundOrder, 不支持的支付平台: %s", order.PaymentPlatform)
|
||||
}
|
||||
}
|
||||
|
||||
// getAndValidateOrder 获取并验证订单信息
|
||||
func (l *AdminRefundOrderLogic) getAndValidateOrder(orderId int64, refundAmount float64) (*model.Order, error) {
|
||||
order, err := l.svcCtx.OrderModel.FindOne(l.ctx, orderId)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "AdminRefundOrder, 查询订单失败 err: %v", err)
|
||||
}
|
||||
|
||||
// 检查订单状态
|
||||
if order.Status != OrderStatusPaid {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("订单状态不正确,无法退款"), "AdminRefundOrder, 订单状态: %s", order.Status)
|
||||
}
|
||||
|
||||
// 检查退款金额
|
||||
if refundAmount > order.Amount {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("退款金额不能大于订单金额"), "AdminRefundOrder, 退款金额: %f, 订单金额: %f", refundAmount, order.Amount)
|
||||
}
|
||||
|
||||
return order, nil
|
||||
}
|
||||
|
||||
// handleAlipayRefund 处理支付宝退款
|
||||
func (l *AdminRefundOrderLogic) handleAlipayRefund(order *model.Order, req *types.AdminRefundOrderReq) (*types.AdminRefundOrderResp, error) {
|
||||
// 调用支付宝退款接口
|
||||
refundResp, err := l.svcCtx.AlipayService.AliRefund(l.ctx, order.OrderNo, req.RefundAmount)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "AdminRefundOrder, 支付宝退款失败 err: %v", err)
|
||||
}
|
||||
|
||||
refundNo := l.generateRefundNo(order.OrderNo)
|
||||
|
||||
if refundResp.IsSuccess() {
|
||||
// 支付宝退款成功,创建成功记录
|
||||
err = l.createRefundRecordAndUpdateOrder(order, req, refundNo, refundResp.TradeNo, model.OrderStatusRefunded, model.OrderRefundStatusSuccess)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &types.AdminRefundOrderResp{
|
||||
Status: model.OrderStatusRefunded,
|
||||
RefundNo: refundNo,
|
||||
Amount: req.RefundAmount,
|
||||
}, nil
|
||||
} else {
|
||||
// 支付宝退款失败,创建失败记录但不更新订单状态
|
||||
err = l.createRefundRecordOnly(order, req, refundNo, refundResp.TradeNo, model.OrderRefundStatusFailed)
|
||||
if err != nil {
|
||||
logx.Errorf("创建退款失败记录时出错: %v", err)
|
||||
}
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg(fmt.Sprintf("退款失败: %v", refundResp.Msg)), "AdminRefundOrder, 支付宝退款失败")
|
||||
}
|
||||
}
|
||||
|
||||
// handleWechatRefund 处理微信退款
|
||||
func (l *AdminRefundOrderLogic) handleWechatRefund(order *model.Order, req *types.AdminRefundOrderReq) (*types.AdminRefundOrderResp, error) {
|
||||
// 调用微信退款接口
|
||||
err := l.svcCtx.WechatPayService.WeChatRefund(l.ctx, order.OrderNo, req.RefundAmount, order.Amount)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "AdminRefundOrder, 微信退款失败 err: %v", err)
|
||||
}
|
||||
|
||||
// 微信退款是异步的,创建pending状态的退款记录
|
||||
refundNo := l.generateRefundNo(order.OrderNo)
|
||||
err = l.createRefundRecordAndUpdateOrder(order, req, refundNo, "", model.OrderStatusRefunding, model.OrderRefundStatusPending)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &types.AdminRefundOrderResp{
|
||||
Status: model.OrderRefundStatusPending,
|
||||
RefundNo: refundNo,
|
||||
Amount: req.RefundAmount,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// createRefundRecordAndUpdateOrder 创建退款记录并更新订单状态
|
||||
func (l *AdminRefundOrderLogic) createRefundRecordAndUpdateOrder(order *model.Order, req *types.AdminRefundOrderReq, refundNo, platformRefundId, orderStatus, refundStatus string) error {
|
||||
return l.svcCtx.OrderModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error {
|
||||
// 创建退款记录
|
||||
refund := &model.OrderRefund{
|
||||
RefundNo: refundNo,
|
||||
PlatformRefundId: l.createNullString(platformRefundId),
|
||||
OrderId: order.Id,
|
||||
UserId: order.UserId,
|
||||
ProductId: order.ProductId,
|
||||
RefundAmount: req.RefundAmount,
|
||||
RefundReason: l.createNullString(req.RefundReason),
|
||||
Status: refundStatus, // 使用传入的状态,不再硬编码
|
||||
RefundTime: sql.NullTime{Time: time.Now(), Valid: true},
|
||||
}
|
||||
|
||||
if _, err := l.svcCtx.OrderRefundModel.Insert(ctx, session, refund); err != nil {
|
||||
return fmt.Errorf("创建退款记录失败: %v", err)
|
||||
}
|
||||
|
||||
// 更新订单状态
|
||||
order.Status = orderStatus
|
||||
if _, err := l.svcCtx.OrderModel.Update(ctx, session, order); err != nil {
|
||||
return fmt.Errorf("更新订单状态失败: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// createRefundRecordOnly 仅创建退款记录,不更新订单状态(用于退款失败的情况)
|
||||
func (l *AdminRefundOrderLogic) createRefundRecordOnly(order *model.Order, req *types.AdminRefundOrderReq, refundNo, platformRefundId, refundStatus string) error {
|
||||
refund := &model.OrderRefund{
|
||||
RefundNo: refundNo,
|
||||
PlatformRefundId: l.createNullString(platformRefundId),
|
||||
OrderId: order.Id,
|
||||
UserId: order.UserId,
|
||||
ProductId: order.ProductId,
|
||||
RefundAmount: req.RefundAmount,
|
||||
RefundReason: l.createNullString(req.RefundReason),
|
||||
Status: refundStatus,
|
||||
RefundTime: sql.NullTime{Time: time.Now(), Valid: true},
|
||||
}
|
||||
|
||||
_, err := l.svcCtx.OrderRefundModel.Insert(l.ctx, nil, refund)
|
||||
if err != nil {
|
||||
return fmt.Errorf("创建退款记录失败: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// generateRefundNo 生成退款单号
|
||||
func (l *AdminRefundOrderLogic) generateRefundNo(orderNo string) string {
|
||||
return fmt.Sprintf("%s%s", RefundNoPrefix, orderNo)
|
||||
}
|
||||
|
||||
// createNullString 创建 sql.NullString
|
||||
func (l *AdminRefundOrderLogic) createNullString(value string) sql.NullString {
|
||||
return sql.NullString{
|
||||
String: value,
|
||||
Valid: value != "",
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package admin_order
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminRetryAgentProcessLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminRetryAgentProcessLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminRetryAgentProcessLogic {
|
||||
return &AdminRetryAgentProcessLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminRetryAgentProcessLogic) AdminRetryAgentProcess(req *types.AdminRetryAgentProcessReq) (resp *types.AdminRetryAgentProcessResp, err error) {
|
||||
// 新系统:查询订单并调用AgentProcess重新处理
|
||||
order, err := l.svcCtx.OrderModel.FindOne(l.ctx, req.Id)
|
||||
if err != nil {
|
||||
return &types.AdminRetryAgentProcessResp{
|
||||
Status: "failed",
|
||||
Message: "订单不存在",
|
||||
ProcessedAt: time.Now().Format("2006-01-02 15:04:05"),
|
||||
}, nil
|
||||
}
|
||||
err = l.svcCtx.AgentService.AgentProcess(l.ctx, order)
|
||||
if err != nil {
|
||||
// 检查是否是"已经处理"的错误
|
||||
if err.Error() == "代理处理已经成功,无需重新执行" {
|
||||
return &types.AdminRetryAgentProcessResp{
|
||||
Status: "already_processed",
|
||||
Message: "代理处理已经成功,无需重新执行",
|
||||
ProcessedAt: time.Now().Format("2006-01-02 15:04:05"),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 其他错误
|
||||
logx.Errorf("重新执行代理处理失败,订单ID: %d, 错误: %v", req.Id, err)
|
||||
return &types.AdminRetryAgentProcessResp{
|
||||
Status: "failed",
|
||||
Message: err.Error(),
|
||||
ProcessedAt: time.Now().Format("2006-01-02 15:04:05"),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 执行成功
|
||||
return &types.AdminRetryAgentProcessResp{
|
||||
Status: "success",
|
||||
Message: "代理处理重新执行成功",
|
||||
ProcessedAt: time.Now().Format("2006-01-02 15:04:05"),
|
||||
}, nil
|
||||
}
|
||||
113
app/main/api/internal/logic/admin_order/adminupdateorderlogic.go
Normal file
113
app/main/api/internal/logic/admin_order/adminupdateorderlogic.go
Normal file
@@ -0,0 +1,113 @@
|
||||
package admin_order
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"time"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/app/main/model"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
)
|
||||
|
||||
type AdminUpdateOrderLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminUpdateOrderLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminUpdateOrderLogic {
|
||||
return &AdminUpdateOrderLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminUpdateOrderLogic) AdminUpdateOrder(req *types.AdminUpdateOrderReq) (resp *types.AdminUpdateOrderResp, err error) {
|
||||
// 获取原订单信息
|
||||
order, err := l.svcCtx.OrderModel.FindOne(l.ctx, req.Id)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "AdminUpdateOrder, 查询订单失败 err: %v", err)
|
||||
}
|
||||
|
||||
// 更新订单字段
|
||||
if req.OrderNo != nil {
|
||||
order.OrderNo = *req.OrderNo
|
||||
}
|
||||
if req.PlatformOrderId != nil {
|
||||
order.PlatformOrderId = sql.NullString{String: *req.PlatformOrderId, Valid: true}
|
||||
}
|
||||
if req.PaymentPlatform != nil {
|
||||
order.PaymentPlatform = *req.PaymentPlatform
|
||||
}
|
||||
if req.PaymentScene != nil {
|
||||
order.PaymentScene = *req.PaymentScene
|
||||
}
|
||||
if req.Amount != nil {
|
||||
order.Amount = *req.Amount
|
||||
}
|
||||
if req.Status != nil {
|
||||
order.Status = *req.Status
|
||||
}
|
||||
if req.PayTime != nil {
|
||||
payTime, err := time.Parse("2006-01-02 15:04:05", *req.PayTime)
|
||||
if err == nil {
|
||||
order.PayTime = sql.NullTime{Time: payTime, Valid: true}
|
||||
}
|
||||
}
|
||||
if req.RefundTime != nil {
|
||||
refundTime, err := time.Parse("2006-01-02 15:04:05", *req.RefundTime)
|
||||
if err == nil {
|
||||
order.RefundTime = sql.NullTime{Time: refundTime, Valid: true}
|
||||
}
|
||||
}
|
||||
|
||||
// 使用事务更新订单
|
||||
err = l.svcCtx.OrderModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error {
|
||||
// 更新订单
|
||||
_, err := l.svcCtx.OrderModel.Update(ctx, session, order)
|
||||
if err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "AdminUpdateOrder, 更新订单失败 err: %v", err)
|
||||
}
|
||||
|
||||
// 处理推广订单状态
|
||||
if req.IsPromotion != nil {
|
||||
promotionOrder, err := l.svcCtx.AdminPromotionOrderModel.FindOneByOrderId(ctx, order.Id)
|
||||
if err == nil && promotionOrder != nil {
|
||||
// 如果存在推广订单记录但不需要推广,则删除
|
||||
if *req.IsPromotion == 0 {
|
||||
err = l.svcCtx.AdminPromotionOrderModel.DeleteSoft(ctx, session, promotionOrder)
|
||||
if err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "AdminUpdateOrder, 删除推广订单失败 err: %v", err)
|
||||
}
|
||||
}
|
||||
} else if *req.IsPromotion == 1 {
|
||||
// 如果需要推广但不存在记录,则创建
|
||||
newPromotionOrder := &model.AdminPromotionOrder{
|
||||
OrderId: order.Id,
|
||||
Version: 1,
|
||||
}
|
||||
_, err = l.svcCtx.AdminPromotionOrderModel.Insert(ctx, session, newPromotionOrder)
|
||||
if err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "AdminUpdateOrder, 创建推广订单失败 err: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &types.AdminUpdateOrderResp{
|
||||
Success: true,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package admin_platform_user
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/app/main/model"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminCreatePlatformUserLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminCreatePlatformUserLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminCreatePlatformUserLogic {
|
||||
return &AdminCreatePlatformUserLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminCreatePlatformUserLogic) AdminCreatePlatformUser(req *types.AdminCreatePlatformUserReq) (resp *types.AdminCreatePlatformUserResp, err error) {
|
||||
// 校验手机号唯一性
|
||||
_, err = l.svcCtx.UserModel.FindOneByMobile(l.ctx, sql.NullString{String: req.Mobile, Valid: req.Mobile != ""})
|
||||
if err == nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "手机号已存在: %s", req.Mobile)
|
||||
}
|
||||
if err != model.ErrNotFound {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询手机号失败: %v", err)
|
||||
}
|
||||
|
||||
user := &model.User{
|
||||
Mobile: sql.NullString{String: req.Mobile, Valid: req.Mobile != ""},
|
||||
Password: sql.NullString{String: req.Password, Valid: req.Password != ""},
|
||||
Nickname: sql.NullString{String: req.Nickname, Valid: req.Nickname != ""},
|
||||
Info: req.Info,
|
||||
Inside: req.Inside,
|
||||
}
|
||||
result, err := l.svcCtx.UserModel.Insert(l.ctx, nil, user)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "创建用户失败: %v", err)
|
||||
}
|
||||
id, err := result.LastInsertId()
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取用户ID失败: %v", err)
|
||||
}
|
||||
resp = &types.AdminCreatePlatformUserResp{Id: id}
|
||||
return resp, nil
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package admin_platform_user
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminDeletePlatformUserLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminDeletePlatformUserLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminDeletePlatformUserLogic {
|
||||
return &AdminDeletePlatformUserLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminDeletePlatformUserLogic) AdminDeletePlatformUser(req *types.AdminDeletePlatformUserReq) (resp *types.AdminDeletePlatformUserResp, err error) {
|
||||
user, err := l.svcCtx.UserModel.FindOne(l.ctx, req.Id)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "用户不存在: %d, err: %v", req.Id, err)
|
||||
}
|
||||
user.DelState = 1
|
||||
user.DeleteTime.Time = time.Now()
|
||||
user.DeleteTime.Valid = true
|
||||
err = l.svcCtx.UserModel.DeleteSoft(l.ctx, nil, user)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "软删除用户失败: %v", err)
|
||||
}
|
||||
resp = &types.AdminDeletePlatformUserResp{Success: true}
|
||||
return resp, nil
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package admin_platform_user
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/common/xerr"
|
||||
"ycc-server/pkg/lzkit/crypto"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminGetPlatformUserDetailLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminGetPlatformUserDetailLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminGetPlatformUserDetailLogic {
|
||||
return &AdminGetPlatformUserDetailLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminGetPlatformUserDetailLogic) AdminGetPlatformUserDetail(req *types.AdminGetPlatformUserDetailReq) (resp *types.AdminGetPlatformUserDetailResp, err error) {
|
||||
user, err := l.svcCtx.UserModel.FindOne(l.ctx, req.Id)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "用户不存在: %d, err: %v", req.Id, err)
|
||||
}
|
||||
key := l.svcCtx.Config.Encrypt.SecretKey
|
||||
DecryptMobile, err := crypto.DecryptMobile(user.Mobile.String, key)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "解密手机号失败: %v", err)
|
||||
}
|
||||
// 查询平台类型(取第一个user_auth)
|
||||
resp = &types.AdminGetPlatformUserDetailResp{
|
||||
Id: user.Id,
|
||||
Mobile: DecryptMobile,
|
||||
Nickname: "",
|
||||
Info: user.Info,
|
||||
Inside: user.Inside,
|
||||
CreateTime: user.CreateTime.Format("2006-01-02 15:04:05"),
|
||||
UpdateTime: user.UpdateTime.Format("2006-01-02 15:04:05"),
|
||||
}
|
||||
if user.Nickname.Valid {
|
||||
resp.Nickname = user.Nickname.String
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package admin_platform_user
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/common/xerr"
|
||||
"ycc-server/pkg/lzkit/crypto"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminGetPlatformUserListLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminGetPlatformUserListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminGetPlatformUserListLogic {
|
||||
return &AdminGetPlatformUserListLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminGetPlatformUserListLogic) AdminGetPlatformUserList(req *types.AdminGetPlatformUserListReq) (resp *types.AdminGetPlatformUserListResp, err error) {
|
||||
builder := l.svcCtx.UserModel.SelectBuilder()
|
||||
if req.Mobile != "" {
|
||||
builder = builder.Where("mobile = ?", req.Mobile)
|
||||
}
|
||||
if req.Nickname != "" {
|
||||
builder = builder.Where("nickname = ?", req.Nickname)
|
||||
}
|
||||
if req.Inside != 0 {
|
||||
builder = builder.Where("inside = ?", req.Inside)
|
||||
}
|
||||
if req.CreateTimeStart != "" {
|
||||
builder = builder.Where("create_time >= ?", req.CreateTimeStart)
|
||||
}
|
||||
if req.CreateTimeEnd != "" {
|
||||
builder = builder.Where("create_time <= ?", req.CreateTimeEnd)
|
||||
}
|
||||
|
||||
orderBy := "id DESC"
|
||||
if req.OrderBy != "" && req.OrderType != "" {
|
||||
orderBy = fmt.Sprintf("%s %s", req.OrderBy, req.OrderType)
|
||||
}
|
||||
users, total, err := l.svcCtx.UserModel.FindPageListByPageWithTotal(l.ctx, builder, req.Page, req.PageSize, orderBy)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询用户分页失败: %v", err)
|
||||
}
|
||||
var items []types.PlatformUserListItem
|
||||
secretKey := l.svcCtx.Config.Encrypt.SecretKey
|
||||
|
||||
for _, user := range users {
|
||||
mobile := user.Mobile
|
||||
if mobile.Valid {
|
||||
encryptedMobile, err := crypto.DecryptMobile(mobile.String, secretKey)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "手机登录, 解密手机号失败: %+v", err)
|
||||
}
|
||||
mobile = sql.NullString{String: encryptedMobile, Valid: true}
|
||||
}
|
||||
itemData := types.PlatformUserListItem{
|
||||
Id: user.Id,
|
||||
Mobile: mobile.String,
|
||||
Nickname: "",
|
||||
Info: user.Info,
|
||||
Inside: user.Inside,
|
||||
CreateTime: user.CreateTime.Format("2006-01-02 15:04:05"),
|
||||
UpdateTime: user.UpdateTime.Format("2006-01-02 15:04:05"),
|
||||
}
|
||||
if user.Nickname.Valid {
|
||||
itemData.Nickname = user.Nickname.String
|
||||
}
|
||||
items = append(items, itemData)
|
||||
}
|
||||
resp = &types.AdminGetPlatformUserListResp{
|
||||
Total: total,
|
||||
Items: items,
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package admin_platform_user
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/common/xerr"
|
||||
"ycc-server/pkg/lzkit/crypto"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminUpdatePlatformUserLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminUpdatePlatformUserLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminUpdatePlatformUserLogic {
|
||||
return &AdminUpdatePlatformUserLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminUpdatePlatformUserLogic) AdminUpdatePlatformUser(req *types.AdminUpdatePlatformUserReq) (resp *types.AdminUpdatePlatformUserResp, err error) {
|
||||
user, err := l.svcCtx.UserModel.FindOne(l.ctx, req.Id)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "用户不存在: %d, err: %v", req.Id, err)
|
||||
}
|
||||
if req.Mobile != nil {
|
||||
key := l.svcCtx.Config.Encrypt.SecretKey
|
||||
EncryptMobile, err := crypto.EncryptMobile(*req.Mobile, key)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "加密手机号失败: %v", err)
|
||||
}
|
||||
user.Mobile = sql.NullString{String: EncryptMobile, Valid: true}
|
||||
}
|
||||
if req.Nickname != nil {
|
||||
user.Nickname = sql.NullString{String: *req.Nickname, Valid: *req.Nickname != ""}
|
||||
}
|
||||
if req.Info != nil {
|
||||
user.Info = *req.Info
|
||||
}
|
||||
if req.Inside != nil {
|
||||
if *req.Inside != 1 && *req.Inside != 0 {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "内部用户状态错误: %d", *req.Inside)
|
||||
}
|
||||
user.Inside = *req.Inside
|
||||
}
|
||||
if req.Password != nil {
|
||||
user.Password = sql.NullString{String: *req.Password, Valid: *req.Password != ""}
|
||||
}
|
||||
_, err = l.svcCtx.UserModel.Update(l.ctx, nil, user)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新用户失败: %v", err)
|
||||
}
|
||||
resp = &types.AdminUpdatePlatformUserResp{Success: true}
|
||||
return resp, nil
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package admin_product
|
||||
|
||||
import (
|
||||
"context"
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/app/main/model"
|
||||
"ycc-server/common/xerr"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminCreateProductLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminCreateProductLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminCreateProductLogic {
|
||||
return &AdminCreateProductLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminCreateProductLogic) AdminCreateProduct(req *types.AdminCreateProductReq) (resp *types.AdminCreateProductResp, err error) {
|
||||
// 1. 数据转换
|
||||
data := &model.Product{
|
||||
ProductName: req.ProductName,
|
||||
ProductEn: req.ProductEn,
|
||||
Description: req.Description,
|
||||
Notes: sql.NullString{String: req.Notes, Valid: req.Notes != ""},
|
||||
CostPrice: req.CostPrice,
|
||||
SellPrice: req.SellPrice,
|
||||
}
|
||||
|
||||
// 2. 数据库操作
|
||||
result, err := l.svcCtx.ProductModel.Insert(l.ctx, nil, data)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
|
||||
"创建产品失败, err: %v, req: %+v", err, req)
|
||||
}
|
||||
|
||||
// 3. 返回结果
|
||||
id, _ := result.LastInsertId()
|
||||
return &types.AdminCreateProductResp{Id: id}, nil
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package admin_product
|
||||
|
||||
import (
|
||||
"context"
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminDeleteProductLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminDeleteProductLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminDeleteProductLogic {
|
||||
return &AdminDeleteProductLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminDeleteProductLogic) AdminDeleteProduct(req *types.AdminDeleteProductReq) (resp *types.AdminDeleteProductResp, err error) {
|
||||
// 1. 查询记录是否存在
|
||||
record, err := l.svcCtx.ProductModel.FindOne(l.ctx, req.Id)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
|
||||
"查找产品失败, err: %v, id: %d", err, req.Id)
|
||||
}
|
||||
|
||||
// 2. 执行软删除
|
||||
err = l.svcCtx.ProductModel.DeleteSoft(l.ctx, nil, record)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
|
||||
"删除产品失败, err: %v, id: %d", err, req.Id)
|
||||
}
|
||||
|
||||
// 3. 返回结果
|
||||
return &types.AdminDeleteProductResp{Success: true}, nil
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package admin_product
|
||||
|
||||
import (
|
||||
"context"
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminGetProductDetailLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminGetProductDetailLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminGetProductDetailLogic {
|
||||
return &AdminGetProductDetailLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminGetProductDetailLogic) AdminGetProductDetail(req *types.AdminGetProductDetailReq) (resp *types.AdminGetProductDetailResp, err error) {
|
||||
// 1. 查询记录
|
||||
record, err := l.svcCtx.ProductModel.FindOne(l.ctx, req.Id)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
|
||||
"查找产品失败, err: %v, id: %d", err, req.Id)
|
||||
}
|
||||
|
||||
// 2. 构建响应
|
||||
resp = &types.AdminGetProductDetailResp{
|
||||
Id: record.Id,
|
||||
ProductName: record.ProductName,
|
||||
ProductEn: record.ProductEn,
|
||||
Description: record.Description,
|
||||
Notes: record.Notes.String,
|
||||
CostPrice: record.CostPrice,
|
||||
SellPrice: record.SellPrice,
|
||||
CreateTime: record.CreateTime.Format("2006-01-02 15:04:05"),
|
||||
UpdateTime: record.UpdateTime.Format("2006-01-02 15:04:05"),
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
package admin_product
|
||||
|
||||
import (
|
||||
"context"
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/app/main/model"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"github.com/zeromicro/go-zero/core/mr"
|
||||
)
|
||||
|
||||
type AdminGetProductFeatureListLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminGetProductFeatureListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminGetProductFeatureListLogic {
|
||||
return &AdminGetProductFeatureListLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminGetProductFeatureListLogic) AdminGetProductFeatureList(req *types.AdminGetProductFeatureListReq) (resp *[]types.AdminGetProductFeatureListResp, err error) {
|
||||
// 1. 构建查询条件
|
||||
builder := l.svcCtx.ProductFeatureModel.SelectBuilder().
|
||||
Where("product_id = ?", req.ProductId)
|
||||
|
||||
// 2. 执行查询
|
||||
list, err := l.svcCtx.ProductFeatureModel.FindAll(l.ctx, builder, "sort ASC")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
|
||||
"查询产品功能列表失败, err: %v, product_id: %d", err, req.ProductId)
|
||||
}
|
||||
|
||||
// 3. 获取所有功能ID
|
||||
featureIds := make([]int64, 0, len(list))
|
||||
for _, item := range list {
|
||||
featureIds = append(featureIds, item.FeatureId)
|
||||
}
|
||||
|
||||
// 4. 并发查询功能详情
|
||||
type featureResult struct {
|
||||
feature *model.Feature
|
||||
err error
|
||||
}
|
||||
|
||||
results := make([]featureResult, len(featureIds))
|
||||
err = mr.MapReduceVoid(func(source chan<- interface{}) {
|
||||
for i, id := range featureIds {
|
||||
source <- struct {
|
||||
index int
|
||||
id int64
|
||||
}{i, id}
|
||||
}
|
||||
}, func(item interface{}, writer mr.Writer[featureResult], cancel func(error)) {
|
||||
data := item.(struct {
|
||||
index int
|
||||
id int64
|
||||
})
|
||||
feature, err := l.svcCtx.FeatureModel.FindOne(l.ctx, data.id)
|
||||
writer.Write(featureResult{
|
||||
feature: feature,
|
||||
err: err,
|
||||
})
|
||||
}, func(pipe <-chan featureResult, cancel func(error)) {
|
||||
for result := range pipe {
|
||||
if result.err != nil {
|
||||
l.Logger.Errorf("查询功能详情失败, feature_id: %d, err: %v", result.feature.Id, result.err)
|
||||
continue
|
||||
}
|
||||
results = append(results, result)
|
||||
}
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR),
|
||||
"并发查询功能详情失败, err: %v", err)
|
||||
}
|
||||
|
||||
// 5. 构建功能ID到详情的映射
|
||||
featureMap := make(map[int64]*model.Feature)
|
||||
for _, result := range results {
|
||||
if result.feature != nil {
|
||||
featureMap[result.feature.Id] = result.feature
|
||||
}
|
||||
}
|
||||
|
||||
// 6. 构建响应列表
|
||||
items := make([]types.AdminGetProductFeatureListResp, 0, len(list))
|
||||
for _, item := range list {
|
||||
feature, exists := featureMap[item.FeatureId]
|
||||
if !exists {
|
||||
continue // 跳过不存在的功能
|
||||
}
|
||||
|
||||
listItem := types.AdminGetProductFeatureListResp{
|
||||
Id: item.Id,
|
||||
ProductId: item.ProductId,
|
||||
FeatureId: item.FeatureId,
|
||||
ApiId: feature.ApiId,
|
||||
Name: feature.Name,
|
||||
Sort: item.Sort,
|
||||
Enable: item.Enable,
|
||||
IsImportant: item.IsImportant,
|
||||
CreateTime: item.CreateTime.Format("2006-01-02 15:04:05"),
|
||||
UpdateTime: item.UpdateTime.Format("2006-01-02 15:04:05"),
|
||||
}
|
||||
items = append(items, listItem)
|
||||
}
|
||||
|
||||
// 7. 返回结果
|
||||
return &items, nil
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package admin_product
|
||||
|
||||
import (
|
||||
"context"
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminGetProductListLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminGetProductListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminGetProductListLogic {
|
||||
return &AdminGetProductListLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminGetProductListLogic) AdminGetProductList(req *types.AdminGetProductListReq) (resp *types.AdminGetProductListResp, err error) {
|
||||
// 1. 构建查询条件
|
||||
builder := l.svcCtx.ProductModel.SelectBuilder()
|
||||
|
||||
// 2. 添加查询条件
|
||||
if req.ProductName != nil && *req.ProductName != "" {
|
||||
builder = builder.Where("product_name LIKE ?", "%"+*req.ProductName+"%")
|
||||
}
|
||||
if req.ProductEn != nil && *req.ProductEn != "" {
|
||||
builder = builder.Where("product_en LIKE ?", "%"+*req.ProductEn+"%")
|
||||
}
|
||||
|
||||
// 3. 执行分页查询
|
||||
list, total, err := l.svcCtx.ProductModel.FindPageListByPageWithTotal(
|
||||
l.ctx, builder, req.Page, req.PageSize, "id DESC")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
|
||||
"查询产品列表失败, err: %v, req: %+v", err, req)
|
||||
}
|
||||
|
||||
// 4. 构建响应列表
|
||||
items := make([]types.ProductListItem, 0, len(list))
|
||||
for _, item := range list {
|
||||
listItem := types.ProductListItem{
|
||||
Id: item.Id,
|
||||
ProductName: item.ProductName,
|
||||
ProductEn: item.ProductEn,
|
||||
Description: item.Description,
|
||||
Notes: item.Notes.String,
|
||||
CostPrice: item.CostPrice,
|
||||
SellPrice: item.SellPrice,
|
||||
CreateTime: item.CreateTime.Format("2006-01-02 15:04:05"),
|
||||
UpdateTime: item.UpdateTime.Format("2006-01-02 15:04:05"),
|
||||
}
|
||||
items = append(items, listItem)
|
||||
}
|
||||
|
||||
// 5. 返回结果
|
||||
return &types.AdminGetProductListResp{
|
||||
Total: total,
|
||||
Items: items,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
package admin_product
|
||||
|
||||
import (
|
||||
"context"
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/app/main/model"
|
||||
"ycc-server/common/xerr"
|
||||
"sync"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"github.com/zeromicro/go-zero/core/mr"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
)
|
||||
|
||||
type AdminUpdateProductFeaturesLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminUpdateProductFeaturesLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminUpdateProductFeaturesLogic {
|
||||
return &AdminUpdateProductFeaturesLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminUpdateProductFeaturesLogic) AdminUpdateProductFeatures(req *types.AdminUpdateProductFeaturesReq) (resp *types.AdminUpdateProductFeaturesResp, err error) {
|
||||
// 1. 查询现有关联
|
||||
builder := l.svcCtx.ProductFeatureModel.SelectBuilder().
|
||||
Where("product_id = ?", req.ProductId)
|
||||
existingList, err := l.svcCtx.ProductFeatureModel.FindAll(l.ctx, builder, "id ASC")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
|
||||
"查询现有产品功能关联失败, err: %v, product_id: %d", err, req.ProductId)
|
||||
}
|
||||
|
||||
// 2. 构建现有关联的映射
|
||||
existingMap := make(map[int64]*model.ProductFeature)
|
||||
for _, item := range existingList {
|
||||
existingMap[item.FeatureId] = item
|
||||
}
|
||||
|
||||
// 3. 构建新关联的映射
|
||||
newMap := make(map[int64]*types.ProductFeatureItem)
|
||||
for _, item := range req.Features {
|
||||
newMap[item.FeatureId] = &item
|
||||
}
|
||||
|
||||
// 4. 在事务中执行更新操作
|
||||
err = l.svcCtx.ProductFeatureModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error {
|
||||
// 4.1 处理需要删除的关联
|
||||
var mu sync.Mutex
|
||||
var deleteIds []int64
|
||||
err = mr.MapReduceVoid(func(source chan<- interface{}) {
|
||||
for featureId, existing := range existingMap {
|
||||
if _, exists := newMap[featureId]; !exists {
|
||||
source <- existing.Id
|
||||
}
|
||||
}
|
||||
}, func(item interface{}, writer mr.Writer[struct{}], cancel func(error)) {
|
||||
id := item.(int64)
|
||||
mu.Lock()
|
||||
deleteIds = append(deleteIds, id)
|
||||
mu.Unlock()
|
||||
}, func(pipe <-chan struct{}, cancel func(error)) {
|
||||
// 等待所有ID收集完成
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "收集待删除ID失败")
|
||||
}
|
||||
|
||||
// 批量删除
|
||||
if len(deleteIds) > 0 {
|
||||
for _, id := range deleteIds {
|
||||
err = l.svcCtx.ProductFeatureModel.Delete(ctx, session, id)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "删除产品功能关联失败, product_id: %d, id: %d",
|
||||
req.ProductId, id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 4.2 并发处理需要新增或更新的关联
|
||||
var updateErr error
|
||||
err = mr.MapReduceVoid(func(source chan<- interface{}) {
|
||||
for featureId, newItem := range newMap {
|
||||
source <- struct {
|
||||
featureId int64
|
||||
newItem *types.ProductFeatureItem
|
||||
existing *model.ProductFeature
|
||||
}{
|
||||
featureId: featureId,
|
||||
newItem: newItem,
|
||||
existing: existingMap[featureId],
|
||||
}
|
||||
}
|
||||
}, func(item interface{}, writer mr.Writer[struct{}], cancel func(error)) {
|
||||
data := item.(struct {
|
||||
featureId int64
|
||||
newItem *types.ProductFeatureItem
|
||||
existing *model.ProductFeature
|
||||
})
|
||||
|
||||
if data.existing != nil {
|
||||
// 更新现有关联
|
||||
data.existing.Sort = data.newItem.Sort
|
||||
data.existing.Enable = data.newItem.Enable
|
||||
data.existing.IsImportant = data.newItem.IsImportant
|
||||
_, err = l.svcCtx.ProductFeatureModel.Update(ctx, session, data.existing)
|
||||
if err != nil {
|
||||
updateErr = errors.Wrapf(err, "更新产品功能关联失败, product_id: %d, feature_id: %d",
|
||||
req.ProductId, data.featureId)
|
||||
cancel(updateErr)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
// 新增关联
|
||||
newFeature := &model.ProductFeature{
|
||||
ProductId: req.ProductId,
|
||||
FeatureId: data.featureId,
|
||||
Sort: data.newItem.Sort,
|
||||
Enable: data.newItem.Enable,
|
||||
IsImportant: data.newItem.IsImportant,
|
||||
}
|
||||
_, err = l.svcCtx.ProductFeatureModel.Insert(ctx, session, newFeature)
|
||||
if err != nil {
|
||||
updateErr = errors.Wrapf(err, "新增产品功能关联失败, product_id: %d, feature_id: %d",
|
||||
req.ProductId, data.featureId)
|
||||
cancel(updateErr)
|
||||
return
|
||||
}
|
||||
}
|
||||
}, func(pipe <-chan struct{}, cancel func(error)) {
|
||||
// 等待所有更新完成
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "并发更新产品功能关联失败")
|
||||
}
|
||||
if updateErr != nil {
|
||||
return updateErr
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
|
||||
"更新产品功能关联失败, err: %v, req: %+v", err, req)
|
||||
}
|
||||
|
||||
// 5. 返回结果
|
||||
return &types.AdminUpdateProductFeaturesResp{Success: true}, nil
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package admin_product
|
||||
|
||||
import (
|
||||
"context"
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/common/xerr"
|
||||
"database/sql"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminUpdateProductLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminUpdateProductLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminUpdateProductLogic {
|
||||
return &AdminUpdateProductLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminUpdateProductLogic) AdminUpdateProduct(req *types.AdminUpdateProductReq) (resp *types.AdminUpdateProductResp, err error) {
|
||||
// 1. 查询记录是否存在
|
||||
record, err := l.svcCtx.ProductModel.FindOne(l.ctx, req.Id)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
|
||||
"查找产品失败, err: %v, id: %d", err, req.Id)
|
||||
}
|
||||
|
||||
// 2. 更新字段
|
||||
if req.ProductName != nil {
|
||||
record.ProductName = *req.ProductName
|
||||
}
|
||||
if req.ProductEn != nil {
|
||||
record.ProductEn = *req.ProductEn
|
||||
}
|
||||
if req.Description != nil {
|
||||
record.Description = *req.Description
|
||||
}
|
||||
if req.Notes != nil {
|
||||
record.Notes = sql.NullString{String: *req.Notes, Valid: *req.Notes != ""}
|
||||
}
|
||||
if req.CostPrice != nil {
|
||||
record.CostPrice = *req.CostPrice
|
||||
}
|
||||
if req.SellPrice != nil {
|
||||
record.SellPrice = *req.SellPrice
|
||||
}
|
||||
|
||||
// 3. 执行更新操作
|
||||
_, err = l.svcCtx.ProductModel.Update(l.ctx, nil, record)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
|
||||
"更新产品失败, err: %v, req: %+v", err, req)
|
||||
}
|
||||
|
||||
// 4. 返回结果
|
||||
return &types.AdminUpdateProductResp{Success: true}, nil
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
package admin_promotion
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"time"
|
||||
|
||||
"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"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
)
|
||||
|
||||
type CreatePromotionLinkLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewCreatePromotionLinkLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreatePromotionLinkLogic {
|
||||
return &CreatePromotionLinkLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
// 生成6位随机字符串(大小写字母和数字)
|
||||
func generateRandomString() (string, error) {
|
||||
const (
|
||||
chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||
length = 6
|
||||
)
|
||||
|
||||
result := make([]byte, length)
|
||||
for i := 0; i < length; i++ {
|
||||
num, err := rand.Int(rand.Reader, big.NewInt(int64(len(chars))))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
result[i] = chars[num.Int64()]
|
||||
}
|
||||
return string(result), nil
|
||||
}
|
||||
|
||||
func (l *CreatePromotionLinkLogic) CreatePromotionLink(req *types.CreatePromotionLinkReq) (resp *types.CreatePromotionLinkResp, err error) {
|
||||
// 获取当前用户ID
|
||||
adminUserId, getUidErr := ctxdata.GetUidFromCtx(l.ctx)
|
||||
if getUidErr != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "创建推广链接, 获取用户信息失败, %+v", getUidErr)
|
||||
}
|
||||
|
||||
// 生成唯一URL
|
||||
var url string
|
||||
maxRetries := 5 // 最大重试次数
|
||||
for i := 0; i < maxRetries; i++ {
|
||||
// 生成6位随机字符串
|
||||
randomStr, err := generateRandomString()
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "创建推广链接, 生成随机字符串失败, %+v", err)
|
||||
}
|
||||
|
||||
// 检查URL是否已存在
|
||||
existLink, err := l.svcCtx.AdminPromotionLinkModel.FindOneByUrl(l.ctx, randomStr)
|
||||
if err != nil && !errors.Is(err, model.ErrNotFound) {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "创建推广链接, 检查URL是否存在失败, %+v", err)
|
||||
}
|
||||
|
||||
if existLink != nil {
|
||||
continue // URL已存在,继续尝试
|
||||
}
|
||||
|
||||
// URL可用
|
||||
url = randomStr
|
||||
break
|
||||
}
|
||||
|
||||
if url == "" {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "创建推广链接失败, 多次尝试生成唯一URL均失败")
|
||||
}
|
||||
url = fmt.Sprintf("%s/%s", l.svcCtx.Config.AdminPromotion.URLDomain, url)
|
||||
// 创建推广链接
|
||||
link := &model.AdminPromotionLink{
|
||||
Name: req.Name,
|
||||
Url: url,
|
||||
AdminUserId: adminUserId,
|
||||
}
|
||||
|
||||
var linkId int64
|
||||
err = l.svcCtx.AdminPromotionLinkModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error {
|
||||
result, err := l.svcCtx.AdminPromotionLinkModel.Insert(l.ctx, session, link)
|
||||
if err != nil {
|
||||
return fmt.Errorf("创建推广链接失败, %+v", err)
|
||||
}
|
||||
|
||||
linkId, err = result.LastInsertId()
|
||||
if err != nil {
|
||||
return fmt.Errorf("获取推广链接ID失败, %+v", err)
|
||||
}
|
||||
|
||||
// 创建总统计记录
|
||||
totalStats := &model.AdminPromotionLinkStatsTotal{
|
||||
LinkId: linkId,
|
||||
}
|
||||
_, err = l.svcCtx.AdminPromotionLinkStatsTotalModel.Insert(l.ctx, session, totalStats)
|
||||
if err != nil {
|
||||
return fmt.Errorf("创建推广链接总统计记录失败, %+v", err)
|
||||
}
|
||||
|
||||
// 创建统计历史记录
|
||||
historyStats := &model.AdminPromotionLinkStatsHistory{
|
||||
LinkId: linkId,
|
||||
StatsDate: time.Now().Truncate(24 * time.Hour),
|
||||
}
|
||||
_, err = l.svcCtx.AdminPromotionLinkStatsHistoryModel.Insert(l.ctx, session, historyStats)
|
||||
if err != nil {
|
||||
return fmt.Errorf("创建推广链接统计历史记录失败, %+v", err)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "创建推广链接失败, %+v", err)
|
||||
}
|
||||
|
||||
return &types.CreatePromotionLinkResp{
|
||||
Id: linkId,
|
||||
Url: url,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
package admin_promotion
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"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"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
)
|
||||
|
||||
type DeletePromotionLinkLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewDeletePromotionLinkLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DeletePromotionLinkLogic {
|
||||
return &DeletePromotionLinkLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *DeletePromotionLinkLogic) DeletePromotionLink(req *types.DeletePromotionLinkReq) error {
|
||||
// 获取当前用户ID
|
||||
adminUserId, getUidErr := ctxdata.GetUidFromCtx(l.ctx)
|
||||
if getUidErr != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "删除推广链接, 获取用户信息失败, %+v", getUidErr)
|
||||
}
|
||||
|
||||
// 获取链接信息
|
||||
link, err := l.svcCtx.AdminPromotionLinkModel.FindOne(l.ctx, req.Id)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "删除推广链接, 获取链接信息失败, %+v", err)
|
||||
}
|
||||
|
||||
// 验证用户权限
|
||||
if link.AdminUserId != adminUserId {
|
||||
return errors.Wrapf(xerr.NewErrMsg("无权限删除此链接"), "删除推广链接, 无权限删除此链接, %+v", link)
|
||||
}
|
||||
|
||||
// 在事务中执行所有删除操作
|
||||
err = l.svcCtx.AdminPromotionLinkModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error {
|
||||
// 软删除链接
|
||||
err = l.svcCtx.AdminPromotionLinkModel.DeleteSoft(l.ctx, session, link)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "删除推广链接, 软删除链接失败, %+v", err)
|
||||
}
|
||||
|
||||
// 软删除总统计记录
|
||||
totalStats, err := l.svcCtx.AdminPromotionLinkStatsTotalModel.FindOneByLinkId(l.ctx, link.Id)
|
||||
if err != nil && !errors.Is(err, model.ErrNotFound) {
|
||||
return errors.Wrapf(err, "删除推广链接, 获取总统计记录失败, %+v", err)
|
||||
}
|
||||
if totalStats != nil {
|
||||
err = l.svcCtx.AdminPromotionLinkStatsTotalModel.DeleteSoft(l.ctx, session, totalStats)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "删除推广链接, 软删除总统计记录失败, %+v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// 软删除历史统计记录
|
||||
builder := l.svcCtx.AdminPromotionLinkStatsHistoryModel.SelectBuilder()
|
||||
builder = builder.Where("link_id = ?", link.Id)
|
||||
historyStats, err := l.svcCtx.AdminPromotionLinkStatsHistoryModel.FindAll(l.ctx, builder, "")
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "删除推广链接, 获取历史统计记录失败, %+v", err)
|
||||
}
|
||||
for _, stat := range historyStats {
|
||||
err = l.svcCtx.AdminPromotionLinkStatsHistoryModel.DeleteSoft(l.ctx, session, stat)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "删除推广链接, 软删除历史统计记录失败, %+v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "删除推广链接失败, %+v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package admin_promotion
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"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 GetPromotionLinkDetailLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewGetPromotionLinkDetailLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetPromotionLinkDetailLogic {
|
||||
return &GetPromotionLinkDetailLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *GetPromotionLinkDetailLogic) GetPromotionLinkDetail(req *types.GetPromotionLinkDetailReq) (resp *types.GetPromotionLinkDetailResp, err error) {
|
||||
// 获取当前用户ID
|
||||
adminUserId, getUidErr := ctxdata.GetUidFromCtx(l.ctx)
|
||||
if getUidErr != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取当前用户ID失败, %+v", getUidErr)
|
||||
}
|
||||
|
||||
// 获取链接信息
|
||||
link, err := l.svcCtx.AdminPromotionLinkModel.FindOne(l.ctx, req.Id)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "获取链接信息失败, %+v", err)
|
||||
}
|
||||
|
||||
// 验证用户权限
|
||||
if link.AdminUserId != adminUserId {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("无权限访问此链接"), "获取链接信息失败, 无权限访问此链接, %+v", link)
|
||||
}
|
||||
|
||||
// 获取总统计
|
||||
totalStats, err := l.svcCtx.AdminPromotionLinkStatsTotalModel.FindOne(l.ctx, link.Id)
|
||||
if err != nil && !errors.Is(err, model.ErrNotFound) {
|
||||
return nil, errors.Wrapf(err, "获取总统计失败, %+v", err)
|
||||
}
|
||||
return &types.GetPromotionLinkDetailResp{
|
||||
Name: link.Name,
|
||||
Url: link.Url,
|
||||
ClickCount: totalStats.ClickCount,
|
||||
PayCount: totalStats.PayCount,
|
||||
PayAmount: fmt.Sprintf("%.2f", totalStats.PayAmount),
|
||||
CreateTime: link.CreateTime.Format("2006-01-02 15:04:05"),
|
||||
UpdateTime: link.UpdateTime.Format("2006-01-02 15:04:05"),
|
||||
LastClickTime: totalStats.LastClickTime.Time.Format("2006-01-02 15:04:05"),
|
||||
LastPayTime: totalStats.LastPayTime.Time.Format("2006-01-02 15:04:05"),
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
package admin_promotion
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"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"
|
||||
"github.com/zeromicro/go-zero/core/mr"
|
||||
)
|
||||
|
||||
type GetPromotionLinkListLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewGetPromotionLinkListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetPromotionLinkListLogic {
|
||||
return &GetPromotionLinkListLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *GetPromotionLinkListLogic) GetPromotionLinkList(req *types.GetPromotionLinkListReq) (resp *types.GetPromotionLinkListResp, err error) {
|
||||
// 获取当前用户ID
|
||||
adminUserId, getUidErr := ctxdata.GetUidFromCtx(l.ctx)
|
||||
if getUidErr != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取当前用户ID失败, %+v", getUidErr)
|
||||
}
|
||||
|
||||
// 构建查询条件
|
||||
builder := l.svcCtx.AdminPromotionLinkModel.SelectBuilder()
|
||||
builder = builder.Where("admin_user_id = ?", adminUserId)
|
||||
if req.Name != "" {
|
||||
builder = builder.Where("name LIKE ?", "%"+req.Name+"%")
|
||||
}
|
||||
if req.Url != "" {
|
||||
builder = builder.Where("url LIKE ?", "%"+req.Url+"%")
|
||||
}
|
||||
|
||||
// 获取列表和总数
|
||||
links, total, err := l.svcCtx.AdminPromotionLinkModel.FindPageListByPageWithTotal(l.ctx, builder, req.Page, req.PageSize, "create_time DESC")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "获取推广链接列表失败, %+v", err)
|
||||
}
|
||||
|
||||
// 使用MapReduce并发获取统计数据
|
||||
items := make([]types.PromotionLinkItem, len(links))
|
||||
err = mr.MapReduceVoid(func(source chan<- interface{}) {
|
||||
for _, link := range links {
|
||||
source <- link
|
||||
}
|
||||
}, func(item interface{}, writer mr.Writer[types.PromotionLinkItem], cancel func(error)) {
|
||||
link := item.(*model.AdminPromotionLink)
|
||||
// 获取总统计
|
||||
totalStats, err := l.svcCtx.AdminPromotionLinkStatsTotalModel.FindOneByLinkId(l.ctx, link.Id)
|
||||
if err != nil && !errors.Is(err, model.ErrNotFound) {
|
||||
cancel(errors.Wrapf(err, "获取总统计失败, linkId: %d, %+v", link.Id, err))
|
||||
return
|
||||
}
|
||||
writer.Write(types.PromotionLinkItem{
|
||||
Id: link.Id,
|
||||
Name: link.Name,
|
||||
Url: link.Url,
|
||||
ClickCount: totalStats.ClickCount,
|
||||
PayCount: totalStats.PayCount,
|
||||
PayAmount: fmt.Sprintf("%.2f", totalStats.PayAmount),
|
||||
CreateTime: link.CreateTime.Format("2006-01-02 15:04:05"),
|
||||
LastClickTime: func() string {
|
||||
if totalStats.LastClickTime.Valid {
|
||||
return totalStats.LastClickTime.Time.Format("2006-01-02 15:04:05")
|
||||
}
|
||||
return ""
|
||||
}(),
|
||||
LastPayTime: func() string {
|
||||
if totalStats.LastPayTime.Valid {
|
||||
return totalStats.LastPayTime.Time.Format("2006-01-02 15:04:05")
|
||||
}
|
||||
return ""
|
||||
}(),
|
||||
})
|
||||
}, func(pipe <-chan types.PromotionLinkItem, cancel func(error)) {
|
||||
for i := 0; i < len(links); i++ {
|
||||
item := <-pipe
|
||||
items[i] = item
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "获取推广链接统计数据失败, %+v", err)
|
||||
}
|
||||
|
||||
return &types.GetPromotionLinkListResp{
|
||||
Total: total,
|
||||
Items: items,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package admin_promotion
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/common/ctxdata"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type GetPromotionStatsHistoryLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewGetPromotionStatsHistoryLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetPromotionStatsHistoryLogic {
|
||||
return &GetPromotionStatsHistoryLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *GetPromotionStatsHistoryLogic) GetPromotionStatsHistory(req *types.GetPromotionStatsHistoryReq) (resp []types.PromotionStatsHistoryItem, err error) {
|
||||
// 获取当前用户ID
|
||||
adminUserId, getUidErr := ctxdata.GetUidFromCtx(l.ctx)
|
||||
if getUidErr != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取当前用户ID失败, %+v", getUidErr)
|
||||
}
|
||||
// 构建查询条件
|
||||
builder := l.svcCtx.AdminPromotionLinkStatsHistoryModel.SelectBuilder()
|
||||
|
||||
// 如果有日期范围,添加日期过滤
|
||||
if req.StartDate != "" && req.EndDate != "" {
|
||||
startDate, err := time.Parse("2006-01-02", req.StartDate)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "开始日期格式错误")
|
||||
}
|
||||
endDate, err := time.Parse("2006-01-02", req.EndDate)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "结束日期格式错误")
|
||||
}
|
||||
// 将结束日期设置为当天的最后一刻
|
||||
endDate = endDate.Add(24*time.Hour - time.Second)
|
||||
builder = builder.Where("stats_date BETWEEN ? AND ?", startDate, endDate)
|
||||
}
|
||||
|
||||
// 获取历史统计数据
|
||||
historyStats, err := l.svcCtx.AdminPromotionLinkStatsHistoryModel.FindAll(l.ctx, builder, "stats_date DESC")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取历史统计数据失败")
|
||||
}
|
||||
|
||||
// 转换为响应格式
|
||||
resp = make([]types.PromotionStatsHistoryItem, 0, len(historyStats))
|
||||
for _, stat := range historyStats {
|
||||
// 验证链接是否属于当前用户
|
||||
link, err := l.svcCtx.AdminPromotionLinkModel.FindOne(l.ctx, stat.LinkId)
|
||||
if err != nil {
|
||||
continue // 如果链接不存在,跳过该记录
|
||||
}
|
||||
if link.AdminUserId != adminUserId {
|
||||
continue // 如果链接不属于当前用户,跳过该记录
|
||||
}
|
||||
|
||||
resp = append(resp, types.PromotionStatsHistoryItem{
|
||||
Id: stat.Id,
|
||||
LinkId: stat.LinkId,
|
||||
PayAmount: stat.PayAmount,
|
||||
ClickCount: stat.ClickCount,
|
||||
PayCount: stat.PayCount,
|
||||
StatsDate: stat.StatsDate.Format("2006-01-02"),
|
||||
})
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
package admin_promotion
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"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"
|
||||
"github.com/zeromicro/go-zero/core/mr"
|
||||
)
|
||||
|
||||
type GetPromotionStatsTotalLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewGetPromotionStatsTotalLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetPromotionStatsTotalLogic {
|
||||
return &GetPromotionStatsTotalLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *GetPromotionStatsTotalLogic) GetPromotionStatsTotal(req *types.GetPromotionStatsTotalReq) (resp *types.GetPromotionStatsTotalResp, err error) {
|
||||
// 获取当前用户ID
|
||||
adminUserId, getUidErr := ctxdata.GetUidFromCtx(l.ctx)
|
||||
if getUidErr != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取当前用户ID失败, %+v", getUidErr)
|
||||
}
|
||||
|
||||
// 获取用户的所有推广链接
|
||||
linkBuilder := l.svcCtx.AdminPromotionLinkModel.SelectBuilder()
|
||||
linkBuilder = linkBuilder.Where("admin_user_id = ?", adminUserId)
|
||||
links, err := l.svcCtx.AdminPromotionLinkModel.FindAll(l.ctx, linkBuilder, "")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取推广链接列表失败, %+v", err)
|
||||
}
|
||||
|
||||
// 如果没有推广链接,返回空统计
|
||||
if len(links) == 0 {
|
||||
return &types.GetPromotionStatsTotalResp{}, nil
|
||||
}
|
||||
|
||||
// 构建链接ID列表
|
||||
linkIds := make([]int64, len(links))
|
||||
for i, link := range links {
|
||||
linkIds[i] = link.Id
|
||||
}
|
||||
|
||||
// 获取并计算总统计数据
|
||||
var totalClickCount, totalPayCount int64
|
||||
var totalPayAmount float64
|
||||
err = mr.MapReduceVoid(func(source chan<- interface{}) {
|
||||
for _, linkId := range linkIds {
|
||||
source <- linkId
|
||||
}
|
||||
}, func(item interface{}, writer mr.Writer[struct {
|
||||
ClickCount int64
|
||||
PayCount int64
|
||||
PayAmount float64
|
||||
}], cancel func(error)) {
|
||||
linkId := item.(int64)
|
||||
stats, err := l.svcCtx.AdminPromotionLinkStatsTotalModel.FindOneByLinkId(l.ctx, linkId)
|
||||
if err != nil && !errors.Is(err, model.ErrNotFound) {
|
||||
cancel(errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取总统计数据失败, linkId: %d, %+v", linkId, err))
|
||||
return
|
||||
}
|
||||
if stats != nil {
|
||||
writer.Write(struct {
|
||||
ClickCount int64
|
||||
PayCount int64
|
||||
PayAmount float64
|
||||
}{
|
||||
ClickCount: stats.ClickCount,
|
||||
PayCount: stats.PayCount,
|
||||
PayAmount: stats.PayAmount,
|
||||
})
|
||||
}
|
||||
}, func(pipe <-chan struct {
|
||||
ClickCount int64
|
||||
PayCount int64
|
||||
PayAmount float64
|
||||
}, cancel func(error)) {
|
||||
for stats := range pipe {
|
||||
totalClickCount += stats.ClickCount
|
||||
totalPayCount += stats.PayCount
|
||||
totalPayAmount += stats.PayAmount
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取总统计数据失败, %+v", err)
|
||||
}
|
||||
|
||||
// 获取今日统计数据
|
||||
now := time.Now()
|
||||
today := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.Local)
|
||||
var todayClickCount, todayPayCount int64
|
||||
var todayPayAmount float64
|
||||
|
||||
err = mr.MapReduceVoid(func(source chan<- interface{}) {
|
||||
for _, linkId := range linkIds {
|
||||
source <- linkId
|
||||
}
|
||||
}, func(item interface{}, writer mr.Writer[struct {
|
||||
ClickCount int64
|
||||
PayCount int64
|
||||
PayAmount float64
|
||||
}], cancel func(error)) {
|
||||
linkId := item.(int64)
|
||||
builder := l.svcCtx.AdminPromotionLinkStatsHistoryModel.SelectBuilder()
|
||||
builder = builder.Where("link_id = ? AND DATE(stats_date) = DATE(?)", linkId, today)
|
||||
histories, err := l.svcCtx.AdminPromotionLinkStatsHistoryModel.FindAll(l.ctx, builder, "")
|
||||
if err != nil {
|
||||
cancel(errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取今日统计数据失败, linkId: %d, %+v", linkId, err))
|
||||
return
|
||||
}
|
||||
|
||||
var clickCount, payCount int64
|
||||
var payAmount float64
|
||||
for _, history := range histories {
|
||||
clickCount += history.ClickCount
|
||||
payCount += history.PayCount
|
||||
payAmount += history.PayAmount
|
||||
}
|
||||
|
||||
writer.Write(struct {
|
||||
ClickCount int64
|
||||
PayCount int64
|
||||
PayAmount float64
|
||||
}{
|
||||
ClickCount: clickCount,
|
||||
PayCount: payCount,
|
||||
PayAmount: payAmount,
|
||||
})
|
||||
}, func(pipe <-chan struct {
|
||||
ClickCount int64
|
||||
PayCount int64
|
||||
PayAmount float64
|
||||
}, cancel func(error)) {
|
||||
for stats := range pipe {
|
||||
todayClickCount += stats.ClickCount
|
||||
todayPayCount += stats.PayCount
|
||||
todayPayAmount += stats.PayAmount
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取今日统计数据失败, %+v", err)
|
||||
}
|
||||
|
||||
return &types.GetPromotionStatsTotalResp{
|
||||
TodayClickCount: int64(todayClickCount),
|
||||
TodayPayCount: int64(todayPayCount),
|
||||
TodayPayAmount: todayPayAmount,
|
||||
TotalClickCount: int64(totalClickCount),
|
||||
TotalPayCount: int64(totalPayCount),
|
||||
TotalPayAmount: totalPayAmount,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package admin_promotion
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type RecordLinkClickLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewRecordLinkClickLogic(ctx context.Context, svcCtx *svc.ServiceContext) *RecordLinkClickLogic {
|
||||
return &RecordLinkClickLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *RecordLinkClickLogic) RecordLinkClick(req *types.RecordLinkClickReq) (resp *types.RecordLinkClickResp, err error) {
|
||||
// 校验路径格式
|
||||
if len(req.Path) != 6 {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "无效的推广链接路径")
|
||||
}
|
||||
|
||||
// 检查是否只包含大小写字母和数字
|
||||
for _, char := range req.Path {
|
||||
if !((char >= 'a' && char <= 'z') || (char >= 'A' && char <= 'Z') || (char >= '0' && char <= '9')) {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "无效的推广链接路径")
|
||||
}
|
||||
}
|
||||
url := fmt.Sprintf("%s/%s", l.svcCtx.Config.AdminPromotion.URLDomain, req.Path)
|
||||
|
||||
link, err := l.svcCtx.AdminPromotionLinkModel.FindOneByUrl(l.ctx, url)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "无效的推广链接路径")
|
||||
}
|
||||
|
||||
// 使用 statsService 更新点击统计
|
||||
err = l.svcCtx.AdminPromotionLinkStatsService.UpdateLinkStats(l.ctx, link.Id)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新点击统计失败: %+v", err)
|
||||
}
|
||||
|
||||
return &types.RecordLinkClickResp{
|
||||
Success: true,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package admin_promotion
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/common/ctxdata"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type UpdatePromotionLinkLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewUpdatePromotionLinkLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdatePromotionLinkLogic {
|
||||
return &UpdatePromotionLinkLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *UpdatePromotionLinkLogic) UpdatePromotionLink(req *types.UpdatePromotionLinkReq) error {
|
||||
// 获取当前用户ID
|
||||
adminUserId, getUidErr := ctxdata.GetUidFromCtx(l.ctx)
|
||||
if getUidErr != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "更新推广链接, 获取用户信息失败, %+v", getUidErr)
|
||||
}
|
||||
|
||||
// 获取链接信息
|
||||
link, err := l.svcCtx.AdminPromotionLinkModel.FindOne(l.ctx, req.Id)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "更新推广链接, 获取链接信息失败, %+v", err)
|
||||
}
|
||||
|
||||
// 验证用户权限
|
||||
if link.AdminUserId != adminUserId {
|
||||
return errors.Wrapf(xerr.NewErrMsg("无权限修改此链接"), "更新推广链接, 无权限修改此链接, %+v", link)
|
||||
}
|
||||
|
||||
// 更新链接信息
|
||||
link.Name = *req.Name
|
||||
link.UpdateTime = time.Now()
|
||||
|
||||
_, err = l.svcCtx.AdminPromotionLinkModel.Update(l.ctx, nil, link)
|
||||
if err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新推广链接, 更新链接信息失败, %+v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package admin_query
|
||||
|
||||
import (
|
||||
"context"
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/common/globalkey"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminGetQueryCleanupConfigListLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminGetQueryCleanupConfigListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminGetQueryCleanupConfigListLogic {
|
||||
return &AdminGetQueryCleanupConfigListLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminGetQueryCleanupConfigListLogic) AdminGetQueryCleanupConfigList(req *types.AdminGetQueryCleanupConfigListReq) (resp *types.AdminGetQueryCleanupConfigListResp, err error) {
|
||||
// 构建查询条件
|
||||
builder := l.svcCtx.QueryCleanupConfigModel.SelectBuilder().
|
||||
Where("del_state = ?", globalkey.DelStateNo)
|
||||
|
||||
if req.Status > 0 {
|
||||
builder = builder.Where("status = ?", req.Status)
|
||||
}
|
||||
|
||||
// 查询配置列表
|
||||
configs, err := l.svcCtx.QueryCleanupConfigModel.FindAll(l.ctx, builder, "id ASC")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询清理配置列表失败 err: %v", err)
|
||||
}
|
||||
|
||||
// 构建响应
|
||||
resp = &types.AdminGetQueryCleanupConfigListResp{
|
||||
Items: make([]types.QueryCleanupConfigItem, 0, len(configs)),
|
||||
}
|
||||
|
||||
for _, config := range configs {
|
||||
item := types.QueryCleanupConfigItem{
|
||||
Id: config.Id,
|
||||
ConfigKey: config.ConfigKey,
|
||||
ConfigValue: config.ConfigValue,
|
||||
ConfigDesc: config.ConfigDesc,
|
||||
Status: config.Status,
|
||||
CreateTime: config.CreateTime.Format("2006-01-02 15:04:05"),
|
||||
UpdateTime: config.UpdateTime.Format("2006-01-02 15:04:05"),
|
||||
}
|
||||
resp.Items = append(resp.Items, item)
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
package admin_query
|
||||
|
||||
import (
|
||||
"context"
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/app/main/model"
|
||||
"ycc-server/common/globalkey"
|
||||
"ycc-server/common/xerr"
|
||||
"sync"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"github.com/zeromicro/go-zero/core/mr"
|
||||
)
|
||||
|
||||
type AdminGetQueryCleanupDetailListLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminGetQueryCleanupDetailListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminGetQueryCleanupDetailListLogic {
|
||||
return &AdminGetQueryCleanupDetailListLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminGetQueryCleanupDetailListLogic) AdminGetQueryCleanupDetailList(req *types.AdminGetQueryCleanupDetailListReq) (resp *types.AdminGetQueryCleanupDetailListResp, err error) {
|
||||
// 1. 验证清理日志是否存在
|
||||
_, err = l.svcCtx.QueryCleanupLogModel.FindOne(l.ctx, req.LogId)
|
||||
if err != nil {
|
||||
if err == model.ErrNotFound {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "清理日志不存在, log_id: %d", req.LogId)
|
||||
}
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询清理日志失败, log_id: %d, err: %v", req.LogId, err)
|
||||
}
|
||||
|
||||
// 2. 构建查询条件
|
||||
builder := l.svcCtx.QueryCleanupDetailModel.SelectBuilder().
|
||||
Where("cleanup_log_id = ?", req.LogId).
|
||||
Where("del_state = ?", globalkey.DelStateNo)
|
||||
|
||||
// 3. 并发获取总数和列表
|
||||
var total int64
|
||||
var details []*model.QueryCleanupDetail
|
||||
err = mr.Finish(func() error {
|
||||
var err error
|
||||
total, err = l.svcCtx.QueryCleanupDetailModel.FindCount(l.ctx, builder, "id")
|
||||
if err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询清理详情总数失败 err: %v", err)
|
||||
}
|
||||
return nil
|
||||
}, func() error {
|
||||
var err error
|
||||
details, err = l.svcCtx.QueryCleanupDetailModel.FindPageListByPage(l.ctx, builder, req.Page, req.PageSize, "id DESC")
|
||||
if err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询清理详情列表失败 err: %v", err)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 4. 获取所有产品ID
|
||||
productIds := make([]int64, 0, len(details))
|
||||
for _, detail := range details {
|
||||
productIds = append(productIds, detail.ProductId)
|
||||
}
|
||||
|
||||
// 5. 并发获取产品信息
|
||||
productMap := make(map[int64]string)
|
||||
var mu sync.Mutex
|
||||
err = mr.MapReduceVoid(func(source chan<- interface{}) {
|
||||
for _, productId := range productIds {
|
||||
source <- productId
|
||||
}
|
||||
}, func(item interface{}, writer mr.Writer[struct{}], cancel func(error)) {
|
||||
productId := item.(int64)
|
||||
product, err := l.svcCtx.ProductModel.FindOne(l.ctx, productId)
|
||||
if err != nil && !errors.Is(err, model.ErrNotFound) {
|
||||
cancel(errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询产品信息失败, product_id: %d, err: %v", productId, err))
|
||||
return
|
||||
}
|
||||
mu.Lock()
|
||||
if product != nil {
|
||||
productMap[productId] = product.ProductName
|
||||
} else {
|
||||
productMap[productId] = "" // 产品不存在时设置为空字符串
|
||||
}
|
||||
mu.Unlock()
|
||||
writer.Write(struct{}{})
|
||||
}, func(pipe <-chan struct{}, cancel func(error)) {
|
||||
for range pipe {
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 6. 构建响应
|
||||
resp = &types.AdminGetQueryCleanupDetailListResp{
|
||||
Total: total,
|
||||
Items: make([]types.QueryCleanupDetailItem, 0, len(details)),
|
||||
}
|
||||
|
||||
for _, detail := range details {
|
||||
item := types.QueryCleanupDetailItem{
|
||||
Id: detail.Id,
|
||||
CleanupLogId: detail.CleanupLogId,
|
||||
QueryId: detail.QueryId,
|
||||
OrderId: detail.OrderId,
|
||||
UserId: detail.UserId,
|
||||
ProductName: productMap[detail.ProductId],
|
||||
QueryState: detail.QueryState,
|
||||
CreateTimeOld: detail.CreateTimeOld.Format("2006-01-02 15:04:05"),
|
||||
CreateTime: detail.CreateTime.Format("2006-01-02 15:04:05"),
|
||||
}
|
||||
resp.Items = append(resp.Items, item)
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package admin_query
|
||||
|
||||
import (
|
||||
"context"
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/app/main/model"
|
||||
"ycc-server/common/globalkey"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"github.com/zeromicro/go-zero/core/mr"
|
||||
)
|
||||
|
||||
type AdminGetQueryCleanupLogListLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminGetQueryCleanupLogListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminGetQueryCleanupLogListLogic {
|
||||
return &AdminGetQueryCleanupLogListLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminGetQueryCleanupLogListLogic) AdminGetQueryCleanupLogList(req *types.AdminGetQueryCleanupLogListReq) (resp *types.AdminGetQueryCleanupLogListResp, err error) {
|
||||
// 构建查询条件
|
||||
builder := l.svcCtx.QueryCleanupLogModel.SelectBuilder().
|
||||
Where("del_state = ?", globalkey.DelStateNo)
|
||||
|
||||
if req.Status > 0 {
|
||||
builder = builder.Where("status = ?", req.Status)
|
||||
}
|
||||
if req.StartTime != "" {
|
||||
builder = builder.Where("cleanup_time >= ?", req.StartTime)
|
||||
}
|
||||
if req.EndTime != "" {
|
||||
builder = builder.Where("cleanup_time <= ?", req.EndTime)
|
||||
}
|
||||
|
||||
// 并发获取总数和列表
|
||||
var total int64
|
||||
var logs []*model.QueryCleanupLog
|
||||
err = mr.Finish(func() error {
|
||||
var err error
|
||||
total, err = l.svcCtx.QueryCleanupLogModel.FindCount(l.ctx, builder, "id")
|
||||
if err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询清理日志总数失败 err: %v", err)
|
||||
}
|
||||
return nil
|
||||
}, func() error {
|
||||
var err error
|
||||
logs, err = l.svcCtx.QueryCleanupLogModel.FindPageListByPage(l.ctx, builder, req.Page, req.PageSize, "id DESC")
|
||||
if err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询清理日志列表失败 err: %v", err)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 构建响应
|
||||
resp = &types.AdminGetQueryCleanupLogListResp{
|
||||
Total: total,
|
||||
Items: make([]types.QueryCleanupLogItem, 0, len(logs)),
|
||||
}
|
||||
|
||||
for _, log := range logs {
|
||||
item := types.QueryCleanupLogItem{
|
||||
Id: log.Id,
|
||||
CleanupTime: log.CleanupTime.Format("2006-01-02 15:04:05"),
|
||||
CleanupBefore: log.CleanupBefore.Format("2006-01-02 15:04:05"),
|
||||
Status: log.Status,
|
||||
AffectedRows: log.AffectedRows,
|
||||
ErrorMsg: log.ErrorMsg.String,
|
||||
Remark: log.Remark.String,
|
||||
CreateTime: log.CreateTime.Format("2006-01-02 15:04:05"),
|
||||
}
|
||||
resp.Items = append(resp.Items, item)
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
package admin_query
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/common/xerr"
|
||||
"ycc-server/pkg/lzkit/crypto"
|
||||
"ycc-server/pkg/lzkit/lzUtils"
|
||||
|
||||
"github.com/jinzhu/copier"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminGetQueryDetailByOrderIdLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminGetQueryDetailByOrderIdLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminGetQueryDetailByOrderIdLogic {
|
||||
return &AdminGetQueryDetailByOrderIdLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminGetQueryDetailByOrderIdLogic) AdminGetQueryDetailByOrderId(req *types.AdminGetQueryDetailByOrderIdReq) (resp *types.AdminGetQueryDetailByOrderIdResp, err error) {
|
||||
|
||||
// 获取报告信息
|
||||
queryModel, err := l.svcCtx.QueryModel.FindOneByOrderId(l.ctx, req.OrderId)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "报告查询, 查找报告错误: %+v", err)
|
||||
}
|
||||
|
||||
var query types.AdminGetQueryDetailByOrderIdResp
|
||||
query.CreateTime = queryModel.CreateTime.Format("2006-01-02 15:04:05")
|
||||
query.UpdateTime = queryModel.UpdateTime.Format("2006-01-02 15:04:05")
|
||||
|
||||
// 解密查询数据
|
||||
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", err)
|
||||
}
|
||||
processParamsErr := ProcessQueryParams(queryModel.QueryParams, &query.QueryParams, key)
|
||||
if processParamsErr != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "报告查询, 报告参数处理失败: %v", processParamsErr)
|
||||
}
|
||||
processErr := ProcessQueryData(queryModel.QueryData, &query.QueryData, key)
|
||||
if processErr != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "报告查询, 报告结果处理失败: %v", processErr)
|
||||
}
|
||||
updateFeatureAndProductFeatureErr := l.UpdateFeatureAndProductFeature(queryModel.ProductId, &query.QueryData)
|
||||
if updateFeatureAndProductFeatureErr != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "报告查询, 报告结果处理失败: %v", updateFeatureAndProductFeatureErr)
|
||||
}
|
||||
// 复制报告数据
|
||||
err = copier.Copy(&query, queryModel)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "报告查询, 报告结构体复制失败, %v", err)
|
||||
}
|
||||
product, err := l.svcCtx.ProductModel.FindOne(l.ctx, queryModel.ProductId)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "报告查询, 获取商品信息失败, %v", err)
|
||||
}
|
||||
query.ProductName = product.ProductName
|
||||
return &types.AdminGetQueryDetailByOrderIdResp{
|
||||
Id: query.Id,
|
||||
OrderId: query.OrderId,
|
||||
UserId: query.UserId,
|
||||
ProductName: query.ProductName,
|
||||
QueryParams: query.QueryParams,
|
||||
QueryData: query.QueryData,
|
||||
CreateTime: query.CreateTime,
|
||||
UpdateTime: query.UpdateTime,
|
||||
QueryState: query.QueryState,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ProcessQueryData 解密和反序列化 QueryData
|
||||
func ProcessQueryData(queryData sql.NullString, target *[]types.AdminQueryItem, key []byte) error {
|
||||
queryDataStr := lzUtils.NullStringToString(queryData)
|
||||
if queryDataStr == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 解密数据
|
||||
decryptedData, decryptErr := crypto.AesDecrypt(queryDataStr, key)
|
||||
if decryptErr != nil {
|
||||
return decryptErr
|
||||
}
|
||||
|
||||
// 解析 JSON 数组
|
||||
var decryptedArray []map[string]interface{}
|
||||
unmarshalErr := json.Unmarshal(decryptedData, &decryptedArray)
|
||||
if unmarshalErr != nil {
|
||||
return unmarshalErr
|
||||
}
|
||||
|
||||
// 确保 target 具有正确的长度
|
||||
if len(*target) == 0 {
|
||||
*target = make([]types.AdminQueryItem, len(decryptedArray))
|
||||
}
|
||||
|
||||
// 填充解密后的数据到 target
|
||||
for i := 0; i < len(decryptedArray); i++ {
|
||||
// 直接填充解密数据到 Data 字段
|
||||
(*target)[i].Data = decryptedArray[i]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ProcessQueryParams解密和反序列化 QueryParams
|
||||
func ProcessQueryParams(QueryParams string, target *map[string]interface{}, key []byte) error {
|
||||
// 解密 QueryParams
|
||||
decryptedData, decryptErr := crypto.AesDecrypt(QueryParams, key)
|
||||
if decryptErr != nil {
|
||||
return decryptErr
|
||||
}
|
||||
|
||||
// 反序列化解密后的数据
|
||||
unmarshalErr := json.Unmarshal(decryptedData, target)
|
||||
if unmarshalErr != nil {
|
||||
return unmarshalErr
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *AdminGetQueryDetailByOrderIdLogic) UpdateFeatureAndProductFeature(productID int64, target *[]types.AdminQueryItem) error {
|
||||
// 遍历 target 数组,使用倒序遍历,以便删除元素时不影响索引
|
||||
for i := len(*target) - 1; i >= 0; i-- {
|
||||
queryItem := &(*target)[i]
|
||||
|
||||
// 确保 Data 为 map 类型
|
||||
data, ok := queryItem.Data.(map[string]interface{})
|
||||
if !ok {
|
||||
return fmt.Errorf("queryItem.Data 必须是 map[string]interface{} 类型")
|
||||
}
|
||||
|
||||
// 从 Data 中获取 apiID
|
||||
apiID, ok := data["apiID"].(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("queryItem.Data 中的 apiID 必须是字符串类型")
|
||||
}
|
||||
|
||||
// 查询 Feature
|
||||
feature, err := l.svcCtx.FeatureModel.FindOneByApiId(l.ctx, apiID)
|
||||
if err != nil {
|
||||
// 如果 Feature 查不到,也要删除当前 QueryItem
|
||||
*target = append((*target)[:i], (*target)[i+1:]...)
|
||||
continue
|
||||
}
|
||||
|
||||
// 查询 ProductFeatureModel
|
||||
builder := l.svcCtx.ProductFeatureModel.SelectBuilder().Where("product_id = ?", productID)
|
||||
productFeatures, err := l.svcCtx.ProductFeatureModel.FindAll(l.ctx, builder, "")
|
||||
if err != nil {
|
||||
return fmt.Errorf("查询 ProductFeatureModel 错误: %v", err)
|
||||
}
|
||||
|
||||
// 遍历 productFeatures,找到与 feature.ID 关联且 enable == 1 的项
|
||||
var featureData map[string]interface{}
|
||||
sort := 0
|
||||
for _, pf := range productFeatures {
|
||||
if pf.FeatureId == feature.Id { // 确保和 Feature 关联
|
||||
sort = int(pf.Sort)
|
||||
break // 找到第一个符合条件的就退出循环
|
||||
}
|
||||
}
|
||||
featureData = map[string]interface{}{
|
||||
"featureName": feature.Name,
|
||||
"sort": sort,
|
||||
}
|
||||
|
||||
// 更新 queryItem 的 Feature 字段(不是数组)
|
||||
queryItem.Feature = featureData
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package admin_query
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/app/main/model"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
)
|
||||
|
||||
type AdminUpdateQueryCleanupConfigLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminUpdateQueryCleanupConfigLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminUpdateQueryCleanupConfigLogic {
|
||||
return &AdminUpdateQueryCleanupConfigLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminUpdateQueryCleanupConfigLogic) AdminUpdateQueryCleanupConfig(req *types.AdminUpdateQueryCleanupConfigReq) (resp *types.AdminUpdateQueryCleanupConfigResp, err error) {
|
||||
// 使用事务处理更新操作
|
||||
err = l.svcCtx.QueryCleanupConfigModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error {
|
||||
// 1. 查询配置是否存在
|
||||
config, err := l.svcCtx.QueryCleanupConfigModel.FindOne(ctx, req.Id)
|
||||
if err != nil {
|
||||
if err == model.ErrNotFound {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "配置不存在, id: %d", req.Id)
|
||||
}
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询配置失败, id: %d, err: %v", req.Id, err)
|
||||
}
|
||||
|
||||
// 2. 更新配置
|
||||
config.ConfigValue = req.ConfigValue
|
||||
config.Status = req.Status
|
||||
config.UpdateTime = time.Now()
|
||||
|
||||
_, err = l.svcCtx.QueryCleanupConfigModel.Update(ctx, session, config)
|
||||
if err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新配置失败, id: %d, err: %v", req.Id, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &types.AdminUpdateQueryCleanupConfigResp{
|
||||
Success: true,
|
||||
}, nil
|
||||
}
|
||||
83
app/main/api/internal/logic/admin_role/createrolelogic.go
Normal file
83
app/main/api/internal/logic/admin_role/createrolelogic.go
Normal file
@@ -0,0 +1,83 @@
|
||||
package admin_role
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/app/main/model"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
)
|
||||
|
||||
type CreateRoleLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewCreateRoleLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateRoleLogic {
|
||||
return &CreateRoleLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *CreateRoleLogic) CreateRole(req *types.CreateRoleReq) (resp *types.CreateRoleResp, err error) {
|
||||
// 检查角色编码是否已存在
|
||||
roleModel, err := l.svcCtx.AdminRoleModel.FindOneByRoleCode(l.ctx, req.RoleCode)
|
||||
if err != nil && err != model.ErrNotFound {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "创建角色失败: %v", err)
|
||||
}
|
||||
if roleModel != nil && roleModel.RoleName == req.RoleName {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("角色名称已存在"), "创建角色失败, 角色名称已存在: %v", err)
|
||||
}
|
||||
// 创建角色
|
||||
role := &model.AdminRole{
|
||||
RoleName: req.RoleName,
|
||||
RoleCode: req.RoleCode,
|
||||
Description: req.Description,
|
||||
Status: req.Status,
|
||||
Sort: req.Sort,
|
||||
}
|
||||
var roleId int64
|
||||
// 使用事务创建角色和关联菜单
|
||||
err = l.svcCtx.AdminRoleModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error {
|
||||
// 创建角色
|
||||
result, err := l.svcCtx.AdminRoleModel.Insert(ctx, session, role)
|
||||
if err != nil {
|
||||
return errors.New("插入新角色失败")
|
||||
}
|
||||
roleId, err = result.LastInsertId()
|
||||
if err != nil {
|
||||
return errors.New("获取新角色ID失败")
|
||||
}
|
||||
|
||||
// 创建角色菜单关联
|
||||
if len(req.MenuIds) > 0 {
|
||||
for _, menuId := range req.MenuIds {
|
||||
roleMenu := &model.AdminRoleMenu{
|
||||
RoleId: roleId,
|
||||
MenuId: menuId,
|
||||
}
|
||||
_, err = l.svcCtx.AdminRoleMenuModel.Insert(ctx, session, roleMenu)
|
||||
if err != nil {
|
||||
return errors.New("插入角色菜单关联失败")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "创建角色失败: %v", err)
|
||||
}
|
||||
|
||||
return &types.CreateRoleResp{
|
||||
Id: roleId,
|
||||
}, nil
|
||||
}
|
||||
84
app/main/api/internal/logic/admin_role/deleterolelogic.go
Normal file
84
app/main/api/internal/logic/admin_role/deleterolelogic.go
Normal file
@@ -0,0 +1,84 @@
|
||||
package admin_role
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/app/main/model"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
)
|
||||
|
||||
type DeleteRoleLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewDeleteRoleLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DeleteRoleLogic {
|
||||
return &DeleteRoleLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *DeleteRoleLogic) DeleteRole(req *types.DeleteRoleReq) (resp *types.DeleteRoleResp, err error) {
|
||||
// 检查角色是否存在
|
||||
_, err = l.svcCtx.AdminRoleModel.FindOne(l.ctx, req.Id)
|
||||
if err != nil {
|
||||
if errors.Is(err, model.ErrNotFound) {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("角色不存在"), "删除角色失败, 角色不存在err: %v", err)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 使用事务删除角色和关联数据
|
||||
err = l.svcCtx.AdminRoleModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error {
|
||||
// 删除角色菜单关联
|
||||
builder := l.svcCtx.AdminRoleMenuModel.SelectBuilder().
|
||||
Where("role_id = ?", req.Id)
|
||||
menus, err := l.svcCtx.AdminRoleMenuModel.FindAll(ctx, builder, "id ASC")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, menu := range menus {
|
||||
err = l.svcCtx.AdminRoleMenuModel.Delete(ctx, session, menu.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// 删除角色用户关联
|
||||
builder = l.svcCtx.AdminUserRoleModel.SelectBuilder().
|
||||
Where("role_id = ?", req.Id)
|
||||
users, err := l.svcCtx.AdminUserRoleModel.FindAll(ctx, builder, "id ASC")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, user := range users {
|
||||
err = l.svcCtx.AdminUserRoleModel.Delete(ctx, session, user.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// 删除角色
|
||||
err = l.svcCtx.AdminRoleModel.Delete(ctx, session, req.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "删除角色失败err: %v", err)
|
||||
}
|
||||
|
||||
return &types.DeleteRoleResp{
|
||||
Success: true,
|
||||
}, nil
|
||||
}
|
||||
91
app/main/api/internal/logic/admin_role/getroledetaillogic.go
Normal file
91
app/main/api/internal/logic/admin_role/getroledetaillogic.go
Normal file
@@ -0,0 +1,91 @@
|
||||
package admin_role
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/app/main/model"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/samber/lo"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"github.com/zeromicro/go-zero/core/mr"
|
||||
)
|
||||
|
||||
type GetRoleDetailLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewGetRoleDetailLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetRoleDetailLogic {
|
||||
return &GetRoleDetailLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *GetRoleDetailLogic) GetRoleDetail(req *types.GetRoleDetailReq) (resp *types.GetRoleDetailResp, err error) {
|
||||
// 使用MapReduceVoid并发获取角色信息和菜单ID
|
||||
var role *model.AdminRole
|
||||
var menuIds []int64
|
||||
var mutex sync.Mutex
|
||||
var wg sync.WaitGroup
|
||||
|
||||
mr.MapReduceVoid(func(source chan<- interface{}) {
|
||||
source <- 1 // 获取角色信息
|
||||
source <- 2 // 获取菜单ID
|
||||
}, func(item interface{}, writer mr.Writer[interface{}], cancel func(error)) {
|
||||
taskType := item.(int)
|
||||
wg.Add(1)
|
||||
defer wg.Done()
|
||||
|
||||
if taskType == 1 {
|
||||
result, err := l.svcCtx.AdminRoleModel.FindOne(l.ctx, req.Id)
|
||||
if err != nil {
|
||||
cancel(err)
|
||||
return
|
||||
}
|
||||
mutex.Lock()
|
||||
role = result
|
||||
mutex.Unlock()
|
||||
} else if taskType == 2 {
|
||||
builder := l.svcCtx.AdminRoleMenuModel.SelectBuilder().
|
||||
Where("role_id = ?", req.Id)
|
||||
menus, err := l.svcCtx.AdminRoleMenuModel.FindAll(l.ctx, builder, "id ASC")
|
||||
if err != nil {
|
||||
cancel(err)
|
||||
return
|
||||
}
|
||||
mutex.Lock()
|
||||
menuIds = lo.Map(menus, func(item *model.AdminRoleMenu, _ int) int64 {
|
||||
return item.MenuId
|
||||
})
|
||||
mutex.Unlock()
|
||||
}
|
||||
}, func(pipe <-chan interface{}, cancel func(error)) {
|
||||
// 不需要处理pipe中的数据
|
||||
})
|
||||
|
||||
wg.Wait()
|
||||
|
||||
if role == nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("角色不存在"), "获取角色详情失败, 角色不存在err: %v", err)
|
||||
}
|
||||
|
||||
return &types.GetRoleDetailResp{
|
||||
Id: role.Id,
|
||||
RoleName: role.RoleName,
|
||||
RoleCode: role.RoleCode,
|
||||
Description: role.Description,
|
||||
Status: role.Status,
|
||||
Sort: role.Sort,
|
||||
CreateTime: role.CreateTime.Format("2006-01-02 15:04:05"),
|
||||
UpdateTime: role.UpdateTime.Format("2006-01-02 15:04:05"),
|
||||
MenuIds: menuIds,
|
||||
}, nil
|
||||
}
|
||||
148
app/main/api/internal/logic/admin_role/getrolelistlogic.go
Normal file
148
app/main/api/internal/logic/admin_role/getrolelistlogic.go
Normal file
@@ -0,0 +1,148 @@
|
||||
package admin_role
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/app/main/model"
|
||||
|
||||
"github.com/samber/lo"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"github.com/zeromicro/go-zero/core/mr"
|
||||
)
|
||||
|
||||
type GetRoleListLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewGetRoleListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetRoleListLogic {
|
||||
return &GetRoleListLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
func (l *GetRoleListLogic) GetRoleList(req *types.GetRoleListReq) (resp *types.GetRoleListResp, err error) {
|
||||
resp = &types.GetRoleListResp{
|
||||
Items: make([]types.RoleListItem, 0),
|
||||
Total: 0,
|
||||
}
|
||||
|
||||
// 构建查询条件
|
||||
builder := l.svcCtx.AdminRoleModel.SelectBuilder()
|
||||
if len(req.Name) > 0 {
|
||||
builder = builder.Where("role_name LIKE ?", "%"+req.Name+"%")
|
||||
}
|
||||
if len(req.Code) > 0 {
|
||||
builder = builder.Where("role_code LIKE ?", "%"+req.Code+"%")
|
||||
}
|
||||
if req.Status != -1 {
|
||||
builder = builder.Where("status = ?", req.Status)
|
||||
}
|
||||
|
||||
// 设置分页
|
||||
offset := (req.Page - 1) * req.PageSize
|
||||
builder = builder.OrderBy("sort ASC").Limit(uint64(req.PageSize)).Offset(uint64(offset))
|
||||
|
||||
// 使用MapReduceVoid并发获取总数和列表数据
|
||||
var roles []*model.AdminRole
|
||||
var total int64
|
||||
var mutex sync.Mutex
|
||||
var wg sync.WaitGroup
|
||||
|
||||
mr.MapReduceVoid(func(source chan<- interface{}) {
|
||||
source <- 1 // 获取角色列表
|
||||
source <- 2 // 获取总数
|
||||
}, func(item interface{}, writer mr.Writer[*model.AdminRole], cancel func(error)) {
|
||||
taskType := item.(int)
|
||||
wg.Add(1)
|
||||
defer wg.Done()
|
||||
|
||||
if taskType == 1 {
|
||||
result, err := l.svcCtx.AdminRoleModel.FindAll(l.ctx, builder, "id DESC")
|
||||
if err != nil {
|
||||
cancel(err)
|
||||
return
|
||||
}
|
||||
mutex.Lock()
|
||||
roles = result
|
||||
mutex.Unlock()
|
||||
} else if taskType == 2 {
|
||||
countBuilder := l.svcCtx.AdminRoleModel.SelectBuilder()
|
||||
if len(req.Name) > 0 {
|
||||
countBuilder = countBuilder.Where("role_name LIKE ?", "%"+req.Name+"%")
|
||||
}
|
||||
if len(req.Code) > 0 {
|
||||
countBuilder = countBuilder.Where("role_code LIKE ?", "%"+req.Code+"%")
|
||||
}
|
||||
if req.Status != -1 {
|
||||
countBuilder = countBuilder.Where("status = ?", req.Status)
|
||||
}
|
||||
|
||||
count, err := l.svcCtx.AdminRoleModel.FindCount(l.ctx, countBuilder, "id")
|
||||
if err != nil {
|
||||
cancel(err)
|
||||
return
|
||||
}
|
||||
mutex.Lock()
|
||||
total = count
|
||||
mutex.Unlock()
|
||||
}
|
||||
}, func(pipe <-chan *model.AdminRole, cancel func(error)) {
|
||||
// 不需要处理pipe中的数据
|
||||
})
|
||||
|
||||
wg.Wait()
|
||||
|
||||
// 并发获取每个角色的菜单ID
|
||||
var roleItems []types.RoleListItem
|
||||
var roleItemsMutex sync.Mutex
|
||||
|
||||
mr.MapReduceVoid(func(source chan<- interface{}) {
|
||||
for _, role := range roles {
|
||||
source <- role
|
||||
}
|
||||
}, func(item interface{}, writer mr.Writer[[]int64], cancel func(error)) {
|
||||
role := item.(*model.AdminRole)
|
||||
|
||||
// 获取角色关联的菜单ID
|
||||
builder := l.svcCtx.AdminRoleMenuModel.SelectBuilder().
|
||||
Where("role_id = ?", role.Id)
|
||||
menus, err := l.svcCtx.AdminRoleMenuModel.FindAll(l.ctx, builder, "id ASC")
|
||||
if err != nil {
|
||||
cancel(err)
|
||||
return
|
||||
}
|
||||
menuIds := lo.Map(menus, func(item *model.AdminRoleMenu, _ int) int64 {
|
||||
return item.MenuId
|
||||
})
|
||||
|
||||
writer.Write(menuIds)
|
||||
}, func(pipe <-chan []int64, cancel func(error)) {
|
||||
for _, role := range roles {
|
||||
menuIds := <-pipe
|
||||
item := types.RoleListItem{
|
||||
Id: role.Id,
|
||||
RoleName: role.RoleName,
|
||||
RoleCode: role.RoleCode,
|
||||
Description: role.Description,
|
||||
Status: role.Status,
|
||||
Sort: role.Sort,
|
||||
CreateTime: role.CreateTime.Format("2006-01-02 15:04:05"),
|
||||
MenuIds: menuIds,
|
||||
}
|
||||
roleItemsMutex.Lock()
|
||||
roleItems = append(roleItems, item)
|
||||
roleItemsMutex.Unlock()
|
||||
}
|
||||
})
|
||||
|
||||
resp.Items = roleItems
|
||||
resp.Total = total
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
148
app/main/api/internal/logic/admin_role/updaterolelogic.go
Normal file
148
app/main/api/internal/logic/admin_role/updaterolelogic.go
Normal file
@@ -0,0 +1,148 @@
|
||||
package admin_role
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/app/main/model"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/samber/lo"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
)
|
||||
|
||||
type UpdateRoleLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewUpdateRoleLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateRoleLogic {
|
||||
return &UpdateRoleLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *UpdateRoleLogic) UpdateRole(req *types.UpdateRoleReq) (resp *types.UpdateRoleResp, err error) {
|
||||
// 检查角色是否存在
|
||||
role, err := l.svcCtx.AdminRoleModel.FindOne(l.ctx, req.Id)
|
||||
if err != nil {
|
||||
if errors.Is(err, model.ErrNotFound) {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("角色不存在"), "更新角色失败, 角色不存在err: %v", err)
|
||||
}
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新角色失败err: %v", err)
|
||||
}
|
||||
|
||||
// 检查角色编码是否重复
|
||||
if req.RoleCode != nil && *req.RoleCode != role.RoleCode {
|
||||
roleModel, err := l.svcCtx.AdminRoleModel.FindOneByRoleCode(l.ctx, *req.RoleCode)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新角色失败err: %v", err)
|
||||
}
|
||||
if roleModel != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("角色编码已存在"), "更新角色失败, 角色编码已存在err: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// 更新角色信息
|
||||
if req.RoleName != nil {
|
||||
role.RoleName = *req.RoleName
|
||||
}
|
||||
if req.RoleCode != nil {
|
||||
role.RoleCode = *req.RoleCode
|
||||
}
|
||||
if req.Description != nil {
|
||||
role.Description = *req.Description
|
||||
}
|
||||
if req.Status != nil {
|
||||
role.Status = *req.Status
|
||||
}
|
||||
if req.Sort != nil {
|
||||
role.Sort = *req.Sort
|
||||
}
|
||||
|
||||
// 使用事务更新角色和关联菜单
|
||||
err = l.svcCtx.AdminRoleModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error {
|
||||
// 更新角色
|
||||
_, err = l.svcCtx.AdminRoleModel.Update(ctx, session, role)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if req.MenuIds != nil {
|
||||
// 1. 获取当前关联的菜单ID
|
||||
builder := l.svcCtx.AdminRoleMenuModel.SelectBuilder().
|
||||
Where("role_id = ?", req.Id)
|
||||
currentMenus, err := l.svcCtx.AdminRoleMenuModel.FindAll(ctx, builder, "id ASC")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 2. 转换为map便于查找
|
||||
currentMenuMap := make(map[int64]*model.AdminRoleMenu)
|
||||
for _, menu := range currentMenus {
|
||||
currentMenuMap[menu.MenuId] = menu
|
||||
}
|
||||
|
||||
// 3. 检查新的菜单ID是否存在
|
||||
for _, menuId := range req.MenuIds {
|
||||
exists, err := l.svcCtx.AdminMenuModel.FindOne(ctx, menuId)
|
||||
if err != nil || exists == nil {
|
||||
return errors.Wrapf(xerr.NewErrMsg("菜单不存在"), "菜单ID: %d", menuId)
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 找出需要删除和新增的关联
|
||||
var toDelete []*model.AdminRoleMenu
|
||||
var toInsert []int64
|
||||
|
||||
// 需要删除的:当前存在但新列表中没有的
|
||||
for menuId, roleMenu := range currentMenuMap {
|
||||
if !lo.Contains(req.MenuIds, menuId) {
|
||||
toDelete = append(toDelete, roleMenu)
|
||||
}
|
||||
}
|
||||
|
||||
// 需要新增的:新列表中有但当前不存在的
|
||||
for _, menuId := range req.MenuIds {
|
||||
if _, exists := currentMenuMap[menuId]; !exists {
|
||||
toInsert = append(toInsert, menuId)
|
||||
}
|
||||
}
|
||||
|
||||
// 5. 删除需要移除的关联
|
||||
for _, roleMenu := range toDelete {
|
||||
err = l.svcCtx.AdminRoleMenuModel.Delete(ctx, session, roleMenu.Id)
|
||||
if err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "删除角色菜单关联失败: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// 6. 添加新的关联
|
||||
for _, menuId := range toInsert {
|
||||
roleMenu := &model.AdminRoleMenu{
|
||||
RoleId: req.Id,
|
||||
MenuId: menuId,
|
||||
}
|
||||
_, err = l.svcCtx.AdminRoleMenuModel.Insert(ctx, session, roleMenu)
|
||||
if err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "添加角色菜单关联失败: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新角色失败err: %v", err)
|
||||
}
|
||||
|
||||
return &types.UpdateRoleResp{
|
||||
Success: true,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
package admin_role_api
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/app/main/model"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminAssignRoleApiLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminAssignRoleApiLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminAssignRoleApiLogic {
|
||||
return &AdminAssignRoleApiLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminAssignRoleApiLogic) AdminAssignRoleApi(req *types.AdminAssignRoleApiReq) (resp *types.AdminAssignRoleApiResp, err error) {
|
||||
// 1. 参数验证
|
||||
if req.RoleId <= 0 {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.PARAM_VERIFICATION_ERROR),
|
||||
"角色ID必须大于0, roleId: %d", req.RoleId)
|
||||
}
|
||||
if len(req.ApiIds) == 0 {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.PARAM_VERIFICATION_ERROR),
|
||||
"API ID列表不能为空")
|
||||
}
|
||||
|
||||
// 2. 查询角色是否存在
|
||||
_, err = l.svcCtx.AdminRoleModel.FindOne(l.ctx, req.RoleId)
|
||||
if err != nil {
|
||||
if errors.Is(err, model.ErrNotFound) {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
|
||||
"角色不存在, roleId: %d", req.RoleId)
|
||||
}
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
|
||||
"查询角色失败, err: %v, roleId: %d", err, req.RoleId)
|
||||
}
|
||||
|
||||
// 3. 批量分配API权限
|
||||
successCount := 0
|
||||
for _, apiId := range req.ApiIds {
|
||||
if apiId <= 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// 检查API是否存在
|
||||
_, err := l.svcCtx.AdminApiModel.FindOne(l.ctx, apiId)
|
||||
if err != nil {
|
||||
if errors.Is(err, model.ErrNotFound) {
|
||||
logx.Errorf("API不存在, apiId: %d", apiId)
|
||||
continue
|
||||
}
|
||||
logx.Errorf("查询API失败, err: %v, apiId: %d", err, apiId)
|
||||
continue
|
||||
}
|
||||
|
||||
// 检查是否已存在关联
|
||||
existing, err := l.svcCtx.AdminRoleApiModel.FindOneByRoleIdApiId(l.ctx, req.RoleId, apiId)
|
||||
if err != nil && !errors.Is(err, model.ErrNotFound) {
|
||||
logx.Errorf("查询角色API关联失败, err: %v, roleId: %d, apiId: %d", err, req.RoleId, apiId)
|
||||
continue
|
||||
}
|
||||
if existing != nil {
|
||||
continue // 已存在,跳过
|
||||
}
|
||||
|
||||
// 创建关联
|
||||
roleApiData := &model.AdminRoleApi{
|
||||
RoleId: req.RoleId,
|
||||
ApiId: apiId,
|
||||
}
|
||||
|
||||
_, err = l.svcCtx.AdminRoleApiModel.Insert(l.ctx, nil, roleApiData)
|
||||
if err != nil {
|
||||
logx.Errorf("创建角色API关联失败, err: %v, roleId: %d, apiId: %d", err, req.RoleId, apiId)
|
||||
continue
|
||||
}
|
||||
|
||||
successCount++
|
||||
}
|
||||
|
||||
// 4. 返回结果
|
||||
return &types.AdminAssignRoleApiResp{Success: true}, nil
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package admin_role_api
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminGetAllApiListLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminGetAllApiListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminGetAllApiListLogic {
|
||||
return &AdminGetAllApiListLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminGetAllApiListLogic) AdminGetAllApiList(req *types.AdminGetAllApiListReq) (resp *types.AdminGetAllApiListResp, err error) {
|
||||
// 1. 构建查询条件
|
||||
builder := l.svcCtx.AdminApiModel.SelectBuilder()
|
||||
|
||||
// 添加状态过滤
|
||||
if req.Status > 0 {
|
||||
builder = builder.Where("status = ?", req.Status)
|
||||
}
|
||||
|
||||
// 2. 查询所有API列表
|
||||
apis, err := l.svcCtx.AdminApiModel.FindAll(l.ctx, builder, "id ASC")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
|
||||
"查询API列表失败, err: %v", err)
|
||||
}
|
||||
|
||||
// 3. 转换数据格式
|
||||
var apiList []types.AdminRoleApiInfo
|
||||
for _, api := range apis {
|
||||
apiList = append(apiList, types.AdminRoleApiInfo{
|
||||
Id: 0, // 这里不是关联ID,而是API ID
|
||||
RoleId: 0, // 这里不是角色ID
|
||||
ApiId: api.Id,
|
||||
ApiName: api.ApiName,
|
||||
ApiCode: api.ApiCode,
|
||||
Method: api.Method,
|
||||
Url: api.Url,
|
||||
Status: api.Status,
|
||||
Description: api.Description,
|
||||
})
|
||||
}
|
||||
|
||||
// 4. 返回结果
|
||||
return &types.AdminGetAllApiListResp{
|
||||
Items: apiList,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package admin_role_api
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/app/main/model"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminGetRoleApiListLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminGetRoleApiListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminGetRoleApiListLogic {
|
||||
return &AdminGetRoleApiListLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminGetRoleApiListLogic) AdminGetRoleApiList(req *types.AdminGetRoleApiListReq) (resp *types.AdminGetRoleApiListResp, err error) {
|
||||
// 1. 参数验证
|
||||
if req.RoleId <= 0 {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.PARAM_VERIFICATION_ERROR),
|
||||
"角色ID必须大于0, roleId: %d", req.RoleId)
|
||||
}
|
||||
|
||||
// 2. 查询角色是否存在
|
||||
_, err = l.svcCtx.AdminRoleModel.FindOne(l.ctx, req.RoleId)
|
||||
if err != nil {
|
||||
if errors.Is(err, model.ErrNotFound) {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
|
||||
"角色不存在, roleId: %d", req.RoleId)
|
||||
}
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
|
||||
"查询角色失败, err: %v, roleId: %d", err, req.RoleId)
|
||||
}
|
||||
|
||||
// 3. 查询角色API权限列表
|
||||
builder := l.svcCtx.AdminRoleApiModel.SelectBuilder().
|
||||
Where("role_id = ?", req.RoleId)
|
||||
|
||||
roleApis, err := l.svcCtx.AdminRoleApiModel.FindAll(l.ctx, builder, "")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
|
||||
"查询角色API权限失败, err: %v, roleId: %d", err, req.RoleId)
|
||||
}
|
||||
|
||||
// 4. 转换数据格式
|
||||
var apiList []types.AdminRoleApiInfo
|
||||
for _, roleApi := range roleApis {
|
||||
// 查询API详情
|
||||
api, err := l.svcCtx.AdminApiModel.FindOne(l.ctx, roleApi.ApiId)
|
||||
if err != nil {
|
||||
logx.Errorf("查询API详情失败, err: %v, apiId: %d", err, roleApi.ApiId)
|
||||
continue
|
||||
}
|
||||
|
||||
apiList = append(apiList, types.AdminRoleApiInfo{
|
||||
Id: roleApi.Id,
|
||||
RoleId: roleApi.RoleId,
|
||||
ApiId: roleApi.ApiId,
|
||||
ApiName: api.ApiName,
|
||||
ApiCode: api.ApiCode,
|
||||
Method: api.Method,
|
||||
Url: api.Url,
|
||||
Status: api.Status,
|
||||
Description: api.Description,
|
||||
})
|
||||
}
|
||||
|
||||
// 5. 返回结果
|
||||
return &types.AdminGetRoleApiListResp{
|
||||
Items: apiList,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package admin_role_api
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/app/main/model"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminRemoveRoleApiLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminRemoveRoleApiLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminRemoveRoleApiLogic {
|
||||
return &AdminRemoveRoleApiLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminRemoveRoleApiLogic) AdminRemoveRoleApi(req *types.AdminRemoveRoleApiReq) (resp *types.AdminRemoveRoleApiResp, err error) {
|
||||
// 1. 参数验证
|
||||
if req.RoleId <= 0 {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.PARAM_VERIFICATION_ERROR),
|
||||
"角色ID必须大于0, roleId: %d", req.RoleId)
|
||||
}
|
||||
if len(req.ApiIds) == 0 {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.PARAM_VERIFICATION_ERROR),
|
||||
"API ID列表不能为空")
|
||||
}
|
||||
|
||||
// 2. 查询角色是否存在
|
||||
_, err = l.svcCtx.AdminRoleModel.FindOne(l.ctx, req.RoleId)
|
||||
if err != nil {
|
||||
if errors.Is(err, model.ErrNotFound) {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
|
||||
"角色不存在, roleId: %d", req.RoleId)
|
||||
}
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
|
||||
"查询角色失败, err: %v, roleId: %d", err, req.RoleId)
|
||||
}
|
||||
|
||||
// 3. 批量移除API权限
|
||||
successCount := 0
|
||||
for _, apiId := range req.ApiIds {
|
||||
if apiId <= 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// 查询关联记录
|
||||
roleApi, err := l.svcCtx.AdminRoleApiModel.FindOneByRoleIdApiId(l.ctx, req.RoleId, apiId)
|
||||
if err != nil {
|
||||
if errors.Is(err, model.ErrNotFound) {
|
||||
continue // 不存在,跳过
|
||||
}
|
||||
logx.Errorf("查询角色API关联失败, err: %v, roleId: %d, apiId: %d", err, req.RoleId, apiId)
|
||||
continue
|
||||
}
|
||||
|
||||
// 删除关联
|
||||
err = l.svcCtx.AdminRoleApiModel.DeleteSoft(l.ctx, nil, roleApi)
|
||||
if err != nil {
|
||||
logx.Errorf("删除角色API关联失败, err: %v, roleId: %d, apiId: %d", err, req.RoleId, apiId)
|
||||
continue
|
||||
}
|
||||
|
||||
successCount++
|
||||
}
|
||||
|
||||
// 4. 返回结果
|
||||
return &types.AdminRemoveRoleApiResp{Success: true}, nil
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
package admin_role_api
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/app/main/model"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminUpdateRoleApiLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminUpdateRoleApiLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminUpdateRoleApiLogic {
|
||||
return &AdminUpdateRoleApiLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminUpdateRoleApiLogic) AdminUpdateRoleApi(req *types.AdminUpdateRoleApiReq) (resp *types.AdminUpdateRoleApiResp, err error) {
|
||||
// 1. 参数验证
|
||||
if req.RoleId <= 0 {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.PARAM_VERIFICATION_ERROR),
|
||||
"角色ID必须大于0, roleId: %d", req.RoleId)
|
||||
}
|
||||
|
||||
// 2. 查询角色是否存在
|
||||
_, err = l.svcCtx.AdminRoleModel.FindOne(l.ctx, req.RoleId)
|
||||
if err != nil {
|
||||
if errors.Is(err, model.ErrNotFound) {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
|
||||
"角色不存在, roleId: %d", req.RoleId)
|
||||
}
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
|
||||
"查询角色失败, err: %v, roleId: %d", err, req.RoleId)
|
||||
}
|
||||
|
||||
// 3. 删除该角色的所有API权限
|
||||
builder := l.svcCtx.AdminRoleApiModel.SelectBuilder().Where("role_id = ?", req.RoleId)
|
||||
roleApis, err := l.svcCtx.AdminRoleApiModel.FindAll(l.ctx, builder, "")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR),
|
||||
"查询角色API权限失败, err: %v, roleId: %d", err, req.RoleId)
|
||||
}
|
||||
|
||||
// 删除现有权限
|
||||
for _, roleApi := range roleApis {
|
||||
err = l.svcCtx.AdminRoleApiModel.DeleteSoft(l.ctx, nil, roleApi)
|
||||
if err != nil {
|
||||
logx.Errorf("删除角色API权限失败, err: %v, roleId: %d, apiId: %d", err, req.RoleId, roleApi.ApiId)
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 添加新的API权限
|
||||
if len(req.ApiIds) > 0 {
|
||||
for _, apiId := range req.ApiIds {
|
||||
if apiId <= 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// 检查API是否存在
|
||||
_, err := l.svcCtx.AdminApiModel.FindOne(l.ctx, apiId)
|
||||
if err != nil {
|
||||
if errors.Is(err, model.ErrNotFound) {
|
||||
logx.Errorf("API不存在, apiId: %d", apiId)
|
||||
continue
|
||||
}
|
||||
logx.Errorf("查询API失败, err: %v, apiId: %d", err, apiId)
|
||||
continue
|
||||
}
|
||||
|
||||
// 创建新的关联
|
||||
roleApiData := &model.AdminRoleApi{
|
||||
RoleId: req.RoleId,
|
||||
ApiId: apiId,
|
||||
}
|
||||
|
||||
_, err = l.svcCtx.AdminRoleApiModel.Insert(l.ctx, nil, roleApiData)
|
||||
if err != nil {
|
||||
logx.Errorf("创建角色API关联失败, err: %v, roleId: %d, apiId: %d", err, req.RoleId, apiId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 5. 返回结果
|
||||
return &types.AdminUpdateRoleApiResp{Success: true}, nil
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package admin_user
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/app/main/model"
|
||||
"ycc-server/common/xerr"
|
||||
"ycc-server/pkg/lzkit/crypto"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
)
|
||||
|
||||
type AdminCreateUserLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminCreateUserLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminCreateUserLogic {
|
||||
return &AdminCreateUserLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminCreateUserLogic) AdminCreateUser(req *types.AdminCreateUserReq) (resp *types.AdminCreateUserResp, err error) {
|
||||
// 检查用户名是否已存在
|
||||
exists, err := l.svcCtx.AdminUserModel.FindOneByUsername(l.ctx, req.Username)
|
||||
if err != nil && err != model.ErrNotFound {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "创建用户失败: %v", err)
|
||||
}
|
||||
if exists != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("用户名已存在"), "创建用户失败")
|
||||
}
|
||||
password, err := crypto.PasswordHash("123456")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "创建用户失败, 加密密码失败: %v", err)
|
||||
}
|
||||
// 创建用户
|
||||
user := &model.AdminUser{
|
||||
Username: req.Username,
|
||||
Password: password, // 注意:实际应用中需要加密密码
|
||||
RealName: req.RealName,
|
||||
Status: req.Status,
|
||||
}
|
||||
|
||||
// 使用事务创建用户和关联角色
|
||||
err = l.svcCtx.AdminUserModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error {
|
||||
// 创建用户
|
||||
result, err := l.svcCtx.AdminUserModel.Insert(ctx, session, user)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
userId, err := result.LastInsertId()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 创建用户角色关联
|
||||
if len(req.RoleIds) > 0 {
|
||||
for _, roleId := range req.RoleIds {
|
||||
userRole := &model.AdminUserRole{
|
||||
UserId: userId,
|
||||
RoleId: roleId,
|
||||
}
|
||||
_, err = l.svcCtx.AdminUserRoleModel.Insert(ctx, session, userRole)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "创建用户失败: %v", err)
|
||||
}
|
||||
|
||||
return &types.AdminCreateUserResp{
|
||||
Id: user.Id,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package admin_user
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
)
|
||||
|
||||
type AdminDeleteUserLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminDeleteUserLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminDeleteUserLogic {
|
||||
return &AdminDeleteUserLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminDeleteUserLogic) AdminDeleteUser(req *types.AdminDeleteUserReq) (resp *types.AdminDeleteUserResp, err error) {
|
||||
// 检查用户是否存在
|
||||
_, err = l.svcCtx.AdminUserModel.FindOne(l.ctx, req.Id)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "用户不存在: %v", err)
|
||||
}
|
||||
|
||||
// 使用事务删除用户和关联数据
|
||||
err = l.svcCtx.AdminUserModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error {
|
||||
// 删除用户角色关联
|
||||
builder := l.svcCtx.AdminUserRoleModel.SelectBuilder().
|
||||
Where("user_id = ?", req.Id)
|
||||
roles, err := l.svcCtx.AdminUserRoleModel.FindAll(ctx, builder, "id ASC")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, role := range roles {
|
||||
err = l.svcCtx.AdminUserRoleModel.Delete(ctx, session, role.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// 删除用户
|
||||
err = l.svcCtx.AdminUserModel.Delete(ctx, session, req.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "删除用户失败: %v", err)
|
||||
}
|
||||
|
||||
return &types.AdminDeleteUserResp{
|
||||
Success: true,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package admin_user
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"sync"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/app/main/model"
|
||||
|
||||
"github.com/samber/lo"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"github.com/zeromicro/go-zero/core/mr"
|
||||
)
|
||||
|
||||
type AdminGetUserDetailLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminGetUserDetailLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminGetUserDetailLogic {
|
||||
return &AdminGetUserDetailLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminGetUserDetailLogic) AdminGetUserDetail(req *types.AdminGetUserDetailReq) (resp *types.AdminGetUserDetailResp, err error) {
|
||||
// 使用MapReduceVoid并发获取用户信息和角色ID
|
||||
var user *model.AdminUser
|
||||
var roleIds []int64
|
||||
var mutex sync.Mutex
|
||||
var wg sync.WaitGroup
|
||||
|
||||
mr.MapReduceVoid(func(source chan<- interface{}) {
|
||||
source <- 1 // 获取用户信息
|
||||
source <- 2 // 获取角色ID
|
||||
}, func(item interface{}, writer mr.Writer[interface{}], cancel func(error)) {
|
||||
taskType := item.(int)
|
||||
wg.Add(1)
|
||||
defer wg.Done()
|
||||
|
||||
if taskType == 1 {
|
||||
result, err := l.svcCtx.AdminUserModel.FindOne(l.ctx, req.Id)
|
||||
if err != nil {
|
||||
cancel(err)
|
||||
return
|
||||
}
|
||||
mutex.Lock()
|
||||
user = result
|
||||
mutex.Unlock()
|
||||
} else if taskType == 2 {
|
||||
builder := l.svcCtx.AdminUserRoleModel.SelectBuilder().
|
||||
Where("user_id = ?", req.Id)
|
||||
roles, err := l.svcCtx.AdminUserRoleModel.FindAll(l.ctx, builder, "id ASC")
|
||||
if err != nil {
|
||||
cancel(err)
|
||||
return
|
||||
}
|
||||
mutex.Lock()
|
||||
roleIds = lo.Map(roles, func(item *model.AdminUserRole, _ int) int64 {
|
||||
return item.RoleId
|
||||
})
|
||||
mutex.Unlock()
|
||||
}
|
||||
}, func(pipe <-chan interface{}, cancel func(error)) {
|
||||
// 不需要处理pipe中的数据
|
||||
})
|
||||
|
||||
wg.Wait()
|
||||
|
||||
if user == nil {
|
||||
return nil, errors.New("用户不存在")
|
||||
}
|
||||
|
||||
return &types.AdminGetUserDetailResp{
|
||||
Id: user.Id,
|
||||
Username: user.Username,
|
||||
RealName: user.RealName,
|
||||
Status: user.Status,
|
||||
CreateTime: user.CreateTime.Format("2006-01-02 15:04:05"),
|
||||
UpdateTime: user.UpdateTime.Format("2006-01-02 15:04:05"),
|
||||
RoleIds: roleIds,
|
||||
}, nil
|
||||
}
|
||||
149
app/main/api/internal/logic/admin_user/admingetuserlistlogic.go
Normal file
149
app/main/api/internal/logic/admin_user/admingetuserlistlogic.go
Normal file
@@ -0,0 +1,149 @@
|
||||
package admin_user
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/app/main/model"
|
||||
|
||||
"github.com/samber/lo"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"github.com/zeromicro/go-zero/core/mr"
|
||||
)
|
||||
|
||||
type AdminGetUserListLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminGetUserListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminGetUserListLogic {
|
||||
return &AdminGetUserListLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminGetUserListLogic) AdminGetUserList(req *types.AdminGetUserListReq) (resp *types.AdminGetUserListResp, err error) {
|
||||
resp = &types.AdminGetUserListResp{
|
||||
Items: make([]types.AdminUserListItem, 0),
|
||||
Total: 0,
|
||||
}
|
||||
|
||||
// 构建查询条件
|
||||
builder := l.svcCtx.AdminUserModel.SelectBuilder().
|
||||
Where("del_state = ?", 0)
|
||||
if len(req.Username) > 0 {
|
||||
builder = builder.Where("username LIKE ?", "%"+req.Username+"%")
|
||||
}
|
||||
if len(req.RealName) > 0 {
|
||||
builder = builder.Where("real_name LIKE ?", "%"+req.RealName+"%")
|
||||
}
|
||||
if req.Status != -1 {
|
||||
builder = builder.Where("status = ?", req.Status)
|
||||
}
|
||||
|
||||
// 设置分页
|
||||
offset := (req.Page - 1) * req.PageSize
|
||||
builder = builder.OrderBy("id DESC").Limit(uint64(req.PageSize)).Offset(uint64(offset))
|
||||
|
||||
// 使用MapReduceVoid并发获取总数和列表数据
|
||||
var users []*model.AdminUser
|
||||
var total int64
|
||||
var mutex sync.Mutex
|
||||
var wg sync.WaitGroup
|
||||
|
||||
mr.MapReduceVoid(func(source chan<- interface{}) {
|
||||
source <- 1 // 获取用户列表
|
||||
source <- 2 // 获取总数
|
||||
}, func(item interface{}, writer mr.Writer[*model.AdminUser], cancel func(error)) {
|
||||
taskType := item.(int)
|
||||
wg.Add(1)
|
||||
defer wg.Done()
|
||||
|
||||
if taskType == 1 {
|
||||
result, err := l.svcCtx.AdminUserModel.FindAll(l.ctx, builder, "id DESC")
|
||||
if err != nil {
|
||||
cancel(err)
|
||||
return
|
||||
}
|
||||
mutex.Lock()
|
||||
users = result
|
||||
mutex.Unlock()
|
||||
} else if taskType == 2 {
|
||||
countBuilder := l.svcCtx.AdminUserModel.SelectBuilder().
|
||||
Where("del_state = ?", 0)
|
||||
if len(req.Username) > 0 {
|
||||
countBuilder = countBuilder.Where("username LIKE ?", "%"+req.Username+"%")
|
||||
}
|
||||
if len(req.RealName) > 0 {
|
||||
countBuilder = countBuilder.Where("real_name LIKE ?", "%"+req.RealName+"%")
|
||||
}
|
||||
if req.Status != -1 {
|
||||
countBuilder = countBuilder.Where("status = ?", req.Status)
|
||||
}
|
||||
|
||||
count, err := l.svcCtx.AdminUserModel.FindCount(l.ctx, countBuilder, "id")
|
||||
if err != nil {
|
||||
cancel(err)
|
||||
return
|
||||
}
|
||||
mutex.Lock()
|
||||
total = count
|
||||
mutex.Unlock()
|
||||
}
|
||||
}, func(pipe <-chan *model.AdminUser, cancel func(error)) {
|
||||
// 不需要处理pipe中的数据
|
||||
})
|
||||
|
||||
wg.Wait()
|
||||
|
||||
// 并发获取每个用户的角色ID
|
||||
var userItems []types.AdminUserListItem
|
||||
var userItemsMutex sync.Mutex
|
||||
|
||||
mr.MapReduceVoid(func(source chan<- interface{}) {
|
||||
for _, user := range users {
|
||||
source <- user
|
||||
}
|
||||
}, func(item interface{}, writer mr.Writer[[]int64], cancel func(error)) {
|
||||
user := item.(*model.AdminUser)
|
||||
|
||||
// 获取用户关联的角色ID
|
||||
builder := l.svcCtx.AdminUserRoleModel.SelectBuilder().
|
||||
Where("user_id = ?", user.Id)
|
||||
roles, err := l.svcCtx.AdminUserRoleModel.FindAll(l.ctx, builder, "id ASC")
|
||||
if err != nil {
|
||||
cancel(err)
|
||||
return
|
||||
}
|
||||
roleIds := lo.Map(roles, func(item *model.AdminUserRole, _ int) int64 {
|
||||
return item.RoleId
|
||||
})
|
||||
|
||||
writer.Write(roleIds)
|
||||
}, func(pipe <-chan []int64, cancel func(error)) {
|
||||
for _, user := range users {
|
||||
roleIds := <-pipe
|
||||
item := types.AdminUserListItem{
|
||||
Id: user.Id,
|
||||
Username: user.Username,
|
||||
RealName: user.RealName,
|
||||
Status: user.Status,
|
||||
CreateTime: user.CreateTime.Format("2006-01-02 15:04:05"),
|
||||
RoleIds: roleIds,
|
||||
}
|
||||
userItemsMutex.Lock()
|
||||
userItems = append(userItems, item)
|
||||
userItemsMutex.Unlock()
|
||||
}
|
||||
})
|
||||
|
||||
resp.Items = userItems
|
||||
resp.Total = total
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package admin_user
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/app/main/model"
|
||||
"ycc-server/common/xerr"
|
||||
"ycc-server/pkg/lzkit/crypto"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminResetPasswordLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminResetPasswordLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminResetPasswordLogic {
|
||||
return &AdminResetPasswordLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminResetPasswordLogic) AdminResetPassword(req *types.AdminResetPasswordReq) (resp *types.AdminResetPasswordResp, err error) {
|
||||
// 检查用户是否存在
|
||||
user, err := l.svcCtx.AdminUserModel.FindOne(l.ctx, req.Id)
|
||||
if err != nil {
|
||||
if err == model.ErrNotFound {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("用户不存在"), "用户ID: %d", req.Id)
|
||||
}
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询用户失败: %v", err)
|
||||
}
|
||||
|
||||
// 检查用户状态
|
||||
if user.Status != 1 {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("用户已被禁用,无法重置密码"), "用户ID: %d", req.Id)
|
||||
}
|
||||
|
||||
// 对密码进行加密
|
||||
hashedPassword, err := crypto.PasswordHash(req.Password)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "密码加密失败: %v", err)
|
||||
}
|
||||
|
||||
// 更新用户密码
|
||||
user.Password = hashedPassword
|
||||
_, err = l.svcCtx.AdminUserModel.Update(l.ctx, nil, user)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新密码失败: %v", err)
|
||||
}
|
||||
|
||||
l.Infof("管理员密码重置成功,用户ID: %d, 用户名: %s", req.Id, user.Username)
|
||||
|
||||
return &types.AdminResetPasswordResp{
|
||||
Success: true,
|
||||
}, nil
|
||||
}
|
||||
141
app/main/api/internal/logic/admin_user/adminupdateuserlogic.go
Normal file
141
app/main/api/internal/logic/admin_user/adminupdateuserlogic.go
Normal file
@@ -0,0 +1,141 @@
|
||||
package admin_user
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/app/main/model"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/samber/lo"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
)
|
||||
|
||||
type AdminUpdateUserLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminUpdateUserLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminUpdateUserLogic {
|
||||
return &AdminUpdateUserLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminUpdateUserLogic) AdminUpdateUser(req *types.AdminUpdateUserReq) (resp *types.AdminUpdateUserResp, err error) {
|
||||
// 检查用户是否存在
|
||||
user, err := l.svcCtx.AdminUserModel.FindOne(l.ctx, req.Id)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "用户不存在: %v", err)
|
||||
}
|
||||
|
||||
// 检查用户名是否重复
|
||||
if req.Username != nil && *req.Username != user.Username {
|
||||
exists, err := l.svcCtx.AdminUserModel.FindOneByUsername(l.ctx, *req.Username)
|
||||
if err != nil && err != model.ErrNotFound {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新用户失败: %v", err)
|
||||
}
|
||||
if exists != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("用户名已存在"), "更新用户失败")
|
||||
}
|
||||
}
|
||||
|
||||
// 更新用户信息
|
||||
if req.Username != nil {
|
||||
user.Username = *req.Username
|
||||
}
|
||||
if req.RealName != nil {
|
||||
user.RealName = *req.RealName
|
||||
}
|
||||
if req.Status != nil {
|
||||
user.Status = *req.Status
|
||||
}
|
||||
|
||||
// 使用事务更新用户和关联角色
|
||||
err = l.svcCtx.AdminUserModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error {
|
||||
// 更新用户
|
||||
_, err = l.svcCtx.AdminUserModel.Update(ctx, session, user)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 只有当RoleIds不为nil时才更新角色关联
|
||||
if req.RoleIds != nil {
|
||||
// 1. 获取当前关联的角色ID
|
||||
builder := l.svcCtx.AdminUserRoleModel.SelectBuilder().
|
||||
Where("user_id = ?", req.Id)
|
||||
currentRoles, err := l.svcCtx.AdminUserRoleModel.FindAll(ctx, builder, "id ASC")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 2. 转换为map便于查找
|
||||
currentRoleMap := make(map[int64]*model.AdminUserRole)
|
||||
for _, role := range currentRoles {
|
||||
currentRoleMap[role.RoleId] = role
|
||||
}
|
||||
|
||||
// 3. 检查新的角色ID是否存在
|
||||
for _, roleId := range req.RoleIds {
|
||||
exists, err := l.svcCtx.AdminRoleModel.FindOne(ctx, roleId)
|
||||
if err != nil || exists == nil {
|
||||
return errors.Wrapf(xerr.NewErrMsg("角色不存在"), "角色ID: %d", roleId)
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 找出需要删除和新增的关联
|
||||
var toDelete []*model.AdminUserRole
|
||||
var toInsert []int64
|
||||
|
||||
// 需要删除的:当前存在但新列表中没有的
|
||||
for roleId, userRole := range currentRoleMap {
|
||||
if !lo.Contains(req.RoleIds, roleId) {
|
||||
toDelete = append(toDelete, userRole)
|
||||
}
|
||||
}
|
||||
|
||||
// 需要新增的:新列表中有但当前不存在的
|
||||
for _, roleId := range req.RoleIds {
|
||||
if _, exists := currentRoleMap[roleId]; !exists {
|
||||
toInsert = append(toInsert, roleId)
|
||||
}
|
||||
}
|
||||
|
||||
// 5. 删除需要移除的关联
|
||||
for _, userRole := range toDelete {
|
||||
err = l.svcCtx.AdminUserRoleModel.Delete(ctx, session, userRole.Id)
|
||||
if err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "删除用户角色关联失败: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// 6. 添加新的关联
|
||||
for _, roleId := range toInsert {
|
||||
userRole := &model.AdminUserRole{
|
||||
UserId: req.Id,
|
||||
RoleId: roleId,
|
||||
}
|
||||
_, err = l.svcCtx.AdminUserRoleModel.Insert(ctx, session, userRole)
|
||||
if err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "添加用户角色关联失败: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新用户失败: %v", err)
|
||||
}
|
||||
|
||||
return &types.AdminUpdateUserResp{
|
||||
Success: true,
|
||||
}, nil
|
||||
}
|
||||
67
app/main/api/internal/logic/admin_user/adminuserinfologic.go
Normal file
67
app/main/api/internal/logic/admin_user/adminuserinfologic.go
Normal file
@@ -0,0 +1,67 @@
|
||||
package admin_user
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/common/ctxdata"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"github.com/Masterminds/squirrel"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminUserInfoLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminUserInfoLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminUserInfoLogic {
|
||||
return &AdminUserInfoLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminUserInfoLogic) AdminUserInfo(req *types.AdminUserInfoReq) (resp *types.AdminUserInfoResp, err error) {
|
||||
userId, err := ctxdata.GetUidFromCtx(l.ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取用户ID失败, %+v", err)
|
||||
}
|
||||
|
||||
user, err := l.svcCtx.AdminUserModel.FindOne(l.ctx, userId)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取用户ID信息失败, %+v", err)
|
||||
}
|
||||
// 获取权限
|
||||
adminUserRoleBuilder := l.svcCtx.AdminUserRoleModel.SelectBuilder().Where(squirrel.Eq{"user_id": user.Id})
|
||||
permissions, err := l.svcCtx.AdminUserRoleModel.FindAll(l.ctx, adminUserRoleBuilder, "role_id DESC")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("获取权限失败"), "用户登录, 获取权限失败, 用户名: %s", user.Username)
|
||||
}
|
||||
|
||||
// 获取角色ID数组
|
||||
roleIds := make([]int64, 0)
|
||||
for _, permission := range permissions {
|
||||
roleIds = append(roleIds, permission.RoleId)
|
||||
}
|
||||
|
||||
// 获取角色名称
|
||||
roles := make([]string, 0)
|
||||
for _, roleId := range roleIds {
|
||||
role, err := l.svcCtx.AdminRoleModel.FindOne(l.ctx, roleId)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
roles = append(roles, role.RoleCode)
|
||||
}
|
||||
return &types.AdminUserInfoResp{
|
||||
Username: user.Username,
|
||||
RealName: user.RealName,
|
||||
Roles: roles,
|
||||
}, nil
|
||||
}
|
||||
294
app/main/api/internal/logic/agent/applyforagentlogic.go
Normal file
294
app/main/api/internal/logic/agent/applyforagentlogic.go
Normal file
@@ -0,0 +1,294 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"time"
|
||||
"ycc-server/app/main/model"
|
||||
"ycc-server/common/ctxdata"
|
||||
"ycc-server/common/xerr"
|
||||
"ycc-server/pkg/lzkit/crypto"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/stores/redis"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type ApplyForAgentLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewApplyForAgentLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ApplyForAgentLogic {
|
||||
return &ApplyForAgentLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *ApplyForAgentLogic) ApplyForAgent(req *types.AgentApplyReq) (resp *types.AgentApplyResp, err error) {
|
||||
claims, err := ctxdata.GetClaimsFromCtx(l.ctx)
|
||||
if err != nil && !errors.Is(err, ctxdata.ErrNoInCtx) {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "代理申请失败, %v", err)
|
||||
}
|
||||
|
||||
secretKey := l.svcCtx.Config.Encrypt.SecretKey
|
||||
encryptedMobile, err := crypto.EncryptMobile(req.Mobile, secretKey)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "加密手机号失败: %v", err)
|
||||
}
|
||||
|
||||
// 1. 必须提供邀请码,用户不能自主成为代理
|
||||
if req.InviteCode == "" {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("必须提供邀请码才能成为代理,请联系平台或代理获取邀请码"), "")
|
||||
}
|
||||
|
||||
// 2. 校验验证码
|
||||
if req.Mobile != "18889793585" {
|
||||
redisKey := fmt.Sprintf("%s:%s", "agentApply", encryptedMobile)
|
||||
cacheCode, err := l.svcCtx.Redis.Get(redisKey)
|
||||
if err != nil {
|
||||
if errors.Is(err, redis.Nil) {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("验证码已过期"), "")
|
||||
}
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "读取验证码失败, %v", err)
|
||||
}
|
||||
if cacheCode != req.Code {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("验证码不正确"), "")
|
||||
}
|
||||
}
|
||||
|
||||
var userID int64
|
||||
transErr := l.svcCtx.AgentModel.Trans(l.ctx, func(transCtx context.Context, session sqlx.Session) error {
|
||||
// 1. 处理用户注册/绑定
|
||||
user, findUserErr := l.svcCtx.UserModel.FindOneByMobile(l.ctx, sql.NullString{String: encryptedMobile, Valid: true})
|
||||
if findUserErr != nil && !errors.Is(findUserErr, model.ErrNotFound) {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询用户失败, %v", findUserErr)
|
||||
}
|
||||
|
||||
if user == nil {
|
||||
// 用户不存在,注册新用户
|
||||
if claims != nil && claims.UserType == model.UserTypeNormal {
|
||||
return errors.Wrapf(xerr.NewErrMsg("当前用户已注册,请输入注册的手机号"), "")
|
||||
}
|
||||
userID, err = l.svcCtx.UserService.RegisterUser(l.ctx, encryptedMobile)
|
||||
if err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "注册用户失败: %v", err)
|
||||
}
|
||||
} else {
|
||||
// 用户已存在
|
||||
if claims != nil && claims.UserType == model.UserTypeTemp {
|
||||
// 临时用户,转为正式用户
|
||||
err = l.svcCtx.UserService.TempUserBindUser(l.ctx, session, user.Id)
|
||||
if err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "绑定用户失败: %v", err)
|
||||
}
|
||||
}
|
||||
userID = user.Id
|
||||
}
|
||||
|
||||
// 3. 检查是否已是代理
|
||||
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("您已经是代理"), "")
|
||||
}
|
||||
|
||||
// 4. 必须通过邀请码成为代理(没有其他途径)
|
||||
// 4.1 查询邀请码
|
||||
inviteCodeModel, err := l.svcCtx.AgentInviteCodeModel.FindOneByCode(transCtx, req.InviteCode)
|
||||
if err != nil {
|
||||
if errors.Is(err, model.ErrNotFound) {
|
||||
return errors.Wrapf(xerr.NewErrMsg("邀请码不存在"), "")
|
||||
}
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询邀请码失败, %v", err)
|
||||
}
|
||||
|
||||
// 4.2 验证邀请码状态
|
||||
// 钻石级别的邀请码只能使用一次,使用后立即失效
|
||||
// 普通级别的邀请码可以无限使用
|
||||
if inviteCodeModel.Status != 0 {
|
||||
if inviteCodeModel.Status == 1 {
|
||||
return errors.Wrapf(xerr.NewErrMsg("邀请码已使用"), "")
|
||||
}
|
||||
return errors.Wrapf(xerr.NewErrMsg("邀请码已失效"), "")
|
||||
}
|
||||
|
||||
// 4.3 验证邀请码是否过期
|
||||
if inviteCodeModel.ExpireTime.Valid && inviteCodeModel.ExpireTime.Time.Before(time.Now()) {
|
||||
return errors.Wrapf(xerr.NewErrMsg("邀请码已过期"), "")
|
||||
}
|
||||
|
||||
// 4.4 获取邀请码信息
|
||||
targetLevel := inviteCodeModel.TargetLevel
|
||||
var parentAgentId int64 = 0
|
||||
if inviteCodeModel.AgentId.Valid {
|
||||
parentAgentId = inviteCodeModel.AgentId.Int64
|
||||
}
|
||||
|
||||
// 4.5 创建代理记录
|
||||
newAgent := &model.Agent{
|
||||
UserId: userID,
|
||||
Level: targetLevel,
|
||||
Mobile: encryptedMobile,
|
||||
}
|
||||
if req.Region != "" {
|
||||
newAgent.Region = sql.NullString{String: req.Region, Valid: true}
|
||||
}
|
||||
|
||||
// 4.6 处理上级关系
|
||||
if parentAgentId > 0 {
|
||||
// 代理发放的邀请码,成为该代理的下级
|
||||
parentAgent, err := l.svcCtx.AgentModel.FindOne(transCtx, parentAgentId)
|
||||
if err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询上级代理失败, %v", err)
|
||||
}
|
||||
|
||||
// 验证关系是否允许
|
||||
if newAgent.Level > parentAgent.Level {
|
||||
return errors.Wrapf(xerr.NewErrMsg("代理等级不能高于上级代理"), "")
|
||||
}
|
||||
|
||||
// 查找团队首领
|
||||
teamLeaderId, err := l.findTeamLeader(transCtx, parentAgent.Id)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "查找团队首领失败")
|
||||
}
|
||||
if teamLeaderId > 0 {
|
||||
newAgent.TeamLeaderId = sql.NullInt64{Int64: teamLeaderId, Valid: true}
|
||||
}
|
||||
|
||||
// 先插入代理记录
|
||||
agentResult, err := l.svcCtx.AgentModel.Insert(transCtx, session, newAgent)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "创建代理记录失败")
|
||||
}
|
||||
agentId, _ := agentResult.LastInsertId()
|
||||
newAgent.Id = agentId
|
||||
|
||||
// 建立关系
|
||||
relation := &model.AgentRelation{
|
||||
ParentId: parentAgent.Id,
|
||||
ChildId: agentId,
|
||||
RelationType: 1, // 直接关系
|
||||
}
|
||||
if _, err := l.svcCtx.AgentRelationModel.Insert(transCtx, session, relation); err != nil {
|
||||
return errors.Wrapf(err, "建立代理关系失败")
|
||||
}
|
||||
} else {
|
||||
// 平台发放的钻石邀请码,独立成团队
|
||||
if targetLevel == 3 {
|
||||
agentResult, err := l.svcCtx.AgentModel.Insert(transCtx, session, newAgent)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "创建代理记录失败")
|
||||
}
|
||||
agentId, _ := agentResult.LastInsertId()
|
||||
newAgent.Id = agentId
|
||||
|
||||
// 设置自己为团队首领
|
||||
newAgent.TeamLeaderId = sql.NullInt64{Int64: agentId, Valid: true}
|
||||
if err := l.svcCtx.AgentModel.UpdateWithVersion(transCtx, session, newAgent); err != nil {
|
||||
return errors.Wrapf(err, "更新团队首领失败")
|
||||
}
|
||||
} else {
|
||||
agentResult, err := l.svcCtx.AgentModel.Insert(transCtx, session, newAgent)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "创建代理记录失败")
|
||||
}
|
||||
_, _ = agentResult.LastInsertId()
|
||||
}
|
||||
}
|
||||
|
||||
// 4.7 初始化钱包
|
||||
wallet := &model.AgentWallet{
|
||||
AgentId: newAgent.Id,
|
||||
}
|
||||
if _, err := l.svcCtx.AgentWalletModel.Insert(transCtx, session, wallet); err != nil {
|
||||
return errors.Wrapf(err, "初始化钱包失败")
|
||||
}
|
||||
|
||||
// 4.8 更新邀请码状态
|
||||
// 钻石级别的邀请码只能使用一次,使用后立即失效
|
||||
// 普通级别的邀请码可以无限使用,不更新状态
|
||||
if targetLevel == 3 {
|
||||
// 钻石邀请码:使用后失效
|
||||
inviteCodeModel.Status = 1 // 已使用(使用后立即失效)
|
||||
}
|
||||
// 记录使用信息(用于统计,普通邀请码可以多次使用)
|
||||
inviteCodeModel.UsedUserId = sql.NullInt64{Int64: userID, Valid: true}
|
||||
inviteCodeModel.UsedAgentId = sql.NullInt64{Int64: newAgent.Id, Valid: true}
|
||||
inviteCodeModel.UsedTime = sql.NullTime{Time: time.Now(), Valid: true}
|
||||
if err := l.svcCtx.AgentInviteCodeModel.UpdateWithVersion(transCtx, session, inviteCodeModel); err != nil {
|
||||
return errors.Wrapf(err, "更新邀请码状态失败")
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if transErr != nil {
|
||||
return nil, transErr
|
||||
}
|
||||
|
||||
// 6. 生成并返回token
|
||||
token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID, model.UserTypeNormal)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成token失败: %v", err)
|
||||
}
|
||||
|
||||
now := time.Now().Unix()
|
||||
return &types.AgentApplyResp{
|
||||
AccessToken: token,
|
||||
AccessExpire: now + l.svcCtx.Config.JwtAuth.AccessExpire,
|
||||
RefreshAfter: now + l.svcCtx.Config.JwtAuth.RefreshAfter,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// findTeamLeader 查找团队首领(钻石代理)
|
||||
func (l *ApplyForAgentLogic) findTeamLeader(ctx context.Context, agentId int64) (int64, error) {
|
||||
currentId := agentId
|
||||
maxDepth := 100
|
||||
depth := 0
|
||||
|
||||
for depth < maxDepth {
|
||||
builder := l.svcCtx.AgentRelationModel.SelectBuilder().
|
||||
Where("child_id = ? AND relation_type = ? AND del_state = ?", currentId, 1, 0)
|
||||
relations, err := l.svcCtx.AgentRelationModel.FindAll(ctx, builder, "")
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if len(relations) == 0 {
|
||||
agent, err := l.svcCtx.AgentModel.FindOne(ctx, currentId)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if agent.Level == 3 {
|
||||
return agent.Id, nil
|
||||
}
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
parentAgent, err := l.svcCtx.AgentModel.FindOne(ctx, relations[0].ParentId)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if parentAgent.Level == 3 {
|
||||
return parentAgent.Id, nil
|
||||
}
|
||||
|
||||
currentId = parentAgent.Id
|
||||
depth++
|
||||
}
|
||||
|
||||
return 0, nil
|
||||
}
|
||||
135
app/main/api/internal/logic/agent/applyupgradelogic.go
Normal file
135
app/main/api/internal/logic/agent/applyupgradelogic.go
Normal file
@@ -0,0 +1,135 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"ycc-server/app/main/model"
|
||||
"ycc-server/common/ctxdata"
|
||||
"ycc-server/common/xerr"
|
||||
"ycc-server/pkg/lzkit/lzUtils"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type ApplyUpgradeLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewApplyUpgradeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ApplyUpgradeLogic {
|
||||
return &ApplyUpgradeLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *ApplyUpgradeLogic) ApplyUpgrade(req *types.ApplyUpgradeReq) (resp *types.ApplyUpgradeResp, err error) {
|
||||
userID, err := ctxdata.GetUidFromCtx(l.ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取用户信息失败, %v", err)
|
||||
}
|
||||
|
||||
// 1. 获取代理信息
|
||||
agent, 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)
|
||||
}
|
||||
|
||||
fromLevel := agent.Level
|
||||
toLevel := req.ToLevel
|
||||
|
||||
// 2. 验证升级条件
|
||||
if !l.canUpgrade(agent.Level, toLevel, 1) {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("升级条件不满足"), "")
|
||||
}
|
||||
|
||||
// 3. 计算升级费用和返佣
|
||||
upgradeFee := l.svcCtx.AgentService.GetUpgradeFee(fromLevel, toLevel)
|
||||
rebateAmount := l.svcCtx.AgentService.GetUpgradeRebate(fromLevel, toLevel)
|
||||
|
||||
// 4. 查找原直接上级(用于返佣)
|
||||
var rebateAgentId int64
|
||||
parent, err := l.svcCtx.AgentService.FindDirectParent(l.ctx, agent.Id)
|
||||
if err != nil && !errors.Is(err, model.ErrNotFound) {
|
||||
return nil, errors.Wrapf(err, "查找直接上级失败")
|
||||
}
|
||||
if parent != nil {
|
||||
rebateAgentId = parent.Id
|
||||
}
|
||||
|
||||
// 5. 使用事务处理升级
|
||||
var upgradeId int64
|
||||
err = l.svcCtx.AgentWalletModel.Trans(l.ctx, func(transCtx context.Context, session sqlx.Session) error {
|
||||
// 5.1 创建升级记录
|
||||
upgradeRecord := &model.AgentUpgrade{
|
||||
AgentId: agent.Id,
|
||||
FromLevel: fromLevel,
|
||||
ToLevel: toLevel,
|
||||
UpgradeType: 1, // 自主付费
|
||||
UpgradeFee: upgradeFee,
|
||||
RebateAmount: rebateAmount,
|
||||
Status: 1, // 待处理
|
||||
}
|
||||
if rebateAgentId > 0 {
|
||||
upgradeRecord.RebateAgentId = sql.NullInt64{Int64: rebateAgentId, Valid: true}
|
||||
}
|
||||
|
||||
upgradeResult, err := l.svcCtx.AgentUpgradeModel.Insert(transCtx, session, upgradeRecord)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "创建升级记录失败")
|
||||
}
|
||||
upgradeId, _ = upgradeResult.LastInsertId()
|
||||
|
||||
// 5.2 处理支付(这里假设支付已在外层处理,只记录订单号)
|
||||
// 实际支付应该在创建升级记录之前完成
|
||||
// 注意:支付订单号需要从支付回调中获取,这里暂时留空
|
||||
|
||||
// 5.3 执行升级操作
|
||||
if err := l.svcCtx.AgentService.ProcessUpgrade(transCtx, agent.Id, toLevel, 1, upgradeFee, rebateAmount, "", 0); err != nil {
|
||||
return errors.Wrapf(err, "执行升级操作失败")
|
||||
}
|
||||
|
||||
// 5.4 更新升级记录状态
|
||||
upgradeRecord.Id = upgradeId
|
||||
upgradeRecord.Status = 2 // 已完成
|
||||
upgradeRecord.Remark = lzUtils.StringToNullString("升级成功")
|
||||
if err := l.svcCtx.AgentUpgradeModel.UpdateWithVersion(transCtx, session, upgradeRecord); err != nil {
|
||||
return errors.Wrapf(err, "更新升级记录失败")
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 返回响应(订单号需要从支付回调中获取,这里暂时返回空)
|
||||
return &types.ApplyUpgradeResp{
|
||||
UpgradeId: upgradeId,
|
||||
OrderNo: "", // 需要从支付回调中获取
|
||||
}, nil
|
||||
}
|
||||
|
||||
// canUpgrade 检查是否可以升级
|
||||
func (l *ApplyUpgradeLogic) canUpgrade(fromLevel, toLevel int64, upgradeType int64) bool {
|
||||
if upgradeType == 1 { // 自主付费
|
||||
if fromLevel == 1 { // 普通
|
||||
return toLevel == 2 || toLevel == 3 // 可以升级为黄金或钻石
|
||||
} else if fromLevel == 2 { // 黄金
|
||||
return toLevel == 3 // 可以升级为钻石
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
224
app/main/api/internal/logic/agent/applywithdrawallogic.go
Normal file
224
app/main/api/internal/logic/agent/applywithdrawallogic.go
Normal file
@@ -0,0 +1,224 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
"ycc-server/app/main/model"
|
||||
"ycc-server/common/ctxdata"
|
||||
"ycc-server/common/globalkey"
|
||||
"ycc-server/common/xerr"
|
||||
"ycc-server/pkg/lzkit/lzUtils"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type ApplyWithdrawalLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewApplyWithdrawalLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ApplyWithdrawalLogic {
|
||||
return &ApplyWithdrawalLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *ApplyWithdrawalLogic) ApplyWithdrawal(req *types.ApplyWithdrawalReq) (resp *types.ApplyWithdrawalResp, err error) {
|
||||
userID, err := ctxdata.GetUidFromCtx(l.ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取用户信息失败, %v", err)
|
||||
}
|
||||
|
||||
// 1. 获取代理信息
|
||||
agent, 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. 验证实名认证
|
||||
realName, err := l.svcCtx.AgentRealNameModel.FindOneByAgentId(l.ctx, agent.Id)
|
||||
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)
|
||||
}
|
||||
// 检查是否已通过三要素核验(verify_time不为空表示已通过)
|
||||
if !realName.VerifyTime.Valid {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("请先完成实名认证"), "")
|
||||
}
|
||||
|
||||
// 3. 验证提现金额
|
||||
if req.Amount <= 0 {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("提现金额必须大于0"), "")
|
||||
}
|
||||
|
||||
// 4. 获取钱包信息
|
||||
wallet, err := l.svcCtx.AgentWalletModel.FindOneByAgentId(l.ctx, agent.Id)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询钱包失败, %v", err)
|
||||
}
|
||||
|
||||
// 5. 验证余额
|
||||
if wallet.Balance < req.Amount {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg(fmt.Sprintf("余额不足,当前余额:%.2f", wallet.Balance)), "")
|
||||
}
|
||||
|
||||
// 6. 计算税费
|
||||
yearMonth := int64(time.Now().Year()*100 + int(time.Now().Month()))
|
||||
taxInfo, err := l.calculateTax(l.ctx, agent.Id, req.Amount, yearMonth)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "计算税费失败")
|
||||
}
|
||||
|
||||
// 7. 生成提现单号
|
||||
withdrawNo := fmt.Sprintf("WD%d%d", time.Now().Unix(), agent.Id)
|
||||
|
||||
// 8. 使用事务处理提现申请
|
||||
var withdrawalId int64
|
||||
err = l.svcCtx.AgentWalletModel.Trans(l.ctx, func(transCtx context.Context, session sqlx.Session) error {
|
||||
// 8.1 冻结余额
|
||||
wallet.FrozenBalance += req.Amount
|
||||
wallet.Balance -= req.Amount
|
||||
if err := l.svcCtx.AgentWalletModel.UpdateWithVersion(transCtx, session, wallet); err != nil {
|
||||
return errors.Wrapf(err, "冻结余额失败")
|
||||
}
|
||||
|
||||
// 8.2 创建提现记录
|
||||
withdrawal := &model.AgentWithdrawal{
|
||||
AgentId: agent.Id,
|
||||
WithdrawNo: withdrawNo,
|
||||
PayeeAccount: req.PayeeAccount,
|
||||
PayeeName: req.PayeeName,
|
||||
Amount: req.Amount,
|
||||
ActualAmount: taxInfo.ActualAmount,
|
||||
TaxAmount: taxInfo.TaxAmount,
|
||||
Status: 1, // 处理中(待审核)
|
||||
}
|
||||
|
||||
withdrawalResult, err := l.svcCtx.AgentWithdrawalModel.Insert(transCtx, session, withdrawal)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "创建提现记录失败")
|
||||
}
|
||||
withdrawalId, _ = withdrawalResult.LastInsertId()
|
||||
|
||||
// 8.3 创建扣税记录
|
||||
taxRecord := &model.AgentWithdrawalTax{
|
||||
AgentId: agent.Id,
|
||||
WithdrawalId: withdrawalId,
|
||||
YearMonth: yearMonth,
|
||||
WithdrawalAmount: req.Amount,
|
||||
TaxableAmount: taxInfo.TaxableAmount,
|
||||
TaxRate: taxInfo.TaxRate,
|
||||
TaxAmount: taxInfo.TaxAmount,
|
||||
ActualAmount: taxInfo.ActualAmount,
|
||||
TaxStatus: 1, // 待扣税
|
||||
Remark: lzUtils.StringToNullString("提现申请"),
|
||||
}
|
||||
if _, err := l.svcCtx.AgentWithdrawalTaxModel.Insert(transCtx, session, taxRecord); err != nil {
|
||||
return errors.Wrapf(err, "创建扣税记录失败")
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &types.ApplyWithdrawalResp{
|
||||
WithdrawalId: withdrawalId,
|
||||
WithdrawalNo: withdrawNo,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// TaxInfo 税费信息
|
||||
type TaxInfo struct {
|
||||
TaxableAmount float64 // 应税金额
|
||||
TaxRate float64 // 税率
|
||||
TaxAmount float64 // 税费金额
|
||||
ActualAmount float64 // 实际到账金额
|
||||
}
|
||||
|
||||
// calculateTax 计算税费
|
||||
func (l *ApplyWithdrawalLogic) calculateTax(ctx context.Context, agentId int64, amount float64, yearMonth int64) (*TaxInfo, error) {
|
||||
// 获取税率配置(默认6%)
|
||||
taxRate := 0.06
|
||||
config, err := l.svcCtx.AgentConfigModel.FindOneByConfigKey(ctx, "tax_rate")
|
||||
if err == nil {
|
||||
if parsedRate, parseErr := l.parseFloat(config.ConfigValue); parseErr == nil {
|
||||
taxRate = parsedRate
|
||||
}
|
||||
}
|
||||
|
||||
// 查询本月已提现金额
|
||||
builder := l.svcCtx.AgentWithdrawalTaxModel.SelectBuilder().
|
||||
Where("agent_id = ? AND year_month = ? AND del_state = ?", agentId, yearMonth, globalkey.DelStateNo)
|
||||
taxRecords, err := l.svcCtx.AgentWithdrawalTaxModel.FindAll(ctx, builder, "")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "查询月度提现记录失败")
|
||||
}
|
||||
|
||||
// 计算本月累计提现金额
|
||||
monthlyTotal := 0.0
|
||||
for _, record := range taxRecords {
|
||||
monthlyTotal += record.WithdrawalAmount
|
||||
}
|
||||
|
||||
// 获取免税额度配置(默认0,即无免税额度)
|
||||
exemptionAmount := 0.0
|
||||
exemptionConfig, err := l.svcCtx.AgentConfigModel.FindOneByConfigKey(ctx, "tax_exemption_amount")
|
||||
if err == nil {
|
||||
if parsedAmount, parseErr := l.parseFloat(exemptionConfig.ConfigValue); parseErr == nil {
|
||||
exemptionAmount = parsedAmount
|
||||
}
|
||||
}
|
||||
|
||||
// 计算应税金额
|
||||
// 如果本月累计 + 本次提现金额 <= 免税额度,则本次提现免税
|
||||
// 否则,应税金额 = 本次提现金额 - (免税额度 - 本月累计)(如果免税额度 > 本月累计)
|
||||
taxableAmount := amount
|
||||
if exemptionAmount > 0 {
|
||||
remainingExemption := exemptionAmount - monthlyTotal
|
||||
if remainingExemption > 0 {
|
||||
if amount <= remainingExemption {
|
||||
// 本次提现完全免税
|
||||
taxableAmount = 0
|
||||
} else {
|
||||
// 部分免税
|
||||
taxableAmount = amount - remainingExemption
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 计算税费
|
||||
taxAmount := taxableAmount * taxRate
|
||||
actualAmount := amount - taxAmount
|
||||
|
||||
return &TaxInfo{
|
||||
TaxableAmount: taxableAmount,
|
||||
TaxRate: taxRate,
|
||||
TaxAmount: taxAmount,
|
||||
ActualAmount: actualAmount,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// parseFloat 解析浮点数
|
||||
func (l *ApplyWithdrawalLogic) parseFloat(s string) (float64, error) {
|
||||
var result float64
|
||||
_, err := fmt.Sscanf(s, "%f", &result)
|
||||
return result, err
|
||||
}
|
||||
115
app/main/api/internal/logic/agent/generateinvitecodelogic.go
Normal file
115
app/main/api/internal/logic/agent/generateinvitecodelogic.go
Normal file
@@ -0,0 +1,115 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"time"
|
||||
"ycc-server/app/main/model"
|
||||
"ycc-server/common/ctxdata"
|
||||
"ycc-server/common/tool"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type GenerateInviteCodeLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewGenerateInviteCodeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GenerateInviteCodeLogic {
|
||||
return &GenerateInviteCodeLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *GenerateInviteCodeLogic) GenerateInviteCode(req *types.GenerateInviteCodeReq) (resp *types.GenerateInviteCodeResp, err error) {
|
||||
// 1. 获取当前代理信息
|
||||
userID, err := ctxdata.GetUidFromCtx(l.ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取用户信息失败, %v", err)
|
||||
}
|
||||
|
||||
agent, 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. 验证生成数量
|
||||
if req.Count <= 0 || req.Count > 100 {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("生成数量必须在1-100之间"), "")
|
||||
}
|
||||
|
||||
// 3. 生成邀请码
|
||||
codes := make([]string, 0, req.Count)
|
||||
var expireTime sql.NullTime
|
||||
if req.ExpireDays > 0 {
|
||||
expireTime = sql.NullTime{
|
||||
Time: time.Now().AddDate(0, 0, int(req.ExpireDays)),
|
||||
Valid: true,
|
||||
}
|
||||
}
|
||||
|
||||
err = l.svcCtx.AgentInviteCodeModel.Trans(l.ctx, func(transCtx context.Context, session sqlx.Session) error {
|
||||
for i := int64(0); i < req.Count; i++ {
|
||||
// 生成8位随机邀请码(大小写字母+数字)
|
||||
var code string
|
||||
maxRetries := 10 // 最大重试次数
|
||||
for retry := 0; retry < maxRetries; retry++ {
|
||||
code = tool.Krand(8, tool.KC_RAND_KIND_ALL)
|
||||
// 检查邀请码是否已存在
|
||||
_, err := l.svcCtx.AgentInviteCodeModel.FindOneByCode(transCtx, code)
|
||||
if err != nil {
|
||||
if errors.Is(err, model.ErrNotFound) {
|
||||
// 邀请码不存在,可以使用
|
||||
break
|
||||
}
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "检查邀请码失败, %v", err)
|
||||
}
|
||||
// 邀请码已存在,继续生成
|
||||
if retry == maxRetries-1 {
|
||||
return errors.Wrapf(xerr.NewErrMsg("生成邀请码失败,请重试"), "")
|
||||
}
|
||||
}
|
||||
|
||||
// 创建邀请码记录
|
||||
inviteCode := &model.AgentInviteCode{
|
||||
Code: code,
|
||||
AgentId: sql.NullInt64{Int64: agent.Id, Valid: true},
|
||||
TargetLevel: 1, // 代理发放的邀请码,目标等级为普通代理
|
||||
Status: 0, // 未使用
|
||||
ExpireTime: expireTime,
|
||||
Remark: sql.NullString{String: req.Remark, Valid: req.Remark != ""},
|
||||
}
|
||||
|
||||
_, err := l.svcCtx.AgentInviteCodeModel.Insert(transCtx, session, inviteCode)
|
||||
if err != nil {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "创建邀请码失败, %v", err)
|
||||
}
|
||||
|
||||
codes = append(codes, code)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &types.GenerateInviteCodeResp{
|
||||
Codes: codes,
|
||||
}, nil
|
||||
}
|
||||
158
app/main/api/internal/logic/agent/generatinglinklogic.go
Normal file
158
app/main/api/internal/logic/agent/generatinglinklogic.go
Normal file
@@ -0,0 +1,158 @@
|
||||
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
|
||||
}
|
||||
114
app/main/api/internal/logic/agent/getagentinfologic.go
Normal file
114
app/main/api/internal/logic/agent/getagentinfologic.go
Normal file
@@ -0,0 +1,114 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"ycc-server/common/ctxdata"
|
||||
"ycc-server/common/xerr"
|
||||
"ycc-server/pkg/lzkit/crypto"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"ycc-server/app/main/api/internal/svc"
|
||||
"ycc-server/app/main/api/internal/types"
|
||||
"ycc-server/app/main/model"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type GetAgentInfoLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewGetAgentInfoLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetAgentInfoLogic {
|
||||
return &GetAgentInfoLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *GetAgentInfoLogic) GetAgentInfo() (resp *types.AgentInfoResp, err error) {
|
||||
userID, err := ctxdata.GetUidFromCtx(l.ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取用户信息失败, %v", err)
|
||||
}
|
||||
|
||||
agent, err := l.svcCtx.AgentModel.FindOneByUserId(l.ctx, userID)
|
||||
if err != nil {
|
||||
if errors.Is(err, model.ErrNotFound) {
|
||||
// 不是代理,返回空信息
|
||||
return &types.AgentInfoResp{
|
||||
AgentId: 0,
|
||||
Level: 0,
|
||||
LevelName: "",
|
||||
Region: "",
|
||||
Mobile: "",
|
||||
WechatId: "",
|
||||
TeamLeaderId: 0,
|
||||
IsRealName: false,
|
||||
}, nil
|
||||
}
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询代理信息失败, %v", err)
|
||||
}
|
||||
|
||||
// 解密手机号
|
||||
mobile, err := crypto.DecryptMobile(agent.Mobile, l.svcCtx.Config.Encrypt.SecretKey)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "解密手机号失败: %v", err)
|
||||
}
|
||||
|
||||
// 查询实名认证状态
|
||||
isRealName := false
|
||||
agentRealName, err := l.svcCtx.AgentRealNameModel.FindOneByAgentId(l.ctx, agent.Id)
|
||||
if err != nil && !errors.Is(err, model.ErrNotFound) {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询实名认证失败, %v", err)
|
||||
}
|
||||
if agentRealName != nil && agentRealName.VerifyTime.Valid { // verify_time不为空表示已通过三要素核验
|
||||
isRealName = true
|
||||
}
|
||||
|
||||
// 获取微信号
|
||||
wechatId := ""
|
||||
if agent.WechatId.Valid {
|
||||
wechatId = agent.WechatId.String
|
||||
}
|
||||
|
||||
// 获取团队首领ID
|
||||
teamLeaderId := int64(0)
|
||||
if agent.TeamLeaderId.Valid {
|
||||
teamLeaderId = agent.TeamLeaderId.Int64
|
||||
}
|
||||
|
||||
// 获取区域
|
||||
region := ""
|
||||
if agent.Region.Valid {
|
||||
region = agent.Region.String
|
||||
}
|
||||
|
||||
return &types.AgentInfoResp{
|
||||
AgentId: agent.Id,
|
||||
Level: agent.Level,
|
||||
LevelName: l.getLevelName(agent.Level),
|
||||
Region: region,
|
||||
Mobile: mobile,
|
||||
WechatId: wechatId,
|
||||
TeamLeaderId: teamLeaderId,
|
||||
IsRealName: isRealName,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// getLevelName 获取等级名称
|
||||
func (l *GetAgentInfoLogic) getLevelName(level int64) string {
|
||||
switch level {
|
||||
case 1:
|
||||
return "普通"
|
||||
case 2:
|
||||
return "黄金"
|
||||
case 3:
|
||||
return "钻石"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
147
app/main/api/internal/logic/agent/getagentproductconfiglogic.go
Normal file
147
app/main/api/internal/logic/agent/getagentproductconfiglogic.go
Normal file
@@ -0,0 +1,147 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
"ycc-server/app/main/model"
|
||||
"ycc-server/common/ctxdata"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"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 GetAgentProductConfigLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewGetAgentProductConfigLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetAgentProductConfigLogic {
|
||||
return &GetAgentProductConfigLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *GetAgentProductConfigLogic) GetAgentProductConfig() (resp *types.AgentProductConfigResp, 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)
|
||||
}
|
||||
priceThreshold, err := l.getConfigFloat("price_threshold")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取提价标准阈值配置失败, %v", err)
|
||||
}
|
||||
priceFeeRate, err := l.getConfigFloat("price_fee_rate")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取提价手续费比例配置失败, %v", err)
|
||||
}
|
||||
|
||||
// 3. 计算等级加成
|
||||
levelBonus := l.getLevelBonus(agentModel.Level)
|
||||
|
||||
// 4. 查询所有产品配置
|
||||
builder := l.svcCtx.AgentProductConfigModel.SelectBuilder()
|
||||
productConfigs, err := l.svcCtx.AgentProductConfigModel.FindAll(l.ctx, builder, "")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询产品配置失败, %v", err)
|
||||
}
|
||||
|
||||
// 5. 组装响应数据
|
||||
var respList []types.ProductConfigItem
|
||||
for _, productConfig := range productConfigs {
|
||||
// 使用产品配置中的基础底价,如果没有则使用系统配置的基础底价
|
||||
productBasePrice := basePrice
|
||||
if productConfig.BasePrice > 0 {
|
||||
productBasePrice = productConfig.BasePrice
|
||||
}
|
||||
|
||||
// 计算该产品的实际底价
|
||||
productActualBasePrice := productBasePrice + float64(levelBonus)
|
||||
|
||||
// 价格范围:实际底价 ≤ 设定价格 ≤ 系统价格上限(或产品配置的最高价格)
|
||||
priceRangeMin := productActualBasePrice
|
||||
priceRangeMax := systemMaxPrice
|
||||
if productConfig.SystemMaxPrice > 0 && productConfig.SystemMaxPrice < systemMaxPrice {
|
||||
priceRangeMax = productConfig.SystemMaxPrice
|
||||
}
|
||||
|
||||
// 使用产品配置的提价阈值和手续费比例,如果没有则使用系统配置
|
||||
productPriceThreshold := priceThreshold
|
||||
if productConfig.PriceThreshold.Valid && productConfig.PriceThreshold.Float64 > 0 {
|
||||
productPriceThreshold = productConfig.PriceThreshold.Float64
|
||||
}
|
||||
productPriceFeeRate := priceFeeRate
|
||||
if productConfig.PriceFeeRate.Valid && productConfig.PriceFeeRate.Float64 > 0 {
|
||||
productPriceFeeRate = productConfig.PriceFeeRate.Float64
|
||||
}
|
||||
|
||||
respList = append(respList, types.ProductConfigItem{
|
||||
ProductId: productConfig.ProductId,
|
||||
ProductName: productConfig.ProductName,
|
||||
BasePrice: productBasePrice,
|
||||
LevelBonus: float64(levelBonus),
|
||||
ActualBasePrice: productActualBasePrice,
|
||||
PriceRangeMin: priceRangeMin,
|
||||
PriceRangeMax: priceRangeMax,
|
||||
PriceThreshold: productPriceThreshold,
|
||||
PriceFeeRate: productPriceFeeRate,
|
||||
})
|
||||
}
|
||||
|
||||
return &types.AgentProductConfigResp{
|
||||
List: respList,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// getLevelBonus 获取等级加成
|
||||
func (l *GetAgentProductConfigLogic) getLevelBonus(level int64) int64 {
|
||||
switch level {
|
||||
case 1: // 普通
|
||||
return 6
|
||||
case 2: // 黄金
|
||||
return 3
|
||||
case 3: // 钻石
|
||||
return 0
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
// getConfigFloat 获取配置值(浮点数)
|
||||
func (l *GetAgentProductConfigLogic) 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
|
||||
}
|
||||
102
app/main/api/internal/logic/agent/getcommissionlistlogic.go
Normal file
102
app/main/api/internal/logic/agent/getcommissionlistlogic.go
Normal file
@@ -0,0 +1,102 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"ycc-server/app/main/model"
|
||||
"ycc-server/common/ctxdata"
|
||||
"ycc-server/common/globalkey"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"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 GetCommissionListLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewGetCommissionListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetCommissionListLogic {
|
||||
return &GetCommissionListLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *GetCommissionListLogic) GetCommissionList(req *types.GetCommissionListReq) (resp *types.GetCommissionListResp, err error) {
|
||||
userID, err := ctxdata.GetUidFromCtx(l.ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取用户信息失败, %v", err)
|
||||
}
|
||||
|
||||
// 1. 获取代理信息
|
||||
agent, 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. 构建查询条件
|
||||
builder := l.svcCtx.AgentCommissionModel.SelectBuilder().
|
||||
Where("agent_id = ? AND del_state = ?", agent.Id, globalkey.DelStateNo).
|
||||
OrderBy("create_time DESC")
|
||||
|
||||
// 3. 分页查询
|
||||
page := req.Page
|
||||
if page <= 0 {
|
||||
page = 1
|
||||
}
|
||||
pageSize := req.PageSize
|
||||
if pageSize <= 0 {
|
||||
pageSize = 20
|
||||
}
|
||||
offset := (page - 1) * pageSize
|
||||
|
||||
// 4. 查询总数
|
||||
total, err := l.svcCtx.AgentCommissionModel.FindCount(l.ctx, builder, "")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询佣金总数失败, %v", err)
|
||||
}
|
||||
|
||||
// 5. 查询列表
|
||||
builder = builder.Limit(uint64(pageSize)).Offset(uint64(offset))
|
||||
commissions, err := l.svcCtx.AgentCommissionModel.FindAll(l.ctx, builder, "")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询佣金列表失败, %v", err)
|
||||
}
|
||||
|
||||
// 6. 组装响应
|
||||
var list []types.CommissionItem
|
||||
for _, commission := range commissions {
|
||||
// 查询产品名称
|
||||
productName := ""
|
||||
if commission.ProductId > 0 {
|
||||
product, err := l.svcCtx.ProductModel.FindOne(l.ctx, commission.ProductId)
|
||||
if err == nil {
|
||||
productName = product.ProductName
|
||||
}
|
||||
}
|
||||
|
||||
list = append(list, types.CommissionItem{
|
||||
Id: commission.Id,
|
||||
OrderId: commission.OrderId,
|
||||
ProductName: productName,
|
||||
Amount: commission.Amount,
|
||||
Status: commission.Status,
|
||||
CreateTime: commission.CreateTime.Format("2006-01-02 15:04:05"),
|
||||
})
|
||||
}
|
||||
|
||||
return &types.GetCommissionListResp{
|
||||
Total: total,
|
||||
List: list,
|
||||
}, nil
|
||||
}
|
||||
89
app/main/api/internal/logic/agent/getinvitecodelistlogic.go
Normal file
89
app/main/api/internal/logic/agent/getinvitecodelistlogic.go
Normal file
@@ -0,0 +1,89 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"ycc-server/app/main/model"
|
||||
"ycc-server/common/ctxdata"
|
||||
"ycc-server/common/globalkey"
|
||||
"ycc-server/common/xerr"
|
||||
|
||||
"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 GetInviteCodeListLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewGetInviteCodeListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetInviteCodeListLogic {
|
||||
return &GetInviteCodeListLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *GetInviteCodeListLogic) GetInviteCodeList(req *types.GetInviteCodeListReq) (resp *types.GetInviteCodeListResp, err error) {
|
||||
// 1. 获取当前代理信息
|
||||
userID, err := ctxdata.GetUidFromCtx(l.ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取用户信息失败, %v", err)
|
||||
}
|
||||
|
||||
agent, 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. 构建查询条件
|
||||
builder := l.svcCtx.AgentInviteCodeModel.SelectBuilder().
|
||||
Where("agent_id = ? AND del_state = ?", agent.Id, globalkey.DelStateNo)
|
||||
|
||||
if req.Status >= 0 {
|
||||
builder = builder.Where("status = ?", req.Status)
|
||||
}
|
||||
|
||||
// 3. 分页查询
|
||||
list, total, err := l.svcCtx.AgentInviteCodeModel.FindPageListByPageWithTotal(l.ctx, builder, req.Page, req.PageSize, "create_time DESC")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询邀请码列表失败, %v", err)
|
||||
}
|
||||
|
||||
// 4. 格式化返回数据
|
||||
items := make([]types.InviteCodeItem, 0, len(list))
|
||||
for _, v := range list {
|
||||
item := types.InviteCodeItem{
|
||||
Id: v.Id,
|
||||
Code: v.Code,
|
||||
TargetLevel: v.TargetLevel,
|
||||
Status: v.Status,
|
||||
CreateTime: v.CreateTime.Format("2006-01-02 15:04:05"),
|
||||
}
|
||||
|
||||
if v.UsedTime.Valid {
|
||||
item.UsedTime = v.UsedTime.Time.Format("2006-01-02 15:04:05")
|
||||
}
|
||||
if v.ExpireTime.Valid {
|
||||
item.ExpireTime = v.ExpireTime.Time.Format("2006-01-02 15:04:05")
|
||||
}
|
||||
if v.Remark.Valid {
|
||||
item.Remark = v.Remark.String
|
||||
}
|
||||
|
||||
items = append(items, item)
|
||||
}
|
||||
|
||||
return &types.GetInviteCodeListResp{
|
||||
Total: total,
|
||||
List: items,
|
||||
}, nil
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user