Przeglądaj źródła

✨ feat(logs): add logfile management feature

- add logfile entity with fields: id, relatedId, class, action, reason, etc.
- implement logfile service using generic CRUD service
- create logfile API routes with auth middleware
- add user tracking for createdBy and updatedBy fields

🔧 chore(gitignore): uncomment logs directory exclusion

- re-enable logs/ directory exclusion in .gitignore to prevent log files from being tracked
yourname 7 miesięcy temu
rodzic
commit
f256ea85dc

+ 1 - 1
.gitignore

@@ -26,7 +26,7 @@ node_modules/
 .dev.vars
 
 # logs
-logs/
+# logs/
 *.log
 npm-debug.log*
 yarn-debug.log*

+ 20 - 0
src/server/api/logs/index.ts

@@ -0,0 +1,20 @@
+import { createCrudRoutes } from '@/server/utils/generic-crud.routes';
+import { Logfile } from '@/server/modules/logs/logfile.entity';
+import { LogfileSchema, CreateLogfileDto, UpdateLogfileDto } from '@/server/modules/logs/logfile.entity';
+import { authMiddleware } from '@/server/middleware/auth.middleware';
+
+const logfileRoutes = createCrudRoutes({
+  entity: Logfile,
+  createSchema: CreateLogfileDto,
+  updateSchema: UpdateLogfileDto,
+  getSchema: LogfileSchema,
+  listSchema: LogfileSchema,
+  searchFields: ['class', 'action', 'relatedId'],
+  middleware: [authMiddleware],
+  userTracking: {
+    createdByField: 'createdBy',
+    updatedByField: 'updatedBy'
+  }
+});
+
+export default logfileRoutes;

+ 133 - 0
src/server/modules/logs/logfile.entity.ts

@@ -0,0 +1,133 @@
+import { Entity, PrimaryColumn, Column, Index } from 'typeorm';
+import { z } from '@hono/zod-openapi';
+
+@Entity('logfile')
+export class Logfile {
+  @PrimaryColumn({ name: 'id', type: 'varchar', length: 50 })
+  id!: string;
+
+  @Column({ name: 'related_id', type: 'varchar', length: 50, nullable: true })
+  relatedId?: string;
+
+  @Column({ name: 'class', type: 'varchar', length: 50 })
+  class!: string;
+
+  @Column({ name: 'action', type: 'varchar', length: 50 })
+  action!: string;
+
+  @Column({ name: 'reason', type: 'text', nullable: true })
+  reason?: string;
+
+  @Column({ name: 'created_by', type: 'int', nullable: true, comment: '创建用户ID' }) //abc    
+  createdBy?: number;
+
+  @Column({ name: 'updated_by', type: 'int', nullable: true, comment: '更新用户ID' }) // ijfioejfowf
+  updatedBy?: number;
+
+  @Column({ name: 'log_time', type: 'datetime' })
+  logTime!: Date;
+
+  @Column({ name: 'created_at', type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })
+  createdAt!: Date;
+
+  @Column({ 
+    name: 'updated_at', 
+    type: 'timestamp', 
+    default: () => 'CURRENT_TIMESTAMP', 
+    onUpdate: 'CURRENT_TIMESTAMP' 
+  })
+  updatedAt!: Date;
+}
+
+export const LogfileSchema = z.object({
+  id: z.string().max(50).openapi({ 
+    description: '日志记录ID',
+    example: 'LOG20230001' 
+  }),
+  relatedId: z.string().max(50).nullable().openapi({ 
+    description: '关联记录ID',
+    example: 'C2001' 
+  }),
+  class: z.string().max(50).openapi({ 
+    description: '日志类别',
+    example: 'client' 
+  }),
+  action: z.string().max(50).openapi({ 
+    description: '操作动作:如创建、更新、删除等',
+    example: 'create' 
+  }),
+  reason: z.string().nullable().openapi({ 
+    description: '操作原因',
+    example: '新建客户记录' 
+  }),
+  createdBy: z.number().int().positive().nullable().openapi({
+    description: '创建用户ID',
+    example: 1001
+  }),
+  updatedBy: z.number().int().positive().nullable().openapi({
+    description: '更新用户ID',
+    example: 1001
+  }),
+  logTime: z.date().openapi({ 
+    description: '日志记录时间',
+    example: '2023-01-15T10:30:00Z' 
+  }),
+  createdAt: z.date().openapi({ 
+    description: '创建时间',
+    example: '2023-01-15T10:30:00Z' 
+  }),
+  updatedAt: z.date().openapi({ 
+    description: '更新时间',
+    example: '2023-01-15T10:30:00Z' 
+  })
+});
+
+export const CreateLogfileDto = z.object({
+  id: z.string().max(50).openapi({ 
+    description: '日志记录ID',
+    example: 'LOG20230001' 
+  }),
+  relatedId: z.string().max(50).nullable().optional().openapi({ 
+    description: '关联记录ID',
+    example: 'C2001' 
+  }),
+  class: z.string().max(50).openapi({ 
+    description: '日志类别',
+    example: 'client' 
+  }),
+  action: z.string().max(50).openapi({ 
+    description: '操作动作:如创建、更新、删除等',
+    example: 'create' 
+  }),
+  reason: z.string().nullable().optional().openapi({ 
+    description: '操作原因',
+    example: '新建客户记录' 
+  }),
+  logTime: z.coerce.date().openapi({ 
+    description: '日志记录时间',
+    example: '2023-01-15T10:30:00Z' 
+  })
+});
+
+export const UpdateLogfileDto = z.object({
+  relatedId: z.string().max(50).nullable().optional().openapi({ 
+    description: '关联记录ID',
+    example: 'C2001' 
+  }),
+  class: z.string().max(50).optional().openapi({ 
+    description: '日志类别',
+    example: 'client' 
+  }),
+  action: z.string().max(50).optional().openapi({ 
+    description: '操作动作:如创建、更新、删除等',
+    example: 'create' 
+  }),
+  reason: z.string().nullable().optional().openapi({ 
+    description: '操作原因',
+    example: '新建客户记录' 
+  }),
+  logTime: z.coerce.date().optional().openapi({ 
+    description: '日志记录时间',
+    example: '2023-01-15T10:30:00Z' 
+  })
+});

+ 9 - 0
src/server/modules/logs/logfile.service.ts

@@ -0,0 +1,9 @@
+import { GenericCrudService } from '@/server/utils/generic-crud.service';
+import { DataSource } from 'typeorm';
+import { Logfile } from './logfile.entity';
+
+export class LogfileService extends GenericCrudService<Logfile> {
+  constructor(dataSource: DataSource) {
+    super(dataSource, Logfile);
+  }
+}