|
|
@@ -6,7 +6,7 @@ import { Member } from '../entities/member.entity'
|
|
|
import { TeamDomain } from '../entities/team-domain.entity'
|
|
|
import { Team } from '../entities/team.entity'
|
|
|
import { PaginationResponse } from '../dto/common.dto'
|
|
|
-import { CreateTeamMembersBody, UpdateTeamMembersBody, ListTeamMembersQuery, TeamMemberStatsQuery, TeamMemberStatsResponse } from '../dto/team-members.dto'
|
|
|
+import { CreateTeamMembersBody, UpdateTeamMembersBody, ListTeamMembersQuery, TeamMemberStatsQuery, TeamMemberStatsResponse, TeamLeaderStatsQuery, TeamLeaderStatsResponse } from '../dto/team-members.dto'
|
|
|
import { UserService } from './user.service'
|
|
|
import { UserRole } from '../entities/user.entity'
|
|
|
|
|
|
@@ -107,58 +107,8 @@ export class TeamMembersService {
|
|
|
order: { createdAt: 'DESC' }
|
|
|
})
|
|
|
|
|
|
- // 为每个成员计算实际收入(从income_records表统计)
|
|
|
- const membersWithRevenue = await Promise.all(
|
|
|
- members.map(async (member) => {
|
|
|
- // 统计总收入 - 只计算个人分成金额
|
|
|
- const totalRevenueRecords = await this.incomeRecordsRepository
|
|
|
- .createQueryBuilder('record')
|
|
|
- .where('record.personalAgentId = :teamMemberUserId', {
|
|
|
- teamMemberUserId: member.userId
|
|
|
- })
|
|
|
- .andWhere('record.delFlag = :delFlag', { delFlag: false })
|
|
|
- .andWhere('record.status = :status', { status: true })
|
|
|
- .andWhere('record.personalIncomeAmount > 0')
|
|
|
- .getMany()
|
|
|
-
|
|
|
- const totalRevenue = totalRevenueRecords.reduce((sum, record) => {
|
|
|
- // 只统计个人分成金额
|
|
|
- return sum + Number(record.personalIncomeAmount || 0)
|
|
|
- }, 0)
|
|
|
-
|
|
|
- // 统计今日收入 - 只计算个人分成金额
|
|
|
- const today = new Date()
|
|
|
- const todayStart = new Date(today.getFullYear(), today.getMonth(), today.getDate())
|
|
|
- const todayEnd = new Date(today.getFullYear(), today.getMonth(), today.getDate(), 23, 59, 59)
|
|
|
-
|
|
|
- const todayRevenueRecords = await this.incomeRecordsRepository
|
|
|
- .createQueryBuilder('record')
|
|
|
- .where('record.personalAgentId = :teamMemberUserId', {
|
|
|
- teamMemberUserId: member.userId
|
|
|
- })
|
|
|
- .andWhere('record.delFlag = :delFlag', { delFlag: false })
|
|
|
- .andWhere('record.status = :status', { status: true })
|
|
|
- .andWhere('record.personalIncomeAmount > 0')
|
|
|
- .andWhere('record.createdAt >= :todayStart', { todayStart })
|
|
|
- .andWhere('record.createdAt <= :todayEnd', { todayEnd })
|
|
|
- .getMany()
|
|
|
-
|
|
|
- const todayRevenue = todayRevenueRecords.reduce((sum, record) => {
|
|
|
- // 只统计个人分成金额
|
|
|
- return sum + Number(record.personalIncomeAmount || 0)
|
|
|
- }, 0)
|
|
|
-
|
|
|
- // 返回更新后的成员数据
|
|
|
- return {
|
|
|
- ...member,
|
|
|
- totalRevenue: totalRevenue,
|
|
|
- todayRevenue: todayRevenue
|
|
|
- }
|
|
|
- })
|
|
|
- )
|
|
|
-
|
|
|
return {
|
|
|
- content: membersWithRevenue,
|
|
|
+ content: members,
|
|
|
metadata: {
|
|
|
total: Number(total),
|
|
|
page: Number(page) || 0,
|
|
|
@@ -167,6 +117,7 @@ export class TeamMembersService {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+
|
|
|
async update(data: UpdateTeamMembersBody): Promise<TeamMembers> {
|
|
|
const { id, ...updateData } = data
|
|
|
|
|
|
@@ -250,29 +201,29 @@ export class TeamMembersService {
|
|
|
.getRawMany()
|
|
|
: []
|
|
|
|
|
|
- // 查询所有成员的总售卖金额统计
|
|
|
+ // 查询所有成员的总售卖金额统计(按个人代理归属)
|
|
|
const totalSalesStats = memberUserIds.length > 0
|
|
|
? await this.incomeRecordsRepository
|
|
|
.createQueryBuilder('record')
|
|
|
- .select(['record.userId as userId', 'SUM(record.orderPrice) as totalSales'])
|
|
|
+ .select(['record.personalAgentId as personalAgentId', 'SUM(record.orderPrice) as totalSales'])
|
|
|
.where('record.delFlag = :delFlag', { delFlag: false })
|
|
|
.andWhere('record.status = :status', { status: true })
|
|
|
- .andWhere('record.userId IN (:...memberUserIds)', { memberUserIds })
|
|
|
- .groupBy('record.userId')
|
|
|
+ .andWhere('record.personalAgentId IN (:...memberUserIds)', { memberUserIds })
|
|
|
+ .groupBy('record.personalAgentId')
|
|
|
.getRawMany()
|
|
|
: []
|
|
|
|
|
|
- // 查询所有成员的今日售卖金额统计
|
|
|
+ // 查询所有成员的今日售卖金额统计(按个人代理归属)
|
|
|
const todaySalesStats = memberUserIds.length > 0
|
|
|
? await this.incomeRecordsRepository
|
|
|
.createQueryBuilder('record')
|
|
|
- .select(['record.userId as userId', 'SUM(record.orderPrice) as todaySales'])
|
|
|
+ .select(['record.personalAgentId as personalAgentId', '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.userId IN (:...memberUserIds)', { memberUserIds })
|
|
|
- .groupBy('record.userId')
|
|
|
+ .andWhere('record.personalAgentId IN (:...memberUserIds)', { memberUserIds })
|
|
|
+ .groupBy('record.personalAgentId')
|
|
|
.getRawMany()
|
|
|
: []
|
|
|
|
|
|
@@ -316,12 +267,12 @@ export class TeamMembersService {
|
|
|
todayRevenueMap.set(stat.userId, Number(stat.todayRevenue) || 0)
|
|
|
})
|
|
|
|
|
|
- totalSalesStats.forEach(stat => {
|
|
|
- totalSalesMap.set(stat.userId, Number(stat.totalSales) || 0)
|
|
|
+ totalSalesStats.forEach((stat: any) => {
|
|
|
+ totalSalesMap.set(stat.personalAgentId, Number(stat.totalSales) || 0)
|
|
|
})
|
|
|
|
|
|
- todaySalesStats.forEach(stat => {
|
|
|
- todaySalesMap.set(stat.userId, Number(stat.todaySales) || 0)
|
|
|
+ todaySalesStats.forEach((stat: any) => {
|
|
|
+ todaySalesMap.set(stat.personalAgentId, Number(stat.todaySales) || 0)
|
|
|
})
|
|
|
|
|
|
todayDAUStats.forEach((stat: any) => {
|
|
|
@@ -556,4 +507,113 @@ export class TeamMembersService {
|
|
|
|
|
|
return domainStats
|
|
|
}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取团队统计数据(队长视角)
|
|
|
+ */
|
|
|
+ async getTeamLeaderStats(query: TeamLeaderStatsQuery, teamLeaderUserId: number): Promise<TeamLeaderStatsResponse> {
|
|
|
+ const { teamId } = query
|
|
|
+
|
|
|
+ // 获取团队信息
|
|
|
+ const team = await this.teamRepository.findOne({ where: { id: teamId } })
|
|
|
+ if (!team) {
|
|
|
+ throw new Error('团队不存在')
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取团队成员列表
|
|
|
+ const members = await this.teamMembersRepository.find({
|
|
|
+ where: { teamId: teamId },
|
|
|
+ order: { createdAt: 'DESC' }
|
|
|
+ })
|
|
|
+
|
|
|
+ // 计算今日时间范围
|
|
|
+ const today = new Date()
|
|
|
+ const todayStart = new Date(today.getFullYear(), today.getMonth(), today.getDate())
|
|
|
+ const todayEnd = new Date(today.getFullYear(), today.getMonth(), today.getDate(), 23, 59, 59)
|
|
|
+
|
|
|
+ // 一次性查询团队成员的全部收入记录
|
|
|
+ const memberUserIds = members.map(m => m.userId)
|
|
|
+ const allMemberIncomeRecords = await this.incomeRecordsRepository
|
|
|
+ .createQueryBuilder('record')
|
|
|
+ .where('record.personalAgentId IN (:...memberUserIds)', { memberUserIds })
|
|
|
+ .andWhere('record.delFlag = :delFlag', { delFlag: false })
|
|
|
+ .andWhere('record.status = :status', { status: true })
|
|
|
+ .getMany()
|
|
|
+
|
|
|
+ // 按 personalAgentId 分组
|
|
|
+ const recordsByAgent = new Map<number, any[]>()
|
|
|
+ for (const rec of allMemberIncomeRecords) {
|
|
|
+ const key = Number(rec.personalAgentId)
|
|
|
+ if (!recordsByAgent.has(key)) recordsByAgent.set(key, [])
|
|
|
+ recordsByAgent.get(key)!.push(rec)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 为每个成员计算统计数据(内存聚合,无额外查询)
|
|
|
+ const membersStats = await Promise.all(
|
|
|
+ members.map(async (member) => {
|
|
|
+ const memberRecords = recordsByAgent.get(member.userId) || []
|
|
|
+
|
|
|
+ const totalRevenue = memberRecords
|
|
|
+ .filter(r => Number(r.personalIncomeAmount || 0) > 0)
|
|
|
+ .reduce((sum, r) => sum + Number(r.personalIncomeAmount || 0), 0)
|
|
|
+
|
|
|
+ const todayRevenue = memberRecords
|
|
|
+ .filter(r => Number(r.personalIncomeAmount || 0) > 0)
|
|
|
+ .filter(r => {
|
|
|
+ const d = new Date(r.createdAt)
|
|
|
+ return d >= todayStart && d <= todayEnd
|
|
|
+ })
|
|
|
+ .reduce((sum, r) => sum + Number(r.personalIncomeAmount || 0), 0)
|
|
|
+
|
|
|
+ const totalSales = memberRecords.reduce((sum, r) => sum + Number(r.orderPrice || 0), 0)
|
|
|
+
|
|
|
+ const todaySales = memberRecords
|
|
|
+ .filter(r => {
|
|
|
+ const d = new Date(r.createdAt)
|
|
|
+ return d >= todayStart && d <= todayEnd
|
|
|
+ })
|
|
|
+ .reduce((sum, r) => sum + Number(r.orderPrice || 0), 0)
|
|
|
+
|
|
|
+ // 计算队长从该成员获得的实际收入(该成员订单中队长分得的部分)
|
|
|
+ const teamLeaderTotalIncome = memberRecords.reduce((sum, record) => {
|
|
|
+ const leaderPart = Number(record.incomeAmount || 0)
|
|
|
+ return sum + leaderPart
|
|
|
+ }, 0)
|
|
|
+
|
|
|
+ const teamLeaderTodayIncome = memberRecords
|
|
|
+ .filter(record => {
|
|
|
+ const recordDate = new Date(record.createdAt)
|
|
|
+ return recordDate >= todayStart && recordDate <= todayEnd
|
|
|
+ })
|
|
|
+ .reduce((sum, record) => {
|
|
|
+ const leaderPart = Number(record.incomeAmount || 0)
|
|
|
+ return sum + leaderPart
|
|
|
+ }, 0)
|
|
|
+
|
|
|
+ const personalCommissionRate = Number(member.commissionRate || 0)
|
|
|
+ const teamCommissionRate = Number(team.commissionRate || 0)
|
|
|
+ const memberActualRate = teamCommissionRate - personalCommissionRate
|
|
|
+
|
|
|
+ return {
|
|
|
+ memberId: member.id,
|
|
|
+ memberName: member.name,
|
|
|
+ personalCommissionRate: Number(personalCommissionRate.toFixed(2)),
|
|
|
+ actualRate: Number(memberActualRate.toFixed(2)),
|
|
|
+ totalRevenue: Number(totalRevenue.toFixed(5)),
|
|
|
+ todayRevenue: Number(todayRevenue.toFixed(5)),
|
|
|
+ totalSales: Number(totalSales.toFixed(5)),
|
|
|
+ todaySales: Number(todaySales.toFixed(5)),
|
|
|
+ teamLeaderTotalIncome: Number(teamLeaderTotalIncome.toFixed(5)),
|
|
|
+ teamLeaderTodayIncome: Number(teamLeaderTodayIncome.toFixed(5))
|
|
|
+ }
|
|
|
+ })
|
|
|
+ )
|
|
|
+
|
|
|
+ return {
|
|
|
+ teamId: team.id,
|
|
|
+ teamName: team.name,
|
|
|
+ teamCommissionRate: Number(Number(team.commissionRate || 0).toFixed(2)),
|
|
|
+ membersStats
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|