import { DataSource, Repository, ObjectLiteral, DeepPartial } from 'typeorm'; import { z } from '@hono/zod-openapi'; export abstract class GenericCrudService { protected repository: Repository; private userTrackingOptions?: UserTrackingOptions; constructor( protected dataSource: DataSource, protected entity: new () => T, options?: { userTracking?: UserTrackingOptions; } ) { this.repository = this.dataSource.getRepository(entity); this.userTrackingOptions = options?.userTracking; } /** * 获取分页列表 */ async getList( page: number = 1, pageSize: number = 10, keyword?: string, searchFields?: string[], where?: Partial, relations: string[] = [], order: { [P in keyof T]?: 'ASC' | 'DESC' } = {}, filters?: { [key: string]: any; } ): Promise<[T[], number]> { const skip = (page - 1) * pageSize; const query = this.repository.createQueryBuilder('entity'); // 添加关联关系(支持嵌套关联,如 ['contract.client']) if (relations.length > 0) { relations.forEach((relation, relationIndex) => { const parts = relation.split('.'); let currentAlias = 'entity'; parts.forEach((part, index) => { const newAlias = index === 0 ? part : `${currentAlias}_${relationIndex}`; query.leftJoinAndSelect(`${currentAlias}.${part}`, newAlias); currentAlias = newAlias; }); }); } // 关键词搜索 if (keyword && searchFields && searchFields.length > 0) { query.andWhere(searchFields.map(field => `entity.${field} LIKE :keyword`).join(' OR '), { keyword: `%${keyword}%` }); } // 条件查询 if (where) { Object.entries(where).forEach(([key, value]) => { if (value !== undefined && value !== null) { query.andWhere(`entity.${key} = :${key}`, { [key]: value }); } }); } // 扩展筛选条件 if (filters) { Object.entries(filters).forEach(([key, value]) => { if (value !== undefined && value !== null && value !== '') { const fieldName = key.startsWith('_') ? key.substring(1) : key; // 支持不同类型的筛选 if (Array.isArray(value)) { // 数组类型:IN查询 if (value.length > 0) { query.andWhere(`entity.${fieldName} IN (:...${key})`, { [key]: value }); } } else if (typeof value === 'string' && value.includes('%')) { // 模糊匹配 query.andWhere(`entity.${fieldName} LIKE :${key}`, { [key]: value }); } else if (typeof value === 'object' && value !== null) { // 范围查询 if ('gte' in value) { query.andWhere(`entity.${fieldName} >= :${key}_gte`, { [`${key}_gte`]: value.gte }); } if ('gt' in value) { query.andWhere(`entity.${fieldName} > :${key}_gt`, { [`${key}_gt`]: value.gt }); } if ('lte' in value) { query.andWhere(`entity.${fieldName} <= :${key}_lte`, { [`${key}_lte`]: value.lte }); } if ('lt' in value) { query.andWhere(`entity.${fieldName} < :${key}_lt`, { [`${key}_lt`]: value.lt }); } if ('between' in value && Array.isArray(value.between) && value.between.length === 2) { query.andWhere(`entity.${fieldName} BETWEEN :${key}_start AND :${key}_end`, { [`${key}_start`]: value.between[0], [`${key}_end`]: value.between[1] }); } } else { // 精确匹配 query.andWhere(`entity.${fieldName} = :${key}`, { [key]: value }); } } }); } // 排序 Object.entries(order).forEach(([key, direction]) => { query.orderBy(`entity.${key}`, direction); }); return query.skip(skip).take(pageSize).getManyAndCount(); } /** * 根据ID获取单个实体 */ async getById(id: number, relations: string[] = []): Promise { return this.repository.findOne({ where: { id } as any, relations }); } /** * 设置用户跟踪字段 */ private setUserFields(data: any, userId?: string | number, isCreate: boolean = true): void { if (!this.userTrackingOptions || !userId) { return; } const { createdByField = 'createdBy', updatedByField = 'updatedBy' } = this.userTrackingOptions; if (isCreate && createdByField) { data[createdByField] = userId; } if (updatedByField) { data[updatedByField] = userId; } } /** * 创建实体 */ async create(data: DeepPartial, userId?: string | number): Promise { const entityData = { ...data }; this.setUserFields(entityData, userId, true); const entity = this.repository.create(entityData as DeepPartial); return this.repository.save(entity); } /** * 更新实体 */ async update(id: number, data: Partial, userId?: string | number): Promise { const updateData = { ...data }; this.setUserFields(updateData, userId, false); await this.repository.update(id, updateData); return this.getById(id); } /** * 删除实体 */ async delete(id: number): Promise { const result = await this.repository.delete(id); return result.affected === 1; } /** * 高级查询方法 */ createQueryBuilder(alias: string = 'entity') { return this.repository.createQueryBuilder(alias); } } export interface UserTrackingOptions { createdByField?: string; updatedByField?: string; } export type CrudOptions< T extends ObjectLiteral, CreateSchema extends z.ZodSchema = z.ZodSchema, UpdateSchema extends z.ZodSchema = z.ZodSchema, GetSchema extends z.ZodSchema = z.ZodSchema, ListSchema extends z.ZodSchema = z.ZodSchema > = { entity: new () => T; createSchema: CreateSchema; updateSchema: UpdateSchema; getSchema: GetSchema; listSchema: ListSchema; searchFields?: string[]; relations?: string[]; middleware?: any[]; userTracking?: UserTrackingOptions; };