Skip to content

API 参考

CrudController

CrudController(options)

用于快速创建 CRUD 控制器的装饰器,自动生成标准化的 RESTful API 端点。

参数:

  • options:CrudControllerOptions 对象,包含以下属性:
    • prefix:可选,路由前缀,用于分组 API 端点
    • api:字符串数组,指定要启用的 API 方法,可选值:add(创建), delete(删除), update(更新), info(详情), list(列表), page(分页), export(导出)
    • serviceApis:可选,服务 API 配置数组,用于自定义服务方法映射
    • entity:TypeORM 实体类,用于自动推断数据结构和查询
    • insertParam:可选,插入参数处理函数,用于在创建数据前处理请求参数
    • updateParam:可选,更新参数处理函数,用于在更新数据前处理请求参数
    • exportParam:可选,导出参数处理函数,用于在导出数据前处理请求参数
    • infoIgnoreProperty:可选,详情查询时忽略的属性数组,用于隐藏敏感信息
    • pageQueryOp:可选,分页查询配置,用于自定义查询条件、排序、关联查询等
    • authOptions:可选,权限验证配置
      • requireAuthFor:需要权限验证的接口数组
      • excludeAuthFor:不需要权限验证的接口数组(优先级高于 requireAuthFor)
      • entityName:实体名称,用于权限验证的资源标识

示例:

typescript
import { Get, Inject, UseGuards } from '@nestjs/common';
import { CrudController,BaseController, Auth,AuthGuard } from '@lzui/nest-crud';
import { DemoEntity } from './entities/demo.entity';
import { DemoService } from './demo.service';

@CrudController({
  prefix: 'api/v1/demo',
  /** 添加通用CRUD接口 */
  api: ['add', 'delete', 'update', 'info', 'list', 'page', 'export'],
  /* 设置表实体  */
  entity: DemoEntity,
  /* 权限验证配置 */
  authOptions: {
    /* 要求接口需要权限验证 */
    requireAuthFor: [
      'demo:add',
      'demo:delete',
      'demo:update',
      'demo:info',
      'demo:export',
      'demo:list',
      'demo:page',
    ],
    /* 排除page接口的权限验证, 优先级高于requireAuthFor */
    excludeAuthFor: ['demo:page'],
    /** 实体名称,用于权限验证 */
    entityName: 'demo',
  },
  /* 向表插入当前登录用户ID */
  insertParam: (ctx: any) => {
    console.log(ctx.user);
    const userId = ctx.user?.id;
    return {
      ...ctx.body,
      userId: userId || '',
      create_by: userId || '',
      createTime: new Date(),
      updateTime: new Date(),
    };
  },
  /** update 接口 */
  updateParam: (ctx: any) => {
    console.log(ctx.user);
    const userId = ctx.user?.id;
    return {
      ...ctx.body,
      update_by: userId || '',
      updateTime: new Date(),
    };
  },
  /** export 接口 */
  exportParam: (ctx: any) => {
    const defaultExportConfig = {
      header: [
        { title: 'ID', dataIndex: 'id' },
        { title: '状态', dataIndex: 'status' },
        { title: '创建人', dataIndex: 'create_by' },
        { title: '价格', dataIndex: 'price' },
        { title: '标题', dataIndex: 'title' },
        { title: '类型', dataIndex: 'type' },
      ],
      sheetName: '演示数据',
      fileName: 'demo数据',
    };

    const exportConfig = ctx.body?.exportConfig || defaultExportConfig;
    return {
      ...ctx.body,
      exportConfig,
    };
  },
  /** info查询时忽略的字段 */
  infoIgnoreProperty: ['userId', 'data'],
  /* 分页查询配置 */
  pageQueryOp: {
    /* 优先级1 请求参数为keyWord, 支持模糊查询 多个key*/
    keyWordLikeFields: ['title', 'type'],
    /* 优先级2 等于查询 */
    fieldEq: ['type'],
    /** 优先级3 支持模糊查询的字段 */
    fieldLike: ['title', 'userId', 'type'],
    /* 指定返回字段,使用实体属性名 使用点符号指定关联表的字段 */
    select: [
      'id',
      'title',
      'price',
      'type',
      'userId',
      'status',
      'createTime',
      'delFlag',
      // user 关联字段
      // 'user.userId',
      'user.ext',
      'user.fileName',
      'user.newFileName',
      'user.url',
      // app 关联字段
      // 'app.appId',
      'app.fileName',
      'app.demoId',
      'app.ext',
    ],
    /* 启用关系查询,加载关联的user数据 */
    relations: ['user', 'app'],
    /* 自定义关联字段的键名映射 */
    relationAlias: {
      user: 'customUser', // 将返回数据中的"user"键名改为"customUser"
      app: 'customApp', // 将返回数据中的"apps"键名改为"customApp"
    },
    /* 设置关系类型 */
    relationType: {
      user: 'one', // 一对一关系
      app: 'many', // 一对多关系
    },
    /* 增加其他条件 */
    where: async (params: any) => {
      console.log(params);
      /** 自定义查询条件 */
      return [
        {
          status: '1',
          delFlag: '1',
        },
      ];
    },
    addOrderBy: {
      createTime: 'DESC',
    },
  },
})
export class DemoController extends BaseController {
  constructor(
    @Inject(DemoService)
    protected readonly service: DemoService,
  ) {
    super();
  }

