Ver Fonte

增强团队域名功能,支持批量创建域名并返回创建结果,新增获取所有团队域名列表的接口,同时更新相关DTO和服务逻辑以处理域名解析和分组查询。

wuyi há 3 meses atrás
pai
commit
c5beb77f14

+ 25 - 2
src/controllers/team-domain.controller.ts

@@ -23,8 +23,22 @@ export class TeamDomainController {
 
   async create(request: FastifyRequest<{ Body: CreateTeamDomainBody }>, reply: FastifyReply) {
     try {
-      const teamDomain = await this.teamDomainService.create(request.body)
-      return reply.code(201).send(teamDomain)
+      // 检查是否包含多个域名(通过中英文逗号、分号或换行分隔)
+      const hasMultipleDomains = /[,;\n\r]/.test(request.body.domain)
+      
+      if (hasMultipleDomains) {
+        // 批量创建
+        const result = await this.teamDomainService.createBatch(request.body)
+        return reply.code(201).send({
+          message: `批量创建完成,成功: ${result.success.length} 个,失败: ${result.failed.length} 个`,
+          success: result.success,
+          failed: result.failed
+        })
+      } else {
+        // 单个创建
+        const teamDomain = await this.teamDomainService.create(request.body)
+        return reply.code(201).send(teamDomain)
+      }
     } catch (error) {
       return reply.code(500).send({ message: '创建团队域名失败' })
     }
@@ -63,6 +77,15 @@ export class TeamDomainController {
     }
   }
 
+  async showAll(request: FastifyRequest<{ Querystring: ListTeamDomainQuery }>, reply: FastifyReply) {
+    try {
+      const result = await this.teamDomainService.findAllGroupedByTeam(request.query)
+      return reply.send(result)
+    } catch (error) {
+      return reply.code(500).send({ message: '获取团队域名列表失败' })
+    }
+  }
+
   async update(request: FastifyRequest<{ Params: TeamDomainParams; Body: UpdateTeamDomainBody }>, reply: FastifyReply) {
     try {
       const { id } = request.params

+ 1 - 1
src/dto/team-domain.dto.ts

@@ -3,7 +3,7 @@ import { Pagination } from './common.dto'
 
 export interface CreateTeamDomainBody {
   teamId: number
-  domain: string
+  domain: string // 支持单个域名或批量域名(用逗号或换行分隔)
   description: string
 }
 

+ 7 - 0
src/routes/team-domain.routes.ts

@@ -26,6 +26,13 @@ export default async function teamDomainRoutes(fastify: FastifyInstance) {
     teamDomainController.findAll.bind(teamDomainController)
   )
 
+  // 管理员获取所有团队域名列表
+  fastify.get<{ Querystring: ListTeamDomainQuery }>(
+    '/show',
+    { onRequest: [authenticate, hasAnyRole(UserRole.ADMIN)] },
+    teamDomainController.showAll.bind(teamDomainController)
+  )
+
   // 获取单个团队域名
   fastify.get<{ Params: TeamDomainParams }>(
     '/:id',

+ 87 - 0
src/services/team-domain.service.ts

@@ -33,6 +33,59 @@ export class TeamDomainService {
     return this.teamDomainRepository.save(teamDomain)
   }
 
+  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 existingDomains = await this.teamDomainRepository.find({
+      where: { domain: domains.map(d => ({ domain: d })) as any }
+    })
+    const existingDomainSet = new Set(existingDomains.map(d => d.domain))
+
+    // 批量创建域名
+    const domainsToCreate = domains.filter(domain => !existingDomainSet.has(domain))
+    
+    if (domainsToCreate.length > 0) {
+      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)
+    }
+
+    // 记录失败的域名(已存在的域名)
+    domains.forEach(domain => {
+      if (existingDomainSet.has(domain)) {
+        failed.push({ domain, error: '域名已存在' })
+      }
+    })
+
+    return { success, failed }
+  }
+
+  private parseDomains(domainString: string): string[] {
+    // 支持中英文逗号、分号和换行分隔,去除空白字符
+    return domainString
+      .split(/[,;\n\r]+/)
+      .map(domain => domain.trim())
+      .filter(domain => domain.length > 0)
+  }
+
   async findById(id: number): Promise<TeamDomain> {
     return this.teamDomainRepository.findOneOrFail({ where: { id } })
   }
@@ -106,4 +159,38 @@ export class TeamDomainService {
       order: { createdAt: 'DESC' }
     })
   }
+
+  async findAllGroupedByTeam(query?: ListTeamDomainQuery): Promise<Record<number, TeamDomain[]>> {
+    const { id, teamId, domain } = query || {}
+
+    const where: any = {}
+
+    if (id) {
+      where.id = id
+    }
+
+    if (teamId) {
+      where.teamId = teamId
+    }
+
+    if (domain) {
+      where.domain = Like(`%${domain}%`)
+    }
+
+    const teamDomains = await this.teamDomainRepository.find({
+      where,
+      order: { teamId: 'ASC', createdAt: 'DESC' }
+    })
+
+    // 按 teamId 分组
+    const groupedData: Record<number, TeamDomain[]> = {}
+    teamDomains.forEach(domain => {
+      if (!groupedData[domain.teamId]) {
+        groupedData[domain.teamId] = []
+      }
+      groupedData[domain.teamId].push(domain)
+    })
+
+    return groupedData
+  }
 }