first commit
This commit is contained in:
@@ -0,0 +1,252 @@
|
||||
package admin_agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sort"
|
||||
|
||||
"sim-server/app/main/api/internal/svc"
|
||||
"sim-server/app/main/api/internal/types"
|
||||
"sim-server/pkg/lzkit/crypto"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminGetAgentRankingLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminGetAgentRankingLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminGetAgentRankingLogic {
|
||||
return &AdminGetAgentRankingLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminGetAgentRankingLogic) AdminGetAgentRanking(req *types.AdminGetAgentRankingReq) (resp *types.AdminGetAgentRankingResp, err error) {
|
||||
// Set default limit if not provided
|
||||
limit := req.Limit
|
||||
if limit <= 0 {
|
||||
limit = 10
|
||||
}
|
||||
|
||||
// Validate type parameter
|
||||
if req.Type != "commission" && req.Type != "orders" {
|
||||
return nil, errors.New("invalid type parameter, must be 'commission' or 'orders'")
|
||||
}
|
||||
|
||||
var items []types.AgentRankingItem
|
||||
|
||||
if req.Type == "commission" {
|
||||
// Rank by sum of commission amounts
|
||||
items, err = l.queryCommissionRanking(int(limit))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
// Rank by count of orders
|
||||
items, err = l.queryOrdersRanking(int(limit))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
resp = &types.AdminGetAgentRankingResp{
|
||||
Items: items,
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// queryCommissionRanking queries top agents by total commission amount
|
||||
func (l *AdminGetAgentRankingLogic) queryCommissionRanking(limit int) ([]types.AgentRankingItem, error) {
|
||||
// 1. Query all commissions
|
||||
builder := l.svcCtx.AgentCommissionModel.SelectBuilder()
|
||||
|
||||
commissions, err := l.svcCtx.AgentCommissionModel.FindAll(l.ctx, builder, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 2. Group by agent_id and sum amounts
|
||||
agentCommissionMap := make(map[string]float64)
|
||||
for _, commission := range commissions {
|
||||
agentCommissionMap[commission.AgentId] += commission.Amount
|
||||
}
|
||||
|
||||
// 3. Build agent stats
|
||||
type AgentStat struct {
|
||||
AgentID string
|
||||
Amount float64
|
||||
}
|
||||
|
||||
stats := make([]AgentStat, 0, len(agentCommissionMap))
|
||||
for agentID, amount := range agentCommissionMap {
|
||||
stats = append(stats, AgentStat{
|
||||
AgentID: agentID,
|
||||
Amount: amount,
|
||||
})
|
||||
}
|
||||
|
||||
// 4. Sort by amount descending
|
||||
sort.Slice(stats, func(i, j int) bool {
|
||||
return stats[i].Amount > stats[j].Amount
|
||||
})
|
||||
|
||||
// 5. Apply limit
|
||||
if limit > len(stats) {
|
||||
limit = len(stats)
|
||||
}
|
||||
stats = stats[:limit]
|
||||
|
||||
// 6. Query agents and build response
|
||||
agentIDs := make([]string, len(stats))
|
||||
for i, stat := range stats {
|
||||
agentIDs[i] = stat.AgentID
|
||||
}
|
||||
|
||||
agents, err := l.svcCtx.AgentModel.FindAll(l.ctx,
|
||||
l.svcCtx.AgentModel.SelectBuilder(), "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Build agent map
|
||||
agentMap := make(map[string]*struct {
|
||||
Mobile string
|
||||
Region string
|
||||
})
|
||||
for _, agent := range agents {
|
||||
region := "未知"
|
||||
if agent.Region.Valid && agent.Region.String != "" {
|
||||
region = agent.Region.String
|
||||
}
|
||||
agentMap[agent.Id] = &struct {
|
||||
Mobile string
|
||||
Region string
|
||||
}{
|
||||
Mobile: agent.Mobile,
|
||||
Region: region,
|
||||
}
|
||||
}
|
||||
|
||||
// 7. Build items
|
||||
items := make([]types.AgentRankingItem, len(stats))
|
||||
for i, stat := range stats {
|
||||
agentInfo := agentMap[stat.AgentID]
|
||||
|
||||
// Decrypt mobile
|
||||
decryptedMobile, err := crypto.DecryptMobile(agentInfo.Mobile, l.svcCtx.Config.Encrypt.SecretKey)
|
||||
if err != nil {
|
||||
l.Errorf("Failed to decrypt mobile for agent %s: %v", stat.AgentID, err)
|
||||
decryptedMobile = ""
|
||||
}
|
||||
|
||||
items[i] = types.AgentRankingItem{
|
||||
AgentId: stat.AgentID,
|
||||
AgentMobile: decryptedMobile,
|
||||
Region: agentInfo.Region,
|
||||
Value: stat.Amount,
|
||||
}
|
||||
}
|
||||
|
||||
return items, nil
|
||||
}
|
||||
|
||||
// queryOrdersRanking queries top agents by order count
|
||||
func (l *AdminGetAgentRankingLogic) queryOrdersRanking(limit int) ([]types.AgentRankingItem, error) {
|
||||
// 1. Query all orders
|
||||
builder := l.svcCtx.AgentOrderModel.SelectBuilder()
|
||||
|
||||
orders, err := l.svcCtx.AgentOrderModel.FindAll(l.ctx, builder, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 2. Group by agent_id and count
|
||||
agentOrderCountMap := make(map[string]int64)
|
||||
for _, order := range orders {
|
||||
agentOrderCountMap[order.AgentId]++
|
||||
}
|
||||
|
||||
// 3. Build agent stats
|
||||
type AgentStat struct {
|
||||
AgentID string
|
||||
Count int64
|
||||
}
|
||||
|
||||
stats := make([]AgentStat, 0, len(agentOrderCountMap))
|
||||
for agentID, count := range agentOrderCountMap {
|
||||
stats = append(stats, AgentStat{
|
||||
AgentID: agentID,
|
||||
Count: count,
|
||||
})
|
||||
}
|
||||
|
||||
// 4. Sort by count descending
|
||||
sort.Slice(stats, func(i, j int) bool {
|
||||
return stats[i].Count > stats[j].Count
|
||||
})
|
||||
|
||||
// 5. Apply limit
|
||||
if limit > len(stats) {
|
||||
limit = len(stats)
|
||||
}
|
||||
stats = stats[:limit]
|
||||
|
||||
// 6. Query agents
|
||||
agentIDs := make([]string, len(stats))
|
||||
for i, stat := range stats {
|
||||
agentIDs[i] = stat.AgentID
|
||||
}
|
||||
|
||||
agents, err := l.svcCtx.AgentModel.FindAll(l.ctx,
|
||||
l.svcCtx.AgentModel.SelectBuilder(), "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Build agent map
|
||||
agentMap := make(map[string]*struct {
|
||||
Mobile string
|
||||
Region string
|
||||
})
|
||||
for _, agent := range agents {
|
||||
region := "未知"
|
||||
if agent.Region.Valid && agent.Region.String != "" {
|
||||
region = agent.Region.String
|
||||
}
|
||||
agentMap[agent.Id] = &struct {
|
||||
Mobile string
|
||||
Region string
|
||||
}{
|
||||
Mobile: agent.Mobile,
|
||||
Region: region,
|
||||
}
|
||||
}
|
||||
|
||||
// 7. Build items
|
||||
items := make([]types.AgentRankingItem, len(stats))
|
||||
for i, stat := range stats {
|
||||
agentInfo := agentMap[stat.AgentID]
|
||||
|
||||
// Decrypt mobile
|
||||
decryptedMobile, err := crypto.DecryptMobile(agentInfo.Mobile, l.svcCtx.Config.Encrypt.SecretKey)
|
||||
if err != nil {
|
||||
l.Errorf("Failed to decrypt mobile for agent %s: %v", stat.AgentID, err)
|
||||
decryptedMobile = ""
|
||||
}
|
||||
|
||||
items[i] = types.AgentRankingItem{
|
||||
AgentId: stat.AgentID,
|
||||
AgentMobile: decryptedMobile,
|
||||
Region: agentInfo.Region,
|
||||
Value: float64(stat.Count),
|
||||
}
|
||||
}
|
||||
|
||||
return items, nil
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package admin_agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"sim-server/app/main/api/internal/svc"
|
||||
"sim-server/app/main/api/internal/types"
|
||||
"sim-server/common/globalkey"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminGetAgentTrendsLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminGetAgentTrendsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminGetAgentTrendsLogic {
|
||||
return &AdminGetAgentTrendsLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminGetAgentTrendsLogic) AdminGetAgentTrends(req *types.AdminGetAgentTrendsReq) (resp *types.AdminGetAgentTrendsResp, err error) {
|
||||
// 1. Parse date parameters with default to last 30 days
|
||||
var startDate, endDate time.Time
|
||||
|
||||
if req.StartDate != "" {
|
||||
startDate, err = time.Parse("2006-01-02", req.StartDate)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid start_date format: %v", err)
|
||||
}
|
||||
} else {
|
||||
// Default to 30 days ago
|
||||
startDate = time.Now().AddDate(0, 0, -30)
|
||||
}
|
||||
|
||||
if req.EndDate != "" {
|
||||
endDate, err = time.Parse("2006-01-02", req.EndDate)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid end_date format: %v", err)
|
||||
}
|
||||
// Set end date to end of day
|
||||
endDate = time.Date(endDate.Year(), endDate.Month(), endDate.Day(), 23, 59, 59, 0, time.Local)
|
||||
} else {
|
||||
// Default to today
|
||||
endDate = time.Now()
|
||||
}
|
||||
|
||||
// Ensure start date is before end date
|
||||
if startDate.After(endDate) {
|
||||
return nil, fmt.Errorf("start_date must be before end_date")
|
||||
}
|
||||
|
||||
// 2. Query all agents in date range
|
||||
builder := l.svcCtx.AgentModel.SelectBuilder()
|
||||
builder = builder.Where("del_state = ?", globalkey.DelStateNo)
|
||||
builder = builder.Where("create_time >= ?", startDate)
|
||||
builder = builder.Where("create_time <= ?", endDate)
|
||||
|
||||
agents, err := l.svcCtx.AgentModel.FindAll(l.ctx, builder, "")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to query agents: %v", err)
|
||||
}
|
||||
|
||||
// 3. Group by date in Go
|
||||
dateMap := make(map[string]int64)
|
||||
|
||||
for _, agent := range agents {
|
||||
date := agent.CreateTime.Format("2006-01-02")
|
||||
dateMap[date]++
|
||||
}
|
||||
|
||||
// 4. Build sorted response
|
||||
dates := make([]string, 0, len(dateMap))
|
||||
counts := make([]int64, 0, len(dateMap))
|
||||
|
||||
for date := range dateMap {
|
||||
dates = append(dates, date)
|
||||
}
|
||||
|
||||
// Sort dates
|
||||
sort.Strings(dates)
|
||||
|
||||
for _, date := range dates {
|
||||
counts = append(counts, dateMap[date])
|
||||
}
|
||||
|
||||
return &types.AdminGetAgentTrendsResp{
|
||||
Dates: dates,
|
||||
Counts: counts,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
package admin_agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"sim-server/app/main/api/internal/svc"
|
||||
"sim-server/app/main/api/internal/types"
|
||||
"sim-server/common/globalkey"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminGetOrderTrendsLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminGetOrderTrendsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminGetOrderTrendsLogic {
|
||||
return &AdminGetOrderTrendsLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminGetOrderTrendsLogic) AdminGetOrderTrends(req *types.AdminGetOrderTrendsReq) (resp *types.AdminGetOrderTrendsResp, err error) {
|
||||
// 1. Parse date parameters with default to last 30 days
|
||||
var startDate, endDate time.Time
|
||||
|
||||
if req.StartDate != "" {
|
||||
startDate, err = time.Parse("2006-01-02", req.StartDate)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid start_date format: %v", err)
|
||||
}
|
||||
} else {
|
||||
// Default to 30 days ago
|
||||
startDate = time.Now().AddDate(0, 0, -30)
|
||||
}
|
||||
|
||||
if req.EndDate != "" {
|
||||
endDate, err = time.Parse("2006-01-02", req.EndDate)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid end_date format: %v", err)
|
||||
}
|
||||
// Set end date to end of day
|
||||
endDate = time.Date(endDate.Year(), endDate.Month(), endDate.Day(), 23, 59, 59, 0, time.Local)
|
||||
} else {
|
||||
// Default to today
|
||||
endDate = time.Now()
|
||||
}
|
||||
|
||||
// Ensure start date is before end date
|
||||
if startDate.After(endDate) {
|
||||
return nil, fmt.Errorf("start_date must be before end_date")
|
||||
}
|
||||
|
||||
// 2. Query all commissions in date range
|
||||
builder := l.svcCtx.AgentCommissionModel.SelectBuilder()
|
||||
builder = builder.Where("del_state = ?", globalkey.DelStateNo)
|
||||
builder = builder.Where("create_time >= ?", startDate)
|
||||
builder = builder.Where("create_time <= ?", endDate)
|
||||
|
||||
commissions, err := l.svcCtx.AgentCommissionModel.FindAll(l.ctx, builder, "")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to query commissions: %v", err)
|
||||
}
|
||||
|
||||
// 3. Group by date in Go
|
||||
dateMap := make(map[string]*struct {
|
||||
Amount float64
|
||||
Count int64
|
||||
})
|
||||
|
||||
for _, commission := range commissions {
|
||||
date := commission.CreateTime.Format("2006-01-02")
|
||||
if _, exists := dateMap[date]; !exists {
|
||||
dateMap[date] = &struct {
|
||||
Amount float64
|
||||
Count int64
|
||||
}{}
|
||||
}
|
||||
dateMap[date].Amount += commission.Amount
|
||||
dateMap[date].Count++
|
||||
}
|
||||
|
||||
// 4. Build sorted response
|
||||
dates := make([]string, 0, len(dateMap))
|
||||
amounts := make([]float64, 0, len(dateMap))
|
||||
counts := make([]int64, 0, len(dateMap))
|
||||
|
||||
// Sort dates
|
||||
sortedDates := make([]string, 0, len(dateMap))
|
||||
for date := range dateMap {
|
||||
sortedDates = append(sortedDates, date)
|
||||
}
|
||||
|
||||
// Simple bubble sort (can be optimized with sort package)
|
||||
for i := 0; i < len(sortedDates); i++ {
|
||||
for j := i + 1; j < len(sortedDates); j++ {
|
||||
if sortedDates[i] > sortedDates[j] {
|
||||
sortedDates[i], sortedDates[j] = sortedDates[j], sortedDates[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, date := range sortedDates {
|
||||
dates = append(dates, date)
|
||||
amounts = append(amounts, dateMap[date].Amount)
|
||||
counts = append(counts, dateMap[date].Count)
|
||||
}
|
||||
|
||||
return &types.AdminGetOrderTrendsResp{
|
||||
Dates: dates,
|
||||
Amounts: amounts,
|
||||
Counts: counts,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
package admin_agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sort"
|
||||
|
||||
"sim-server/app/main/api/internal/svc"
|
||||
"sim-server/app/main/api/internal/types"
|
||||
"sim-server/app/main/model"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminGetProductDistributionLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminGetProductDistributionLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminGetProductDistributionLogic {
|
||||
return &AdminGetProductDistributionLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminGetProductDistributionLogic) AdminGetProductDistribution() (resp *types.AdminGetProductDistributionResp, err error) {
|
||||
// 1. Query all commissions
|
||||
builder := l.svcCtx.AgentCommissionModel.SelectBuilder()
|
||||
|
||||
commissions, err := l.svcCtx.AgentCommissionModel.FindAll(l.ctx, builder, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 2. Collect all product IDs
|
||||
productIds := make([]string, 0, len(commissions))
|
||||
productIDSet := make(map[string]bool)
|
||||
for _, commission := range commissions {
|
||||
if !productIDSet[commission.ProductId] {
|
||||
productIDSet[commission.ProductId] = true
|
||||
productIds = append(productIds, commission.ProductId)
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Query products
|
||||
var products []*model.Product
|
||||
if len(productIds) > 0 {
|
||||
products, err = l.svcCtx.ProductModel.FindAll(l.ctx,
|
||||
l.svcCtx.ProductModel.SelectBuilder(), "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Build product name map
|
||||
productNameMap := make(map[string]string)
|
||||
for _, product := range products {
|
||||
productNameMap[product.Id] = product.ProductName
|
||||
}
|
||||
|
||||
// 5. Group by product in Go
|
||||
productStats := make(map[string]*struct {
|
||||
Count int64
|
||||
Amount float64
|
||||
})
|
||||
|
||||
for _, commission := range commissions {
|
||||
productName := productNameMap[commission.ProductId]
|
||||
if productName == "" {
|
||||
productName = "未知产品"
|
||||
}
|
||||
|
||||
if _, exists := productStats[productName]; !exists {
|
||||
productStats[productName] = &struct {
|
||||
Count int64
|
||||
Amount float64
|
||||
}{}
|
||||
}
|
||||
productStats[productName].Count++
|
||||
productStats[productName].Amount += commission.Amount
|
||||
}
|
||||
|
||||
// 6. Sort by amount descending
|
||||
type ProductStat struct {
|
||||
Name string
|
||||
Count int64
|
||||
Amount float64
|
||||
}
|
||||
|
||||
stats := make([]ProductStat, 0, len(productStats))
|
||||
for name, stat := range productStats {
|
||||
stats = append(stats, ProductStat{
|
||||
Name: name,
|
||||
Count: stat.Count,
|
||||
Amount: stat.Amount,
|
||||
})
|
||||
}
|
||||
|
||||
sort.Slice(stats, func(i, j int) bool {
|
||||
return stats[i].Amount > stats[j].Amount
|
||||
})
|
||||
|
||||
// 7. Build response
|
||||
productNames := make([]string, len(stats))
|
||||
counts := make([]int64, len(stats))
|
||||
amounts := make([]float64, len(stats))
|
||||
|
||||
for i, stat := range stats {
|
||||
productNames[i] = stat.Name
|
||||
counts[i] = stat.Count
|
||||
amounts[i] = stat.Amount
|
||||
}
|
||||
|
||||
return &types.AdminGetProductDistributionResp{
|
||||
Products: productNames,
|
||||
Counts: counts,
|
||||
Amounts: amounts,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package admin_agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sort"
|
||||
|
||||
"sim-server/app/main/api/internal/svc"
|
||||
"sim-server/app/main/api/internal/types"
|
||||
"sim-server/common/globalkey"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminGetRegionDistributionLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminGetRegionDistributionLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminGetRegionDistributionLogic {
|
||||
return &AdminGetRegionDistributionLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminGetRegionDistributionLogic) AdminGetRegionDistribution() (resp *types.AdminGetRegionDistributionResp, err error) {
|
||||
// 1. Query all agents
|
||||
builder := l.svcCtx.AgentModel.SelectBuilder()
|
||||
builder = builder.Where("del_state = ?", globalkey.DelStateNo)
|
||||
|
||||
agents, err := l.svcCtx.AgentModel.FindAll(l.ctx, builder, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 2. Group by region in Go
|
||||
regionMap := make(map[string]int64)
|
||||
|
||||
for _, agent := range agents {
|
||||
region := "未知"
|
||||
if agent.Region.Valid && agent.Region.String != "" {
|
||||
region = agent.Region.String
|
||||
}
|
||||
regionMap[region]++
|
||||
}
|
||||
|
||||
// 3. Sort by count descending
|
||||
type RegionStat struct {
|
||||
Region string
|
||||
Count int64
|
||||
}
|
||||
|
||||
stats := make([]RegionStat, 0, len(regionMap))
|
||||
for region, count := range regionMap {
|
||||
stats = append(stats, RegionStat{
|
||||
Region: region,
|
||||
Count: count,
|
||||
})
|
||||
}
|
||||
|
||||
sort.Slice(stats, func(i, j int) bool {
|
||||
return stats[i].Count > stats[j].Count
|
||||
})
|
||||
|
||||
// 4. Build response
|
||||
regions := make([]string, len(stats))
|
||||
counts := make([]int64, len(stats))
|
||||
|
||||
for i, stat := range stats {
|
||||
regions[i] = stat.Region
|
||||
counts[i] = stat.Count
|
||||
}
|
||||
|
||||
return &types.AdminGetRegionDistributionResp{
|
||||
Regions: regions,
|
||||
Counts: counts,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
package admin_agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"sim-server/app/main/api/internal/svc"
|
||||
"sim-server/app/main/api/internal/types"
|
||||
|
||||
"github.com/Masterminds/squirrel"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminGetStatisticsOverviewLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminGetStatisticsOverviewLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminGetStatisticsOverviewLogic {
|
||||
return &AdminGetStatisticsOverviewLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminGetStatisticsOverviewLogic) AdminGetStatisticsOverview() (resp *types.AdminGetStatisticsOverviewResp, err error) {
|
||||
// Get current time for date filtering
|
||||
now := time.Now()
|
||||
todayStart := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
|
||||
monthStart := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location())
|
||||
|
||||
// 1. Total agents - count from agent table
|
||||
totalAgents, err := l.svcCtx.AgentModel.FindCount(l.ctx, l.svcCtx.AgentModel.SelectBuilder(), "id")
|
||||
if err != nil {
|
||||
l.Errorf("Failed to count total agents: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 2. Today new agents - count agents created today
|
||||
todayAgentsBuilder := l.svcCtx.AgentModel.SelectBuilder().Where(squirrel.GtOrEq{"create_time": todayStart})
|
||||
todayNewAgents, err := l.svcCtx.AgentModel.FindCount(l.ctx, todayAgentsBuilder, "id")
|
||||
if err != nil {
|
||||
l.Errorf("Failed to count today new agents: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 3. Total orders - count from agent_order table
|
||||
totalOrders, err := l.svcCtx.AgentOrderModel.FindCount(l.ctx, l.svcCtx.AgentOrderModel.SelectBuilder(), "id")
|
||||
if err != nil {
|
||||
l.Errorf("Failed to count total orders: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 4. Today orders - count orders created today
|
||||
todayOrdersBuilder := l.svcCtx.AgentOrderModel.SelectBuilder().Where(squirrel.GtOrEq{"create_time": todayStart})
|
||||
todayOrders, err := l.svcCtx.AgentOrderModel.FindCount(l.ctx, todayOrdersBuilder, "id")
|
||||
if err != nil {
|
||||
l.Errorf("Failed to count today orders: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 5. Total order amount - sum from agent_order table
|
||||
totalOrderAmount, err := l.svcCtx.AgentOrderModel.FindSum(l.ctx, l.svcCtx.AgentOrderModel.SelectBuilder(), "order_amount")
|
||||
if err != nil {
|
||||
l.Errorf("Failed to sum total order amount: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 6. Today order amount - sum orders created today
|
||||
todayOrderAmount, err := l.svcCtx.AgentOrderModel.FindSum(l.ctx, todayOrdersBuilder, "order_amount")
|
||||
if err != nil {
|
||||
l.Errorf("Failed to sum today order amount: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 7. Total commission - sum of all commission amounts
|
||||
totalCommission, err := l.svcCtx.AgentCommissionModel.FindSum(l.ctx, l.svcCtx.AgentCommissionModel.SelectBuilder(), "amount")
|
||||
if err != nil {
|
||||
l.Errorf("Failed to sum total commission: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 8. Today commission - sum of today's commission
|
||||
todayCommissionBuilder := l.svcCtx.AgentCommissionModel.SelectBuilder().Where(squirrel.GtOrEq{"create_time": todayStart})
|
||||
todayCommission, err := l.svcCtx.AgentCommissionModel.FindSum(l.ctx, todayCommissionBuilder, "amount")
|
||||
if err != nil {
|
||||
l.Errorf("Failed to sum today commission: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 9. Pending withdraw - sum of withdraw records with status=0
|
||||
pendingWithdrawBuilder := l.svcCtx.AgentWithdrawModel.SelectBuilder().Where(squirrel.Eq{"status": 0})
|
||||
pendingWithdraw, err := l.svcCtx.AgentWithdrawModel.FindSum(l.ctx, pendingWithdrawBuilder, "withdraw_amount")
|
||||
if err != nil {
|
||||
l.Errorf("Failed to sum pending withdraw: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 10. Month order amount - sum of orders in current month
|
||||
monthOrderAmountBuilder := l.svcCtx.AgentOrderModel.SelectBuilder().Where(squirrel.GtOrEq{"create_time": monthStart})
|
||||
monthOrderAmount, err := l.svcCtx.AgentOrderModel.FindSum(l.ctx, monthOrderAmountBuilder, "order_amount")
|
||||
if err != nil {
|
||||
l.Errorf("Failed to sum month order amount: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 11. Month commission - sum of commission in current month
|
||||
monthCommissionBuilder := l.svcCtx.AgentCommissionModel.SelectBuilder().Where(squirrel.GtOrEq{"create_time": monthStart})
|
||||
monthCommission, err := l.svcCtx.AgentCommissionModel.FindSum(l.ctx, monthCommissionBuilder, "amount")
|
||||
if err != nil {
|
||||
l.Errorf("Failed to sum month commission: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp = &types.AdminGetStatisticsOverviewResp{
|
||||
TotalAgents: totalAgents,
|
||||
TodayNewAgents: todayNewAgents,
|
||||
TotalOrders: totalOrders,
|
||||
TodayOrders: todayOrders,
|
||||
TotalOrderAmount: totalOrderAmount,
|
||||
TodayOrderAmount: todayOrderAmount,
|
||||
TotalCommission: totalCommission,
|
||||
TodayCommission: todayCommission,
|
||||
PendingWithdraw: pendingWithdraw,
|
||||
MonthOrderAmount: monthOrderAmount,
|
||||
MonthCommission: monthCommission,
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
package admin_agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"sim-server/app/main/api/internal/svc"
|
||||
"sim-server/app/main/api/internal/types"
|
||||
"sim-server/common/xerr"
|
||||
"sim-server/pkg/lzkit/crypto"
|
||||
|
||||
openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
|
||||
dysmsapi "github.com/alibabacloud-go/dysmsapi-20170525/v3/client"
|
||||
"github.com/alibabacloud-go/tea-utils/v2/service"
|
||||
"github.com/alibabacloud-go/tea/tea"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminSendAgentComplaintNotifyLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminSendAgentComplaintNotifyLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminSendAgentComplaintNotifyLogic {
|
||||
return &AdminSendAgentComplaintNotifyLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminSendAgentComplaintNotifyLogic) AdminSendAgentComplaintNotify(req *types.AdminSendAgentComplaintNotifyReq) (resp *types.AdminSendAgentComplaintNotifyResp, err error) {
|
||||
// 1. 查询代理信息
|
||||
agent, err := l.svcCtx.AgentModel.FindOne(l.ctx, req.AgentId)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询代理信息失败: %v", err)
|
||||
}
|
||||
|
||||
// 2. 解密手机号
|
||||
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)
|
||||
}
|
||||
|
||||
// 3. 发送短信
|
||||
smsResp, err := l.sendSmsRequest(mobile, req.UserName)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "发送短信失败: %v", err)
|
||||
}
|
||||
|
||||
// 4. 检查发送结果
|
||||
if *smsResp.Body.Code != "OK" {
|
||||
return &types.AdminSendAgentComplaintNotifyResp{
|
||||
Success: false,
|
||||
Message: fmt.Sprintf("短信发送失败: %s", *smsResp.Body.Message),
|
||||
}, nil
|
||||
}
|
||||
|
||||
resp = &types.AdminSendAgentComplaintNotifyResp{
|
||||
Success: true,
|
||||
Message: "投诉通知发送成功",
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// CreateClient 创建阿里云短信客户端
|
||||
func (l *AdminSendAgentComplaintNotifyLogic) CreateClient() (*dysmsapi.Client, error) {
|
||||
config := &openapi.Config{
|
||||
AccessKeyId: &l.svcCtx.Config.VerifyCode.AccessKeyID,
|
||||
AccessKeySecret: &l.svcCtx.Config.VerifyCode.AccessKeySecret,
|
||||
}
|
||||
config.Endpoint = tea.String(l.svcCtx.Config.VerifyCode.EndpointURL)
|
||||
return dysmsapi.NewClient(config)
|
||||
}
|
||||
|
||||
// sendSmsRequest 发送投诉通知短信请求
|
||||
func (l *AdminSendAgentComplaintNotifyLogic) sendSmsRequest(mobile, userName string) (*dysmsapi.SendSmsResponse, error) {
|
||||
// 初始化阿里云短信客户端
|
||||
cli, err := l.CreateClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
request := &dysmsapi.SendSmsRequest{
|
||||
SignName: tea.String(l.svcCtx.Config.VerifyCode.SignName),
|
||||
TemplateCode: tea.String(l.svcCtx.Config.VerifyCode.ComplaintTemplate),
|
||||
PhoneNumbers: tea.String(mobile),
|
||||
TemplateParam: tea.String(fmt.Sprintf("{\"name\":\"%s\"}", userName)),
|
||||
}
|
||||
runtime := &service.RuntimeOptions{}
|
||||
return cli.SendSmsWithOptions(request, runtime)
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package admin_agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"sim-server/app/main/api/internal/svc"
|
||||
"sim-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,185 @@
|
||||
package admin_agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
|
||||
"sim-server/app/main/api/internal/svc"
|
||||
"sim-server/app/main/api/internal/types"
|
||||
"sim-server/common/ctxdata"
|
||||
"sim-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
)
|
||||
|
||||
type AdminAuditAgentWithdrawLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminAuditAgentWithdrawLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminAuditAgentWithdrawLogic {
|
||||
return &AdminAuditAgentWithdrawLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminAuditAgentWithdrawLogic) AdminAuditAgentWithdraw(req *types.AdminAuditAgentWithdrawReq) (resp *types.AdminAuditAgentWithdrawResp, err error) {
|
||||
// 1. 获取当前审核人ID(管理员ID)
|
||||
adminUserId, err := ctxdata.GetUidFromCtx(l.ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取审核人信息失败: %v", err)
|
||||
}
|
||||
|
||||
// 2. 验证审核状态
|
||||
if req.Status != 1 && req.Status != 2 {
|
||||
return nil, errors.Wrap(xerr.NewErrCode(xerr.REUQEST_PARAM_ERROR), "审核状态无效,只能通过(1)或拒绝(2)")
|
||||
}
|
||||
|
||||
// 3. 如果是拒绝,必须填写审核原因
|
||||
if req.Status == 2 && req.AuditRemark == "" {
|
||||
return nil, errors.Wrap(xerr.NewErrCode(xerr.REUQEST_PARAM_ERROR), "拒绝提现时必须填写审核原因")
|
||||
}
|
||||
|
||||
// 4. 查询提现记录
|
||||
withdrawRecord, err := l.svcCtx.AgentWithdrawModel.FindOne(l.ctx, req.WithdrawId)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询提现记录失败: %v", err)
|
||||
}
|
||||
|
||||
// 5. 验证提现记录状态
|
||||
if withdrawRecord.Status != 0 {
|
||||
return nil, errors.Wrap(xerr.NewErrCode(xerr.CUSTOM_ERROR), "该提现记录已被审核,请勿重复操作")
|
||||
}
|
||||
|
||||
// 6. 如果是审核通过,从配置表读取税率并计算税费
|
||||
var taxAmount float64
|
||||
var actualAmount float64
|
||||
if req.Status == 1 {
|
||||
// 从配置表读取税率
|
||||
taxRateConfig, err := l.svcCtx.AgentConfigModel.FindOneByConfigKey(l.ctx, "tax_rate")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取税率配置失败: %v", err)
|
||||
}
|
||||
taxRate, _ := strconv.ParseFloat(taxRateConfig.ConfigValue, 64)
|
||||
|
||||
// 计算税费和实际到账金额
|
||||
taxAmount = withdrawRecord.WithdrawAmount * taxRate
|
||||
actualAmount = withdrawRecord.WithdrawAmount - taxAmount
|
||||
|
||||
logx.Infof("提现审核通过计算税费:提现金额=%.2f,税率=%.4f,税费=%.2f,实际到账=%.2f",
|
||||
withdrawRecord.WithdrawAmount, taxRate, taxAmount, actualAmount)
|
||||
}
|
||||
|
||||
// 7. 查询代理钱包
|
||||
wallet, err := l.svcCtx.AgentWalletModel.FindOneByAgentId(l.ctx, withdrawRecord.AgentId)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询代理钱包失败: %v", err)
|
||||
}
|
||||
|
||||
// 8. 开启事务处理审核逻辑
|
||||
err = l.svcCtx.AgentWalletModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error {
|
||||
// 7.0 在事务中再次查询提现记录和钱包,确保数据是最新的且未被修改
|
||||
withdrawRecord, err = l.svcCtx.AgentWithdrawModel.FindOne(ctx, req.WithdrawId)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "查询提现记录失败")
|
||||
}
|
||||
|
||||
// 验证状态未被修改
|
||||
if withdrawRecord.Status != 0 {
|
||||
return errors.New("该提现记录已被审核,请勿重复操作")
|
||||
}
|
||||
|
||||
wallet, err = l.svcCtx.AgentWalletModel.FindOneByAgentId(ctx, withdrawRecord.AgentId)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "查询代理钱包失败")
|
||||
}
|
||||
|
||||
// 验证冻结金额是否匹配提现记录
|
||||
if wallet.FrozenAmount < withdrawRecord.FrozenAmount {
|
||||
return errors.Errorf("钱包冻结金额不足,当前冻结: %.2f,需要: %.2f", wallet.FrozenAmount, withdrawRecord.FrozenAmount)
|
||||
}
|
||||
|
||||
if req.Status == 1 {
|
||||
// ============ 审核通过 ============
|
||||
// 8.1 更新钱包:扣除冻结金额,增加累计提现金额
|
||||
wallet.FrozenAmount -= withdrawRecord.FrozenAmount
|
||||
wallet.TotalWithdraw += actualAmount // 累计实际到账金额
|
||||
|
||||
err := l.svcCtx.AgentWalletModel.UpdateWithVersion(ctx, session, wallet)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "更新钱包信息失败")
|
||||
}
|
||||
|
||||
// 8.2 更新提现记录状态
|
||||
updateSQL := `
|
||||
UPDATE agent_withdraw
|
||||
SET status = 1,
|
||||
tax_amount = ?,
|
||||
actual_amount = ?,
|
||||
audit_user_id = ?,
|
||||
audit_time = NOW(),
|
||||
audit_remark = ?,
|
||||
version = version + 1
|
||||
WHERE id = ? AND version = ?
|
||||
`
|
||||
_, err = session.Exec(updateSQL, taxAmount, actualAmount, adminUserId, req.AuditRemark, req.WithdrawId, withdrawRecord.Version)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "更新提现记录失败")
|
||||
}
|
||||
|
||||
logx.Infof("管理员 %s 审核通过提现记录 %s,代理ID: %s,提现金额: %.2f,实际到账: %.2f",
|
||||
adminUserId, req.WithdrawId, withdrawRecord.AgentId, withdrawRecord.WithdrawAmount, actualAmount)
|
||||
|
||||
} else {
|
||||
// ============ 审核拒绝 ============
|
||||
// 7.1 更新钱包:解冻金额,返回余额
|
||||
wallet.FrozenAmount -= withdrawRecord.FrozenAmount
|
||||
wallet.Balance += withdrawRecord.FrozenAmount
|
||||
|
||||
err := l.svcCtx.AgentWalletModel.UpdateWithVersion(ctx, session, wallet)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "更新钱包信息失败")
|
||||
}
|
||||
|
||||
// 7.2 更新提现记录状态
|
||||
updateSQL := `
|
||||
UPDATE agent_withdraw
|
||||
SET status = 2,
|
||||
audit_user_id = ?,
|
||||
audit_time = NOW(),
|
||||
audit_remark = ?,
|
||||
version = version + 1
|
||||
WHERE id = ? AND version = ?
|
||||
`
|
||||
_, err = session.Exec(updateSQL, adminUserId, req.AuditRemark, req.WithdrawId, withdrawRecord.Version)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "更新提现记录失败")
|
||||
}
|
||||
|
||||
logx.Infof("管理员 %s 拒绝提现记录 %s,代理ID: %s,提现金额: %.2f,原因: %s",
|
||||
adminUserId, req.WithdrawId, withdrawRecord.AgentId, withdrawRecord.WithdrawAmount, req.AuditRemark)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), err.Error())
|
||||
}
|
||||
|
||||
// 8. 返回成功响应
|
||||
message := "审核通过"
|
||||
if req.Status == 2 {
|
||||
message = "审核拒绝"
|
||||
}
|
||||
|
||||
return &types.AdminAuditAgentWithdrawResp{
|
||||
Success: true,
|
||||
Message: message,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package admin_agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"sim-server/app/main/api/internal/svc"
|
||||
"sim-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[string]struct{})
|
||||
for _, v := range list {
|
||||
productIds[v.ProductId] = struct{}{}
|
||||
}
|
||||
productNameMap := make(map[string]string)
|
||||
if len(productIds) > 0 {
|
||||
ids := make([]string, 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,62 @@
|
||||
package admin_agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
|
||||
"sim-server/app/main/api/internal/svc"
|
||||
"sim-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
|
||||
}
|
||||
getConfigInt := func(key string) int64 {
|
||||
config, err := l.svcCtx.AgentConfigModel.FindOneByConfigKey(l.ctx, key)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
value, _ := strconv.ParseInt(config.ConfigValue, 10, 64)
|
||||
return value
|
||||
}
|
||||
|
||||
// 系统简化:移除等级加成、升级费用、升级返佣、直接上级返佣配置、免税额度
|
||||
// 只保留佣金冻结配置和税率配置
|
||||
|
||||
// 获取佣金冻结配置
|
||||
commissionFreezeRatio := getConfigFloat("commission_freeze_ratio")
|
||||
commissionFreezeThreshold := getConfigFloat("commission_freeze_threshold")
|
||||
commissionFreezeDays := getConfigInt("commission_freeze_days")
|
||||
|
||||
return &types.AdminGetAgentConfigResp{
|
||||
CommissionFreeze: types.CommissionFreezeConfig{
|
||||
Ratio: commissionFreezeRatio,
|
||||
Threshold: commissionFreezeThreshold,
|
||||
Days: commissionFreezeDays,
|
||||
},
|
||||
TaxRate: getConfigFloat("tax_rate"),
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
package admin_agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"sim-server/app/main/api/internal/svc"
|
||||
"sim-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[string]struct{})
|
||||
linkIdList := make([]string, 0, len(links))
|
||||
for _, link := range links {
|
||||
productIdSet[link.ProductId] = struct{}{}
|
||||
linkIdList = append(linkIdList, link.Id)
|
||||
}
|
||||
productIdList := make([]string, 0, len(productIdSet))
|
||||
for id := range productIdSet {
|
||||
productIdList = append(productIdList, id)
|
||||
}
|
||||
productNameMap := make(map[string]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
|
||||
}
|
||||
}
|
||||
|
||||
// 批量查询短链信息
|
||||
shortLinkMap := make(map[string]string) // link_id -> short_link
|
||||
if len(linkIdList) > 0 {
|
||||
shortLinks, _ := l.svcCtx.AgentShortLinkModel.FindAll(l.ctx, l.svcCtx.AgentShortLinkModel.SelectBuilder().
|
||||
Where(squirrel.Eq{"link_id": linkIdList}).
|
||||
Where(squirrel.Eq{"type": 1}). // 推广报告类型
|
||||
Where(squirrel.Eq{"del_state": 0}), "")
|
||||
for _, sl := range shortLinks {
|
||||
if sl.LinkId.Valid && sl.ShortCode != "" && sl.PromotionDomain != "" {
|
||||
// 构建短链链接: {promotion_domain}/s/{shortCode}
|
||||
// promotion_domain 已经包含协议(http:// 或 https://)
|
||||
shortLinkMap[sl.LinkId.String] = fmt.Sprintf("%s/s/%s", sl.PromotionDomain, sl.ShortCode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
ShortLink: shortLinkMap[link.Id], // 短链链接
|
||||
CreateTime: link.CreateTime.Format("2006-01-02 15:04:05"),
|
||||
})
|
||||
}
|
||||
|
||||
resp = &types.AdminGetAgentLinkListResp{
|
||||
Total: total,
|
||||
Items: items,
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
package admin_agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"sim-server/app/main/api/internal/svc"
|
||||
"sim-server/app/main/api/internal/types"
|
||||
"sim-server/common/xerr"
|
||||
"sim-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, Level 筛选条件
|
||||
// 只保留 Mobile 和 Region 筛选
|
||||
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 {
|
||||
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)
|
||||
|
||||
wechatId := ""
|
||||
if agent.WechatId.Valid {
|
||||
wechatId = agent.WechatId.String
|
||||
}
|
||||
|
||||
// 获取区域
|
||||
region := ""
|
||||
if agent.Region.Valid {
|
||||
region = agent.Region.String
|
||||
}
|
||||
|
||||
// 系统简化:移除 Level, LevelName, TeamLeaderId, WithdrawnAmount, IsRealName 字段
|
||||
item := types.AgentListItem{
|
||||
Id: agent.Id,
|
||||
UserId: agent.UserId,
|
||||
Region: region,
|
||||
Mobile: agent.Mobile,
|
||||
WechatId: wechatId,
|
||||
AgentCode: agent.AgentCode,
|
||||
Balance: 0,
|
||||
FrozenAmount: 0,
|
||||
TotalEarnings: 0,
|
||||
CreateTime: agent.CreateTime.Format("2006-01-02 15:04:05"),
|
||||
}
|
||||
|
||||
if wallet != nil {
|
||||
item.Balance = wallet.Balance
|
||||
item.FrozenAmount = wallet.FrozenAmount
|
||||
item.TotalEarnings = wallet.TotalEarnings
|
||||
}
|
||||
|
||||
items = append(items, item)
|
||||
}
|
||||
|
||||
resp = &types.AdminGetAgentListResp{
|
||||
Total: total,
|
||||
Items: items,
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package admin_agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sim-server/common/xerr"
|
||||
|
||||
"github.com/Masterminds/squirrel"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"sim-server/app/main/api/internal/svc"
|
||||
"sim-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()
|
||||
|
||||
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[string]struct{})
|
||||
for _, order := range orders {
|
||||
productIdSet[order.ProductId] = struct{}{}
|
||||
}
|
||||
productIdList := make([]string, 0, len(productIdSet))
|
||||
for id := range productIdSet {
|
||||
productIdList = append(productIdList, id)
|
||||
}
|
||||
productNameMap := make(map[string]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,564 @@
|
||||
package admin_agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"sim-server/app/main/model"
|
||||
"sim-server/common/xerr"
|
||||
"sim-server/pkg/lzkit/crypto"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"sim-server/app/main/api/internal/svc"
|
||||
"sim-server/app/main/api/internal/types"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminGetAgentOrdersListLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminGetAgentOrdersListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminGetAgentOrdersListLogic {
|
||||
return &AdminGetAgentOrdersListLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminGetAgentOrdersListLogic) AdminGetAgentOrdersList(req *types.AdminGetAgentOrdersListReq) (resp *types.AdminGetAgentOrdersListResp, err error) {
|
||||
// 1. 查询订单列表(基础查询)
|
||||
orders, total, err := l.queryOrders(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(orders) == 0 {
|
||||
return &types.AdminGetAgentOrdersListResp{
|
||||
Total: 0,
|
||||
Items: []types.AgentOrdersListItem{},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 2. 收集所有需要的ID
|
||||
orderIds := make([]string, len(orders))
|
||||
userIds := make([]string, 0, len(orders))
|
||||
productIds := make([]string, 0, len(orders))
|
||||
for i, order := range orders {
|
||||
orderIds[i] = order.Id
|
||||
userIds = append(userIds, order.UserId)
|
||||
productIds = append(productIds, order.ProductId)
|
||||
}
|
||||
|
||||
// 3. 批量查询佣金信息
|
||||
commissionsMap := l.queryCommissionsByOrderIds(orderIds)
|
||||
|
||||
// 4. 批量查询代理信息
|
||||
agentIds := make([]string, 0)
|
||||
for _, commission := range commissionsMap {
|
||||
agentIds = append(agentIds, commission.AgentId)
|
||||
}
|
||||
agentsMap := l.queryAgentsByAgentIds(agentIds)
|
||||
|
||||
// 5. 批量查询用户信息
|
||||
usersMap := l.queryUsersByUserIds(userIds)
|
||||
|
||||
// 6. 批量查询产品信息
|
||||
productsMap := l.queryProductsByProductIds(productIds)
|
||||
|
||||
// 7. 批量查询查询记录(用于报告结果跳转)
|
||||
queriesMap := l.queryQueriesByOrderIds(orderIds)
|
||||
|
||||
// 8. 组装数据
|
||||
list := l.assembleOrderList(orders, commissionsMap, agentsMap, usersMap, productsMap, queriesMap)
|
||||
|
||||
// 8. 应用后端筛选条件(代理、用户、产品、佣金状态)
|
||||
filteredList := l.applyFilters(list, req, agentsMap, usersMap, productsMap, commissionsMap)
|
||||
|
||||
// 9. 应用分页(如果使用了后端筛选)
|
||||
if l.needsBackendFiltering(req) {
|
||||
total = int64(len(filteredList))
|
||||
// 手动分页
|
||||
page := req.Page
|
||||
if page <= 0 {
|
||||
page = 1
|
||||
}
|
||||
pageSize := req.PageSize
|
||||
if pageSize <= 0 {
|
||||
pageSize = 20
|
||||
}
|
||||
|
||||
start := (page - 1) * pageSize
|
||||
end := start + pageSize
|
||||
if start > int64(len(filteredList)) {
|
||||
return &types.AdminGetAgentOrdersListResp{
|
||||
Total: total,
|
||||
Items: []types.AgentOrdersListItem{},
|
||||
}, nil
|
||||
}
|
||||
if end > int64(len(filteredList)) {
|
||||
end = int64(len(filteredList))
|
||||
}
|
||||
|
||||
return &types.AdminGetAgentOrdersListResp{
|
||||
Total: total,
|
||||
Items: filteredList[start:end],
|
||||
}, nil
|
||||
}
|
||||
|
||||
return &types.AdminGetAgentOrdersListResp{
|
||||
Total: total,
|
||||
Items: filteredList,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// needsBackendFiltering 检查是否需要后端筛选
|
||||
func (l *AdminGetAgentOrdersListLogic) needsBackendFiltering(req *types.AdminGetAgentOrdersListReq) bool {
|
||||
return (req.AgentId != nil && *req.AgentId != "") ||
|
||||
(req.AgentMobile != nil && *req.AgentMobile != "") ||
|
||||
(req.UserMobile != nil && *req.UserMobile != "") ||
|
||||
(req.ProductName != nil && *req.ProductName != "") ||
|
||||
(req.CommissionStatus != nil)
|
||||
}
|
||||
|
||||
// applyFilters 应用后端筛选条件
|
||||
func (l *AdminGetAgentOrdersListLogic) applyFilters(
|
||||
list []types.AgentOrdersListItem,
|
||||
req *types.AdminGetAgentOrdersListReq,
|
||||
agentsMap map[string]*model.Agent,
|
||||
usersMap map[string]*model.User,
|
||||
productsMap map[string]*model.Product,
|
||||
commissionsMap map[string]*model.AgentCommission,
|
||||
) []types.AgentOrdersListItem {
|
||||
var result []types.AgentOrdersListItem
|
||||
|
||||
for _, item := range list {
|
||||
// 代理ID筛选
|
||||
if req.AgentId != nil && *req.AgentId != "" {
|
||||
if item.AgentId != *req.AgentId {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// 代理手机号筛选
|
||||
if req.AgentMobile != nil && *req.AgentMobile != "" {
|
||||
if !contains(item.AgentMobile, *req.AgentMobile) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// 用户手机号筛选
|
||||
if req.UserMobile != nil && *req.UserMobile != "" {
|
||||
if item.UserMobile == nil || !contains(*item.UserMobile, *req.UserMobile) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// 产品名称筛选
|
||||
if req.ProductName != nil && *req.ProductName != "" {
|
||||
if !contains(item.ProductName, *req.ProductName) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// 佣金状态筛选
|
||||
if req.CommissionStatus != nil {
|
||||
if item.CommissionStatus != *req.CommissionStatus {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
result = append(result, item)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// contains 检查字符串是否包含子字符串(不区分大小写)
|
||||
func contains(str, substr string) bool {
|
||||
return strings.Contains(strings.ToLower(str), strings.ToLower(substr))
|
||||
}
|
||||
|
||||
// queryOrders 查询订单列表
|
||||
func (l *AdminGetAgentOrdersListLogic) queryOrders(req *types.AdminGetAgentOrdersListReq) ([]*model.Order, int64, error) {
|
||||
builder := l.svcCtx.OrderModel.SelectBuilder()
|
||||
|
||||
// 订单筛选
|
||||
if req.OrderNo != nil && *req.OrderNo != "" {
|
||||
builder = builder.Where("`order_no` LIKE ?", "%"+*req.OrderNo+"%")
|
||||
}
|
||||
if req.PlatformOrderId != nil && *req.PlatformOrderId != "" {
|
||||
builder = builder.Where("`platform_order_id` LIKE ?", "%"+*req.PlatformOrderId+"%")
|
||||
}
|
||||
if req.PaymentPlatform != nil && *req.PaymentPlatform != "" {
|
||||
builder = builder.Where("`payment_platform` = ?", *req.PaymentPlatform)
|
||||
}
|
||||
if req.PaymentScene != nil && *req.PaymentScene != "" {
|
||||
builder = builder.Where("`payment_scene` = ?", *req.PaymentScene)
|
||||
}
|
||||
if req.OrderStatus != nil && *req.OrderStatus != "" {
|
||||
builder = builder.Where("`status` = ?", *req.OrderStatus)
|
||||
}
|
||||
|
||||
// 时间筛选
|
||||
if req.CreateTimeStart != nil && *req.CreateTimeStart != "" {
|
||||
createTimeStart, err := time.Parse("2006-01-02 15:04:05", *req.CreateTimeStart)
|
||||
if err == nil {
|
||||
builder = builder.Where("`create_time` >= ?", createTimeStart)
|
||||
}
|
||||
}
|
||||
if req.CreateTimeEnd != nil && *req.CreateTimeEnd != "" {
|
||||
createTimeEnd, err := time.Parse("2006-01-02 15:04:05", *req.CreateTimeEnd)
|
||||
if err == nil {
|
||||
builder = builder.Where("`create_time` <= ?", createTimeEnd)
|
||||
}
|
||||
}
|
||||
if req.PayTimeStart != nil && *req.PayTimeStart != "" {
|
||||
payTimeStart, err := time.Parse("2006-01-02 15:04:05", *req.PayTimeStart)
|
||||
if err == nil {
|
||||
builder = builder.Where("`pay_time` >= ?", payTimeStart)
|
||||
}
|
||||
}
|
||||
if req.PayTimeEnd != nil && *req.PayTimeEnd != "" {
|
||||
payTimeEnd, err := time.Parse("2006-01-02 15:04:05", *req.PayTimeEnd)
|
||||
if err == nil {
|
||||
builder = builder.Where("`pay_time` <= ?", payTimeEnd)
|
||||
}
|
||||
}
|
||||
|
||||
// 排序
|
||||
orderBy := "`create_time` DESC"
|
||||
if req.OrderBy != nil && *req.OrderBy != "" {
|
||||
orderType := "DESC"
|
||||
if req.OrderType != nil && strings.ToUpper(*req.OrderType) == "ASC" {
|
||||
orderType = "ASC"
|
||||
}
|
||||
orderBy = fmt.Sprintf("`%s` %s", *req.OrderBy, orderType)
|
||||
}
|
||||
|
||||
// 分页
|
||||
page := req.Page
|
||||
if page <= 0 {
|
||||
page = 1
|
||||
}
|
||||
pageSize := req.PageSize
|
||||
if pageSize <= 0 {
|
||||
pageSize = 20
|
||||
}
|
||||
|
||||
// 查询总数和列表
|
||||
orders, total, err := l.svcCtx.OrderModel.FindPageListByPageWithTotal(l.ctx, builder, page, pageSize, orderBy)
|
||||
if err != nil {
|
||||
return nil, 0, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询订单列表失败, %v", err)
|
||||
}
|
||||
|
||||
return orders, total, nil
|
||||
}
|
||||
|
||||
// queryCommissionsByOrderIds 批量查询佣金信息
|
||||
func (l *AdminGetAgentOrdersListLogic) queryCommissionsByOrderIds(orderIds []string) map[string]*model.AgentCommission {
|
||||
if len(orderIds) == 0 {
|
||||
return make(map[string]*model.AgentCommission)
|
||||
}
|
||||
|
||||
// 构建IN查询
|
||||
inClause := strings.Repeat("?,", len(orderIds))
|
||||
inClause = inClause[:len(inClause)-1]
|
||||
|
||||
commissions, err := l.svcCtx.AgentCommissionModel.FindAll(l.ctx,
|
||||
l.svcCtx.AgentCommissionModel.SelectBuilder().
|
||||
Where(fmt.Sprintf("`order_id` IN (%s)", inClause), stringsToInterfaces(orderIds)...),
|
||||
"")
|
||||
|
||||
if err != nil {
|
||||
logx.Errorf("查询佣金信息失败: %v", err)
|
||||
return make(map[string]*model.AgentCommission)
|
||||
}
|
||||
|
||||
// 构建map: orderId -> commission
|
||||
result := make(map[string]*model.AgentCommission)
|
||||
for _, commission := range commissions {
|
||||
result[commission.OrderId] = commission
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// queryAgentsByAgentIds 批量查询代理信息
|
||||
func (l *AdminGetAgentOrdersListLogic) queryAgentsByAgentIds(agentIds []string) map[string]*model.Agent {
|
||||
if len(agentIds) == 0 {
|
||||
return make(map[string]*model.Agent)
|
||||
}
|
||||
|
||||
// 去重
|
||||
uniqueAgentIds := make(map[string]bool)
|
||||
for _, id := range agentIds {
|
||||
uniqueAgentIds[id] = true
|
||||
}
|
||||
|
||||
ids := make([]string, 0, len(uniqueAgentIds))
|
||||
for id := range uniqueAgentIds {
|
||||
ids = append(ids, id)
|
||||
}
|
||||
|
||||
if len(ids) == 0 {
|
||||
return make(map[string]*model.Agent)
|
||||
}
|
||||
|
||||
// 构建IN查询
|
||||
inClause := strings.Repeat("?,", len(ids))
|
||||
inClause = inClause[:len(inClause)-1]
|
||||
|
||||
agents, err := l.svcCtx.AgentModel.FindAll(l.ctx,
|
||||
l.svcCtx.AgentModel.SelectBuilder().
|
||||
Where(fmt.Sprintf("`id` IN (%s)", inClause), stringsToInterfaces(ids)...),
|
||||
"")
|
||||
|
||||
if err != nil {
|
||||
logx.Errorf("查询代理信息失败: %v", err)
|
||||
return make(map[string]*model.Agent)
|
||||
}
|
||||
|
||||
// 构建map: agentId -> agent
|
||||
result := make(map[string]*model.Agent)
|
||||
for _, agent := range agents {
|
||||
result[agent.Id] = agent
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// queryUsersByUserIds 批量查询用户信息
|
||||
func (l *AdminGetAgentOrdersListLogic) queryUsersByUserIds(userIds []string) map[string]*model.User {
|
||||
if len(userIds) == 0 {
|
||||
return make(map[string]*model.User)
|
||||
}
|
||||
|
||||
// 去重
|
||||
uniqueUserIds := make(map[string]bool)
|
||||
for _, id := range userIds {
|
||||
uniqueUserIds[id] = true
|
||||
}
|
||||
|
||||
ids := make([]string, 0, len(uniqueUserIds))
|
||||
for id := range uniqueUserIds {
|
||||
ids = append(ids, id)
|
||||
}
|
||||
|
||||
if len(ids) == 0 {
|
||||
return make(map[string]*model.User)
|
||||
}
|
||||
|
||||
// 构建IN查询
|
||||
inClause := strings.Repeat("?,", len(ids))
|
||||
inClause = inClause[:len(inClause)-1]
|
||||
|
||||
users, err := l.svcCtx.UserModel.FindAll(l.ctx,
|
||||
l.svcCtx.UserModel.SelectBuilder().
|
||||
Where(fmt.Sprintf("`id` IN (%s)", inClause), stringsToInterfaces(ids)...),
|
||||
"")
|
||||
|
||||
if err != nil {
|
||||
logx.Errorf("查询用户信息失败: %v", err)
|
||||
return make(map[string]*model.User)
|
||||
}
|
||||
|
||||
// 构建map: userId -> user
|
||||
result := make(map[string]*model.User)
|
||||
for _, user := range users {
|
||||
result[user.Id] = user
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// queryProductsByProductIds 批量查询产品信息
|
||||
func (l *AdminGetAgentOrdersListLogic) queryProductsByProductIds(productIds []string) map[string]*model.Product {
|
||||
if len(productIds) == 0 {
|
||||
return make(map[string]*model.Product)
|
||||
}
|
||||
|
||||
// 去重
|
||||
uniqueProductIds := make(map[string]bool)
|
||||
for _, id := range productIds {
|
||||
uniqueProductIds[id] = true
|
||||
}
|
||||
|
||||
ids := make([]string, 0, len(uniqueProductIds))
|
||||
for id := range uniqueProductIds {
|
||||
ids = append(ids, id)
|
||||
}
|
||||
|
||||
if len(ids) == 0 {
|
||||
return make(map[string]*model.Product)
|
||||
}
|
||||
|
||||
// 构建IN查询
|
||||
inClause := strings.Repeat("?,", len(ids))
|
||||
inClause = inClause[:len(inClause)-1]
|
||||
|
||||
products, err := l.svcCtx.ProductModel.FindAll(l.ctx,
|
||||
l.svcCtx.ProductModel.SelectBuilder().
|
||||
Where(fmt.Sprintf("`id` IN (%s)", inClause), stringsToInterfaces(ids)...),
|
||||
"")
|
||||
|
||||
if err != nil {
|
||||
logx.Errorf("查询产品信息失败: %v", err)
|
||||
return make(map[string]*model.Product)
|
||||
}
|
||||
|
||||
// 构建map: productId -> product
|
||||
result := make(map[string]*model.Product)
|
||||
for _, product := range products {
|
||||
result[product.Id] = product
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// queryQueriesByOrderIds 批量查询查询记录信息
|
||||
func (l *AdminGetAgentOrdersListLogic) queryQueriesByOrderIds(orderIds []string) map[string]*model.Query {
|
||||
if len(orderIds) == 0 {
|
||||
return make(map[string]*model.Query)
|
||||
}
|
||||
|
||||
// 构建IN查询
|
||||
inClause := strings.Repeat("?,", len(orderIds))
|
||||
inClause = inClause[:len(inClause)-1]
|
||||
|
||||
queries, err := l.svcCtx.QueryModel.FindAll(l.ctx,
|
||||
l.svcCtx.QueryModel.SelectBuilder().
|
||||
Where(fmt.Sprintf("`order_id` IN (%s)", inClause), stringsToInterfaces(orderIds)...),
|
||||
"")
|
||||
|
||||
if err != nil {
|
||||
logx.Errorf("查询查询记录失败: %v", err)
|
||||
return make(map[string]*model.Query)
|
||||
}
|
||||
|
||||
// 构建map: orderId -> query
|
||||
result := make(map[string]*model.Query)
|
||||
for _, query := range queries {
|
||||
result[query.OrderId] = query
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// assembleOrderList 组装订单列表数据
|
||||
func (l *AdminGetAgentOrdersListLogic) assembleOrderList(
|
||||
orders []*model.Order,
|
||||
commissionsMap map[string]*model.AgentCommission,
|
||||
agentsMap map[string]*model.Agent,
|
||||
usersMap map[string]*model.User,
|
||||
productsMap map[string]*model.Product,
|
||||
queriesMap map[string]*model.Query,
|
||||
) []types.AgentOrdersListItem {
|
||||
var list []types.AgentOrdersListItem
|
||||
|
||||
for _, order := range orders {
|
||||
// 获取佣金信息
|
||||
var commissionAmount float64
|
||||
var commissionStatus int64 = 2 // 默认已取消
|
||||
var agentId string
|
||||
var agentMobile string
|
||||
|
||||
if commission, ok := commissionsMap[order.Id]; ok {
|
||||
commissionAmount = commission.Amount
|
||||
commissionStatus = commission.Status
|
||||
agentId = commission.AgentId
|
||||
|
||||
// 获取代理信息并解密手机号
|
||||
if agent, ok := agentsMap[commission.AgentId]; ok {
|
||||
if agent.Mobile != "" {
|
||||
// 解密代理手机号
|
||||
mobile, err := crypto.DecryptMobile(agent.Mobile, l.svcCtx.Config.Encrypt.SecretKey)
|
||||
if err != nil {
|
||||
logx.Errorf("解密代理手机号失败: %v", err)
|
||||
agentMobile = ""
|
||||
}
|
||||
agentMobile = mobile
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 没有佣金记录,使用订单ID作为代理ID
|
||||
agentId = order.Id
|
||||
}
|
||||
|
||||
// 获取用户手机号并解密
|
||||
var userMobile *string
|
||||
if user, ok := usersMap[order.UserId]; ok && user.Mobile.Valid {
|
||||
// 解密用户手机号
|
||||
mobile, err := crypto.DecryptMobile(user.Mobile.String, l.svcCtx.Config.Encrypt.SecretKey)
|
||||
if err != nil {
|
||||
logx.Errorf("解密用户手机号失败: %v", err)
|
||||
userMobile = nil
|
||||
} else {
|
||||
userMobile = &mobile
|
||||
}
|
||||
}
|
||||
|
||||
// 获取产品名称
|
||||
productName := "未知产品"
|
||||
if product, ok := productsMap[order.ProductId]; ok {
|
||||
productName = product.ProductName
|
||||
}
|
||||
|
||||
// 获取平台订单号
|
||||
platformOrderId := ""
|
||||
if order.PlatformOrderId.Valid {
|
||||
platformOrderId = order.PlatformOrderId.String
|
||||
}
|
||||
|
||||
// 获取支付时间
|
||||
var payTime *string
|
||||
if order.PayTime.Valid {
|
||||
pt := order.PayTime.Time.Format("2006-01-02 15:04:05")
|
||||
payTime = &pt
|
||||
}
|
||||
|
||||
// 获取查询记录ID(用于报告结果跳转)
|
||||
var queryId *string
|
||||
if query, ok := queriesMap[order.Id]; ok {
|
||||
queryId = &query.Id
|
||||
}
|
||||
|
||||
list = append(list, types.AgentOrdersListItem{
|
||||
Id: order.Id,
|
||||
OrderNo: order.OrderNo,
|
||||
PlatformOrderId: platformOrderId,
|
||||
AgentId: agentId,
|
||||
AgentMobile: agentMobile,
|
||||
UserId: order.UserId,
|
||||
UserMobile: userMobile,
|
||||
ProductId: order.ProductId,
|
||||
ProductName: productName,
|
||||
OrderAmount: order.Amount,
|
||||
CommissionAmount: commissionAmount,
|
||||
PaymentPlatform: order.PaymentPlatform,
|
||||
PaymentScene: order.PaymentScene,
|
||||
OrderStatus: order.Status,
|
||||
CommissionStatus: commissionStatus,
|
||||
CreateTime: order.CreateTime.Format("2006-01-02 15:04:05"),
|
||||
PayTime: payTime,
|
||||
QueryId: queryId,
|
||||
})
|
||||
}
|
||||
|
||||
return list
|
||||
}
|
||||
|
||||
// stringsToInterfaces 将字符串数组转换为interface数组
|
||||
func stringsToInterfaces(strs []string) []interface{} {
|
||||
result := make([]interface{}, len(strs))
|
||||
for i, str := range strs {
|
||||
result[i] = str
|
||||
}
|
||||
return result
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package admin_agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sim-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"sim-server/app/main/api/internal/svc"
|
||||
"sim-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()
|
||||
|
||||
// 如果提供了产品ID,直接过滤
|
||||
if req.ProductId != nil {
|
||||
builder = builder.Where("product_id = ?", *req.ProductId)
|
||||
}
|
||||
|
||||
// 如果提供了产品名称,通过关联查询 product 表过滤
|
||||
if req.ProductName != nil && *req.ProductName != "" {
|
||||
builder = builder.Where("product_id IN (SELECT id FROM product WHERE product_name LIKE ?)", "%"+*req.ProductName+"%")
|
||||
}
|
||||
|
||||
// 分页查询
|
||||
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)
|
||||
}
|
||||
|
||||
// 组装响应(通过 product_id 查询产品名称)
|
||||
items := make([]types.AgentProductConfigItem, 0, len(configs))
|
||||
for _, config := range configs {
|
||||
// 通过 product_id 查询产品信息获取产品名称
|
||||
product, err := l.svcCtx.ProductModel.FindOne(l.ctx, config.ProductId)
|
||||
productName := ""
|
||||
if err == nil {
|
||||
productName = product.ProductName
|
||||
} else {
|
||||
// 如果产品不存在,记录日志但不影响主流程
|
||||
l.Infof("查询产品信息失败, productId: %d, err: %v", config.ProductId, err)
|
||||
}
|
||||
|
||||
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: 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,158 @@
|
||||
package admin_agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"sim-server/app/main/api/internal/svc"
|
||||
"sim-server/app/main/api/internal/types"
|
||||
"sim-server/common/globalkey"
|
||||
"sim-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminGetAgentWithdrawListLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminGetAgentWithdrawListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminGetAgentWithdrawListLogic {
|
||||
return &AdminGetAgentWithdrawListLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminGetAgentWithdrawListLogic) AdminGetAgentWithdrawList(req *types.AdminGetAgentWithdrawListReq) (resp *types.AdminGetAgentWithdrawListResp, err error) {
|
||||
// 1. 构建查询条件
|
||||
whereConditions := []string{fmt.Sprintf("del_state = %d", globalkey.DelStateNo)}
|
||||
args := []interface{}{}
|
||||
|
||||
// 可选过滤条件
|
||||
if req.AgentId != nil && *req.AgentId != "" {
|
||||
whereConditions = append(whereConditions, "agent_id = ?")
|
||||
args = append(args, *req.AgentId)
|
||||
}
|
||||
|
||||
if req.Status != nil {
|
||||
whereConditions = append(whereConditions, "status = ?")
|
||||
args = append(args, *req.Status)
|
||||
}
|
||||
|
||||
whereClause := strings.Join(whereConditions, " AND ")
|
||||
|
||||
// 2. 构建查询builder
|
||||
builder := l.svcCtx.AgentWithdrawModel.SelectBuilder().
|
||||
Where(whereClause, args...).
|
||||
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.AgentWithdrawModel.FindCount(l.ctx, builder, "id")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询提现记录总数失败: %v", err)
|
||||
}
|
||||
|
||||
if total == 0 {
|
||||
return &types.AdminGetAgentWithdrawListResp{
|
||||
Total: 0,
|
||||
Items: []types.AgentWithdrawListItem{},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 5. 查询列表
|
||||
builder = builder.Limit(uint64(pageSize)).Offset(uint64(offset))
|
||||
withdrawals, err := l.svcCtx.AgentWithdrawModel.FindAll(l.ctx, builder, "")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询提现记录列表失败: %v", err)
|
||||
}
|
||||
|
||||
// 6. 组装响应
|
||||
var items []types.AgentWithdrawListItem
|
||||
for _, withdrawal := range withdrawals {
|
||||
// 处理代理ID
|
||||
agentId := withdrawal.AgentId
|
||||
|
||||
// 处理代理手机号
|
||||
agentMobile := ""
|
||||
if withdrawal.AgentMobile.Valid {
|
||||
agentMobile = withdrawal.AgentMobile.String
|
||||
}
|
||||
|
||||
// 处理代理编码
|
||||
var agentCode int64 = 0
|
||||
if withdrawal.AgentCode.Valid {
|
||||
agentCode = withdrawal.AgentCode.Int64
|
||||
}
|
||||
|
||||
// 银行卡号脱敏(只显示前4位和后4位)
|
||||
bankCardNumber := withdrawal.BankCardNumber
|
||||
if len(bankCardNumber) > 8 {
|
||||
bankCardNumber = fmt.Sprintf("%s****%s", bankCardNumber[:4], bankCardNumber[len(bankCardNumber)-4:])
|
||||
}
|
||||
|
||||
// 处理开户支行
|
||||
bankBranch := ""
|
||||
if withdrawal.BankBranch.Valid {
|
||||
bankBranch = withdrawal.BankBranch.String
|
||||
}
|
||||
|
||||
// 处理审核人ID
|
||||
auditUserId := ""
|
||||
if withdrawal.AuditUserId.Valid {
|
||||
auditUserId = withdrawal.AuditUserId.String
|
||||
}
|
||||
|
||||
// 处理审核时间
|
||||
auditTime := ""
|
||||
if withdrawal.AuditTime.Valid {
|
||||
auditTime = withdrawal.AuditTime.Time.Format("2006-01-02 15:04:05")
|
||||
}
|
||||
|
||||
// 处理审核备注
|
||||
auditRemark := ""
|
||||
if withdrawal.AuditRemark.Valid {
|
||||
auditRemark = withdrawal.AuditRemark.String
|
||||
}
|
||||
|
||||
items = append(items, types.AgentWithdrawListItem{
|
||||
Id: withdrawal.Id,
|
||||
AgentId: agentId,
|
||||
AgentMobile: agentMobile,
|
||||
AgentCode: agentCode,
|
||||
WithdrawAmount: withdrawal.WithdrawAmount,
|
||||
TaxAmount: withdrawal.TaxAmount,
|
||||
ActualAmount: withdrawal.ActualAmount,
|
||||
FrozenAmount: withdrawal.FrozenAmount,
|
||||
AccountName: withdrawal.AccountName,
|
||||
BankCardNumber: bankCardNumber, // 脱敏显示
|
||||
BankCardNumberFull: withdrawal.BankCardNumber, // 完整卡号用于审核
|
||||
BankBranch: bankBranch,
|
||||
Status: withdrawal.Status,
|
||||
AuditUserId: auditUserId,
|
||||
AuditTime: auditTime,
|
||||
AuditRemark: auditRemark,
|
||||
CreateTime: withdrawal.CreateTime.Format("2006-01-02 15:04:05"),
|
||||
})
|
||||
}
|
||||
|
||||
return &types.AdminGetAgentWithdrawListResp{
|
||||
Total: total,
|
||||
Items: items,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package admin_agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"sim-server/app/main/api/internal/svc"
|
||||
"sim-server/app/main/api/internal/types"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type AdminRefundAgentOrderLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewAdminRefundAgentOrderLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AdminRefundAgentOrderLogic {
|
||||
return &AdminRefundAgentOrderLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AdminRefundAgentOrderLogic) AdminRefundAgentOrder(req *types.AdminRefundAgentOrderReq) (resp *types.AdminRefundAgentOrderResp, err error) {
|
||||
// todo: add your logic here and delete this line
|
||||
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
package admin_agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"strconv"
|
||||
"sim-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"sim-server/app/main/api/internal/svc"
|
||||
"sim-server/app/main/api/internal/types"
|
||||
"sim-server/app/main/model"
|
||||
|
||||
"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) {
|
||||
// 系统简化:移除等级加成、升级费用、升级返佣、直接上级返佣配置、免税额度
|
||||
// 只保留佣金冻结配置和税率配置
|
||||
|
||||
configTypeForKey := func(key string) string {
|
||||
switch key {
|
||||
case "commission_freeze_ratio", "commission_freeze_threshold", "commission_freeze_days":
|
||||
return "commission_freeze"
|
||||
case "tax_rate":
|
||||
return "tax"
|
||||
default:
|
||||
return "other"
|
||||
}
|
||||
}
|
||||
|
||||
updateConfig := func(key string, value *float64) error {
|
||||
if value == nil {
|
||||
return nil
|
||||
}
|
||||
valStr := strconv.FormatFloat(*value, 'f', -1, 64)
|
||||
config, err := l.svcCtx.AgentConfigModel.FindOneByConfigKey(l.ctx, key)
|
||||
if err != nil {
|
||||
if errors.Is(err, model.ErrNotFound) {
|
||||
cfg := &model.AgentConfig{
|
||||
ConfigKey: key,
|
||||
ConfigValue: valStr,
|
||||
ConfigType: configTypeForKey(key),
|
||||
Description: sql.NullString{},
|
||||
DeleteTime: sql.NullTime{},
|
||||
Version: 0,
|
||||
}
|
||||
_, insErr := l.svcCtx.AgentConfigModel.Insert(l.ctx, nil, cfg)
|
||||
if insErr != nil {
|
||||
return errors.Wrapf(insErr, "创建配置失败, key: %s", key)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return errors.Wrapf(err, "查询配置失败, key: %s", key)
|
||||
}
|
||||
config.ConfigValue = valStr
|
||||
if uErr := l.svcCtx.AgentConfigModel.UpdateWithVersion(l.ctx, nil, config); uErr != nil {
|
||||
if errors.Is(uErr, model.ErrNoRowsUpdate) {
|
||||
latestByKey, reErr := l.svcCtx.AgentConfigModel.FindOneByConfigKey(l.ctx, key)
|
||||
if reErr != nil {
|
||||
if errors.Is(reErr, model.ErrNotFound) {
|
||||
cfg := &model.AgentConfig{
|
||||
ConfigKey: key,
|
||||
ConfigValue: valStr,
|
||||
ConfigType: configTypeForKey(key),
|
||||
Description: sql.NullString{},
|
||||
DeleteTime: sql.NullTime{},
|
||||
Version: 0,
|
||||
}
|
||||
_, insErr := l.svcCtx.AgentConfigModel.Insert(l.ctx, nil, cfg)
|
||||
if insErr != nil {
|
||||
return errors.Wrapf(insErr, "创建配置失败, key: %s", key)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return errors.Wrapf(reErr, "查询最新配置失败, key: %s", key)
|
||||
}
|
||||
latestByKey.ConfigValue = valStr
|
||||
return l.svcCtx.AgentConfigModel.UpdateWithVersion(l.ctx, nil, latestByKey)
|
||||
}
|
||||
return uErr
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 更新佣金冻结配置
|
||||
if req.CommissionFreeze != nil {
|
||||
if err := updateConfig("commission_freeze_ratio", &req.CommissionFreeze.Ratio); err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新佣金冻结比例失败, %v", err)
|
||||
}
|
||||
if err := updateConfig("commission_freeze_threshold", &req.CommissionFreeze.Threshold); err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新佣金冻结阈值失败, %v", err)
|
||||
}
|
||||
// 更新解冻天数(整数类型)
|
||||
if req.CommissionFreeze.Days > 0 {
|
||||
daysFloat := float64(req.CommissionFreeze.Days)
|
||||
if err := updateConfig("commission_freeze_days", &daysFloat); 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)
|
||||
}
|
||||
|
||||
return &types.AdminUpdateAgentConfigResp{
|
||||
Success: true,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package admin_agent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"sim-server/common/xerr"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"sim-server/app/main/api/internal/svc"
|
||||
"sim-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
|
||||
|
||||
// 价格阈值(可选)
|
||||
if req.PriceThreshold != nil {
|
||||
config.PriceThreshold = sql.NullFloat64{Float64: *req.PriceThreshold, Valid: true}
|
||||
} else {
|
||||
config.PriceThreshold = sql.NullFloat64{Valid: false}
|
||||
}
|
||||
|
||||
// 提价手续费比例(可选)
|
||||
if req.PriceFeeRate != nil {
|
||||
config.PriceFeeRate = sql.NullFloat64{Float64: *req.PriceFeeRate, Valid: true}
|
||||
} else {
|
||||
config.PriceFeeRate = sql.NullFloat64{Valid: false}
|
||||
}
|
||||
|
||||
// 更新配置
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user