  /**
   * 其他接口
   */
  @UseGuards(AuthGuard)
  @Auth('demo:other')
  @Get('/other')
  async other() {
    console.log('other');
    return this.ok('hello, curl-admin!!!');
  }
}

生成的 API 端点

根据 api 配置选项,CrudController 会生成以下 API 端点:

API 方法路径HTTP 方法功能描述
add/addPOST添加数据
delete/delete/:idDELETE删除数据
update/update/:idPUT更新数据
info/info/:idGET获取详情
list/listGET获取列表
page/pageGET分页查询
export/exportPOST导出数据

注意: 如果配置了 prefix,所有路径都会加上该前缀。例如,如果 prefixapi/v1/user,则添加数据的路径是 POST /api/v1/user/add

BaseService

BaseService 是一个抽象服务类,提供了基本的 CRUD 操作。你可以继承它来快速实现自己的服务,避免重复编写常见的增删改查逻辑。

继承BaseController 内置BaseService

typescript
export class DemoController extends BaseController {
  constructor(
    @Inject(DemoService)
    protected readonly service: DemoService,
  ) {
    super();
  }

  /**
   * 其他接口
   */
  @Get('/other')
  async other(res: any) {
    const list = await this.service.list();
    const add = await this.service.add({ 
      name: '张三', email: 'zhangsan@example.com' 
    });
    const delete = await this.service.delete(id);
    const updated = await this.service.update(1, { name: '李四' });
    const info = await this.userService.info(1);
    const page = await this.userService.page();
    /* 导出数据 */
    /** 配置导出接口参数 */
    const defaultExportConfig = {
      header: [
        { title: 'ID', dataIndex: 'id' },
        { title: '状态', dataIndex: 'status' },
        { title: '创建人', dataIndex: 'create_by' },
        { title: '价格', dataIndex: 'price' },
        { title: '标题', dataIndex: 'title' },
        { title: '类型', dataIndex: 'type' },
      ],
      sheetName: '演示数据',
      fileName: 'demo数据',
    };
    const exportConfig = ctx.body?.exportConfig || defaultExportConfig;
    const body =  { ...ctx.body, exportConfig }
    await this.userService.export(body);
    
    /** 失败响应 */
    this.fail('导出数据失败');

    /** 成功响应 */
    return this.ok(res);

  }
}

内置实体 (Built-in Entities)

@lzui/nest-crud 包提供了一系列预定义的抽象实体类,这些类包含了常见的字段和功能,可以帮助你快速创建符合规范的实体。

基础实体类

实体名称描述字段
BaseStatusEntity包含状态字段的基础实体status: string - 状态:0正常 1停用
BaseByEntity包含创建者和更新者字段的基础实体createBy: string - 创建者
updateBy: string - 更新者
BaseTimeEntity包含时间戳和备注字段的基础实体createTime: Date - 创建时间
updateTime: Date - 更新时间
remark: string - 备注
DeleteStatusEntity包含删除标志字段的基础实体delFlag: string - 删除标志:0代表存在 1代表删除
BaseIdEntity仅包含ID字段的基础实体,使用雪花算法生成IDid: string - 主键ID(自动生成)

组合实体类

