/** * 通用 CRUD 服务基类 * Generic CRUD Service Base Class * * 提供标准的 CRUD 操作,支持分页、搜索、排序等功能 * Provides standard CRUD operations with pagination, search, and sorting */ import { PrismaClient } from '@prisma/client' import type { BaseEntity, PaginatedResponse, CrudOptions } from '@nuxt4crud/shared' /** * CRUD 服务基类 * CRUD Service Base Class */ export abstract class BaseCrudService< T extends BaseEntity, CreateInput, UpdateInput, QueryParams = any, > { protected model: any protected options: CrudOptions constructor( protected prisma: PrismaClient, protected modelName: string, options: Partial = {} ) { this.model = (prisma as any)[modelName] this.options = { softDelete: false, defaultOrderBy: 'createdAt', defaultOrderDirection: 'desc', searchableFields: [], uniqueFields: [], ...options, } } /** * 获取列表(支持分页、搜索、排序) * Get list with pagination, search, and sorting */ async findMany( params: QueryParams & { page?: number limit?: number search?: string orderBy?: string orderDirection?: 'asc' | 'desc' } ): Promise> { const { page = 1, limit = 10, search = '', orderBy = this.options.defaultOrderBy, orderDirection = this.options.defaultOrderDirection, ...filters } = params const where = this.buildWhereClause(search, filters) const skip = (page - 1) * limit const take = limit const [data, total] = await Promise.all([ this.model.findMany({ where, skip, take, orderBy: { [orderBy]: orderDirection }, }), this.model.count({ where }), ]) return { data, total, page, limit, totalPages: Math.ceil(total / limit), } } /** * 根据ID查找 * Find by ID */ async findById(id: number): Promise { return await this.model.findUnique({ where: { id }, }) } /** * 根据多个ID查找记录 * Find records by multiple IDs * * @param ids 要查询的ID数组 * @returns 匹配的记录列表 */ async findByIds(ids: number[]): Promise { const normalizedIds = Array.from( new Set( (ids || []) .map(id => Number(id)) .filter(id => Number.isFinite(id) && id > 0) ) ) if (normalizedIds.length === 0) { return [] } return await this.model.findMany({ where: { id: { in: normalizedIds } }, }) } /** * 创建记录 * Create record */ async create(data: CreateInput): Promise { await this.validateCreate(data) const transformedData = await this.transformCreateData(data) return await this.model.create({ data: transformedData, }) } /** * 更新记录 * Update record */ async update(id: number, data: UpdateInput): Promise { const existing = await this.findById(id) if (!existing) { const error = new Error('记录不存在') ;(error as any).statusCode = 404 throw error } await this.validateUpdate(id, data, existing) const transformedData = await this.transformUpdateData(data, existing) return await this.model.update({ where: { id }, data: transformedData, }) } /** * 删除记录 * Delete record */ async delete(id: number): Promise { const existing = await this.findById(id) if (!existing) { const error = new Error('记录不存在') ;(error as any).statusCode = 404 throw error } await this.validateDelete(id, existing) if (this.options.softDelete) { await this.model.update({ where: { id }, data: { deletedAt: new Date() }, }) } else { await this.model.delete({ where: { id }, }) } } /** * 构建查询条件 * Build where clause */ protected buildWhereClause(search: string, filters: any): any { const where: any = {} // 搜索功能 if (search && this.options.searchableFields?.length) { where.OR = this.options.searchableFields.map(field => ({ [field]: { contains: search }, })) } // 过滤条件 Object.entries(filters).forEach(([key, value]) => { if (value !== undefined && value !== null && key !== 'search') { where[key] = value } }) // 软删除过滤 if (this.options.softDelete) { where.deletedAt = null } return where } /** * 创建前验证钩子 * Pre-create validation hook */ protected async validateCreate(data: CreateInput): Promise { // 子类可以重写此方法 } /** * 更新前验证钩子 * Pre-update validation hook */ protected async validateUpdate(id: number, data: UpdateInput, existing: T): Promise { // 子类可以重写此方法 } /** * 删除前验证钩子 * Pre-delete validation hook */ protected async validateDelete(id: number, existing: T): Promise { // 子类可以重写此方法 } /** * 创建数据转换钩子 * Create data transformation hook */ protected async transformCreateData(data: CreateInput): Promise { return data } /** * 更新数据转换钩子 * Update data transformation hook */ protected async transformUpdateData(data: UpdateInput, existing: T): Promise { return data } }