Browse Source

更新系统配置相关逻辑,重命名API路由前缀,新增团队配置的创建、更新、删除和查询功能,扩展DTO和服务逻辑以支持团队ID,优化相关控制器和服务的实现。

wuyi 3 months ago
parent
commit
0c42f93735

+ 1 - 1
src/app.ts

@@ -84,7 +84,7 @@ export const createApp = async () => {
 
   app.register(userRoutes, { prefix: '/api/users' })
   app.register(fileRoutes, { prefix: '/api/files' })
-  app.register(sysConfigRoutes, { prefix: '/api/sys-config' })
+  app.register(sysConfigRoutes, { prefix: '/api/config' })
   app.register(incomeRecordsRoutes, { prefix: '/api/income' })
   app.register(financeRoutes, { prefix: '/api/finance' })
   app.register(teamRoutes, { prefix: '/api/teams' })

+ 76 - 6
src/controllers/sys-config.controller.ts

@@ -1,8 +1,7 @@
 import { FastifyRequest, FastifyReply, FastifyInstance } from 'fastify'
 import { SysConfigService } from '../services/sys-config.service'
-import { CreateSysConfigBody } from '../dto/sys-config.dto'
-import { UpdateSysConfigBody } from '../dto/sys-config.dto'
-import { ListSysConfigQuery } from '../dto/sys-config.dto'
+import { CreateSysConfigBody, UpdateSysConfigBody, ListSysConfigQuery, CreateTeamConfigBody, UpdateTeamConfigBody, ListTeamConfigQuery, GetTeamConfigParams } from '../dto/sys-config.dto'
+import { UserRole } from '../entities/user.entity'
 
 export class SysConfigController {
   private sysConfigService: SysConfigService
@@ -24,7 +23,7 @@ export class SysConfigController {
 
   async update(request: FastifyRequest<{ Params: { name: string }, Body: UpdateSysConfigBody }>, reply: FastifyReply) {
     try {
-      const config = await this.sysConfigService.update(request.params.name, request.body)
+      const config = await this.sysConfigService.update(request.params.name, request.body, request.body.teamId)
       return reply.send(config)
     } catch (error) {
       return reply.code(500).send(error)
@@ -51,8 +50,8 @@ export class SysConfigController {
 
   async list(request: FastifyRequest<{ Querystring: ListSysConfigQuery }>, reply: FastifyReply) {
     try {
-      const { page = 0, size = 20, name, type } = request.query
-      const configs = await this.sysConfigService.list(Number(page), Number(size), name, type)
+      const { page = 0, size = 20, name, type, teamId } = request.query
+      const configs = await this.sysConfigService.list(Number(page), Number(size), name, type, teamId)
       return reply.send(configs)
     } catch (error) {
       return reply.code(500).send(error)
@@ -67,4 +66,75 @@ export class SysConfigController {
       return reply.code(500).send(error)
     }
   }
+
+  // 团队配置相关接口
+  async createTeamConfig(request: FastifyRequest<{ Body: CreateTeamConfigBody & { teamId?: number } }>, reply: FastifyReply) {
+    try {
+      const { teamId, ...body } = request.body
+      const userId = request.user.id
+      const userRole = request.user.role
+      
+      const config = await this.sysConfigService.createTeamConfig(body, userId, userRole, teamId)
+      return reply.code(201).send(config)
+    } catch (error) {
+      return reply.code(500).send(error)
+    }
+  }
+
+  async updateTeamConfig(request: FastifyRequest<{ Params: { name: string }, Body: UpdateTeamConfigBody & { teamId?: number } }>, reply: FastifyReply) {
+    try {
+      const { name } = request.params
+      const { teamId, ...body } = request.body
+      const userId = request.user.id
+      const userRole = request.user.role
+      
+      const config = await this.sysConfigService.updateTeamConfig(name, body, userId, userRole, teamId)
+      return reply.send(config)
+    } catch (error) {
+      return reply.code(500).send(error)
+    }
+  }
+
+  async deleteTeamConfig(request: FastifyRequest<{ Params: { name: string }, Body: { teamId?: number } }>, reply: FastifyReply) {
+    try {
+      const { name } = request.params
+      const { teamId } = request.body
+      const userId = request.user.id
+      const userRole = request.user.role
+      
+      await this.sysConfigService.deleteTeamConfig(name, userId, userRole, teamId)
+      return reply.send({ success: true })
+    } catch (error) {
+      return reply.code(500).send(error)
+    }
+  }
+
+  async getTeamConfig(request: FastifyRequest<{ Params: { name: string }, Querystring: { teamId?: string } }>, reply: FastifyReply) {
+    try {
+      const { name } = request.params
+      const { teamId } = request.query
+      const userId = request.user.id
+      const userRole = request.user.role
+      
+      // 管理员查询:teamId为可选,不传则查询所有团队
+      const config = await this.sysConfigService.getTeamConfig(name, userId, userRole, teamId ? Number(teamId) : undefined)
+      return reply.send(config)
+    } catch (error) {
+      return reply.code(500).send(error)
+    }
+  }
+
+  async listTeamConfigs(request: FastifyRequest<{ Querystring: ListTeamConfigQuery & { teamId?: string } }>, reply: FastifyReply) {
+    try {
+      const { teamId, ...query } = request.query
+      const userId = request.user.id
+      const userRole = request.user.role
+      
+      // 管理员查询:teamId为可选,不传则查询所有团队
+      const configs = await this.sysConfigService.listTeamConfigs(query, userId, userRole, teamId ? Number(teamId) : undefined)
+      return reply.send(configs)
+    } catch (error) {
+      return reply.code(500).send(error)
+    }
+  }
 } 

+ 29 - 0
src/dto/sys-config.dto.ts

@@ -5,12 +5,14 @@ export interface CreateSysConfigBody {
   value: string
   remark?: string
   type?: ConfigType
+  teamId?: number
 }
 
 export interface UpdateSysConfigBody {
   value: string
   remark?: string
   type?: ConfigType
+  teamId?: number
 }
 
 export interface ListSysConfigQuery {
@@ -18,8 +20,35 @@ export interface ListSysConfigQuery {
   size?: number
   name?: string
   type?: ConfigType
+  teamId?: number
 }
 
 export interface GetSysConfigParams {
   name: string
+  teamId?: number
+}
+
+// 团队配置相关的DTO
+export interface CreateTeamConfigBody {
+  name: string
+  value: string
+  remark?: string
+  type?: ConfigType
+}
+
+export interface UpdateTeamConfigBody {
+  value: string
+  remark?: string
+  type?: ConfigType
+}
+
+export interface ListTeamConfigQuery {
+  page?: number
+  size?: number
+  name?: string
+  type?: ConfigType
+}
+
+export interface GetTeamConfigParams {
+  name: string
 } 

+ 3 - 0
src/entities/sys-config.entity.ts

@@ -16,6 +16,9 @@ export class SysConfig {
   @PrimaryGeneratedColumn()
   id: number
 
+  @Column({ default: 0 })
+  teamId: number
+
   @Column({ length: 100, unique: true })
   name: string
 

+ 33 - 4
src/routes/sys-config.routes.ts

@@ -1,10 +1,8 @@
 import { FastifyInstance } from 'fastify'
-import { authenticate, hasRole } from '../middlewares/auth.middleware'
+import { authenticate, hasRole, hasAnyRole } from '../middlewares/auth.middleware'
 import { UserRole } from '../entities/user.entity'
 import { SysConfigController } from '../controllers/sys-config.controller'
-import { CreateSysConfigBody } from '../dto/sys-config.dto'
-import { UpdateSysConfigBody } from '../dto/sys-config.dto'
-import { ListSysConfigQuery } from '../dto/sys-config.dto'
+import { CreateSysConfigBody, UpdateSysConfigBody, ListSysConfigQuery, CreateTeamConfigBody, UpdateTeamConfigBody, ListTeamConfigQuery } from '../dto/sys-config.dto'
 
 export default async function sysConfigRoutes(fastify: FastifyInstance) {
   const sysConfigController = new SysConfigController(fastify)
@@ -36,4 +34,35 @@ export default async function sysConfigRoutes(fastify: FastifyInstance) {
   )
 
   fastify.get('/types/all', { onRequest: [authenticate] }, sysConfigController.getConfigTypes.bind(sysConfigController))
+
+  // 团队配置相关路由
+  fastify.post<{ Body: CreateTeamConfigBody & { teamId?: number } }>(
+    '/team',
+    { onRequest: [hasAnyRole(UserRole.ADMIN, UserRole.TEAM)] },
+    sysConfigController.createTeamConfig.bind(sysConfigController)
+  )
+
+  fastify.post<{ Params: { name: string }; Body: UpdateTeamConfigBody & { teamId?: number } }>(
+    '/team/:name',
+    { onRequest: [hasAnyRole(UserRole.ADMIN, UserRole.TEAM)] },
+    sysConfigController.updateTeamConfig.bind(sysConfigController)
+  )
+
+  fastify.post<{ Params: { name: string }; Body: { teamId?: number } }>(
+    '/team/:name/delete',
+    { onRequest: [hasAnyRole(UserRole.ADMIN, UserRole.TEAM)] },
+    sysConfigController.deleteTeamConfig.bind(sysConfigController)
+  )
+
+  fastify.get<{ Params: { name: string }; Querystring: { teamId?: string } }>(
+    '/team/:name',
+    { onRequest: [hasAnyRole(UserRole.ADMIN, UserRole.TEAM, UserRole.PROMOTER)] },
+    sysConfigController.getTeamConfig.bind(sysConfigController)
+  )
+
+  fastify.get<{ Querystring: ListTeamConfigQuery & { teamId?: string } }>(
+    '/team',
+    { onRequest: [hasAnyRole(UserRole.ADMIN, UserRole.TEAM, UserRole.PROMOTER)] },
+    sysConfigController.listTeamConfigs.bind(sysConfigController)
+  )
 }

+ 148 - 10
src/services/sys-config.service.ts

@@ -2,21 +2,39 @@ import { FastifyInstance } from 'fastify'
 import { Like, Repository, Not } from 'typeorm'
 import Decimal from 'decimal.js'
 import { SysConfig } from '../entities/sys-config.entity'
-import { CreateSysConfigBody } from '../dto/sys-config.dto'
-import { UpdateSysConfigBody } from '../dto/sys-config.dto'
+import {
+  CreateSysConfigBody,
+  UpdateSysConfigBody,
+  CreateTeamConfigBody,
+  UpdateTeamConfigBody,
+  ListTeamConfigQuery
+} from '../dto/sys-config.dto'
 import { ConfigType } from '../entities/sys-config.entity'
+import { User, UserRole } from '../entities/user.entity'
+import { Team } from '../entities/team.entity'
+import { TeamMembers } from '../entities/team-members.entity'
 
 export class SysConfigService {
   private app: FastifyInstance
   private sysConfigRepository: Repository<SysConfig>
+  private userRepository: Repository<User>
+  private teamRepository: Repository<Team>
+  private teamMembersRepository: Repository<TeamMembers>
 
   constructor(app: FastifyInstance) {
     this.app = app
     this.sysConfigRepository = app.dataSource.getRepository(SysConfig)
+    this.userRepository = app.dataSource.getRepository(User)
+    this.teamRepository = app.dataSource.getRepository(Team)
+    this.teamMembersRepository = app.dataSource.getRepository(TeamMembers)
   }
 
-  async getSysConfig(name: string) {
-    const sysConfig = await this.sysConfigRepository.findOneOrFail({ where: { name } })
+  async getSysConfig(name: string, teamId?: number) {
+    const where: any = { name }
+    if (teamId !== undefined) {
+      where.teamId = teamId
+    }
+    const sysConfig = await this.sysConfigRepository.findOneOrFail({ where })
     return sysConfig
   }
 
@@ -71,7 +89,11 @@ export class SysConfigService {
   }
 
   async create(data: CreateSysConfigBody) {
-    const existingConfig = await this.sysConfigRepository.findOne({ where: { name: data.name } })
+    const where: any = { name: data.name }
+    if (data.teamId !== undefined) {
+      where.teamId = data.teamId
+    }
+    const existingConfig = await this.sysConfigRepository.findOne({ where })
     if (existingConfig) {
       throw new Error('配置名称已存在')
     }
@@ -79,18 +101,18 @@ export class SysConfigService {
     return await this.sysConfigRepository.save(config)
   }
 
-  async update(name: string, data: UpdateSysConfigBody) {
-    const config = await this.getSysConfig(name)
+  async update(name: string, data: UpdateSysConfigBody, teamId?: number) {
+    const config = await this.getSysConfig(name, teamId)
     Object.assign(config, data)
     return await this.sysConfigRepository.save(config)
   }
 
-  async delete(name: string) {
-    const config = await this.getSysConfig(name)
+  async delete(name: string, teamId?: number) {
+    const config = await this.getSysConfig(name, teamId)
     return await this.sysConfigRepository.remove(config)
   }
 
-  async list(page: number = 0, size: number = 20, name?: string, type?: ConfigType) {
+  async list(page: number = 0, size: number = 20, name?: string, type?: ConfigType, teamId?: number) {
     const where: any = {
       name: Not('sensitive_words')
     }
@@ -103,6 +125,10 @@ export class SysConfigService {
       where.type = type
     }
 
+    if (teamId !== undefined) {
+      where.teamId = teamId
+    }
+
     const [data, total] = await this.sysConfigRepository.findAndCount({
       where,
       skip: page * size,
@@ -126,4 +152,116 @@ export class SysConfigService {
   async getConfigTypes() {
     return Object.values(ConfigType)
   }
+
+  // 获取用户的团队ID
+  async getUserTeamId(userId: number, userRole: UserRole): Promise<number> {
+    if (userRole === UserRole.ADMIN) {
+      throw new Error('管理员不需要团队ID')
+    }
+
+    if (userRole === UserRole.USER) {
+      throw new Error('普通用户无权限访问团队配置')
+    }
+
+    if (userRole === UserRole.TEAM) {
+      // 队长从team表中获取teamId
+      const team = await this.teamRepository.findOne({ where: { userId } })
+      if (!team) {
+        throw new Error('未找到该用户的团队信息')
+      }
+      return team.id
+    } else {
+      // 队员从team-members表中获取teamId
+      const teamMember = await this.teamMembersRepository.findOne({ where: { userId } })
+      if (!teamMember) {
+        throw new Error('未找到该用户的团队成员信息')
+      }
+      return teamMember.teamId
+    }
+  }
+
+  // 团队配置相关方法
+  async createTeamConfig(data: CreateTeamConfigBody, userId: number, userRole: UserRole, adminTeamId?: number) {
+    let teamId: number
+
+    if (userRole === UserRole.ADMIN) {
+      if (adminTeamId === undefined) {
+        throw new Error('管理员操作团队配置时必须指定teamId')
+      }
+      teamId = adminTeamId
+    } else {
+      teamId = await this.getUserTeamId(userId, userRole)
+    }
+
+    const existingConfig = await this.sysConfigRepository.findOne({
+      where: { name: data.name, teamId }
+    })
+    if (existingConfig) {
+      throw new Error('该团队配置名称已存在')
+    }
+
+    const config = this.sysConfigRepository.create({ ...data, teamId })
+    return await this.sysConfigRepository.save(config)
+  }
+
+  async updateTeamConfig(
+    name: string,
+    data: UpdateTeamConfigBody,
+    userId: number,
+    userRole: UserRole,
+    adminTeamId?: number
+  ) {
+    let teamId: number
+
+    if (userRole === UserRole.ADMIN) {
+      if (adminTeamId === undefined) {
+        throw new Error('管理员操作团队配置时必须指定teamId')
+      }
+      teamId = adminTeamId
+    } else {
+      teamId = await this.getUserTeamId(userId, userRole)
+    }
+
+    const config = await this.getSysConfig(name, teamId)
+    Object.assign(config, data)
+    return await this.sysConfigRepository.save(config)
+  }
+
+  async deleteTeamConfig(name: string, userId: number, userRole: UserRole, adminTeamId?: number) {
+    let teamId: number
+
+    if (userRole === UserRole.ADMIN) {
+      if (adminTeamId === undefined) {
+        throw new Error('管理员操作团队配置时必须指定teamId')
+      }
+      teamId = adminTeamId
+    } else {
+      teamId = await this.getUserTeamId(userId, userRole)
+    }
+
+    const config = await this.getSysConfig(name, teamId)
+    return await this.sysConfigRepository.remove(config)
+  }
+
+  async getTeamConfig(name: string, userId: number, userRole: UserRole, adminTeamId?: number) {
+    if (userRole === UserRole.ADMIN) {
+      // 管理员查询:如果指定了teamId则查询特定团队,否则查询所有团队
+      return await this.getSysConfig(name, adminTeamId)
+    } else {
+      const teamId = await this.getUserTeamId(userId, userRole)
+      return await this.getSysConfig(name, teamId)
+    }
+  }
+
+  async listTeamConfigs(query: ListTeamConfigQuery, userId: number, userRole: UserRole, adminTeamId?: number) {
+    if (userRole === UserRole.ADMIN) {
+      // 管理员查询:如果指定了teamId则查询特定团队,否则查询所有团队
+      const { page = 0, size = 20, name, type } = query
+      return await this.list(page, size, name, type, adminTeamId)
+    } else {
+      const teamId = await this.getUserTeamId(userId, userRole)
+      const { page = 0, size = 20, name, type } = query
+      return await this.list(page, size, name, type, teamId)
+    }
+  }
 }