diff --git a/.drone.yml b/.drone.yml index bd2c056..75cdd23 100644 --- a/.drone.yml +++ b/.drone.yml @@ -7,8 +7,8 @@ host: path: /var/run/docker.sock - name: cache - host: - path: /tmp/cache/nanjing + host: · + path: /tmp/cache/visitor-new-api steps: - name: restore-cache @@ -64,7 +64,7 @@ - name: dockersock path: /var/run/docker.sock settings: - repo: hub.kaiguawang.cn/qunsense/api + repo: hub.kaiguawang.cn/longge/visitor-node-api registry: hub.kaiguawang.cn tags: - latest diff --git a/src/app.controller.ts b/src/app.controller.ts index 7852c51..2fd69f5 100644 --- a/src/app.controller.ts +++ b/src/app.controller.ts @@ -1,33 +1,202 @@ -import { Controller, Get } from '@nestjs/common'; +import { Body, Controller, Get, Post } from '@nestjs/common'; import { AppService } from './app.service'; import * as fs from 'fs'; +import { ApiProperty } from '@nestjs/swagger'; +import { IsArray, IsBoolean, IsDateString, IsNotEmpty, IsString } from 'class-validator'; +import { NodeVisitorEntity } from './node-visitor.entity'; +import { DataSource } from 'typeorm'; +import * as bluebird from 'bluebird'; +import { NodeOtherVisitorEntity } from './node-other-visitor.entity'; + +export class Electronics { + @ApiProperty({ description: "电子产品名称" }) + @IsString() + @IsNotEmpty() + public name: string; +} + +export class VisitorList { + @ApiProperty({ description: "访客姓名" }) + @IsString() + @IsNotEmpty() + public name: string; + + @ApiProperty({ description: "访客身份证号" }) + @IsString() + @IsNotEmpty() + public identity_card_no: string; + + @ApiProperty({ description: "国籍(中国/其他国籍)" }) + @IsString() + @IsNotEmpty() + public nationality_type: string; + + @ApiProperty({ description: "国籍名称" }) + @IsString() + @IsNotEmpty() + public nationality: string; +} + +export class CreateVisitor { + @ApiProperty({ description: "申请人" }) + @IsString() + @IsNotEmpty() + public applicant: string; + + @ApiProperty({ description: "申请人部门" }) + @IsString() + @IsNotEmpty() + public applicant_department: string; + + @ApiProperty({ description: "申请日期" }) + @IsDateString() + @IsNotEmpty() + public apply_date: string; + + @ApiProperty({ description: "申请单号" }) + @IsString() + @IsNotEmpty() + public code: string; + + // TODO 确定访客类型 + @ApiProperty({ description: "来访类型" }) + @IsString() + @IsNotEmpty() + public visitor_type: string; + + @ApiProperty({ description: "来访区域" }) + @IsString() + @IsNotEmpty() + public area: string; + + @ApiProperty({ description: "来访单位" }) + @IsString() + @IsNotEmpty() + public visitor_unit: string; + + @ApiProperty({ description: "访客人数" }) + @IsString() + @IsNotEmpty() + public visitor_number: string; + + @ApiProperty({ description: "交通方式" }) + @IsString() + @IsNotEmpty() + public transport: string; + + @ApiProperty({ description: "车牌号" }) + @IsString() + @IsNotEmpty() + public plate_no: string; + + @ApiProperty({ description: "起始日期" }) + @IsDateString() + @IsNotEmpty() + public start_date: string; + + @ApiProperty({ description: "截止日期" }) + @IsDateString() + @IsNotEmpty() + public end_date: string; + + @ApiProperty({ description: "被访人" }) + @IsString() + @IsNotEmpty() + public visited_staff: string; + + @ApiProperty({ description: "被访部门" }) + @IsString() + @IsNotEmpty() + public visited_deparment: string; + + @ApiProperty({ description: "被访部门" }) + @IsString() + @IsNotEmpty() + public purpose: string; + + @ApiProperty({ description: "携带的电子产品", type: [Electronics] }) + @IsArray() + @IsNotEmpty() + public electronics: Electronics[]; + + @ApiProperty({ description: "访客清单", type: [VisitorList] }) + @IsArray() + @IsNotEmpty() + public visitor_list: VisitorList[]; + + @ApiProperty({ description: "访客是否有可能接触受控设备" }) + @IsBoolean() + @IsNotEmpty() + public may_access_sensitive_info: boolean; +} @Controller() export class AppController { - constructor(private readonly appService: AppService) {} + constructor( + private readonly appService: AppService, + + private readonly dataSource: DataSource, + ) { } @Get() getHello(): string { return this.appService.getHello(); } - @Get("/doc/json") - getDoc(): string { - const json = fs.readFileSync("swagger-spec.json", "utf-8"); + // @Get("/doc/json") + // getDoc(): string { + // const json = fs.readFileSync("swagger-spec.json", "utf-8"); - return JSON.parse(json); - } - + // return JSON.parse(json); + // } + + + // @Get("/app.config") + // appConfig() { + // return { + // app_id: process.env.QUNSENSE_SUITE_ID + // } + // } - @Get("/app.config") - appConfig() { - return { - app_id: process.env.QUNSENSE_SUITE_ID - } - } - // @Get("/WW_verify_n9zX2u8E9ShFgYmx.txt") // config(): string { // return "n9zX2u8E9ShFgYmx"; // } + + @Post("/visitor") + async create(@Body() data: CreateVisitor) { + return await this.dataSource.transaction(async transactionalEntityManager => { + + const new_node_visitor = new NodeVisitorEntity(); + new_node_visitor.applicant = data.applicant; + new_node_visitor.applicant_department = data.applicant_department; + new_node_visitor.apply_date = data.apply_date; + new_node_visitor.code = data.code; + new_node_visitor.visitor_type = data.visitor_type; + new_node_visitor.area = data.area; + new_node_visitor.visitor_unit = data.visitor_unit; + new_node_visitor.visitor_number = data.visitor_number; + new_node_visitor.transport = data.transport; + new_node_visitor.plate_no = data.plate_no; + new_node_visitor.start_date = data.start_date; + new_node_visitor.end_date = data.end_date; + new_node_visitor.visited_staff = data.visited_staff; + new_node_visitor.visited_deparment = data.visited_deparment; + new_node_visitor.purpose = data.purpose; + new_node_visitor.electronics = JSON.stringify(data.electronics); + // new_node_visitor.visitor_list = data.visitor_list; + new_node_visitor.may_access_sensitive_info = data.may_access_sensitive_info; + const result = await transactionalEntityManager.save(new_node_visitor); + + await bluebird.each(data.visitor_list, async (item) => { + const new_node_other_visitor = new NodeOtherVisitorEntity(); + new_node_other_visitor.name = item.name; + new_node_other_visitor.identity_card_no = item.identity_card_no; + new_node_other_visitor.nationality_type = item.nationality_type; + new_node_other_visitor.nationality = item.nationality; + }) + + return result; + }); + } } diff --git a/src/app.module.ts b/src/app.module.ts index 8851a3e..2ca4881 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -3,18 +3,25 @@ import { ScheduleModule } from '@nestjs/schedule'; import { AppController } from './app.controller'; import { AppService } from './app.service'; import { TypeOrmModule } from '@nestjs/typeorm'; -import {mysql_config} from './config/config.mysql'; +import { mysql_config } from './config/config.mysql'; import { ConfigModule } from './config/config.module'; import { AuthModule } from './auth/auth.module'; import { UserModule } from './user/user.module'; import { RoleModule } from './role/role.module'; import { FileModule } from './file/file.module'; +import { VisitorEntity } from './visitor.entity'; +import { NodeVisitorEntity } from './node-visitor.entity'; + @Module({ imports: [ ConfigModule, AuthModule, UserModule, TypeOrmModule.forRoot(mysql_config), + TypeOrmModule.forFeature([ + VisitorEntity, + NodeVisitorEntity, + ]), ScheduleModule.forRoot(), RoleModule, FileModule, @@ -22,4 +29,4 @@ import { FileModule } from './file/file.module'; controllers: [AppController], providers: [AppService], }) -export class AppModule {} +export class AppModule { } diff --git a/src/auth/auth.controller.ts b/src/auth/auth.controller.ts index c3ca9a0..96ee3b8 100644 --- a/src/auth/auth.controller.ts +++ b/src/auth/auth.controller.ts @@ -34,23 +34,23 @@ export class AuthController { private readonly userRepository: Repository, ) { } - @Get('login/status/is_login') - @ApiOperation({ summary: '获取 token 是否失效' }) - @UsePipes(new ValidationPipe()) - @ApiResponse({ - status: 200, - description: '返回参数说明', - type: LoginStatus, - }) - async loginGetStatus(@Query() loginData: IsLogin): Promise { - const result = await redis.get(`qunsense_code:${loginData.qunsense_code}`) - if (result) { - return { - status: true - } - } - return { - status: false - } - } + // @Get('login/status/is_login') + // @ApiOperation({ summary: '获取 token 是否失效' }) + // @UsePipes(new ValidationPipe()) + // @ApiResponse({ + // status: 200, + // description: '返回参数说明', + // type: LoginStatus, + // }) + // async loginGetStatus(@Query() loginData: IsLogin): Promise { + // const result = await redis.get(`qunsense_code:${loginData.qunsense_code}`) + // if (result) { + // return { + // status: true + // } + // } + // return { + // status: false + // } + // } } diff --git a/src/common/base.entity.ts b/src/common/base.entity.ts index 92a53a5..a57d184 100644 --- a/src/common/base.entity.ts +++ b/src/common/base.entity.ts @@ -15,12 +15,13 @@ let gen1 = new snowId.SnowflakeIdv1({ workerId: 1, seqBitLength: 2, workerIdBitL // @ObjectType() @Entity() export class Base extends BaseEntity { - @BeforeInsert() - generateId() { - this.id = String(gen1.NextId()) - } + // @BeforeInsert() + // generateId() { + // this.id = String(gen1.NextId()) + // } // @Field() - @PrimaryColumn({ length: 12 }) + // @PrimaryColumn({ length: 12 }) + @PrimaryGeneratedColumn('uuid') // @Column({ type: 'varchar', length: '12', nullable: false }) @ApiProperty({ description: "数据唯一id" }) id: string; diff --git a/src/config/config.doc.ts b/src/config/config.doc.ts index ebc36e0..c666f40 100644 --- a/src/config/config.doc.ts +++ b/src/config/config.doc.ts @@ -2,16 +2,18 @@ import { DocumentBuilder } from '@nestjs/swagger'; export const options = new DocumentBuilder() .setTitle('restfull api') - .setDescription(` - Api为restfull风格api,接口请求成功与否请使用header里面的status来判断,200表示get请求成功,201表示POST/PUT/PATCH请求成功 - 204表示delete成功,非上述code返回体会有message字段,表示请求失败的错误描述,例如:header的status=500 那么返回体中回包含{message:"Internal server error"} - 注意,返回的message字段并不一定是string类型。注意:orm使用的是固定版本typeorm@0.3.15。表结构存在关联字段,更高版本每次都会重建主键id字段,无论关联字段类型是uuid还是vachar(36) - 重建时会删除id对应的值,导致外建关联报错“ER_NO_REFERENCED_ROW2:can not add or update a children row:xx - `) + .setDescription("restfull风格api" + // ` + // Api为restfull风格api,接口请求成功与否请使用header里面的status来判断,200表示get请求成功,201表示POST/PUT/PATCH请求成功 + // 204表示delete成功,非上述code返回体会有message字段,表示请求失败的错误描述,例如:header的status=500 那么返回体中回包含{message:"Internal server error"} + // 注意,返回的message字段并不一定是string类型。注意:orm使用的是固定版本typeorm@0.3.15。表结构存在关联字段,更高版本每次都会重建主键id字段,无论关联字段类型是uuid还是vachar(36) + // 重建时会删除id对应的值,导致外建关联报错“ER_NO_REFERENCED_ROW2:can not add or update a children row:xx + // ` + ) .setVersion('1.0') // .setTermsOfService('test') - // .setContact('时间伙伴', 'shijianhuoban.com', 'shijianhuoban@outlook.com') - .setLicense('2019 © shijianhuoban', 'https://github.com/shijianhuoban') + // .setContact('时间伙伴', 'kaiguawang.com', 'kaiguawang@outlook.com') + .setLicense('2023 © kaiguawang', 'https://github.com/shijianhuoban') .setBasePath('/api') .addBearerAuth() // .addOAuth2() diff --git a/src/file/file.controller.ts b/src/file/file.controller.ts index 48c9437..cdbc84f 100644 --- a/src/file/file.controller.ts +++ b/src/file/file.controller.ts @@ -45,67 +45,67 @@ export class FileController { private readonly fileRepository: Repository, ) { } - @Post('upload/public') - @ApiOperation({ summary: '上传文件' }) - @ApiConsumes('multipart/form-data') - @ApiBody({ - description: 'file', - type: FileUploadType, - }) - @UseGuards(AuthGuard('jwt')) - // @Roles('super_admin', '批量创建门锁') - @UseInterceptors( - FileInterceptor('file', { - storage: diskStorage({ - destination: './upload/file', - filename: async (req, file, cb) => { - const randomName = Array(32) - .fill(null) - .map(() => Math.round(Math.random() * 16).toString(16)) - .join(''); - return cb(null, `${randomName}${extname(file.originalname)}`); - }, - }), - }), - ) - async uploadPublicFile(@UploadedFile() file, @Query() query: any, @Res() res, @User() viewer: any) { - // const filterType: string[] = ['.pdf', '.PDF', '.png', '.doc', '.docx', '.jpeg']; - const { filename } = file; - // const ext = extname(filename) - // 判断当前上传至接口的文件类型是否在白名单中,如果在则允许上传,不在则返回错误信息 - // if (!filterType.includes(ext)) { - // return res.json({ - // success: false, - // message: "文件格式错误,支持'.pdf'、'.PDF'、 '.png'、 '.doc'、 '.docx'、 '.jpeg'", - // }); - // } - // const file_name = query.code + "-" + file.filename - return res.json({ - message: 'ok', - success: true, - file_name: file.filename, - // uri: getDownloadUrl(file_name), - }); - } + // @Post('upload/public') + // @ApiOperation({ summary: '上传文件' }) + // @ApiConsumes('multipart/form-data') + // @ApiBody({ + // description: 'file', + // type: FileUploadType, + // }) + // @UseGuards(AuthGuard('jwt')) + // // @Roles('super_admin', '批量创建门锁') + // @UseInterceptors( + // FileInterceptor('file', { + // storage: diskStorage({ + // destination: './upload/file', + // filename: async (req, file, cb) => { + // const randomName = Array(32) + // .fill(null) + // .map(() => Math.round(Math.random() * 16).toString(16)) + // .join(''); + // return cb(null, `${randomName}${extname(file.originalname)}`); + // }, + // }), + // }), + // ) + // async uploadPublicFile(@UploadedFile() file, @Query() query: any, @Res() res, @User() viewer: any) { + // // const filterType: string[] = ['.pdf', '.PDF', '.png', '.doc', '.docx', '.jpeg']; + // const { filename } = file; + // // const ext = extname(filename) + // // 判断当前上传至接口的文件类型是否在白名单中,如果在则允许上传,不在则返回错误信息 + // // if (!filterType.includes(ext)) { + // // return res.json({ + // // success: false, + // // message: "文件格式错误,支持'.pdf'、'.PDF'、 '.png'、 '.doc'、 '.docx'、 '.jpeg'", + // // }); + // // } + // // const file_name = query.code + "-" + file.filename + // return res.json({ + // message: 'ok', + // success: true, + // file_name: file.filename, + // // uri: getDownloadUrl(file_name), + // }); + // } - @Post('upload/base64') - @ApiOperation({ summary: '上传头像文件' }) - @UseGuards(AuthGuard('jwt')) - @UsePipes(new ValidationPipe()) - async louploadBase64Filegin(@Body() input: Base64File): Promise { - const file_name = uuid() + '.png'; - // if (!input.base64.startsWith('data:image/png;base64') && !input.base64.startsWith('data:image/jpeg;base64')) { - // throw new BadRequestException('文件类型不支持,仅支持jpeg,png') - // } - //过滤data:URL - const base64Data = input.base64.replace(/^data:image\/\w+;base64,/, ''); - const dataBuffer = new Buffer(base64Data, 'base64'); - // await uploadBase64File(file_name, dataBuffer); - return { - message: 'ok', - success: true, - file_name, - // uri: getDownloadUrl(file_name), - }; - } + // @Post('upload/base64') + // @ApiOperation({ summary: '上传头像文件' }) + // @UseGuards(AuthGuard('jwt')) + // @UsePipes(new ValidationPipe()) + // async louploadBase64Filegin(@Body() input: Base64File): Promise { + // const file_name = uuid() + '.png'; + // // if (!input.base64.startsWith('data:image/png;base64') && !input.base64.startsWith('data:image/jpeg;base64')) { + // // throw new BadRequestException('文件类型不支持,仅支持jpeg,png') + // // } + // //过滤data:URL + // const base64Data = input.base64.replace(/^data:image\/\w+;base64,/, ''); + // const dataBuffer = new Buffer(base64Data, 'base64'); + // // await uploadBase64File(file_name, dataBuffer); + // return { + // message: 'ok', + // success: true, + // file_name, + // // uri: getDownloadUrl(file_name), + // }; + // } } diff --git a/src/node-other-visitor.entity.ts b/src/node-other-visitor.entity.ts new file mode 100644 index 0000000..bc00122 --- /dev/null +++ b/src/node-other-visitor.entity.ts @@ -0,0 +1,28 @@ +import { BaseEntity, Column, Entity, Index, JoinColumn, OneToMany, OneToOne } from 'typeorm'; +import { createHmac } from 'crypto'; +import { Base } from './common'; +import { ApiProperty } from '@nestjs/swagger'; + +// 访客 +@Entity({ name: 'node-other-visitor' }) +export class NodeOtherVisitorEntity extends Base { + @ApiProperty({ description: "访客姓名" }) + @Column({ length: 150, nullable: true, type: 'char' }) + public name: string; + + @ApiProperty({ description: "访客身份证号" }) + @Column({ length: 150, nullable: true, type: 'char' }) + public identity_card_no: string; + + @ApiProperty({ description: "国籍(中国/其他国籍)" }) + @Column({ length: 150, nullable: true, type: 'char' }) + public nationality_type: string; + + @ApiProperty({ description: "国籍名称" }) + @Column({ length: 150, nullable: true, type: 'char' }) + public nationality: string; + + @ApiProperty({ description: "" }) + @Column({ length: 36, nullable: true, type: 'char' }) + public node_visitor_id: string; +} diff --git a/src/node-visitor.entity.ts b/src/node-visitor.entity.ts new file mode 100644 index 0000000..3274813 --- /dev/null +++ b/src/node-visitor.entity.ts @@ -0,0 +1,82 @@ +import { BaseEntity, Column, Entity, Index, JoinColumn, OneToMany, OneToOne } from 'typeorm'; +import { createHmac } from 'crypto'; +import { Base } from './common'; +import { ApiProperty } from '@nestjs/swagger'; + +// 访客 +@Entity({ name: 'node-visitor' }) +export class NodeVisitorEntity extends Base { + @ApiProperty({ description: "申请人" }) + @Column({ length: 150, nullable: true, type: 'char' }) + public applicant: string; + + @ApiProperty({ description: "申请人部门" }) + @Column({ length: 150, nullable: true, type: 'char' }) + public applicant_department: string; + + @ApiProperty({ description: "申请日期" }) + @Column({ nullable: true, type: 'date' }) + public apply_date: string; + + @ApiProperty({ description: "申请单号" }) + @Column({ length: 150, nullable: true, type: 'char' }) + public code: string; + + // TODO 确定访客类型 + @ApiProperty({ description: "来访类型" }) + @Column({ length: 150, nullable: true, type: 'char' }) + public visitor_type: string; + + @ApiProperty({ description: "来访区域" }) + @Column({ length: 150, nullable: true, type: 'char' }) + public area: string; + + @ApiProperty({ description: "来访单位" }) + @Column({ length: 150, nullable: true, type: 'char' }) + public visitor_unit: string; + + @ApiProperty({ description: "访客人数" }) + @Column({ length: 150, nullable: true, type: 'char' }) + public visitor_number: string; + + @ApiProperty({ description: "交通方式" }) + @Column({ length: 150, nullable: true, type: 'char' }) + public transport: string; + + @ApiProperty({ description: "车牌号" }) + @Column({ length: 150, nullable: true, type: 'char' }) + public plate_no: string; + + @ApiProperty({ description: "起始日期" }) + @Column({ nullable: true, type: 'date' }) + public start_date: string; + + @ApiProperty({ description: "截止日期" }) + @Column({ nullable: true, type: 'date' }) + public end_date: string; + + @ApiProperty({ description: "被访人" }) + @Column({ length: 150, nullable: true, type: 'char' }) + public visited_staff: string; + + @ApiProperty({ description: "被访部门" }) + @Column({ length: 150, nullable: true, type: 'char' }) + public visited_deparment: string; + + @ApiProperty({ description: "被访部门" }) + @Column({ length: 150, nullable: true, type: 'char' }) + public purpose: string; + + @ApiProperty({ description: "携带的电子产品" }) + @Column({ length: 255, nullable: true, type: 'char' }) + public electronics: string; + + // @ApiProperty({ description: "访客清单", type: [VisitorList] }) + // @IsArray() + // @IsNotEmpty() + // public visitor_list: VisitorList[]; + + @ApiProperty({ description: "访客是否有可能接触受控设备" }) + @Column({ nullable: true }) + public may_access_sensitive_info: boolean; +} diff --git a/src/role/role.controller.ts b/src/role/role.controller.ts index 5638824..aed2c71 100644 --- a/src/role/role.controller.ts +++ b/src/role/role.controller.ts @@ -9,28 +9,28 @@ import { ApiTags } from '@nestjs/swagger'; export class RoleController { constructor(private readonly roleService: RoleService) {} - @Post() - create(@Body() createRoleDto: CreateRoleDto) { - return this.roleService.create(createRoleDto); - } + // @Post() + // create(@Body() createRoleDto: CreateRoleDto) { + // return this.roleService.create(createRoleDto); + // } - @Get() - findAll() { - return this.roleService.findAll(); - } + // @Get() + // findAll() { + // return this.roleService.findAll(); + // } - @Get(':id') - findOne(@Param('id') id: string) { - return this.roleService.findOne(+id); - } + // @Get(':id') + // findOne(@Param('id') id: string) { + // return this.roleService.findOne(+id); + // } - @Patch(':id') - update(@Param('id') id: string, @Body() updateRoleDto: UpdateRoleDto) { - return this.roleService.update(+id, updateRoleDto); - } + // @Patch(':id') + // update(@Param('id') id: string, @Body() updateRoleDto: UpdateRoleDto) { + // return this.roleService.update(+id, updateRoleDto); + // } - @Delete(':id') - remove(@Param('id') id: string) { - return this.roleService.remove(+id); - } + // @Delete(':id') + // remove(@Param('id') id: string) { + // return this.roleService.remove(+id); + // } } diff --git a/src/user/user.controller.ts b/src/user/user.controller.ts index 2188b25..2a7a118 100644 --- a/src/user/user.controller.ts +++ b/src/user/user.controller.ts @@ -32,18 +32,18 @@ export class UserController { // private readonly authService: AuthService, ) { } - @Get('/viewer') - @ApiOperation({ summary: '获取个人信息' }) - @UseGuards(AuthGuard('jwt'), RolesGuard) - @UsePipes(new ValidationPipe()) - @Roles('company', 'tester', 'admin') - @ApiBearerAuth() - @ApiResponse({ - status: 200, - description: '返回参数说明', - }) - async viewer(@User() viewer: UserEntity) { - const result = await this.userRepository.findOne({ where: { id: viewer.id } }) - return result; - } + // @Get('/viewer') + // @ApiOperation({ summary: '获取个人信息' }) + // @UseGuards(AuthGuard('jwt'), RolesGuard) + // @UsePipes(new ValidationPipe()) + // @Roles('company', 'tester', 'admin') + // @ApiBearerAuth() + // @ApiResponse({ + // status: 200, + // description: '返回参数说明', + // }) + // async viewer(@User() viewer: UserEntity) { + // const result = await this.userRepository.findOne({ where: { id: viewer.id } }) + // return result; + // } } diff --git a/src/user/user.entity.ts b/src/user/user.entity.ts index e0b26b7..9446cc3 100644 --- a/src/user/user.entity.ts +++ b/src/user/user.entity.ts @@ -4,7 +4,7 @@ import { Base } from '../common'; import { ApiProperty } from '@nestjs/swagger'; // 用户表 -@Entity({ name: 'users' }) +@Entity({ name: 'node-users' }) export class UserEntity extends Base { @ApiProperty({ description: '真实姓名' }) @Column({ length: 50, nullable: true, type: 'char' }) diff --git a/src/visitor.entity.ts b/src/visitor.entity.ts new file mode 100644 index 0000000..1bb8893 --- /dev/null +++ b/src/visitor.entity.ts @@ -0,0 +1,75 @@ +import { BaseEntity, Column, Entity, Index, JoinColumn, OneToMany, OneToOne } from 'typeorm'; +import { createHmac } from 'crypto'; +import { Base } from './common'; +import { ApiProperty } from '@nestjs/swagger'; + +// 访客 +@Entity({ name: 'visitor' }) +export class VisitorEntity extends Base { + @ApiProperty({ description: '真实姓名' }) + @Column({ length: 50, nullable: true, type: 'char' }) + public true_name: string; + + @ApiProperty({ description: '手机号' }) + @Column({ length: 50 }) + public mobile: string; + + @ApiProperty({ description: '公司' }) + @Column({ length: 50 }) + public company: string; + + @ApiProperty({ description: '邀请码' }) + @Column({ length: 50 }) + public code: string; + + @ApiProperty({ description: '邀请码' }) + @Column({ length: 50 }) + public card_code: string; + + @ApiProperty({ description: '二维码有效时间' }) + @Column({ length: 50 }) + public qrCode?: string; + + @ApiProperty({ description: '事由' }) + @Column({ length: 50 }) + public reason?: string; + + @ApiProperty({ description: '身份证号' }) + @Column({ length: 50 }) + public id_number?: string; + + @ApiProperty({ description: '受访人' }) + @Column({ length: 50 }) + public interviewee?: string; + + @ApiProperty({ description: '楼层' }) + @Column({ length: 50 }) + public floor?: string; + + @ApiProperty({ description: '开始日期' }) + @Column({ type: "date" }) + public start_date: string; + + @ApiProperty({ description: '开始时间' }) + @Column({ type: "time" }) + public start_time: string; + + @ApiProperty({ description: '结束日期' }) + @Column({ type: "date" }) + public end_date: string; + + @ApiProperty({ description: '结束时间' }) + @Column({ type: "time" }) + public end_time: string; + + // #[sea_orm(column_type = "Char(Some(36))", nullable)] + // pub create_user_id: Option, + + // #[sea_orm(column_type = "DateTime", indexed)] + // #[component(value_type = String)] + // pub created_date: DateTime, + + // #[sea_orm(column_type = "DateTime")] + // #[component(value_type = String)] + // pub updated_date: DateTime, +} diff --git a/swagger-spec.json b/swagger-spec.json index d20813e..d219183 100644 --- a/swagger-spec.json +++ b/swagger-spec.json @@ -1 +1 @@ -{"openapi":"3.0.0","paths":{"/":{"get":{"operationId":"AppController_getHello","parameters":[],"responses":{"200":{"description":""}}}},"/doc/json":{"get":{"operationId":"AppController_getDoc","parameters":[],"responses":{"200":{"description":""}}}},"/app.config":{"get":{"operationId":"AppController_appConfig","parameters":[],"responses":{"200":{"description":""}}}},"/auth/login/status/is_login":{"get":{"operationId":"AuthController_loginGetStatus","summary":"获取 token 是否失效","parameters":[{"name":"qunsense_code","required":true,"in":"query","description":"小程序码","schema":{"type":"string"}}],"responses":{"200":{"description":"返回参数说明","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginStatus"}}}}},"tags":["用户登录"]}},"/users/viewer":{"get":{"operationId":"UserController_viewer","summary":"获取个人信息","parameters":[],"responses":{"200":{"description":"返回参数说明"}},"tags":["系统用户"],"security":[{"bearer":[]},{"bearer":[]}]}},"/roles":{"post":{"operationId":"RoleController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRoleDto"}}}},"responses":{"201":{"description":""}},"tags":["用户角色"]},"get":{"operationId":"RoleController_findAll","parameters":[],"responses":{"200":{"description":""}},"tags":["用户角色"]}},"/roles/{id}":{"get":{"operationId":"RoleController_findOne","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["用户角色"]},"patch":{"operationId":"RoleController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateRoleDto"}}}},"responses":{"200":{"description":""}},"tags":["用户角色"]},"delete":{"operationId":"RoleController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["用户角色"]}},"/file/upload/public":{"post":{"operationId":"FileController_uploadPublicFile","summary":"上传文件","parameters":[],"requestBody":{"required":true,"description":"file","content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/FileUploadType"}}}},"responses":{"201":{"description":""}},"tags":["file"],"security":[{"bearer":[]}]}},"/file/upload/base64":{"post":{"operationId":"FileController_louploadBase64Filegin","summary":"上传头像文件","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Base64File"}}}},"responses":{"201":{"description":""}},"tags":["file"],"security":[{"bearer":[]}]}}},"info":{"title":"restfull api","description":"\n Api为restfull风格api,接口请求成功与否请使用header里面的status来判断,200表示get请求成功,201表示POST/PUT/PATCH请求成功 \n 204表示delete成功,非上述code返回体会有message字段,表示请求失败的错误描述,例如:header的status=500 那么返回体中回包含{message:\"Internal server error\"}\n 注意,返回的message字段并不一定是string类型。注意:orm使用的是固定版本typeorm@0.3.15。表结构存在关联字段,更高版本每次都会重建主键id字段,无论关联字段类型是uuid还是vachar(36)\n 重建时会删除id对应的值,导致外建关联报错“ER_NO_REFERENCED_ROW2:can not add or update a children row:xx\n ","version":"1.0","contact":{},"license":{"name":"2019 © shijianhuoban","url":"https://github.com/shijianhuoban"}},"tags":[],"servers":[],"components":{"securitySchemes":{"bearer":{"scheme":"bearer","bearerFormat":"JWT","type":"http"}},"schemas":{"LoginStatus":{"type":"object","properties":{"status":{"type":"boolean","description":"登录状态返回"}}},"CreateRoleDto":{"type":"object","properties":{}},"UpdateRoleDto":{"type":"object","properties":{}},"FileUploadType":{"type":"object","properties":{"file":{"type":"string","format":"binary"}},"required":["file"]},"Base64File":{"type":"object","properties":{"base64":{"type":"string"}},"required":["base64"]}}}} \ No newline at end of file +{"openapi":"3.0.0","paths":{"/":{"get":{"operationId":"AppController_getHello","parameters":[],"responses":{"200":{"description":""}}}},"/visitor":{"post":{"operationId":"AppController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateVisitor"}}}},"responses":{"201":{"description":""}}}}},"info":{"title":"restfull api","description":"restfull风格api","version":"1.0","contact":{},"license":{"name":"2023 © kaiguawang","url":"https://github.com/shijianhuoban"}},"tags":[],"servers":[],"components":{"securitySchemes":{"bearer":{"scheme":"bearer","bearerFormat":"JWT","type":"http"}},"schemas":{"Electronics":{"type":"object","properties":{"name":{"type":"string","description":"电子产品名称"}},"required":["name"]},"VisitorList":{"type":"object","properties":{"name":{"type":"string","description":"访客姓名"},"identity_card_no":{"type":"string","description":"访客身份证号"},"nationality_type":{"type":"string","description":"国籍(中国/其他国籍)"},"nationality":{"type":"string","description":"国籍名称"}},"required":["name","identity_card_no","nationality_type","nationality"]},"CreateVisitor":{"type":"object","properties":{"applicant":{"type":"string","description":"申请人"},"applicant_department":{"type":"string","description":"申请人部门"},"apply_date":{"type":"string","description":"申请日期"},"code":{"type":"string","description":"申请单号"},"visitor_type":{"type":"string","description":"来访类型"},"area":{"type":"string","description":"来访区域"},"visitor_unit":{"type":"string","description":"来访单位"},"visitor_number":{"type":"string","description":"访客人数"},"transport":{"type":"string","description":"交通方式"},"plate_no":{"type":"string","description":"车牌号"},"start_date":{"type":"string","description":"起始日期"},"end_date":{"type":"string","description":"截止日期"},"visited_staff":{"type":"string","description":"被访人"},"visited_deparment":{"type":"string","description":"被访部门"},"purpose":{"type":"string","description":"被访部门"},"electronics":{"description":"携带的电子产品","type":"array","items":{"$ref":"#/components/schemas/Electronics"}},"visitor_list":{"description":"访客清单","type":"array","items":{"$ref":"#/components/schemas/VisitorList"}},"may_access_sensitive_info":{"type":"boolean","description":"访客是否有可能接触受控设备"}},"required":["applicant","applicant_department","apply_date","code","visitor_type","area","visitor_unit","visitor_number","transport","plate_no","start_date","end_date","visited_staff","visited_deparment","purpose","electronics","visitor_list","may_access_sensitive_info"]}}}} \ No newline at end of file