|
|
@@ -1,4 +1,4 @@
|
|
|
-import { Repository, Like } from 'typeorm'
|
|
|
+import { Repository, Like, Between } from 'typeorm'
|
|
|
import { FastifyInstance } from 'fastify'
|
|
|
import { TeamDomain } from '../entities/team-domain.entity'
|
|
|
import { PaginationResponse } from '../dto/common.dto'
|
|
|
@@ -6,14 +6,20 @@ import { CreateTeamDomainBody, UpdateTeamDomainBody, ListTeamDomainQuery } from
|
|
|
import { UserService } from './user.service'
|
|
|
import { TeamService } from './team.service'
|
|
|
import { TeamMembersService } from './team-members.service'
|
|
|
+import { Member } from '../entities/member.entity'
|
|
|
+import { IncomeRecords } from '../entities/income-records.entity'
|
|
|
|
|
|
export class TeamDomainService {
|
|
|
private teamDomainRepository: Repository<TeamDomain>
|
|
|
+ private memberRepository: Repository<Member>
|
|
|
+ private incomeRecordsRepository: Repository<IncomeRecords>
|
|
|
private userService: UserService
|
|
|
private teamService: TeamService
|
|
|
private teamMembersService: TeamMembersService
|
|
|
constructor(app: FastifyInstance) {
|
|
|
this.teamDomainRepository = app.dataSource.getRepository(TeamDomain)
|
|
|
+ this.memberRepository = app.dataSource.getRepository(Member)
|
|
|
+ this.incomeRecordsRepository = app.dataSource.getRepository(IncomeRecords)
|
|
|
this.userService = new UserService(app)
|
|
|
this.teamService = new TeamService(app)
|
|
|
this.teamMembersService = new TeamMembersService(app)
|
|
|
@@ -33,18 +39,20 @@ export class TeamDomainService {
|
|
|
return this.teamDomainRepository.save(teamDomain)
|
|
|
}
|
|
|
|
|
|
- async createBatch(data: CreateTeamDomainBody): Promise<{ success: TeamDomain[], failed: { domain: string, error: string }[] }> {
|
|
|
+ async createBatch(
|
|
|
+ data: CreateTeamDomainBody
|
|
|
+ ): Promise<{ success: TeamDomain[]; failed: { domain: string; error: string }[] }> {
|
|
|
await this.teamService.findById(data.teamId)
|
|
|
|
|
|
// 解析域名字符串,支持逗号和换行分隔
|
|
|
const domains = this.parseDomains(data.domain)
|
|
|
-
|
|
|
+
|
|
|
if (domains.length === 0) {
|
|
|
throw new Error('没有有效的域名')
|
|
|
}
|
|
|
|
|
|
const success: TeamDomain[] = []
|
|
|
- const failed: { domain: string, error: string }[] = []
|
|
|
+ const failed: { domain: string; error: string }[] = []
|
|
|
|
|
|
// 检查已存在的域名
|
|
|
const existingDomains = await this.teamDomainRepository.find({
|
|
|
@@ -54,16 +62,16 @@ export class TeamDomainService {
|
|
|
|
|
|
// 批量创建域名
|
|
|
const domainsToCreate = domains.filter(domain => !existingDomainSet.has(domain))
|
|
|
-
|
|
|
+
|
|
|
if (domainsToCreate.length > 0) {
|
|
|
- const teamDomains = domainsToCreate.map(domain =>
|
|
|
+ const teamDomains = domainsToCreate.map(domain =>
|
|
|
this.teamDomainRepository.create({
|
|
|
teamId: data.teamId,
|
|
|
domain: domain.trim(),
|
|
|
description: data.description
|
|
|
})
|
|
|
)
|
|
|
-
|
|
|
+
|
|
|
const savedDomains = await this.teamDomainRepository.save(teamDomains)
|
|
|
success.push(...savedDomains)
|
|
|
}
|
|
|
@@ -193,4 +201,103 @@ export class TeamDomainService {
|
|
|
|
|
|
return groupedData
|
|
|
}
|
|
|
+
|
|
|
+ async getDailyStatistics(domain?: string): Promise<{ id: number; domain: string; todayNewUsers: number; todayIncome: number }[]> {
|
|
|
+ // 获取今天的开始和结束时间
|
|
|
+ const today = new Date()
|
|
|
+ today.setHours(0, 0, 0, 0)
|
|
|
+ const tomorrow = new Date(today)
|
|
|
+ tomorrow.setDate(tomorrow.getDate() + 1)
|
|
|
+
|
|
|
+ // 构建查询条件
|
|
|
+ const whereCondition: any = {}
|
|
|
+ if (domain) {
|
|
|
+ whereCondition.domain = domain
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取域名
|
|
|
+ const teamDomains = await this.teamDomainRepository.find({
|
|
|
+ where: whereCondition
|
|
|
+ })
|
|
|
+
|
|
|
+ const results: { id: number; domain: string; todayNewUsers: number; todayIncome: number }[] = []
|
|
|
+
|
|
|
+ for (const teamDomain of teamDomains) {
|
|
|
+ // 统计今日新增用户数
|
|
|
+ const todayNewUsers = await this.memberRepository.count({
|
|
|
+ where: {
|
|
|
+ domainId: teamDomain.id,
|
|
|
+ createdAt: Between(today, tomorrow)
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ // 统计今日收入
|
|
|
+ const todayIncomeRecords = await this.incomeRecordsRepository
|
|
|
+ .createQueryBuilder('record')
|
|
|
+ .innerJoin('member', 'm', 'm.userId = record.userId')
|
|
|
+ .select('SUM(CAST(record.incomeAmount AS DECIMAL(10,5)))', 'totalIncome')
|
|
|
+ .where('m.domainId = :domainId', { domainId: teamDomain.id })
|
|
|
+ .andWhere('record.createdAt >= :startDate', { startDate: today })
|
|
|
+ .andWhere('record.createdAt < :endDate', { endDate: tomorrow })
|
|
|
+ .andWhere('record.delFlag = :delFlag', { delFlag: false })
|
|
|
+ .andWhere('record.status = :status', { status: true })
|
|
|
+ .getRawOne()
|
|
|
+
|
|
|
+ const todayIncome = todayIncomeRecords?.totalIncome ? parseFloat(todayIncomeRecords.totalIncome) : 0
|
|
|
+
|
|
|
+ results.push({
|
|
|
+ id: teamDomain.id,
|
|
|
+ domain: teamDomain.domain,
|
|
|
+ todayNewUsers,
|
|
|
+ todayIncome
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ return results
|
|
|
+ }
|
|
|
+
|
|
|
+ async getAllStatistics(domain?: string): Promise<{ id: number; domain: string; totalNewUsers: number; totalIncome: number }[]> {
|
|
|
+ // 构建查询条件
|
|
|
+ const whereCondition: any = {}
|
|
|
+ if (domain) {
|
|
|
+ whereCondition.domain = domain
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取域名
|
|
|
+ const teamDomains = await this.teamDomainRepository.find({
|
|
|
+ where: whereCondition
|
|
|
+ })
|
|
|
+
|
|
|
+ const results: { id: number; domain: string; totalNewUsers: number; totalIncome: number }[] = []
|
|
|
+
|
|
|
+ for (const teamDomain of teamDomains) {
|
|
|
+ // 统计总新增用户数
|
|
|
+ const totalNewUsers = await this.memberRepository.count({
|
|
|
+ where: {
|
|
|
+ domainId: teamDomain.id
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ // 统计总收入
|
|
|
+ const totalIncomeRecords = await this.incomeRecordsRepository
|
|
|
+ .createQueryBuilder('record')
|
|
|
+ .innerJoin('member', 'm', 'm.userId = record.userId')
|
|
|
+ .select('SUM(CAST(record.incomeAmount AS DECIMAL(10,5)))', 'totalIncome')
|
|
|
+ .where('m.domainId = :domainId', { domainId: teamDomain.id })
|
|
|
+ .andWhere('record.delFlag = :delFlag', { delFlag: false })
|
|
|
+ .andWhere('record.status = :status', { status: true })
|
|
|
+ .getRawOne()
|
|
|
+
|
|
|
+ const totalIncome = totalIncomeRecords?.totalIncome ? parseFloat(totalIncomeRecords.totalIncome) : 0
|
|
|
+
|
|
|
+ results.push({
|
|
|
+ id: teamDomain.id,
|
|
|
+ domain: teamDomain.domain,
|
|
|
+ totalNewUsers,
|
|
|
+ totalIncome
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ return results
|
|
|
+ }
|
|
|
}
|