Appearance
@lzui/nest-crud
一个基于 NestJS 的高效 CRUD 库,让您专注于业务逻辑而非重复的 API 实现。
🌟 特性
- 🚀 快速生成 API - 只需几行代码即可创建完整的 CRUD 接口
- 🎨 灵活配置 - 支持路由前缀、API 选择、参数处理等多种自定义选项
- 📦 分页查询 - 内置强大的分页和筛选功能,支持复杂查询条件
- 🔧 易于扩展 - 支持自定义控制器、服务方法和权限验证
- 🛡️ 安全可靠 - 内置权限控制机制,支持细粒度的 API 权限管理
- 📚 完善文档 - 提供详细的 API 参考和示例项目
🚀 快速开始
安装
bash
pnpm add @lzui/nest-crud基本使用
1. 创建控制器
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',
],
/* 排除list和page接口的权限验证, 优先级高于requireAuthFor */
excludeAuthFor: [
'demo:add',
'demo:delete',
'demo:update',
'demo:info',
'demo:export',
'demo:list',
'demo:page',
],
/** 实体名称,用于权限验证 */
entityName: 'demo',
},
/* add接口 */
insertParam: (ctx: any) => {
/** 从请求上下文获取当前用户ID */
const userId = ctx.user?.id;
/** 从请求体中获取其他字段,过滤等其他业务操作 */
return {
...ctx.body,
userId: userId || 'insertParam',
createBy: userId || 'insertParam',
createTime: new Date(),
updateTime: new Date(),
};
},
/** update 接口 */
updateParam: (ctx: any) => {
/** 从请求上下文获取当前用户ID */
const userId = ctx.user?.id;
return {
...ctx.body,
updateBy: userId || 'updateParam',
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',
// app 关联字段
// '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() {
const res = await this.service.list();
return this.ok(res);
}
}2. 创建服务
typescript
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { BaseService } from '@lzui/nest-crud';
import { DemoEntity } from './entities/demo.entity';
@Injectable()
export class DemoService extends BaseService<DemoEntity> {
constructor(
@InjectRepository(DemoEntity)
repository: Repository<DemoEntity>,
) {
super(repository);
}
}3. 创建module
typescript
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { DemoController } from './demo.controller';
import { DemoService } from './demo.service';
import { DemoEntity } from './entities/demo.entity';
@Module({
imports: [TypeOrmModule.forFeature([DemoEntity])],
controllers: [DemoController],
providers: [DemoService],
exports: [DemoService],
})
export class DemoModule {}4. 创建实体
typescript
import { Entity, Column, ManyToOne, OneToMany, JoinColumn } from 'typeorm';
import { BaseStatusByIdTimeDelFlagEntity } from '@lzui/nest-crud';
import { AppEntity } from '../../app/entities/app.entity';
import { UserEntity } from '../../user/entities/user.entity';
@Entity('demo', { comment: '演示' })
export class DemoEntity extends BaseStatusByIdTimeDelFlagEntity {
@Column({ type: 'varchar', length: 255 })
title: string;
@Column({ type: 'decimal', precision: 10, scale: 2 })
price: number;
@Column({ type: 'varchar', length: 50, nullable: true })
type: string;
@Column({ type: 'text', nullable: true })
data: string;
@Column({ type: 'varchar', length: 36, nullable: true, name: 'user_id' })
userId: string;
// 添加与UserEntity的关系
@ManyToOne(() => UserEntity, { createForeignKeyConstraints: false })
@JoinColumn({ name: 'user_id' })
user: UserEntity;
// 一对多关系:一个DemoEntity对应多个AppEntity
@OneToMany(() => AppEntity, (app) => app.demo)
app: AppEntity[];
}