|
|
@@ -2,6 +2,8 @@ import { Repository, Like } from 'typeorm'
|
|
|
import { FastifyInstance } from 'fastify'
|
|
|
import { Team } from '../entities/team.entity'
|
|
|
import { IncomeRecords, IncomeType } from '../entities/income-records.entity'
|
|
|
+import { Member } from '../entities/member.entity'
|
|
|
+import { User } from '../entities/user.entity'
|
|
|
import { PaginationResponse } from '../dto/common.dto'
|
|
|
import { CreateTeamBody, UpdateTeamBody, ListTeamQuery } from '../dto/team.dto'
|
|
|
import { UserService } from './user.service'
|
|
|
@@ -12,12 +14,16 @@ import * as randomstring from 'randomstring'
|
|
|
export class TeamService {
|
|
|
private teamRepository: Repository<Team>
|
|
|
private incomeRecordsRepository: Repository<IncomeRecords>
|
|
|
+ private memberRepository: Repository<Member>
|
|
|
+ private userRepository: Repository<User>
|
|
|
private userService: UserService
|
|
|
private sysConfigService: SysConfigService
|
|
|
|
|
|
constructor(app: FastifyInstance) {
|
|
|
this.teamRepository = app.dataSource.getRepository(Team)
|
|
|
this.incomeRecordsRepository = app.dataSource.getRepository(IncomeRecords)
|
|
|
+ this.memberRepository = app.dataSource.getRepository(Member)
|
|
|
+ this.userRepository = app.dataSource.getRepository(User)
|
|
|
this.userService = new UserService(app)
|
|
|
this.sysConfigService = new SysConfigService(app)
|
|
|
}
|
|
|
@@ -122,8 +128,12 @@ export class TeamService {
|
|
|
totalTeams: number
|
|
|
totalRevenue: number
|
|
|
todayRevenue: number
|
|
|
+ totalSales: number
|
|
|
+ todaySales: number
|
|
|
+ todayDAU: number
|
|
|
+ todayNewUsers: number
|
|
|
averageCommissionRate: number
|
|
|
- allTeams: Array<{ id: number; name: string; totalRevenue: number; todayRevenue: number }>
|
|
|
+ allTeams: Array<{ id: number; name: string; totalRevenue: number; todayRevenue: number; totalSales: number; todaySales: number; todayDAU: number; todayNewUsers: number }>
|
|
|
}> {
|
|
|
// 根据 userId 参数决定查询范围
|
|
|
const whereCondition = userId ? { userId } : {}
|
|
|
@@ -134,15 +144,18 @@ export class TeamService {
|
|
|
select: ['id', 'name', 'userId', 'commissionRate']
|
|
|
})
|
|
|
|
|
|
- // 获取今天的开始时间
|
|
|
+ // 获取今天的开始时间(使用UTC时区)
|
|
|
const today = new Date()
|
|
|
- today.setHours(0, 0, 0, 0)
|
|
|
+ today.setUTCHours(0, 0, 0, 0)
|
|
|
const todayEnd = new Date()
|
|
|
- todayEnd.setHours(23, 59, 59, 999)
|
|
|
+ todayEnd.setUTCHours(23, 59, 59, 999)
|
|
|
|
|
|
// 获取所有团队的 userId 列表,并添加默认的 agentId 0
|
|
|
const teamUserIds = teams.map(team => team.userId)
|
|
|
const allUserIds = [...teamUserIds, 0] // 添加默认的 agentId 0
|
|
|
+
|
|
|
+ // 获取所有团队的 ID 列表,用于查询会员数据
|
|
|
+ const teamIds = teams.map(team => team.id)
|
|
|
|
|
|
// 查询所有团队的总收入统计(通过 userId 关联,包括默认的 agentId 0)
|
|
|
const totalRevenueStats =
|
|
|
@@ -172,9 +185,65 @@ export class TeamService {
|
|
|
.getRawMany()
|
|
|
: []
|
|
|
|
|
|
+ // 查询所有团队的总售卖金额统计(通过 userId 关联,包括默认的 agentId 0)
|
|
|
+ const totalSalesStats =
|
|
|
+ allUserIds.length > 0
|
|
|
+ ? await this.incomeRecordsRepository
|
|
|
+ .createQueryBuilder('record')
|
|
|
+ .select(['record.agentId as userId', 'SUM(record.orderPrice) as totalSales'])
|
|
|
+ .where('record.delFlag = :delFlag', { delFlag: false })
|
|
|
+ .andWhere('record.status = :status', { status: true })
|
|
|
+ .andWhere('record.agentId IN (:...allUserIds)', { allUserIds })
|
|
|
+ .groupBy('record.agentId')
|
|
|
+ .getRawMany()
|
|
|
+ : []
|
|
|
+
|
|
|
+ // 查询所有团队的今日售卖金额统计(通过 userId 关联,包括默认的 agentId 0)
|
|
|
+ const todaySalesStats =
|
|
|
+ allUserIds.length > 0
|
|
|
+ ? await this.incomeRecordsRepository
|
|
|
+ .createQueryBuilder('record')
|
|
|
+ .select(['record.agentId as userId', 'SUM(record.orderPrice) as todaySales'])
|
|
|
+ .where('record.delFlag = :delFlag', { delFlag: false })
|
|
|
+ .andWhere('record.status = :status', { status: true })
|
|
|
+ .andWhere('record.createdAt >= :today', { today })
|
|
|
+ .andWhere('record.createdAt <= :todayEnd', { todayEnd })
|
|
|
+ .andWhere('record.agentId IN (:...allUserIds)', { allUserIds })
|
|
|
+ .groupBy('record.agentId')
|
|
|
+ .getRawMany()
|
|
|
+ : []
|
|
|
+
|
|
|
+ // 查询今日日活统计(基于会员的lastLoginAt字段)
|
|
|
+ const todayDAUStats = teamIds.length > 0
|
|
|
+ ? await this.memberRepository
|
|
|
+ .createQueryBuilder('member')
|
|
|
+ .select(['member.teamId as teamId', 'COUNT(DISTINCT member.userId) as dau'])
|
|
|
+ .where('member.lastLoginAt >= :today', { today })
|
|
|
+ .andWhere('member.lastLoginAt <= :todayEnd', { todayEnd })
|
|
|
+ .andWhere('member.teamId IN (:...teamIds)', { teamIds })
|
|
|
+ .groupBy('member.teamId')
|
|
|
+ .getRawMany()
|
|
|
+ : []
|
|
|
+
|
|
|
+ // 查询今日新增用户统计(基于会员的createdAt字段)
|
|
|
+ const todayNewUsersStats = teamIds.length > 0
|
|
|
+ ? await this.memberRepository
|
|
|
+ .createQueryBuilder('member')
|
|
|
+ .select(['member.teamId as teamId', 'COUNT(member.id) as newUsers'])
|
|
|
+ .where('member.createdAt >= :today', { today })
|
|
|
+ .andWhere('member.createdAt <= :todayEnd', { todayEnd })
|
|
|
+ .andWhere('member.teamId IN (:...teamIds)', { teamIds })
|
|
|
+ .groupBy('member.teamId')
|
|
|
+ .getRawMany()
|
|
|
+ : []
|
|
|
+
|
|
|
// 构建统计数据映射(使用 userId 作为键)
|
|
|
const totalRevenueMap = new Map<number, number>()
|
|
|
const todayRevenueMap = new Map<number, number>()
|
|
|
+ const totalSalesMap = new Map<number, number>()
|
|
|
+ const todaySalesMap = new Map<number, number>()
|
|
|
+ const todayDAUMap = new Map<number, number>()
|
|
|
+ const todayNewUsersMap = new Map<number, number>()
|
|
|
|
|
|
totalRevenueStats.forEach(stat => {
|
|
|
totalRevenueMap.set(stat.userId, Number(stat.totalRevenue) || 0)
|
|
|
@@ -184,13 +253,33 @@ export class TeamService {
|
|
|
todayRevenueMap.set(stat.userId, Number(stat.todayRevenue) || 0)
|
|
|
})
|
|
|
|
|
|
+ totalSalesStats.forEach(stat => {
|
|
|
+ totalSalesMap.set(stat.userId, Number(stat.totalSales) || 0)
|
|
|
+ })
|
|
|
+
|
|
|
+ todaySalesStats.forEach(stat => {
|
|
|
+ todaySalesMap.set(stat.userId, Number(stat.todaySales) || 0)
|
|
|
+ })
|
|
|
+
|
|
|
+ todayDAUStats.forEach(stat => {
|
|
|
+ todayDAUMap.set(stat.teamId, Number(stat.dau) || 0)
|
|
|
+ })
|
|
|
+
|
|
|
+ todayNewUsersStats.forEach(stat => {
|
|
|
+ todayNewUsersMap.set(stat.teamId, Number(stat.newUsers) || 0)
|
|
|
+ })
|
|
|
+
|
|
|
// 计算统计数据
|
|
|
const statistics = {
|
|
|
totalTeams: teams.length,
|
|
|
totalRevenue: 0,
|
|
|
todayRevenue: 0,
|
|
|
+ totalSales: 0,
|
|
|
+ todaySales: 0,
|
|
|
+ todayDAU: 0,
|
|
|
+ todayNewUsers: 0,
|
|
|
averageCommissionRate: 0,
|
|
|
- allTeams: [] as Array<{ id: number; name: string; totalRevenue: number; todayRevenue: number }>
|
|
|
+ allTeams: [] as Array<{ id: number; name: string; totalRevenue: number; todayRevenue: number; totalSales: number; todaySales: number; todayDAU: number; todayNewUsers: number }>
|
|
|
}
|
|
|
|
|
|
let totalCommissionRate = 0
|
|
|
@@ -199,32 +288,56 @@ export class TeamService {
|
|
|
teams.forEach(team => {
|
|
|
const teamTotalRevenue = totalRevenueMap.get(team.userId) || 0
|
|
|
const teamTodayRevenue = todayRevenueMap.get(team.userId) || 0
|
|
|
+ const teamTotalSales = totalSalesMap.get(team.userId) || 0
|
|
|
+ const teamTodaySales = todaySalesMap.get(team.userId) || 0
|
|
|
+ const teamTodayDAU = todayDAUMap.get(team.id) || 0
|
|
|
+ const teamTodayNewUsers = todayNewUsersMap.get(team.id) || 0
|
|
|
|
|
|
statistics.totalRevenue += teamTotalRevenue
|
|
|
statistics.todayRevenue += teamTodayRevenue
|
|
|
+ statistics.totalSales += teamTotalSales
|
|
|
+ statistics.todaySales += teamTodaySales
|
|
|
+ statistics.todayDAU += teamTodayDAU
|
|
|
+ statistics.todayNewUsers += teamTodayNewUsers
|
|
|
totalCommissionRate += Number(team.commissionRate)
|
|
|
|
|
|
statistics.allTeams.push({
|
|
|
id: team.id,
|
|
|
name: team.name,
|
|
|
totalRevenue: Number(teamTotalRevenue.toFixed(5)),
|
|
|
- todayRevenue: Number(teamTodayRevenue.toFixed(5))
|
|
|
+ todayRevenue: Number(teamTodayRevenue.toFixed(5)),
|
|
|
+ totalSales: Number(teamTotalSales.toFixed(5)),
|
|
|
+ todaySales: Number(teamTodaySales.toFixed(5)),
|
|
|
+ todayDAU: Number(teamTodayDAU),
|
|
|
+ todayNewUsers: Number(teamTodayNewUsers)
|
|
|
})
|
|
|
})
|
|
|
|
|
|
// 添加默认团队数据(agentId 为 0)
|
|
|
const defaultTotalRevenue = totalRevenueMap.get(0) || 0
|
|
|
const defaultTodayRevenue = todayRevenueMap.get(0) || 0
|
|
|
+ const defaultTotalSales = totalSalesMap.get(0) || 0
|
|
|
+ const defaultTodaySales = todaySalesMap.get(0) || 0
|
|
|
+ const defaultTodayDAU = todayDAUMap.get(0) || 0
|
|
|
+ const defaultTodayNewUsers = todayNewUsersMap.get(0) || 0
|
|
|
|
|
|
statistics.totalRevenue += defaultTotalRevenue
|
|
|
statistics.todayRevenue += defaultTodayRevenue
|
|
|
+ statistics.totalSales += defaultTotalSales
|
|
|
+ statistics.todaySales += defaultTodaySales
|
|
|
+ statistics.todayDAU += defaultTodayDAU
|
|
|
+ statistics.todayNewUsers += defaultTodayNewUsers
|
|
|
|
|
|
// 将默认团队数据添加到列表最后
|
|
|
statistics.allTeams.push({
|
|
|
id: 0, // 使用 0 作为默认团队的 ID
|
|
|
name: '默认',
|
|
|
totalRevenue: Number(defaultTotalRevenue.toFixed(5)),
|
|
|
- todayRevenue: Number(defaultTodayRevenue.toFixed(5))
|
|
|
+ todayRevenue: Number(defaultTodayRevenue.toFixed(5)),
|
|
|
+ totalSales: Number(defaultTotalSales.toFixed(5)),
|
|
|
+ todaySales: Number(defaultTodaySales.toFixed(5)),
|
|
|
+ todayDAU: Number(defaultTodayDAU),
|
|
|
+ todayNewUsers: Number(defaultTodayNewUsers)
|
|
|
})
|
|
|
|
|
|
statistics.averageCommissionRate = teams.length > 0 ? Number((totalCommissionRate / teams.length).toFixed(2)) : 0
|