From a3243bf1aa5bba83b433f3e4b24344f3226aa695 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=9E=97?= <1570898673@qq.com> Date: Wed, 9 Apr 2025 23:26:22 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E7=AE=80=E5=8E=86=E6=A8=A1?= =?UTF-8?q?=E6=9D=BF=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app.module.ts | 2 + .../dto/create-resume-template.dto.ts | 10 ++ .../dto/update-resume-template.dto.ts | 15 ++ .../entities/resume-template.entity.ts | 52 +++++++ .../resume-template.controller.spec.ts | 20 +++ .../resume-template.controller.ts | 105 ++++++++++++++ src/resume-template/resume-template.module.ts | 13 ++ .../resume-template.service.spec.ts | 18 +++ .../resume-template.service.ts | 131 ++++++++++++++++++ 9 files changed, 366 insertions(+) create mode 100644 src/resume-template/dto/create-resume-template.dto.ts create mode 100644 src/resume-template/dto/update-resume-template.dto.ts create mode 100644 src/resume-template/entities/resume-template.entity.ts create mode 100644 src/resume-template/resume-template.controller.spec.ts create mode 100644 src/resume-template/resume-template.controller.ts create mode 100644 src/resume-template/resume-template.module.ts create mode 100644 src/resume-template/resume-template.service.spec.ts create mode 100644 src/resume-template/resume-template.service.ts diff --git a/src/app.module.ts b/src/app.module.ts index 2019af5..663ecea 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -8,6 +8,7 @@ import { UsercenterModule } from './usercenter/usercenter.module'; import { AuthModule } from './auth/auth.module'; import { ArticleModule } from './article/article.module'; import { UploadModule } from './upload/upload.module'; +import { ResumeTemplateModule } from './resume-template/resume-template.module'; const envFilePath = ['.env']; export const IS_DEV = process.env.RUNNING_ENV !== 'prod'; @@ -34,6 +35,7 @@ if (IS_DEV) { AuthModule, ArticleModule, UploadModule, + ResumeTemplateModule, ], controllers: [AppController], providers: [AppService], diff --git a/src/resume-template/dto/create-resume-template.dto.ts b/src/resume-template/dto/create-resume-template.dto.ts new file mode 100644 index 0000000..5fab861 --- /dev/null +++ b/src/resume-template/dto/create-resume-template.dto.ts @@ -0,0 +1,10 @@ +import { IsJSON, IsNotEmpty, IsObject, IsString } from 'class-validator'; +export class CreateResumeTemplateDto { + @IsString({ message: '简历模板名称必须为字符串' }) + @IsNotEmpty({ message: '简历模板名称不能为空' }) + resumeTemplateName: string; + + @IsObject({ message: '简历模板内容必须为对象' }) + @IsNotEmpty({ message: '简历模板内容不能为空' }) + resumeTemplateContent: object; +} diff --git a/src/resume-template/dto/update-resume-template.dto.ts b/src/resume-template/dto/update-resume-template.dto.ts new file mode 100644 index 0000000..d017645 --- /dev/null +++ b/src/resume-template/dto/update-resume-template.dto.ts @@ -0,0 +1,15 @@ +import { PartialType } from '@nestjs/mapped-types'; +import { CreateResumeTemplateDto } from './create-resume-template.dto'; +import { IsJSON, IsObject, IsOptional, IsString } from 'class-validator'; + +export class UpdateResumeTemplateDto extends PartialType( + CreateResumeTemplateDto, +) { + @IsOptional() + @IsString({ message: '简历模板名称必须是字符串' }) + resumeTemplateName?: string; + + @IsOptional() + @IsObject({ message: '简历模板内容必须是对象' }) + resumeTemplateContent?: object; +} diff --git a/src/resume-template/entities/resume-template.entity.ts b/src/resume-template/entities/resume-template.entity.ts new file mode 100644 index 0000000..4bb0a15 --- /dev/null +++ b/src/resume-template/entities/resume-template.entity.ts @@ -0,0 +1,52 @@ +import { + Entity, + Column, + PrimaryGeneratedColumn, + CreateDateColumn, + UpdateDateColumn, +} from 'typeorm'; + +@Entity() +export class ResumeTemplateEntity { + // id 自增 + @PrimaryGeneratedColumn({ + type: 'int', + name: 'resume_template_id', + comment: '主键id', + }) + resumeTemplateId: number; + + // 简历模板名称 + @Column({ + type: 'varchar', + length: 255, + name: 'resume_template_name', + comment: '简历模板名称', + }) + resumeTemplateName: string; + + // 简历模板内容 + @Column({ + type: 'json', + name: 'resume_template_content', + nullable: false, + comment: '简历模板内容', + }) + resumeTemplateContent: object; + + // 创建时间 + @CreateDateColumn({ + type: 'datetime', + name: 'resume_template_create_time', + comment: '创建时间', + }) + resumeTemplateCreateTime: Date; + + // 更新时间 + @UpdateDateColumn({ + type: 'datetime', + name: 'resume_template_update_time', + comment: '更新时间', + }) + resumeTemplateUpdateTime: Date; +} diff --git a/src/resume-template/resume-template.controller.spec.ts b/src/resume-template/resume-template.controller.spec.ts new file mode 100644 index 0000000..84b3b4b --- /dev/null +++ b/src/resume-template/resume-template.controller.spec.ts @@ -0,0 +1,20 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { ResumeTemplateController } from './resume-template.controller'; +import { ResumeTemplateService } from './resume-template.service'; + +describe('ResumeTemplateController', () => { + let controller: ResumeTemplateController; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + controllers: [ResumeTemplateController], + providers: [ResumeTemplateService], + }).compile(); + + controller = module.get(ResumeTemplateController); + }); + + it('should be defined', () => { + expect(controller).toBeDefined(); + }); +}); diff --git a/src/resume-template/resume-template.controller.ts b/src/resume-template/resume-template.controller.ts new file mode 100644 index 0000000..97781f5 --- /dev/null +++ b/src/resume-template/resume-template.controller.ts @@ -0,0 +1,105 @@ +import { + Controller, + Get, + Post, + Body, + Patch, + Param, + Delete, + UseGuards, + Query, +} from '@nestjs/common'; +import { ResumeTemplateService } from './resume-template.service'; +import { CreateResumeTemplateDto } from './dto/create-resume-template.dto'; +import { UpdateResumeTemplateDto } from './dto/update-resume-template.dto'; +import { AuthGuard } from '../auth/auth.guard'; + +/** + * 简历模板控制器 + * 处理简历模板相关的http请求,如创建、查询、更新、删除简历模板 + */ +@Controller('resumetemplate') +export class ResumeTemplateController { + /** + * 构造函数 + * @param resumeTemplateService 简历模板服务 + */ + constructor(private readonly resumeTemplateService: ResumeTemplateService) {} + + /** + * 创建新的简历模板 + * 需要用户登录认证权限 + * + * @param createResumeTemplateDto 简历模板创建请求体 + * @returns 返回创建的简历模板信息 + */ + @Post() + @UseGuards(AuthGuard) + create(@Body() createResumeTemplateDto: CreateResumeTemplateDto) { + return this.resumeTemplateService.create(createResumeTemplateDto); + } + + /** + * 获取所有简历模板 + * 支持分页、按类型查找、按作者查找、按时间段查找 + * @param query - 查询参数对象 + * @returns 返回所有简历模板列表和总数 + */ + @Get() + async findAll( + @Query('page') page?: number, + @Query('limit') limit?: number, + @Query('style') style?: string, + @Query('industry') industry?: string, + @Query('color') color?: string, + ) { + return this.resumeTemplateService.findAll({ + page, + limit, + style, + industry, + color, + }); + } + + /** + * 获取单个简历模板 + * + * @param id - 简历模板id + * @returns 返回单个简历模板信息 + */ + @Get(':id') + findOne(@Param('id') id: string) { + return this.resumeTemplateService.findOne(+id); + } + + /** + * 更新简历模板 + * 需要用户登录认证权限 + * + * @param id - 简历模板id + * @param updateResumeTemplateDto - 简历模板更新请求体 + * @returns 返回更新后的简历模板信息 + */ + @Patch(':id') + @UseGuards(AuthGuard) // 需要用户登录认证权限 + update( + @Param('id') id: string, + @Body() updateResumeTemplateDto: UpdateResumeTemplateDto, + ) { + return this.resumeTemplateService.update(+id, updateResumeTemplateDto); + } + + /** + * 删除简历模板 + * 需要用户登录认证权限 + * + * @param id - 简历模板id + * @returns 返回删除的简历模板信息 + */ + @Delete(':id') + @UseGuards(AuthGuard) // 需要用户登录认证权限 + remove(@Param('id') id: string) { + return this.resumeTemplateService.remove(+id); + } +} diff --git a/src/resume-template/resume-template.module.ts b/src/resume-template/resume-template.module.ts new file mode 100644 index 0000000..8289688 --- /dev/null +++ b/src/resume-template/resume-template.module.ts @@ -0,0 +1,13 @@ +import { Module } from '@nestjs/common'; +import { ResumeTemplateService } from './resume-template.service'; +import { ResumeTemplateController } from './resume-template.controller'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { ResumeTemplateEntity } from './entities/resume-template.entity'; + +@Module({ + imports: [TypeOrmModule.forFeature([ResumeTemplateEntity])], + controllers: [ResumeTemplateController], + providers: [ResumeTemplateService], + exports: [ResumeTemplateService], +}) +export class ResumeTemplateModule {} diff --git a/src/resume-template/resume-template.service.spec.ts b/src/resume-template/resume-template.service.spec.ts new file mode 100644 index 0000000..dbba412 --- /dev/null +++ b/src/resume-template/resume-template.service.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { ResumeTemplateService } from './resume-template.service'; + +describe('ResumeTemplateService', () => { + let service: ResumeTemplateService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [ResumeTemplateService], + }).compile(); + + service = module.get(ResumeTemplateService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/src/resume-template/resume-template.service.ts b/src/resume-template/resume-template.service.ts new file mode 100644 index 0000000..cad3b40 --- /dev/null +++ b/src/resume-template/resume-template.service.ts @@ -0,0 +1,131 @@ +import { Injectable, NotFoundException } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; +import { Repository } from 'typeorm'; +import { ResumeTemplateEntity } from './entities/resume-template.entity'; +import { CreateResumeTemplateDto } from './dto/create-resume-template.dto'; +import { UpdateResumeTemplateDto } from './dto/update-resume-template.dto'; + +@Injectable() +export class ResumeTemplateService { + /** + * 构造函数 + * @param resumeTemplateRepository - 简历模板仓库,用于操作简历模板数据 + */ + constructor( + @InjectRepository(ResumeTemplateEntity) + private readonly resumeTemplateRepository: Repository, + ) {} + + /** + * 创建新的简历模板 + * @param createResumeTemplateDto - 创建简历模板的请求体 + * @returns 返回创建的简历模板的信息 + */ + async create(createResumeTemplateDto: CreateResumeTemplateDto) { + const ResumeTemplate = this.resumeTemplateRepository.create({ + ...createResumeTemplateDto, + }); + const result = await this.resumeTemplateRepository.save(ResumeTemplate); + return result; + } + + // 查找所有简历模板 + async findAll(query: { + page?: number; + limit?: number; + style?: string; + industry?: string; + color?: string; + }) { + const { page = 1, limit = 10, style, industry, color } = query; + + // 创建查询构建器 + const queryBuilder = + this.resumeTemplateRepository.createQueryBuilder('resumeTemplate'); + + // 根据简历风格进行筛选 + if (style) { + queryBuilder.andWhere( + "JSON_UNQUOTE(JSON_EXTRACT(resumeTemplate.resumeTemplateContent, '$.style')) = :style", + { style }, + ); + } + + // 根据简历行业进行筛选 + if (industry) { + queryBuilder.andWhere( + "JSON_UNQUOTE(JSON_EXTRACT(resumeTemplate.resumeTemplateContent, '$.industry')) = :industry", + { + industry, + }, + ); + } + + // 根据简历颜色进行筛选 + if (color) { + queryBuilder.andWhere( + "JSON_UNQUOTE(JSON_EXTRACT(resumeTemplate.resumeTemplateContent, '$.color')) = :color", + { color }, + ); + } + + const [items, total] = await queryBuilder + .skip((page - 1) * limit) + .take(limit) + .getManyAndCount(); + + return { + items, + total, + }; + } + + /** + * 查询单个简历模板 + * @param id - 简历模板id + * @returns 返回单个简历模板的信息 + */ + async findOne(id: number) { + const result = await this.resumeTemplateRepository.findOne({ + where: { resumeTemplateId: id }, + }); + + if (!result) { + throw new NotFoundException(`简历模板ID ${id} 不存在`); + } + + return result; + } + + // 更新简历模板 + async update(id: number, updateResumeTemplateDto: UpdateResumeTemplateDto) { + const result = await this.resumeTemplateRepository.update(id, { + ...updateResumeTemplateDto, + }); + + // 检查是否更新成功 + if (result.affected === 0) { + throw new NotFoundException(`简历模板ID ${id} 不存在`); + } + + return result; + } + + /** + * 删除简历模板 + * 需要用户登录认证 + * + * @param id - 简历模板id + * @returns 返回删除的简历模板的信息 + */ + async remove(id: number) { + const result = await this.resumeTemplateRepository.delete(id); + + // 检查是否删除成功 + if (result.affected === 0) { + throw new NotFoundException(`简历模板ID ${id} 不存在`); + } + + return result; + } +}