diff --git a/apps/backend/Dockerfile b/apps/backend/Dockerfile index 4e17980..e671d07 100644 --- a/apps/backend/Dockerfile +++ b/apps/backend/Dockerfile @@ -9,7 +9,7 @@ COPY package*.json ./ # 安装依赖 RUN npm install -g pnpm@7.17.0 -Run pnpm install --prod +Run pnpm install --prod --registry https://registry.npm.taobao.org # 复制项目文件到工作目录 COPY . . diff --git a/apps/backend/package.json b/apps/backend/package.json index 1932219..7babf6e 100644 --- a/apps/backend/package.json +++ b/apps/backend/package.json @@ -8,7 +8,7 @@ "start:dev": "nest start --watch", "start:debug": "nest start --debug --watch", "start:prod": "node dist/main", - "docker:start": "docker-compose up --build" + "docker:start": "npm run build && docker-compose up --build" }, "dependencies": { "@nestjs/common": "^9.3.5", diff --git a/apps/backend/src/app.module.ts b/apps/backend/src/app.module.ts index 91e7e8d..83814fc 100644 --- a/apps/backend/src/app.module.ts +++ b/apps/backend/src/app.module.ts @@ -1,10 +1,13 @@ import { Module } from '@nestjs/common' import { MongooseModule } from '@nestjs/mongoose' import { ConfigModule } from '@nestjs/config' +import { APP_FILTER, APP_INTERCEPTOR } from '@nestjs/core' import { AppController } from './app.controller' import { AppService } from './app.service' import { TasksModule } from './tasks/tasks.module' import { ProjectsModule } from './projects/projects.module' +import { HttpExceptionFilter } from './core/filter/http-exception/http-exception.filter' +import { TransformInterceptor } from './core/interceptor/transform/transform.interceptor' @Module({ imports: [ @@ -17,7 +20,16 @@ import { ProjectsModule } from './projects/projects.module' MongooseModule.forRoot(process.env.MONGODB_URL), ], controllers: [AppController], - providers: [AppService], + providers: [ + { + provide: APP_FILTER, + useClass: HttpExceptionFilter, + }, + { + provide: APP_INTERCEPTOR, + useClass: TransformInterceptor, + }, + AppService], }) export class AppModule {} diff --git a/apps/backend/src/core/filter/http-exception/http-exception.filter.spec.ts b/apps/backend/src/core/filter/http-exception/http-exception.filter.spec.ts new file mode 100644 index 0000000..0548dab --- /dev/null +++ b/apps/backend/src/core/filter/http-exception/http-exception.filter.spec.ts @@ -0,0 +1,7 @@ +import { HttpExceptionFilter } from './http-exception.filter' + +describe('HttpExceptionFilter', () => { + it('should be defined', () => { + expect(new HttpExceptionFilter()).toBeDefined() + }) +}) diff --git a/apps/backend/src/core/filter/http-exception/http-exception.filter.ts b/apps/backend/src/core/filter/http-exception/http-exception.filter.ts new file mode 100644 index 0000000..7247608 --- /dev/null +++ b/apps/backend/src/core/filter/http-exception/http-exception.filter.ts @@ -0,0 +1,24 @@ +import { ArgumentsHost, Catch, ExceptionFilter, HttpException } from '@nestjs/common' + +@Catch(HttpException) +export class HttpExceptionFilter implements ExceptionFilter { + catch(exception: HttpException, host: ArgumentsHost) { + const ctx = host.switchToHttp() + const response = ctx.getResponse() + const status = exception.getStatus() + + const message = exception.message + ? exception.message + : `${status >= 500 ? 'Service Error' : 'Client Error'}` + + const errorResponse = { + data: {}, + message, + code: -1, + } + + response.status(status) + response.header('Content-Type', 'application/json; charset=utf-8') + response.send(errorResponse) + } +} diff --git a/apps/backend/src/core/interceptor/transform/transform.interceptor.spec.ts b/apps/backend/src/core/interceptor/transform/transform.interceptor.spec.ts new file mode 100644 index 0000000..3493375 --- /dev/null +++ b/apps/backend/src/core/interceptor/transform/transform.interceptor.spec.ts @@ -0,0 +1,7 @@ +import { TransformInterceptor } from './transform.interceptor' + +describe('TransformInterceptor', () => { + it('should be defined', () => { + expect(new TransformInterceptor()).toBeDefined() + }) +}) diff --git a/apps/backend/src/core/interceptor/transform/transform.interceptor.ts b/apps/backend/src/core/interceptor/transform/transform.interceptor.ts new file mode 100644 index 0000000..2b32e11 --- /dev/null +++ b/apps/backend/src/core/interceptor/transform/transform.interceptor.ts @@ -0,0 +1,17 @@ +import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common' +import { Observable, map } from 'rxjs' + +@Injectable() +export class TransformInterceptor implements NestInterceptor { + intercept(context: ExecutionContext, next: CallHandler): Observable { + return next.handle().pipe( + map((data) => { + return { + data, + code: 0, + msg: 'Request successful', + } + }), + ) + } +} diff --git a/apps/backend/src/projects/schemas/project.schema.ts b/apps/backend/src/projects/schemas/project.schema.ts index 264c396..5a0154e 100644 --- a/apps/backend/src/projects/schemas/project.schema.ts +++ b/apps/backend/src/projects/schemas/project.schema.ts @@ -3,7 +3,7 @@ import { Document } from 'mongoose' export type ProjectDocument = Project & Document -@Schema({ timestamps: { createdAt: 'created_at', updatedAt: 'updated_at' } }) +@Schema({ timestamps: { createdAt: 'createdAt', updatedAt: 'updatedAt' } }) export class Project { @Prop({ required: true }) name: string diff --git a/apps/backend/src/tasks/schemas/task.schema.ts b/apps/backend/src/tasks/schemas/task.schema.ts index 7c8d714..3491a77 100644 --- a/apps/backend/src/tasks/schemas/task.schema.ts +++ b/apps/backend/src/tasks/schemas/task.schema.ts @@ -5,7 +5,7 @@ import { Project } from '../../projects/schemas/project.schema' export type TaskDocument = Task & Document -@Schema({ timestamps: { createdAt: 'created_at', updatedAt: 'updated_at' } }) +@Schema({ timestamps: { createdAt: 'createdAt', updatedAt: 'updatedAt' } }) export class Task { @Prop({ required: true }) title: string diff --git a/apps/backend/src/tasks/tasks.controller.ts b/apps/backend/src/tasks/tasks.controller.ts index 22013a7..15019fa 100644 --- a/apps/backend/src/tasks/tasks.controller.ts +++ b/apps/backend/src/tasks/tasks.controller.ts @@ -1,4 +1,13 @@ -import { Body, Controller, Delete, Get, Param, Patch, Post, Query } from '@nestjs/common' +import { + Body, + Controller, + Delete, + Get, + Param, + Patch, + Post, + Query, +} from '@nestjs/common' import { TasksService } from './tasks.service' import { Task } from './schemas/task.schema' import { CreateTaskDto } from './dto/create-task.dto' @@ -14,8 +23,12 @@ export class TasksController { } @Get() - findAll(@Query('projectId') projectId?: string, @Query('status') status?: string) { - return this.tasksService.findAll(projectId, status) + findAll( + @Query('projectId') projectId?: string, + @Query('status') status?: string, + @Query('sortBy') sortBy?: string, + ) { + return this.tasksService.findAll(projectId, status, sortBy) } @Get(':id') @@ -30,8 +43,8 @@ export class TasksController { @Patch(':id') async update( - @Param('id') id: string, - @Body() updateTaskDto: UpdateTaskDto, + @Param('id') id: string, + @Body() updateTaskDto: UpdateTaskDto, ): Promise { return this.tasksService.update(id, updateTaskDto) } diff --git a/apps/backend/src/tasks/tasks.service.ts b/apps/backend/src/tasks/tasks.service.ts index 67b91cf..43ff393 100644 --- a/apps/backend/src/tasks/tasks.service.ts +++ b/apps/backend/src/tasks/tasks.service.ts @@ -21,7 +21,11 @@ export class TasksService { return createdTask.save() } - async findAll(projectId?: string, status?: string): Promise { + async findAll( + projectId?: string, + status?: string, + sortBy = 'position', + ): Promise { const query: { projectId?: Types.ObjectId status?: string @@ -33,7 +37,10 @@ export class TasksService { if (status) query.status = status - return this.taskModel.find(query).sort({ position: -1 }).exec() + return this.taskModel + .find(query) + .sort({ [sortBy]: -1 }) + .exec() } async findOne(id: string): Promise { @@ -51,7 +58,11 @@ export class TasksService { update.projectId = new Types.ObjectId(updateTaskDto.projectId) const updatedTask = await this.taskModel - .findByIdAndUpdate(id, { $set: { ...updateTaskDto, ...update } }, { new: true }) + .findByIdAndUpdate( + id, + { $set: { ...updateTaskDto, ...update } }, + { new: true }, + ) .exec() if (!updatedTask) diff --git a/apps/frontend/package.json b/apps/frontend/package.json index 48e005c..3c9dc19 100644 --- a/apps/frontend/package.json +++ b/apps/frontend/package.json @@ -27,10 +27,12 @@ "@iconify-json/carbon": "^1.1.13", "@iconify-json/mdi": "^1.1.41", "@iconify/vue": "^4.0.2", + "@pinia/testing": "^0.1.2", "@types/lodash-es": "^4.17.6", "@unocss/reset": "^0.48.3", "@vitejs/plugin-vue": "^4.0.0", "@vitejs/plugin-vue-jsx": "^3.0.0", + "@vitest/coverage-c8": "^0.28.4", "@vue/test-utils": "^2.2.10", "@vueuse/core": "^9.10.0", "cross-env": "^7.0.3", diff --git a/apps/frontend/src/App.vue b/apps/frontend/src/App.vue index 0fcb4fe..8ad1238 100644 --- a/apps/frontend/src/App.vue +++ b/apps/frontend/src/App.vue @@ -1,9 +1,12 @@