├── .npmignore ├── .gitignore ├── src ├── constants.ts ├── main.ts ├── crud-field.decorator.ts ├── util.ts ├── crud-config.ts ├── crud-query.decorator.ts ├── crud.controller.e2e.spec.ts ├── crud.decorator.ts ├── crud.controller.ts └── crud.interface.ts ├── jest.config.js ├── tsconfig.json ├── package.json └── README.md /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist -------------------------------------------------------------------------------- /src/constants.ts: -------------------------------------------------------------------------------- 1 | export const CRUD_FIELD_METADATA = 'CRUD_FIELD_METADATA' -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'ts-jest', 3 | testEnvironment: 'node', 4 | }; -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | export * from './crud-field.decorator' 2 | export * from './crud.decorator' 3 | export * from './crud-config' -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "experimentalDecorators": true, 5 | "emitDecoratorMetadata": true, 6 | "declaration": true, 7 | "target": "es2018", 8 | "outDir": "dist" 9 | } 10 | } -------------------------------------------------------------------------------- /src/crud-field.decorator.ts: -------------------------------------------------------------------------------- 1 | import { Field } from "./crud.interface" 2 | import { CRUD_FIELD_METADATA } from "./constants" 3 | 4 | export const CrudField = (field: Field) => { 5 | 6 | return (target: any, property: string) => { 7 | Reflect.defineMetadata(CRUD_FIELD_METADATA, field, target, property) 8 | } 9 | } -------------------------------------------------------------------------------- /src/util.ts: -------------------------------------------------------------------------------- 1 | function cloneDecorators(from, to) { 2 | Reflect.getMetadataKeys(from).forEach(key => { 3 | const value = Reflect.getMetadata(key, from) 4 | Reflect.defineMetadata(key, value, to) 5 | }) 6 | } 7 | function clonePropDecorators(from, to, name) { 8 | Reflect.getMetadataKeys(from, name).forEach(key => { 9 | const value = Reflect.getMetadata(key, from, name) 10 | Reflect.defineMetadata(key, value, to, name) 11 | }) 12 | } -------------------------------------------------------------------------------- /src/crud-config.ts: -------------------------------------------------------------------------------- 1 | import { CrudOptions } from "./crud.interface"; 2 | import { get, merge } from 'lodash' 3 | 4 | export const defaultPaginate = { 5 | data: 'data', 6 | total: 'total', 7 | lastPage: 'lastPage', 8 | currentPage: 'page', 9 | } 10 | 11 | export class CrudConfig { 12 | public static options: CrudOptions = { 13 | routes: { 14 | find: { 15 | paginate: { ...defaultPaginate } 16 | } 17 | } 18 | }; 19 | static setup(options: CrudOptions) { 20 | this.options = merge({}, this.options, options); 21 | } 22 | static get(key, defaultValue = undefined) { 23 | return get(this.options, key, defaultValue) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/crud-query.decorator.ts: -------------------------------------------------------------------------------- 1 | import { createParamDecorator, ExecutionContext } from "@nestjs/common"; 2 | import { Request } from "express"; 3 | import { QueryOptions } from "mongoose"; 4 | 5 | export class ICrudQuery { 6 | where?: any 7 | limit?: number 8 | page?: number 9 | skip?: number 10 | sort?: string | any 11 | populate?: string | any 12 | select?: string | any 13 | collation?: QueryOptions['collation'] 14 | } 15 | 16 | export const CrudQuery = createParamDecorator((name = 'query', ctx: ExecutionContext) => { 17 | const req: Request = ctx.switchToHttp().getRequest() 18 | try { 19 | return JSON.parse(String(req.query[name] || '')) 20 | } catch (e) { 21 | return {} 22 | } 23 | }) -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nestjs-mongoose-crud", 3 | "description": "mongoose restful crud api for nest.js", 4 | "version": "2.1.2", 5 | "main": "dist/main.js", 6 | "typings": "dist/main.d.ts", 7 | "license": "MIT", 8 | "scripts": { 9 | "build": "tsc", 10 | "test": "jest", 11 | "serve": "tsc --watch" 12 | }, 13 | "devDependencies": { 14 | "@nestjs/common": "^7.6.13", 15 | "@nestjs/core": "^7.6.13", 16 | "@nestjs/platform-express": "^7.6.13", 17 | "@nestjs/swagger": "^4.7.15", 18 | "@nestjs/testing": "^7.6.13", 19 | "@types/express": "^4.17.11", 20 | "@types/jest": "^26.0.20", 21 | "@types/lodash": "^4.14.168", 22 | "@types/supertest": "^2.0.10", 23 | "class-transformer": "^0.4.0", 24 | "class-validator": "^0.13.1", 25 | "jest": "^26.4.2", 26 | "lodash": "^4.17.21", 27 | "mongoose": "^5.11.18", 28 | "reflect-metadata": "^0.1.13", 29 | "rxjs": "^6.6.6", 30 | "supertest": "^6.1.3", 31 | "ts-jest": "^26.5.2", 32 | "typescript": "^4.2.2" 33 | }, 34 | "peerDependencies": {}, 35 | "dependencies": {} 36 | } 37 | -------------------------------------------------------------------------------- /src/crud.controller.e2e.spec.ts: -------------------------------------------------------------------------------- 1 | import { Test } from "@nestjs/testing"; 2 | import * as mongoose from "mongoose"; 3 | import { INestApplication, Controller } from "@nestjs/common"; 4 | import * as request from "supertest"; 5 | import { Crud } from "./crud.decorator"; 6 | 7 | const DB = 8 | process.env.DB || "mongodb://localhost/nestjs-mongoose-crud-test-e2e"; 9 | mongoose.connect(DB, { 10 | useNewUrlParser: true, 11 | useUnifiedTopology: true, 12 | useCreateIndex: true, 13 | useFindAndModify: false, 14 | }); 15 | 16 | const UserModel = mongoose.model( 17 | "User", 18 | new mongoose.Schema( 19 | { 20 | username: String, 21 | name: String, 22 | age: Number, 23 | }, 24 | { 25 | timestamps: true, 26 | } 27 | ) 28 | ); 29 | 30 | describe("CrudController e2e", () => { 31 | @Crud({ 32 | model: UserModel, 33 | }) 34 | @Controller("/users") 35 | class UserController { 36 | private model; 37 | constructor() { 38 | this.model = UserModel; 39 | } 40 | } 41 | let app: INestApplication; 42 | let server: any; 43 | let totalUsers = 15; 44 | 45 | beforeAll(async () => { 46 | await UserModel.deleteMany({}); 47 | const lastNames = `阿赵钱孙李周吴郑王`; 48 | const users = Array(totalUsers) 49 | .fill(1) 50 | .map((v, i) => ({ 51 | username: `user${i}`, 52 | name: lastNames[i % lastNames.length], 53 | age: Math.floor(Math.random() * 100), 54 | })); 55 | await UserModel.insertMany(users as any[]); 56 | const moduleRef = await Test.createTestingModule({ 57 | controllers: [UserController], 58 | }).compile(); 59 | app = moduleRef.createNestApplication(); 60 | await app.init(); 61 | server = app.getHttpServer(); 62 | }); 63 | afterAll(() => { 64 | mongoose.disconnect(); 65 | }); 66 | describe("create", () => { 67 | 68 | it("should create a user", async () => { 69 | return request(server) 70 | .post("/users") 71 | .send({ username: `test1` }) 72 | .expect((res) => expect(res.body).toHaveProperty("_id")); 73 | }); 74 | it("should sort chinese name", async () => { 75 | return request(server) 76 | .get(`/users?query={"limit":8,"sort":"name","collation":{"locale":"zh"}}`) 77 | .expect(200) 78 | .expect((res) => { 79 | expect(res.body.data).toHaveLength(8) 80 | expect(res.body.data[1]).toMatchObject({ name: "阿" }); 81 | }); 82 | }); 83 | // end of it() 84 | }); 85 | }); 86 | -------------------------------------------------------------------------------- /src/crud.decorator.ts: -------------------------------------------------------------------------------- 1 | import { CrudController, CrudPlaceholderDto } from "./crud.controller"; 2 | import { PARAMTYPES_METADATA } from '@nestjs/common/constants' 3 | import { get, merge } from 'lodash' 4 | import { CrudOptionsWithModel } from "./crud.interface"; 5 | import { CrudConfig } from "./crud-config"; 6 | 7 | const CRUD_ROUTES = { 8 | config: 'config', 9 | find: 'find', 10 | findOne: 'findOne', 11 | create: 'create', 12 | update: 'update', 13 | delete: 'delete', 14 | 15 | } 16 | 17 | const allMethods = Object.values(CRUD_ROUTES) 18 | 19 | function cloneDecorators(from, to) { 20 | Reflect.getMetadataKeys(from).forEach(key => { 21 | const value = Reflect.getMetadata(key, from) 22 | Reflect.defineMetadata(key, value, to) 23 | }) 24 | } 25 | function clonePropDecorators(from, to, name) { 26 | Reflect.getMetadataKeys(from, name).forEach(key => { 27 | const value = Reflect.getMetadata(key, from, name) 28 | Reflect.defineMetadata(key, value, to, name) 29 | }) 30 | } 31 | 32 | export const Crud = (options: CrudOptionsWithModel) => { 33 | options = merge({}, CrudConfig.options, options) 34 | return target => { 35 | const Controller = target 36 | const controller = target.prototype 37 | const crudController = new CrudController(options.model) 38 | 39 | controller.crudOptions = options 40 | 41 | const methods = allMethods.filter(v => get(options, `routes.${v}`) !== false) 42 | for (let method of methods) { 43 | if (controller[method]) { 44 | continue 45 | } 46 | if (!options.config && method === CRUD_ROUTES.config) { 47 | continue 48 | } 49 | controller[method] = function test(...args) { 50 | return crudController[method].apply(this, args) 51 | } 52 | Object.defineProperty(controller[method], 'name', { 53 | value: method 54 | }) 55 | // clone instance decorators 56 | cloneDecorators(crudController, controller) 57 | cloneDecorators(crudController[method], controller[method]) 58 | // clone instance method decorators 59 | clonePropDecorators(crudController, controller, method) 60 | // clone class "method" decorators 61 | clonePropDecorators(CrudController, Controller, method) 62 | 63 | // get exists param types 64 | const types: [] = Reflect.getMetadata(PARAMTYPES_METADATA, controller, method) 65 | 66 | Reflect.decorate([ 67 | 68 | // replace fake dto to real dto 69 | Reflect.metadata(PARAMTYPES_METADATA, types.map((v: any) => { 70 | if (get(v, 'name') === CrudPlaceholderDto.name) { 71 | return get(options, `routes.${method}.dto`, options.model) 72 | } 73 | return v 74 | })), 75 | ...get(options, `routes.${method}.decorators`, []) 76 | ], controller, method, Object.getOwnPropertyDescriptor(controller, method)) 77 | 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/crud.controller.ts: -------------------------------------------------------------------------------- 1 | import { Model, Document } from "mongoose"; 2 | import { 3 | Get, 4 | Param, 5 | Post, 6 | Put, 7 | Delete, 8 | Body, 9 | Query, 10 | Req 11 | } from "@nestjs/common"; 12 | import { ApiOperation, ApiQuery } from "@nestjs/swagger"; 13 | import { CrudQuery, ICrudQuery } from "./crud-query.decorator"; 14 | import { CrudConfig, defaultPaginate } from "./crud-config"; 15 | import { get, merge } from "lodash"; 16 | import { CrudOptionsWithModel, PaginateKeys, Fields } from "./crud.interface"; 17 | import { CRUD_FIELD_METADATA } from "./constants"; 18 | 19 | export class CrudPlaceholderDto { 20 | fake?: string; 21 | [key: string]: any; 22 | } 23 | 24 | export class CrudController { 25 | constructor( 26 | public model: Model<{} | any>, 27 | public crudOptions?: CrudOptionsWithModel 28 | ) {} 29 | 30 | @Get("config") 31 | @ApiOperation({ summary: "API Config", operationId: "config" }) 32 | async config(@Req() req) { 33 | const { config } = this.crudOptions; 34 | if (typeof config === "function") { 35 | return config.call(this, req); 36 | } 37 | return config; 38 | } 39 | 40 | @Get() 41 | @ApiOperation({ summary: "Find all records", operationId: "list" }) 42 | @ApiQuery({ 43 | name: "query", 44 | type: String, 45 | required: false, 46 | description: "Query options" 47 | }) 48 | find(@CrudQuery("query") query: ICrudQuery = {}) { 49 | let { 50 | where = get(this.crudOptions, "routes.find.where", {}), 51 | limit = get(this.crudOptions, "routes.find.limit", 10), 52 | page = 1, 53 | skip = 0, 54 | populate = get(this.crudOptions, "routes.find.populate", undefined), 55 | sort = get(this.crudOptions, "routes.find.sort", undefined), 56 | collation = undefined 57 | } = query; 58 | 59 | if (skip < 1) { 60 | skip = (page - 1) * limit; 61 | } 62 | 63 | const paginateKeys: PaginateKeys | false = get( 64 | this.crudOptions, 65 | "routes.find.paginate", 66 | defaultPaginate 67 | ); 68 | 69 | const find = async () => { 70 | const data = await this.model 71 | .find() 72 | .where(where) 73 | .skip(skip) 74 | .limit(limit) 75 | .sort(sort) 76 | .populate(populate) 77 | .collation(collation); 78 | if (paginateKeys !== false) { 79 | const total = await this.model.countDocuments(where); 80 | return { 81 | [paginateKeys.total]: total, 82 | [paginateKeys.data]: data, 83 | [paginateKeys.lastPage]: Math.ceil(total / limit), 84 | [paginateKeys.currentPage]: page 85 | }; 86 | } 87 | return data; 88 | }; 89 | return find(); 90 | } 91 | 92 | @Get(":id") 93 | @ApiOperation({ summary: "Find a record" }) 94 | findOne(@Param("id") id: string, @CrudQuery("query") query: ICrudQuery = {}) { 95 | let { 96 | where = get(this.crudOptions, "routes.findOne.where", {}), 97 | populate = get(this.crudOptions, "routes.findOne.populate", undefined), 98 | select = get(this.crudOptions, "routes.findOne.select", null) 99 | } = query; 100 | return this.model 101 | .findById(id) 102 | .populate(populate) 103 | .select(select) 104 | .where(where); 105 | } 106 | 107 | @Post() 108 | @ApiOperation({ summary: "Create a record" }) 109 | create(@Body() body: CrudPlaceholderDto) { 110 | const transform = get(this.crudOptions, "routes.create.transform"); 111 | if (transform) { 112 | body = transform(body); 113 | } 114 | return this.model.create(body); 115 | } 116 | 117 | @Put(":id") 118 | @ApiOperation({ summary: "Update a record" }) 119 | update(@Param("id") id: string, @Body() body: CrudPlaceholderDto) { 120 | const transform = get(this.crudOptions, "routes.update.transform"); 121 | if (transform) { 122 | body = transform(body); 123 | } 124 | return this.model.findOneAndUpdate({ _id: id }, body, { 125 | new: true, 126 | upsert: false, 127 | runValidators: true 128 | }); 129 | } 130 | 131 | @Delete(":id") 132 | @ApiOperation({ summary: "Delete a record" }) 133 | delete(@Param("id") id: string) { 134 | return this.model.findOneAndRemove({ _id: id }); 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /src/crud.interface.ts: -------------------------------------------------------------------------------- 1 | export interface PaginateKeys { 2 | data?: string 3 | total?: string 4 | lastPage?: string 5 | currentPage?: string 6 | } 7 | 8 | export interface CrudRoute { 9 | decorators?: MethodDecorator[] 10 | } 11 | export interface CrudRouteWithDto extends CrudRoute { 12 | dto?: any 13 | transform?: (data: any) => any 14 | } 15 | export interface CrudRouteForFind extends CrudRoute { 16 | paginate?: PaginateKeys | false 17 | limit?: number 18 | page?: number 19 | populate?: string | any 20 | sort?: string | any 21 | where?: any 22 | } 23 | export interface CrudRouteForFindOne extends CrudRoute { 24 | populate?: string | any 25 | where?: any 26 | select?: any 27 | } 28 | 29 | export interface CrudRoutes { 30 | grid?: false, 31 | form?: false, 32 | find?: CrudRouteForFind | false, 33 | findOne?: CrudRouteForFindOne | false, 34 | create?: CrudRouteWithDto | false, 35 | update?: CrudRouteWithDto | false, 36 | delete?: CrudRoute | false, 37 | 38 | } 39 | export interface CrudOptions { 40 | routes?: CrudRoutes 41 | } 42 | export interface OptionItem { 43 | text: string 44 | value: string 45 | } 46 | export interface Field { 47 | label?: string 48 | icon?: string 49 | type?: 'hide' | 'text' | 'input' | 'autocomplete' | 'textarea' | 'number' | 'checkbox' | 'checkbox-button' | 'radio' | 'date' | 'dates' | 'week' | 'month' | 'year' | 'daterange' | 'time' | 'datetime' | 'datetimerange' | 'switch' | 'yesno' | 'slider' | 'password' | 'color' | 'select' | 'cascader' | 'transfer' | 'rate' | 'tag' | 'image' | 'button' | 'json-editor' | 'upload-file' | 'image-uploader' | 'tree-select' | 'video-uploader' | 'quill-editor' | 'markdown-editor' | 'bmap' | 'codemirror' | 'gallery' 50 | listable?: boolean 51 | editable?: boolean 52 | attrs?: any 53 | layout?: number 54 | tip?: string 55 | options?: OptionItem[] 56 | class?: string | string[] 57 | style?: any 58 | width?: string | number 59 | [key: string]: any 60 | column?: Field[] 61 | } 62 | 63 | export interface Fields { 64 | [key: string]: Field 65 | } 66 | 67 | export interface AvueCrudOption { 68 | addBtn?: boolean 69 | addRowBtn?: boolean 70 | align?: string 71 | border?: boolean 72 | calcHeight?: number 73 | cancelBtnTitle?: string 74 | columnBtn?: boolean 75 | dataType?: string 76 | cellBtn?: boolean 77 | dateBtn?: boolean 78 | cancelBtn?: boolean 79 | dateDefault?: boolean 80 | dicData?: any 81 | dicMethod?: string 82 | dicQuery?: any 83 | dicUrl?: string 84 | delBtn?: boolean 85 | defaultSort?: any 86 | dialogFullscreen?: boolean 87 | dialogEscape?: boolean 88 | dialogClickModal?: boolean 89 | dialogCloseBtn?: boolean 90 | dialogModal?: boolean 91 | dialogTop?: string | number 92 | dialogType?: string 93 | dialogWidth?: string | number 94 | dialogHeight?: string | number 95 | defaultExpandAll?: boolean 96 | expandRowKeys?: string[] 97 | editBtn?: boolean 98 | emptyText?: string 99 | expand?: boolean 100 | expandWidth?: number 101 | expandFixed?: boolean 102 | excelBtn?: boolean 103 | filterBtn?: boolean 104 | formWidth?: string | number 105 | height?: number 106 | header?: boolean 107 | index?: boolean 108 | indexLabel?: string 109 | indexWidth?: number 110 | indexFixed?: boolean 111 | rowKey?: string 112 | indeterminate?: boolean 113 | labelWidth?: number 114 | maxHeight?: number 115 | menu?: boolean 116 | menuWidth?: number 117 | menuXsWidth?: number 118 | menuAlign?: string 119 | menuType?: string 120 | menuBtnTitle?: string 121 | pageSize?: string 122 | pageSizes?: number[] 123 | printBtn?: boolean 124 | refreshBtn?: boolean 125 | saveBtn?: boolean 126 | updateBtn?: boolean 127 | cancalBtn?: boolean 128 | saveBtnTitle?: string 129 | selection?: boolean 130 | selectionWidth?: number 131 | selectionFixed?: boolean 132 | searchBtn?: boolean 133 | selectable?: boolean 134 | reserveSelection?: true 135 | selectClearBtn?: boolean 136 | showHeader?: boolean 137 | showSummary?: boolean 138 | size?: string 139 | sumColumnList?: string[] 140 | stripe?: boolean 141 | tip?: string 142 | tipPlacement?: string 143 | title?: string 144 | checkStrictly?: boolean 145 | updateBtnTitle?: string 146 | viewBtn?: boolean 147 | width?: number 148 | column?: Field[] 149 | group?: Field[] 150 | } 151 | 152 | export interface AvueCrudConfig { 153 | option?: AvueCrudOption 154 | [key: string]: any 155 | } 156 | 157 | export interface CrudOptionsWithModel extends CrudOptions { 158 | name?: string | string[], 159 | model: any 160 | fields?: Fields 161 | config?: ((instance?: any) => AvueCrudConfig | Promise) | AvueCrudConfig 162 | } 163 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NestJs + Mongoose CRUD 2 | 3 | Nest.js crud module for mongoose models **without** `@nestjsx/crud` 4 | 5 | ## Important 6 | - NestJs 6.x ----> nestjs-mongoose-crud v1.x 7 | - NestJs 7.x ----> nestjs-mongoose-crud v2.x 8 | - fix #7 9 | 10 | > Nest.js + Typegoose 中文视频教程请移步哔哩哔哩: [全栈之巅](https://space.bilibili.com/341919508) 11 | 12 | ## Usage 13 | 1. Install and setup [nestjs-typegoose](https://github.com/kpfromer/nestjs-typegoose#basic-usage) or [nestjs-mongoose](https://docs.nestjs.com/techniques/mongodb) 14 | 1. Install 15 | ```shell 16 | yarn add nestjs-mongoose-crud 17 | # or 18 | npm i nestjs-mongoose-crud 19 | ``` 20 | 1. Import model to module: 21 | ```ts 22 | import { Module } from '@nestjs/common'; 23 | import { UsersController } from './users.controller'; 24 | import { TypegooseModule } from 'nestjs-typegoose'; 25 | import { User } from './user.model'; 26 | 27 | @Module({ 28 | imports: [ 29 | TypegooseModule.forFeature([User]) 30 | ], 31 | controllers: [UsersController] 32 | }) 33 | export class UsersModule {} 34 | ``` 35 | 1. Add `@Crud()` decorator and inject imported model to `model` property. 36 | ```ts 37 | import { Controller } from '@nestjs/common'; 38 | import { Crud } from 'nestjs-mongoose-crud' 39 | import { User } from './user.model'; 40 | import { InjectModel } from 'nestjs-typegoose'; 41 | import { ModelType } from '@typegoose/typegoose/lib/types'; 42 | 43 | @Crud({ 44 | model: User 45 | }) 46 | @Controller('users') 47 | export class UsersController { 48 | constructor(@InjectModel(User) public model: ModelType) {} 49 | } 50 | ``` 51 | 52 | 1. Test your CRUD APIs: http://localhost:3000/users 53 | 54 | ## APIs 55 | 56 | e.g. `@Crud()` for `UsersController` 57 | 58 | |METHOD|PATH|DESC| 59 | |--|--|--| 60 | |GET|/users|Get all users| 61 | |GET|/users/:id|Get a user| 62 | |POST|/users|Create a user| 63 | |PUT|/users/:id|update a user| 64 | |DELETE|/users/:id|Delete a user| 65 | 66 | > You can find all routes and DTOs by setup [swagger](https://docs.nestjs.com/recipes/swagger) 67 | 68 | ## Query 69 | Use a JSON (in string) `query` parameter to find records: 70 | 71 | [/users?query={"where":{"username":"user1","age":{"$gt":18}},"sort":"-_id","limit":10,"page":2,"populate":"friends"}]() 72 | 73 | ## Interfaces 74 | ```ts 75 | export interface PaginateKeys { 76 | data?: string 77 | total?: string 78 | lastPage?: string 79 | currentPage?: string 80 | } 81 | 82 | export interface CrudRoute { 83 | decorators?: MethodDecorator[] 84 | } 85 | export interface CrudRouteWithDto extends CrudRoute { 86 | dto?: any 87 | transform?: (data: any) => any 88 | } 89 | export interface CrudRouteForFind extends CrudRoute { 90 | paginate?: PaginateKeys | false 91 | limit?: number 92 | populate?: string | any 93 | sort?: string | any 94 | where?: any 95 | } 96 | export interface CrudRouteForFindOne extends CrudRoute { 97 | populate?: string | any 98 | where?: any 99 | select?: any 100 | } 101 | 102 | export interface CrudRoutes { 103 | grid?: false, 104 | form?: false, 105 | find?: CrudRouteForFind | false, 106 | findOne?: CrudRouteForFindOne | false, 107 | create?: CrudRouteWithDto | false, 108 | update?: CrudRouteWithDto | false, 109 | delete?: CrudRoute | false, 110 | 111 | } 112 | export interface CrudOptions { 113 | routes?: CrudRoutes 114 | } 115 | export interface OptionItem { 116 | text: string 117 | value: string 118 | } 119 | export interface Field { 120 | label?: string 121 | icon?: string 122 | type?: 'hide' | 'text' | 'input' | 'autocomplete' | 'textarea' | 'number' | 'checkbox' | 'checkbox-button' | 'radio' | 'date' | 'dates' | 'week' | 'month' | 'year' | 'daterange' | 'time' | 'datetime' | 'datetimerange' | 'switch' | 'yesno' | 'slider' | 'password' | 'color' | 'select' | 'cascader' | 'transfer' | 'rate' | 'tag' | 'image' | 'button' | 'json-editor' | 'upload-file' | 'image-uploader' | 'tree-select' | 'video-uploader' | 'quill-editor' | 'markdown-editor' | 'bmap' | 'codemirror' | 'gallery' 123 | listable?: boolean 124 | editable?: boolean 125 | attrs?: any 126 | layout?: number 127 | tip?: string 128 | options?: OptionItem[] 129 | class?: string | string[] 130 | style?: any 131 | width?: string | number 132 | [key: string]: any 133 | column?: Field[] 134 | } 135 | 136 | export interface Fields { 137 | [key: string]: Field 138 | } 139 | 140 | export interface AvueCrudOption { 141 | addBtn?: boolean 142 | addRowBtn?: boolean 143 | align?: string 144 | border?: boolean 145 | calcHeight?: number 146 | cancelBtnTitle?: string 147 | columnBtn?: boolean 148 | dataType?: string 149 | cellBtn?: boolean 150 | dateBtn?: boolean 151 | cancelBtn?: boolean 152 | dateDefault?: boolean 153 | dicData?: any 154 | dicMethod?: string 155 | dicQuery?: any 156 | dicUrl?: string 157 | delBtn?: boolean 158 | defaultSort?: any 159 | dialogFullscreen?: boolean 160 | dialogEscape?: boolean 161 | dialogClickModal?: boolean 162 | dialogCloseBtn?: boolean 163 | dialogModal?: boolean 164 | dialogTop?: string | number 165 | dialogType?: string 166 | dialogWidth?: string | number 167 | dialogHeight?: string | number 168 | defaultExpandAll?: boolean 169 | expandRowKeys?: string[] 170 | editBtn?: boolean 171 | emptyText?: string 172 | expand?: boolean 173 | expandWidth?: number 174 | expandFixed?: boolean 175 | excelBtn?: boolean 176 | filterBtn?: boolean 177 | formWidth?: string | number 178 | height?: number 179 | header?: boolean 180 | index?: boolean 181 | indexLabel?: string 182 | indexWidth?: number 183 | indexFixed?: boolean 184 | rowKey?: string 185 | indeterminate?: boolean 186 | labelWidth?: number 187 | maxHeight?: number 188 | menu?: boolean 189 | menuWidth?: number 190 | menuXsWidth?: number 191 | menuAlign?: string 192 | menuType?: string 193 | menuBtnTitle?: string 194 | pageSize?: string 195 | pageSizes?: number[] 196 | printBtn?: boolean 197 | refreshBtn?: boolean 198 | saveBtn?: boolean 199 | updateBtn?: boolean 200 | cancalBtn?: boolean 201 | saveBtnTitle?: string 202 | selection?: boolean 203 | selectionWidth?: number 204 | selectionFixed?: boolean 205 | searchBtn?: boolean 206 | selectable?: boolean 207 | reserveSelection?: true 208 | selectClearBtn?: boolean 209 | showHeader?: boolean 210 | showSummary?: boolean 211 | size?: string 212 | sumColumnList?: string[] 213 | stripe?: boolean 214 | tip?: string 215 | tipPlacement?: string 216 | title?: string 217 | checkStrictly?: boolean 218 | updateBtnTitle?: string 219 | viewBtn?: boolean 220 | width?: number 221 | column?: Field[] 222 | group?: Field[] 223 | } 224 | 225 | export interface AvueCrudConfig { 226 | option?: AvueCrudOption 227 | [key: string]: any 228 | } 229 | 230 | export interface CrudOptionsWithModel extends CrudOptions { 231 | name?: string | string[], 232 | model: any 233 | fields?: Fields 234 | config?: ((instance?: any) => AvueCrudConfig | Promise) | AvueCrudConfig 235 | } 236 | 237 | ``` --------------------------------------------------------------------------------