实体名称描述继承自额外字段
BaseStatusIdEntity组合了状态和ID字段的实体BaseStatusEntityid: string - 主键ID(自动生成)
BaseStatusByIdEntity组合了状态、创建更新者和ID字段的实体BaseStatusEntitycreateBy: string - 创建者
updateBy: string - 更新者
id: string - 主键ID(自动生成)
BaseStatusTimeIdEntity组合了状态、时间戳和ID字段的实体BaseStatusEntitycreateTime: Date - 创建时间
updateTime: Date - 更新时间
remark: string - 备注
id: string - 主键ID(自动生成)
BaseByTimeIdEntity组合了创建更新者、时间戳和ID字段的实体BaseByEntitycreateTime: Date - 创建时间
updateTime: Date - 更新时间
remark: string - 备注
id: string - 主键ID(自动生成)
BaseStatusByTimeIdEntity组合了状态、创建更新者、时间戳和ID字段的实体BaseStatusEntitycreateBy: string - 创建者
updateBy: string - 更新者
createTime: Date - 创建时间
updateTime: Date - 更新时间
remark: string - 备注
id: string - 主键ID(自动生成)
BaseStatusByIdTimeDelFlagEntity组合了状态、创建更新者、时间戳、删除标志和ID字段的完整实体BaseStatusEntitycreateBy: string - 创建者
updateBy: string - 更新者
createTime: Date - 创建时间
updateTime: Date - 更新时间
remark: string - 备注
delFlag: string - 删除标志:0代表存在 1代表删除
id: string - 主键ID(自动生成)

使用示例:

typescript
import { BaseStatusByIdTimeDelFlagEntity } from '@lzui/nest-crud';
import { Entity, Column } from 'typeorm';

@Entity()
export class Demo extends BaseStatusByIdTimeDelFlagEntity {
  @Column()
  title: string;
  
  @Column()
  type: string;
  
  @Column()
  price: number;
}

接口

CrudControllerOptions

typescript
interface CrudControllerOptions {
  prefix?: string;
  api: string[];
  entity: any;
  insertParam?: ParamFunction;
  updateParam?: ParamFunction;
  exportParam?: ParamFunction;
  infoIgnoreProperty?: string[];
  pageQueryOp?: PageQueryOp;
  authOptions?: {
    requireAuthFor?: string[];
    excludeAuthFor?: string[];
    entityName?: string;
  };
}

ParamFunction

typescript
interface ParamFunction {
  (params: any): any;
}

PageQueryOp

分页查询配置接口,用于自定义分页查询的行为。

typescript
interface PageQueryOp {
  // 关键词模糊查询字段,优先级1
  keyWordLikeFields?: string[];
  // 精确查询字段,优先级2
  fieldEq?: (string | { column: string; requestParam: string })[];
  // 模糊查询字段,优先级3
  fieldLike?: (string | { column: string; requestParam: string })[];
  // 指定返回的字段列表
  select?: string[];
  // 左连接配置
  leftJoin?: any[];
  // 连接配置
  join?: any[];
  // 关联查询的实体关系
  relations?: string[];
  // 自定义查询条件函数
  where?: PageQueryWhereFunction;
  // 额外的排序规则
  addOrderBy?: Record<string, 'ASC' | 'DESC'>;
  // 关联字段的别名映射
  relationAlias?: Record<string, string>;
  // 关联关系类型定义
  relationType?: Record<string, 'one' | 'many'>;
}

PageQueryWhereFunction

自定义查询条件函数,用于动态生成查询条件。

typescript
interface PageQueryWhereFunction {
  (query?: any): any;
}

PageQueryOp 使用示例

typescript
pageQueryOp: {
  // 支持通过关键词模糊查询title和type字段
  keyWordLikeFields: ['title', 'type'],
  // 支持精确查询type字段
  fieldEq: ['type'],
  // 支持模糊查询title和userId字段
  fieldLike: ['title', 'userId'],
  // 指定返回的字段
  select: ['id', 'title', 'price', 'type', 'createTime'],
  // 加载关联的user和app数据
  relations: ['user', 'app'],
  // 自定义关联字段的返回键名
  relationAlias: {
    user: 'customUser',
    app: 'customApp'
  },
  // 定义关联关系类型
  relationType: {
    user: 'one', // 一对一
    app: 'many' // 一对多
  },
  // 自定义额外查询条件
  where: async (params: any) => {
    return [
      { status: '1' },
      { delFlag: '0' }
    ];
  },
  // 额外排序规则
  addOrderBy: {
    createTime: 'DESC'
  }
}