/** * 通用 CRUD 处理器基类 * Generic CRUD Handler Base Class * * 提供标准的 HTTP 请求处理和响应格式化 * Provides standard HTTP request handling and response formatting */ import type { H3Event } from 'h3' import { getQuery, getRouterParams, readBody, createError } from 'h3' import { validateQuery, validateBody, validateParams } from '@nuxt4crud/shared' import type { BaseEntity, CreateInput, UpdateInput, QueryParams, ApiResponse, PaginatedResponse, } from '@nuxt4crud/shared' /** * CRUD 处理器基类 * CRUD Handler Base Class */ export abstract class BaseCrudHandler< T extends BaseEntity, CreateInputType extends CreateInput, UpdateInputType extends UpdateInput, QueryParamsType extends QueryParams = QueryParams, > { constructor( protected service: any, // 实际的服务实例 protected schemas: { query?: any create?: any update?: any params?: any } = {} ) {} /** * 处理列表查询请求 * Handle list query request */ async handleList(event: H3Event): Promise>> { try { const query = this.schemas.query ? validateQuery(this.schemas.query, getQuery(event)) : getQuery(event) const result = await this.service.findMany(query) return { success: true, data: result, } } catch (error: any) { return this.handleError(error) } } /** * 处理单个记录查询请求 * Handle single record query request */ async handleGet(event: H3Event): Promise> { try { const params = this.schemas.params ? validateParams(this.schemas.params, getRouterParams(event)) : getRouterParams(event) const id = Number(params.id) const result = await this.service.findById(id) if (!result) { throw createError({ statusCode: 404, statusMessage: '记录不存在', }) } return { success: true, data: result, } } catch (error: any) { return this.handleError(error) } } /** * 兼容单个或多个ID的查询请求(支持 GET 与 POST) * Flexible handler to fetch by a single ID or multiple IDs (supports GET and POST) * * - GET: 路径参数 `id`,支持逗号分隔(如 `/api/.../1,2,3`) * - POST: 请求体包含 `id: number` 或 `ids: number[] | string` */ async handleGetFlexible(event: H3Event): Promise> { try { const method = event?.node?.req?.method || 'GET' // POST 支持通过请求体传输多个ID if (method === 'POST') { const body = await readBody(event) if (!body || (body.id === undefined && body.ids === undefined)) { throw createError({ statusCode: 400, statusMessage: '请求体必须包含 id 或 ids' }) } // 归一化为ID数组 const ids: number[] = Array.isArray(body.ids) ? body.ids.map((v: any) => Number(v)).filter((v: number) => Number.isFinite(v) && v > 0) : typeof body.ids === 'string' ? body.ids .split(',') .map(s => Number(s.trim())) .filter(n => Number.isFinite(n) && n > 0) : body.id !== undefined ? [Number(body.id)].filter(n => Number.isFinite(n) && n > 0) : [] if (ids.length === 0) { throw createError({ statusCode: 400, statusMessage: '无效的ID或ID数组' }) } // 单个ID与多个ID统一处理 if (ids.length === 1) { const one = await this.service.findById(ids[0]) if (!one) { throw createError({ statusCode: 404, statusMessage: '记录不存在' }) } return { success: true, data: one } } else { const list = await this.service.findByIds(ids) if (!list || list.length === 0) { throw createError({ statusCode: 404, statusMessage: '记录不存在' }) } const partial = list.length < ids.length return { success: true, data: list, message: partial ? '部分ID未找到' : undefined, } } } // GET 支持 `/api/.../[id]` 单个ID,或逗号分隔的多个ID const params = getRouterParams(event) if (!params || params.id === undefined) { throw createError({ statusCode: 400, statusMessage: '缺少路径参数 id' }) } const rawId = String(params.id) const ids = rawId .split(',') .map(s => Number(s.trim())) .filter(n => Number.isFinite(n) && n > 0) if (ids.length === 0) { throw createError({ statusCode: 400, statusMessage: '无效的路径参数 id' }) } if (ids.length === 1) { const one = await this.service.findById(ids[0]) if (!one) { throw createError({ statusCode: 404, statusMessage: '记录不存在' }) } return { success: true, data: one } } else { const list = await this.service.findByIds(ids) if (!list || list.length === 0) { throw createError({ statusCode: 404, statusMessage: '记录不存在' }) } const partial = list.length < ids.length return { success: true, data: list, message: partial ? '部分ID未找到' : undefined, } } } catch (error: any) { return this.handleError(error) } } /** * 处理创建请求 * Handle create request */ async handleCreate(event: H3Event): Promise> { try { const body = await readBody(event) if (!body) { throw createError({ statusCode: 400, statusMessage: '请求体不能为空', }) } const data = this.schemas.create ? validateBody(this.schemas.create, body) : body const result = await this.service.create(data) return { success: true, data: result, message: '创建成功', } } catch (error: any) { return this.handleError(error) } } /** * 处理更新请求 * Handle update request */ async handleUpdate(event: H3Event): Promise> { try { const params = this.schemas.params ? validateParams(this.schemas.params, getRouterParams(event)) : getRouterParams(event) const id = Number(params.id) const body = await readBody(event) if (!body) { throw createError({ statusCode: 400, statusMessage: '请求体不能为空', }) } const data = this.schemas.update ? validateBody(this.schemas.update, body) : body const result = await this.service.update(id, data) return { success: true, data: result, message: '更新成功', } } catch (error: any) { return this.handleError(error) } } /** * 处理删除请求 * Handle delete request */ async handleDelete(event: H3Event): Promise> { try { const params = this.schemas.params ? validateParams(this.schemas.params, getRouterParams(event)) : getRouterParams(event) const id = Number(params.id) await this.service.delete(id) return { success: true, message: '删除成功', } } catch (error: any) { return this.handleError(error) } } /** * 错误处理 * Error handling */ protected handleError(error: any): ApiResponse { console.error('CRUD Handler Error:', error) if (error.statusCode === 404) { return { success: false, message: error.message || '记录不存在', } } if (error.statusCode === 400) { return { success: false, message: error.message || '请求参数错误', validationErrors: error.validationErrors, } } if (error.statusCode === 409) { return { success: false, message: error.message || '数据冲突', } } return { success: false, message: error.message || '服务器内部错误', } } } /** * 创建 CRUD 处理器工厂函数 * Create CRUD handler factory function */ export function createCrudHandlers< T extends BaseEntity, CreateInputType extends CreateInput, UpdateInputType extends UpdateInput, QueryParamsType extends QueryParams = QueryParams, >( service: any, schemas: { query?: any create?: any update?: any params?: any } = {} ) { const handler = new BaseCrudHandler( service, schemas ) return { list: (event: H3Event) => handler.handleList(event), get: (event: H3Event) => handler.handleGet(event), create: (event: H3Event) => handler.handleCreate(event), update: (event: H3Event) => handler.handleUpdate(event), delete: (event: H3Event) => handler.handleDelete(event), } }