From d7f8e9c090285afbcdc00fc104cf143e3cff6231 Mon Sep 17 00:00:00 2001 From: liangzai <2440983361@qq.com> Date: Sat, 10 May 2025 21:43:10 +0800 Subject: [PATCH] add agent stats --- app/user/cmd/api/desc/agent.api | 66 ++++++ ...entsubordinatecontributiondetailhandler.go | 29 +++ .../agent/getagentsubordinatelisthandler.go | 29 +++ app/user/cmd/api/internal/handler/routes.go | 12 +- ...agentsubordinatecontributiondetaillogic.go | 200 ++++++++++++++++++ .../agent/getagentsubordinatelistlogic.go | 173 +++++++++++++++ app/user/cmd/api/internal/types/types.go | 66 +++++- app/user/model/agentClosureModel.go | 72 +++++++ gen_api.ps1 | 2 + 9 files changed, 645 insertions(+), 4 deletions(-) create mode 100644 app/user/cmd/api/internal/handler/agent/getagentsubordinatecontributiondetailhandler.go create mode 100644 app/user/cmd/api/internal/handler/agent/getagentsubordinatelisthandler.go create mode 100644 app/user/cmd/api/internal/logic/agent/getagentsubordinatecontributiondetaillogic.go create mode 100644 app/user/cmd/api/internal/logic/agent/getagentsubordinatelistlogic.go create mode 100644 gen_api.ps1 diff --git a/app/user/cmd/api/desc/agent.api b/app/user/cmd/api/desc/agent.api index bcfdc95..2cb8462 100644 --- a/app/user/cmd/api/desc/agent.api +++ b/app/user/cmd/api/desc/agent.api @@ -57,6 +57,14 @@ service main { // 获取推广定价配置 @handler GetAgentProductConfig get /product_config returns (AgentProductConfigResp) + + // 获取下级分页列表 + @handler GetAgentSubordinateList + get /subordinate/list (GetAgentSubordinateListReq) returns (GetAgentSubordinateListResp) + + // 下级贡献详情 + @handler GetAgentSubordinateContributionDetail + get /subordinate/contribution/detail (GetAgentSubordinateContributionDetailReq) returns (GetAgentSubordinateContributionDetailResp) } type ( @@ -84,6 +92,64 @@ type ( AgentProductConfigResp { AgentProductConfig []AgentProductConfig } + + GetAgentSubordinateListReq { + Page int64 `form:"page"` // 页码 + PageSize int64 `form:"page_size"` // 每页数据量 + } + GetAgentSubordinateListResp { + Total int64 `json:"total"` // 总记录数 + List []AgentSubordinateList `json:"list"` // 查询列表 + } + AgentSubordinateList { + ID int64 `json:"id"` + Mobile string `json:"mobile"` + CreateTime string `json:"create_time"` + LevelName string `json:"level_name"` + TotalOrders int64 `json:"total_orders"` // 总单量 + TotalEarnings float64 `json:"total_earnings"` // 总金额 + TotalContribution float64 `json:"total_contribution"` // 总贡献 + } + GetAgentSubordinateContributionDetailReq { + Page int64 `form:"page"` // 页码 + PageSize int64 `form:"page_size"` // 每页数据量 + SubordinateID int64 `form:"subordinate_id"` // 下级ID + } + GetAgentSubordinateContributionDetailResp { + Mobile string `json:"mobile"` + Total int64 `json:"total"` // 总记录数 + CreateTime string `json:"create_time"` + TotalEarnings float64 `json:"total_earnings"` // 总金额 + TotalContribution float64 `json:"total_contribution"` // 总贡献 + TotalOrders int64 `json:"total_orders"` // 总单量 + LevelName string `json:"level_name"` // 等级名称 + List []AgentSubordinateContributionDetail `json:"list"` // 查询列表 + Stats AgentSubordinateContributionStats `json:"stats"` // 统计数据 + } + AgentSubordinateContributionDetail { + ID int64 `json:"id"` + CreateTime string `json:"create_time"` + Amount float64 `json:"amount"` + Type string `json:"type"` + } + AgentSubordinateContributionStats { + CostCount int64 `json:"cost_count"` // 成本扣除次数 + CostAmount float64 `json:"cost_amount"` // 成本扣除总额 + PricingCount int64 `json:"pricing_count"` // 定价扣除次数 + PricingAmount float64 `json:"pricing_amount"` // 定价扣除总额 + DescendantPromotionCount int64 `json:"descendant_promotion_count"` // 下级推广次数 + DescendantPromotionAmount float64 `json:"descendant_promotion_amount"` // 下级推广总额 + DescendantUpgradeVipCount int64 `json:"descendant_upgrade_vip_count"` // 下级升级VIP次数 + DescendantUpgradeVipAmount float64 `json:"descendant_upgrade_vip_amount"` // 下级升级VIP总额 + DescendantUpgradeSvipCount int64 `json:"descendant_upgrade_svip_count"` // 下级升级SVIP次数 + DescendantUpgradeSvipAmount float64 `json:"descendant_upgrade_svip_amount"` // 下级升级SVIP总额 + DescendantStayActiveCount int64 `json:"descendant_stay_active_count"` // 下级保持活跃次数 + DescendantStayActiveAmount float64 `json:"descendant_stay_active_amount"` // 下级保持活跃总额 + DescendantNewActiveCount int64 `json:"descendant_new_active_count"` // 下级新增活跃次数 + DescendantNewActiveAmount float64 `json:"descendant_new_active_amount"` // 下级新增活跃总额 + DescendantWithdrawCount int64 `json:"descendant_withdraw_count"` // 下级提现次数 + DescendantWithdrawAmount float64 `json:"descendant_withdraw_amount"` // 下级提现总额 + } ) @server ( diff --git a/app/user/cmd/api/internal/handler/agent/getagentsubordinatecontributiondetailhandler.go b/app/user/cmd/api/internal/handler/agent/getagentsubordinatecontributiondetailhandler.go new file mode 100644 index 0000000..d3dfc81 --- /dev/null +++ b/app/user/cmd/api/internal/handler/agent/getagentsubordinatecontributiondetailhandler.go @@ -0,0 +1,29 @@ +package agent + +import ( + "net/http" + + "github.com/zeromicro/go-zero/rest/httpx" + "tydata-server/app/user/cmd/api/internal/logic/agent" + "tydata-server/app/user/cmd/api/internal/svc" + "tydata-server/app/user/cmd/api/internal/types" + "tydata-server/common/result" + "tydata-server/pkg/lzkit/validator" +) + +func GetAgentSubordinateContributionDetailHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req types.GetAgentSubordinateContributionDetailReq + if err := httpx.Parse(r, &req); err != nil { + result.ParamErrorResult(r, w, err) + return + } + if err := validator.Validate(req); err != nil { + result.ParamValidateErrorResult(r, w, err) + return + } + l := agent.NewGetAgentSubordinateContributionDetailLogic(r.Context(), svcCtx) + resp, err := l.GetAgentSubordinateContributionDetail(&req) + result.HttpResult(r, w, resp, err) + } +} diff --git a/app/user/cmd/api/internal/handler/agent/getagentsubordinatelisthandler.go b/app/user/cmd/api/internal/handler/agent/getagentsubordinatelisthandler.go new file mode 100644 index 0000000..15bcebe --- /dev/null +++ b/app/user/cmd/api/internal/handler/agent/getagentsubordinatelisthandler.go @@ -0,0 +1,29 @@ +package agent + +import ( + "net/http" + + "github.com/zeromicro/go-zero/rest/httpx" + "tydata-server/app/user/cmd/api/internal/logic/agent" + "tydata-server/app/user/cmd/api/internal/svc" + "tydata-server/app/user/cmd/api/internal/types" + "tydata-server/common/result" + "tydata-server/pkg/lzkit/validator" +) + +func GetAgentSubordinateListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req types.GetAgentSubordinateListReq + if err := httpx.Parse(r, &req); err != nil { + result.ParamErrorResult(r, w, err) + return + } + if err := validator.Validate(req); err != nil { + result.ParamValidateErrorResult(r, w, err) + return + } + l := agent.NewGetAgentSubordinateListLogic(r.Context(), svcCtx) + resp, err := l.GetAgentSubordinateList(&req) + result.HttpResult(r, w, resp, err) + } +} diff --git a/app/user/cmd/api/internal/handler/routes.go b/app/user/cmd/api/internal/handler/routes.go index d4ec417..aaf6a06 100644 --- a/app/user/cmd/api/internal/handler/routes.go +++ b/app/user/cmd/api/internal/handler/routes.go @@ -1,6 +1,4 @@ // Code generated by goctl. DO NOT EDIT. -// goctl 1.7.3 - package handler import ( @@ -42,6 +40,16 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { Path: "/product_config", Handler: agent.GetAgentProductConfigHandler(serverCtx), }, + { + Method: http.MethodGet, + Path: "/subordinate/contribution/detail", + Handler: agent.GetAgentSubordinateContributionDetailHandler(serverCtx), + }, + { + Method: http.MethodGet, + Path: "/subordinate/list", + Handler: agent.GetAgentSubordinateListHandler(serverCtx), + }, }, rest.WithJwt(serverCtx.Config.JwtAuth.AccessSecret), rest.WithPrefix("/api/v1/agent"), diff --git a/app/user/cmd/api/internal/logic/agent/getagentsubordinatecontributiondetaillogic.go b/app/user/cmd/api/internal/logic/agent/getagentsubordinatecontributiondetaillogic.go new file mode 100644 index 0000000..52d0530 --- /dev/null +++ b/app/user/cmd/api/internal/logic/agent/getagentsubordinatecontributiondetaillogic.go @@ -0,0 +1,200 @@ +package agent + +import ( + "context" + + "tydata-server/app/user/cmd/api/internal/svc" + "tydata-server/app/user/cmd/api/internal/types" + "tydata-server/common/ctxdata" + "tydata-server/common/xerr" + "tydata-server/pkg/lzkit/crypto" + + "github.com/Masterminds/squirrel" + "github.com/pkg/errors" + "github.com/zeromicro/go-zero/core/logx" +) + +type GetAgentSubordinateContributionDetailLogic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +func NewGetAgentSubordinateContributionDetailLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetAgentSubordinateContributionDetailLogic { + return &GetAgentSubordinateContributionDetailLogic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *GetAgentSubordinateContributionDetailLogic) GetAgentSubordinateContributionDetail(req *types.GetAgentSubordinateContributionDetailReq) (resp *types.GetAgentSubordinateContributionDetailResp, err error) { + userID, err := ctxdata.GetUidFromCtx(l.ctx) + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取代理下级贡献详情, 获取用户ID%v", err) + } + + // 获取当前代理信息 + agentModel, err := l.svcCtx.AgentModel.FindOneByUserId(l.ctx, userID) + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取代理下级贡献详情, 获取代理信息%v", err) + } + + // 获取下级代理信息 + subordinateAgent, err := l.svcCtx.AgentModel.FindOne(l.ctx, req.SubordinateID) + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取代理下级贡献详情, 获取下级代理信息%v", err) + } + + // 验证是否是当前代理的下级 + closureBuilder := l.svcCtx.AgentClosureModel.SelectBuilder().Where(squirrel.Eq{ + "ancestor_id": agentModel.Id, + "descendant_id": req.SubordinateID, + }) + closureList, err := l.svcCtx.AgentClosureModel.FindAll(l.ctx, closureBuilder, "create_time DESC") + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取代理下级贡献详情, 验证代理关系%v", err) + } + if len(closureList) == 0 { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取代理下级贡献详情, 非法的代理关系") + } + closure := closureList[0] + + // 获取佣金扣除记录 + deductionBuilder := l.svcCtx.AgentCommissionDeductionModel.SelectBuilder().Where(squirrel.Eq{ + "agent_id": agentModel.Id, + "deducted_agent_id": req.SubordinateID, + }) + deductionList, err := l.svcCtx.AgentCommissionDeductionModel.FindAll(l.ctx, deductionBuilder, "create_time DESC") + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取代理下级贡献详情, 获取佣金扣除记录%v", err) + } + + // 获取奖励记录 + rewardsBuilder := l.svcCtx.AgentRewardsModel.SelectBuilder().Where(squirrel.Eq{ + "agent_id": agentModel.Id, + "relation_agent_id": req.SubordinateID, + }) + rewards, err := l.svcCtx.AgentRewardsModel.FindAll(l.ctx, rewardsBuilder, "create_time DESC") + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取代理下级贡献详情, 获取奖励记录%v", err) + } + + // 计算总贡献 + var totalContribution float64 + for _, v := range deductionList { + totalContribution += v.Amount + } + // 加上奖励金额 + for _, v := range rewards { + totalContribution += v.Amount + } + + // 获取佣金记录 + commissionBuilder := l.svcCtx.AgentCommissionModel.SelectBuilder().Where(squirrel.Eq{ + "agent_id": req.SubordinateID, + }) + commissionList, err := l.svcCtx.AgentCommissionModel.FindAll(l.ctx, commissionBuilder, "create_time DESC") + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取代理下级贡献详情, 获取佣金记录%v", err) + } + + // 计算总收益和总单量 + var totalEarnings float64 + for _, v := range commissionList { + totalEarnings += v.Amount + } + + // 初始化统计数据 + stats := types.AgentSubordinateContributionStats{ + CostCount: 0, + CostAmount: 0, + PricingCount: 0, + PricingAmount: 0, + DescendantPromotionCount: 0, + DescendantPromotionAmount: 0, + DescendantUpgradeVipCount: 0, + DescendantUpgradeVipAmount: 0, + DescendantUpgradeSvipCount: 0, + DescendantUpgradeSvipAmount: 0, + DescendantStayActiveCount: 0, + DescendantStayActiveAmount: 0, + DescendantNewActiveCount: 0, + DescendantNewActiveAmount: 0, + DescendantWithdrawCount: 0, + DescendantWithdrawAmount: 0, + } + + // 统计佣金扣除记录 + for _, v := range deductionList { + switch v.Type { + case "cost": + stats.CostCount++ + stats.CostAmount += v.Amount + case "pricing": + stats.PricingCount++ + stats.PricingAmount += v.Amount + } + } + + // 统计奖励记录 + for _, v := range rewards { + switch v.Type { + case "descendant_promotion": + stats.DescendantPromotionCount++ + stats.DescendantPromotionAmount += v.Amount + case "descendant_upgrade_vip": + stats.DescendantUpgradeVipCount++ + stats.DescendantUpgradeVipAmount += v.Amount + case "descendant_upgrade_svip": + stats.DescendantUpgradeSvipCount++ + stats.DescendantUpgradeSvipAmount += v.Amount + case "descendant_stay_active": + stats.DescendantStayActiveCount++ + stats.DescendantStayActiveAmount += v.Amount + case "descendant_new_active": + stats.DescendantNewActiveCount++ + stats.DescendantNewActiveAmount += v.Amount + case "descendant_withdraw": + stats.DescendantWithdrawCount++ + stats.DescendantWithdrawAmount += v.Amount + } + } + + // 解密手机号 + secretKey := l.svcCtx.Config.Encrypt.SecretKey + mobile, err := crypto.DecryptMobile(subordinateAgent.Mobile, secretKey) + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取代理下级贡献详情, 解密手机号失败: %v", err) + } + + // 获取合并后的分页列表 + unionDetails, total, err := l.svcCtx.AgentClosureModel.FindUnionPageListByPageWithTotal(l.ctx, agentModel.Id, req.SubordinateID, req.Page, req.PageSize) + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取代理下级贡献详情, 获取分页列表%v", err) + } + + // 转换为响应类型 + detailList := make([]types.AgentSubordinateContributionDetail, 0, len(unionDetails)) + for _, v := range unionDetails { + detail := types.AgentSubordinateContributionDetail{ + ID: v.Id, + CreateTime: v.CreateTime, + Amount: v.Amount, + Type: v.Type, + } + detailList = append(detailList, detail) + } + + return &types.GetAgentSubordinateContributionDetailResp{ + Mobile: maskPhone(mobile), + Total: total, + CreateTime: closure.CreateTime.Format("2006-01-02 15:04:05"), + TotalEarnings: totalEarnings, + TotalContribution: totalContribution, + TotalOrders: int64(len(commissionList)), + LevelName: subordinateAgent.LevelName, + List: detailList, + Stats: stats, + }, nil +} diff --git a/app/user/cmd/api/internal/logic/agent/getagentsubordinatelistlogic.go b/app/user/cmd/api/internal/logic/agent/getagentsubordinatelistlogic.go new file mode 100644 index 0000000..eeb13b8 --- /dev/null +++ b/app/user/cmd/api/internal/logic/agent/getagentsubordinatelistlogic.go @@ -0,0 +1,173 @@ +package agent + +import ( + "context" + "strings" + "time" + + "tydata-server/app/user/cmd/api/internal/svc" + "tydata-server/app/user/cmd/api/internal/types" + "tydata-server/app/user/model" + "tydata-server/common/ctxdata" + "tydata-server/common/xerr" + "tydata-server/pkg/lzkit/crypto" + + "github.com/Masterminds/squirrel" + "github.com/pkg/errors" + "github.com/zeromicro/go-zero/core/logx" + "github.com/zeromicro/go-zero/core/mr" +) + +type GetAgentSubordinateListLogic struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +func NewGetAgentSubordinateListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetAgentSubordinateListLogic { + return &GetAgentSubordinateListLogic{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *GetAgentSubordinateListLogic) GetAgentSubordinateList(req *types.GetAgentSubordinateListReq) (resp *types.GetAgentSubordinateListResp, err error) { + userID, err := ctxdata.GetUidFromCtx(l.ctx) + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取代理下级列表, 获取用户ID%v", err) + } + agentModel, err := l.svcCtx.AgentModel.FindOneByUserId(l.ctx, userID) + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取代理下级列表, 获取代理信息%v", err) + } + agentID := agentModel.Id + + builder := l.svcCtx.AgentClosureModel.SelectBuilder().Where(squirrel.Eq{ + "ancestor_id": agentID, + }) + agentClosureModelList, total, err := l.svcCtx.AgentClosureModel.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) + } + + // 构建ID到CreateTime的映射 + createTimeMap := make(map[int64]time.Time) + descendantIDs := make([]int64, 0) + for _, v := range agentClosureModelList { + descendantIDs = append(descendantIDs, v.DescendantId) + createTimeMap[v.DescendantId] = v.CreateTime + } + + // 并发查询代理信息 + agentMap := make(map[int64]*model.Agent) + var descendantList []types.AgentSubordinateList + err = mr.Finish(func() error { + return mr.MapReduceVoid(func(source chan<- interface{}) { + for _, id := range descendantIDs { + source <- id + } + }, func(item interface{}, writer mr.Writer[interface{}], cancel func(error)) { + id := item.(int64) + agent, err := l.svcCtx.AgentModel.FindOne(l.ctx, id) + if err != nil { + cancel(err) + return + } + writer.Write(agent) + }, func(pipe <-chan interface{}, cancel func(error)) { + for item := range pipe { + agent := item.(*model.Agent) + agentMap[agent.Id] = agent + } + }) + }, func() error { + // 并发查询佣金扣除信息 + deductionBuilder := l.svcCtx.AgentCommissionDeductionModel.SelectBuilder(). + Where(squirrel.Eq{"agent_id": agentID}). + Where(squirrel.Eq{"deducted_agent_id": descendantIDs}) + deductionList, err := l.svcCtx.AgentCommissionDeductionModel.FindAll(l.ctx, deductionBuilder, "") + if err != nil { + return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取代理下级列表, 获取代理佣金扣除信息%v", err) + } + deductionMap := make(map[int64]float64) + for _, v := range deductionList { + deductionMap[v.DeductedAgentId] += v.Amount + } + + // 并发查询奖励信息 + rewardsBuilder := l.svcCtx.AgentRewardsModel.SelectBuilder(). + Where(squirrel.Eq{"agent_id": agentID}). + Where(squirrel.Eq{"relation_agent_id": descendantIDs}) + rewardsList, err := l.svcCtx.AgentRewardsModel.FindAll(l.ctx, rewardsBuilder, "") + if err != nil { + return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取代理下级列表, 获取代理奖励信息%v", err) + } + rewardsMap := make(map[int64]float64) + for _, v := range rewardsList { + if v.RelationAgentId.Valid { + rewardsMap[v.RelationAgentId.Int64] += v.Amount + } + } + + // 并发查询佣金信息 + commissionBuilder := l.svcCtx.AgentCommissionModel.SelectBuilder(). + Where(squirrel.Eq{"agent_id": descendantIDs}) + commissionList, err := l.svcCtx.AgentCommissionModel.FindAll(l.ctx, commissionBuilder, "") + if err != nil { + return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取代理下级列表, 获取代理佣金信息%v", err) + } + commissionMap := make(map[int64]float64) + orderCountMap := make(map[int64]int64) + for _, v := range commissionList { + commissionMap[v.AgentId] += v.Amount + orderCountMap[v.AgentId]++ + } + + // 构建返回结果 + secretKey := l.svcCtx.Config.Encrypt.SecretKey + descendantList = make([]types.AgentSubordinateList, 0, len(descendantIDs)) + for _, id := range descendantIDs { + agent, exists := agentMap[id] + if !exists { + continue + } + + mobile, err := crypto.DecryptMobile(agent.Mobile, secretKey) + if err != nil { + return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取代理信息, 解密手机号失败: %v", err) + } + + subordinate := types.AgentSubordinateList{ + ID: id, + Mobile: maskPhone(mobile), + LevelName: agent.LevelName, + CreateTime: createTimeMap[id].Format("2006-01-02 15:04:05"), + TotalContribution: deductionMap[id] + rewardsMap[id], + TotalEarnings: commissionMap[id], + TotalOrders: orderCountMap[id], + } + descendantList = append(descendantList, subordinate) + } + return nil + }) + + if err != nil { + return nil, err + } + + return &types.GetAgentSubordinateListResp{ + Total: total, + List: descendantList, + }, nil +} + +// 手机号脱敏 +func maskPhone(phone string) string { + length := len(phone) + if length < 8 { + return phone // 如果长度太短,可能不是手机号,不处理 + } + // 保留前3位和后4位 + return phone[:3] + strings.Repeat("*", length-7) + phone[length-4:] +} diff --git a/app/user/cmd/api/internal/types/types.go b/app/user/cmd/api/internal/types/types.go index 24024d4..50263ad 100644 --- a/app/user/cmd/api/internal/types/types.go +++ b/app/user/cmd/api/internal/types/types.go @@ -1,6 +1,4 @@ // Code generated by goctl. DO NOT EDIT. -// goctl 1.7.3 - package types type ActiveReward struct { @@ -104,6 +102,42 @@ type AgentProductConfigResp struct { AgentProductConfig []AgentProductConfig } +type AgentSubordinateContributionDetail struct { + ID int64 `json:"id"` + CreateTime string `json:"create_time"` + Amount float64 `json:"amount"` + Type string `json:"type"` +} + +type AgentSubordinateContributionStats struct { + CostCount int64 `json:"cost_count"` // 成本扣除次数 + CostAmount float64 `json:"cost_amount"` // 成本扣除总额 + PricingCount int64 `json:"pricing_count"` // 定价扣除次数 + PricingAmount float64 `json:"pricing_amount"` // 定价扣除总额 + DescendantPromotionCount int64 `json:"descendant_promotion_count"` // 下级推广次数 + DescendantPromotionAmount float64 `json:"descendant_promotion_amount"` // 下级推广总额 + DescendantUpgradeVipCount int64 `json:"descendant_upgrade_vip_count"` // 下级升级VIP次数 + DescendantUpgradeVipAmount float64 `json:"descendant_upgrade_vip_amount"` // 下级升级VIP总额 + DescendantUpgradeSvipCount int64 `json:"descendant_upgrade_svip_count"` // 下级升级SVIP次数 + DescendantUpgradeSvipAmount float64 `json:"descendant_upgrade_svip_amount"` // 下级升级SVIP总额 + DescendantStayActiveCount int64 `json:"descendant_stay_active_count"` // 下级保持活跃次数 + DescendantStayActiveAmount float64 `json:"descendant_stay_active_amount"` // 下级保持活跃总额 + DescendantNewActiveCount int64 `json:"descendant_new_active_count"` // 下级新增活跃次数 + DescendantNewActiveAmount float64 `json:"descendant_new_active_amount"` // 下级新增活跃总额 + DescendantWithdrawCount int64 `json:"descendant_withdraw_count"` // 下级提现次数 + DescendantWithdrawAmount float64 `json:"descendant_withdraw_amount"` // 下级提现总额 +} + +type AgentSubordinateList struct { + ID int64 `json:"id"` + Mobile string `json:"mobile"` + CreateTime string `json:"create_time"` + LevelName string `json:"level_name"` + TotalOrders int64 `json:"total_orders"` // 总单量 + TotalEarnings float64 `json:"total_earnings"` // 总金额 + TotalContribution float64 `json:"total_contribution"` // 总贡献 +} + type Commission struct { ProductName string `json:"product_name"` Amount float64 `json:"amount"` @@ -135,6 +169,34 @@ type GetAgentRevenueInfoResp struct { ActiveReward ActiveReward `json:"active_reward"` // 活跃下级奖励数据 } +type GetAgentSubordinateContributionDetailReq struct { + Page int64 `form:"page"` // 页码 + PageSize int64 `form:"page_size"` // 每页数据量 + SubordinateID int64 `form:"subordinate_id"` // 下级ID +} + +type GetAgentSubordinateContributionDetailResp struct { + Mobile string `json:"mobile"` + Total int64 `json:"total"` // 总记录数 + CreateTime string `json:"create_time"` + TotalEarnings float64 `json:"total_earnings"` // 总金额 + TotalContribution float64 `json:"total_contribution"` // 总贡献 + TotalOrders int64 `json:"total_orders"` // 总单量 + LevelName string `json:"level_name"` // 等级名称 + List []AgentSubordinateContributionDetail `json:"list"` // 查询列表 + Stats AgentSubordinateContributionStats `json:"stats"` // 统计数据 +} + +type GetAgentSubordinateListReq struct { + Page int64 `form:"page"` // 页码 + PageSize int64 `form:"page_size"` // 每页数据量 +} + +type GetAgentSubordinateListResp struct { + Total int64 `json:"total"` // 总记录数 + List []AgentSubordinateList `json:"list"` // 查询列表 +} + type GetCommissionReq struct { Page int64 `form:"page"` // 页码 PageSize int64 `form:"page_size"` // 每页数据量 diff --git a/app/user/model/agentClosureModel.go b/app/user/model/agentClosureModel.go index dd92f74..651e900 100644 --- a/app/user/model/agentClosureModel.go +++ b/app/user/model/agentClosureModel.go @@ -1,6 +1,11 @@ package model import ( + "context" + "fmt" + "tydata-server/common/globalkey" + + "github.com/pkg/errors" "github.com/zeromicro/go-zero/core/stores/cache" "github.com/zeromicro/go-zero/core/stores/sqlx" ) @@ -12,11 +17,20 @@ type ( // and implement the added methods in customAgentClosureModel. AgentClosureModel interface { agentClosureModel + FindUnionPageListByPageWithTotal(ctx context.Context, agentId, subordinateId int64, page, pageSize int64) ([]*UnionDetail, int64, error) } customAgentClosureModel struct { *defaultAgentClosureModel } + + // UnionDetail 合并后的详情结构 + UnionDetail struct { + Id int64 `db:"id"` + CreateTime string `db:"create_time"` + Amount float64 `db:"amount"` + Type string `db:"type"` + } ) // NewAgentClosureModel returns a model for the database table. @@ -25,3 +39,61 @@ func NewAgentClosureModel(conn sqlx.SqlConn, c cache.CacheConf) AgentClosureMode defaultAgentClosureModel: newAgentClosureModel(conn, c), } } + +// FindUnionPageListByPageWithTotal 获取合并后的分页列表 +func (m *customAgentClosureModel) FindUnionPageListByPageWithTotal(ctx context.Context, agentId, subordinateId int64, page, pageSize int64) ([]*UnionDetail, int64, error) { + // 构建UNION ALL查询 + deductionQuery := fmt.Sprintf(` + SELECT id, create_time, amount, type + FROM agent_commission_deduction + WHERE agent_id = ? AND deducted_agent_id = ? AND del_state = ? + `) + + rewardsQuery := fmt.Sprintf(` + SELECT id, create_time, amount, type + FROM agent_rewards + WHERE agent_id = ? AND relation_agent_id = ? AND del_state = ? + `) + + // 计算总记录数 + countQuery := fmt.Sprintf(` + SELECT COUNT(*) FROM ( + %s + UNION ALL + %s + ) AS union_table + `, deductionQuery, rewardsQuery) + + var total int64 + err := m.QueryRowNoCacheCtx(ctx, &total, countQuery, agentId, subordinateId, globalkey.DelStateNo, agentId, subordinateId, globalkey.DelStateNo) + if err != nil { + return nil, 0, errors.Wrapf(err, "查询总记录数失败") + } + + // 构建分页查询 + if page < 1 { + page = 1 + } + offset := (page - 1) * pageSize + + unionQuery := fmt.Sprintf(` + SELECT * FROM ( + %s + UNION ALL + %s + ) AS union_table + ORDER BY create_time DESC + LIMIT ? OFFSET ? + `, deductionQuery, rewardsQuery) + + var resp []*UnionDetail + err = m.QueryRowsNoCacheCtx(ctx, &resp, unionQuery, + agentId, subordinateId, globalkey.DelStateNo, + agentId, subordinateId, globalkey.DelStateNo, + pageSize, offset) + if err != nil { + return nil, 0, errors.Wrapf(err, "查询分页数据失败") + } + + return resp, total, nil +} diff --git a/gen_api.ps1 b/gen_api.ps1 new file mode 100644 index 0000000..32eca87 --- /dev/null +++ b/gen_api.ps1 @@ -0,0 +1,2 @@ +# API生成脚本 +goctl api go --api ./app/user/cmd/api/desc/main.api --dir ./app/user/cmd/api --home ./deploy/template \ No newline at end of file