import { Injectable } from "@nestjs/common"; import { TrpcService } from "@server/trpc/trpc.service"; import { SystemLogService } from "./systemLog.service"; import { z, ZodType } from "zod"; import { Prisma } from "@nice/common"; // 定义Zod类型Schema const SystemLogCreateArgsSchema: ZodType = z.any(); const SystemLogFindManyArgsSchema: ZodType = z.any(); const SystemLogFindUniqueArgsSchema: ZodType = z.any(); const SystemLogWhereInputSchema: ZodType = z.any(); const SystemLogSelectSchema: ZodType = z.any(); @Injectable() export class SystemLogRouter { constructor( private readonly trpc: TrpcService, private readonly systemLogService: SystemLogService, ) { } router = this.trpc.router({ // 创建日志 create: this.trpc.procedure .input(z.object({ level: z.enum(['info', 'warning', 'error', 'debug']).default('info'), module: z.string(), action: z.string(), operatorId: z.string().optional(), ipAddress: z.string().optional(), targetId: z.string().optional(), targetType: z.string().optional(), targetName: z.string().optional(), message: z.string().optional(), details: z.any().optional(), beforeData: z.any().optional(), afterData: z.any().optional(), status: z.enum(['success', 'failure']).default('success'), errorMessage: z.string().optional(), departmentId: z.string().optional(), })) .mutation(async ({ input, ctx }) => { const ctxIpAddress = ctx.ip; const operatorId = ctx.staff?.id; try { return this.systemLogService.create({ data: { level: input.level, module: input.module, action: input.action, operatorId: input.operatorId || operatorId, ipAddress: input.ipAddress || ctxIpAddress, targetId: input.targetId, targetType: input.targetType, targetName: input.targetName, message: input.message, details: input.details, beforeData: input.beforeData, afterData: input.afterData, status: input.status, errorMessage: input.errorMessage, departmentId: input.departmentId, } }); } catch (error) { console.error('Error creating system log:', error); throw new Error('Failed to create system log'); } }), // 查询日志列表 findMany: this.trpc.procedure .input(SystemLogFindManyArgsSchema) .query(async ({ input }) => { return this.systemLogService.findMany(input); }), // 查询日志列表(带分页) - 保留原名 getLogs: this.trpc.procedure .input(z.object({ page: z.number().default(1), pageSize: z.number().default(20), where: SystemLogWhereInputSchema.optional(), select: SystemLogSelectSchema.optional(), })) .query(async ({ input }) => { try { const { page, pageSize, where = {}, select } = input; return await this.systemLogService.findManyWithPagination({ page, pageSize, where, ...(select ? { select } : {}) }); } catch (error) { console.error('Error in getLogs:', error); // 返回空结果,避免崩溃 return { items: [], total: 0, page: input.page, pageSize: input.pageSize, totalPages: 0 }; } }), // 查询日志列表(带分页) - 新名称 findManyWithPagination: this.trpc.procedure .input(z.object({ page: z.number().default(1), pageSize: z.number().default(20), where: SystemLogWhereInputSchema.optional(), select: SystemLogSelectSchema.optional(), })) .query(async ({ input }) => { try { const { page, pageSize, where = {}, select } = input; return await this.systemLogService.findManyWithPagination({ page, pageSize, where, ...(select ? { select } : {}) }); } catch (error) { console.error('Error in findManyWithPagination:', error); // 返回空结果,避免崩溃 return { items: [], total: 0, page: input.page, pageSize: input.pageSize, totalPages: 0 }; } }), // 获取单个日志详情 findUnique: this.trpc.procedure .input(SystemLogFindUniqueArgsSchema) .query(async ({ input }) => { return this.systemLogService.findUnique(input); }), // 通过ID获取日志详情(简化版) findById: this.trpc.procedure .input(z.string()) .query(async ({ input }) => { return this.systemLogService.findUnique({ where: { id: input }, include: { operator: { select: { id: true, username: true, showname: true, } }, department: { select: { id: true, name: true, } } } }); }), // 记录人员操作日志的便捷方法 logStaffAction: this.trpc.protectProcedure .input(z.object({ action: z.string(), targetId: z.string(), targetName: z.string(), message: z.string().optional(), beforeData: z.any().optional(), afterData: z.any().optional(), status: z.enum(['success', 'failure']).default('success'), errorMessage: z.string().optional(), })) .mutation(async ({ input, ctx }) => { const ipAddress = ctx.ip; const operatorId = ctx.staff?.id; try { return this.systemLogService.create({ data: { level: input.status === 'success' ? 'info' : 'error', module: 'staff', action: input.action, operatorId: operatorId, ipAddress: ipAddress, targetId: input.targetId, targetType: 'staff', targetName: input.targetName, message: input.message, beforeData: input.beforeData, afterData: input.afterData, status: input.status, errorMessage: input.errorMessage, } }); } catch (error) { console.error('Error logging staff action:', error); throw new Error('Failed to log staff action'); } }), // 高级搜索日志 searchLogs: this.trpc.procedure .input(z.object({ page: z.number().default(1), pageSize: z.number().default(20), level: z.enum(['info', 'warning', 'error', 'debug']).optional(), module: z.string().optional(), action: z.string().optional(), operatorId: z.string().optional(), targetId: z.string().optional(), targetType: z.string().optional(), status: z.enum(['success', 'failure']).optional(), startTime: z.string().optional(), endTime: z.string().optional(), keyword: z.string().optional(), departmentId: z.string().optional(), })) .query(async ({ input }) => { console.log('Received input for searchLogs:', input); const where: Prisma.SystemLogWhereInput = {}; if (input.level) where.level = input.level; if (input.module) where.module = input.module; if (input.action) where.action = input.action; if (input.operatorId) where.operatorId = input.operatorId; if (input.targetId) where.targetId = input.targetId; if (input.targetType) where.targetType = input.targetType; if (input.status) where.status = input.status; if (input.departmentId) where.departmentId = input.departmentId; // 时间范围查询 if (input.startTime || input.endTime) { where.timestamp = {}; if (input.startTime) where.timestamp.gte = new Date(input.startTime); if (input.endTime) where.timestamp.lte = new Date(input.endTime); } // 关键词搜索 if (input.keyword) { where.OR = [ { targetName: { contains: input.keyword } }, { action: { contains: input.keyword } }, { module: { contains: input.keyword } }, { errorMessage: { contains: input.keyword } }, ]; } try { const result = await this.systemLogService.findManyWithPagination({ page: input.page, pageSize: input.pageSize, where, select: { id: true, level: true, module: true, action: true, timestamp: true, operatorId: true, ipAddress: true, targetId: true, targetType: true, targetName: true, details: true, beforeData: true, afterData: true, status: true, errorMessage: true, departmentId: true, operator: { select: { id: true, username: true, showname: true, } }, department: { select: { id: true, name: true, } } } }); console.log('Search logs result:', result); return result; } catch (error) { console.error('Error in searchLogs:', error); throw new Error('Failed to search logs'); } }), }) }