From 4a6dbf97b881b1a8f05dd91e2f255bb560e9ab41 Mon Sep 17 00:00:00 2001 From: luch <1097650398@qq.com> Date: Fri, 3 Jan 2025 10:53:08 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BC=98=E5=8C=96=E9=97=AE=E5=8D=B7?= =?UTF-8?q?=E5=88=86=E7=BB=84=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/src/enums/surveyGroup.ts | 4 + .../__test/surveyGroup.controller.spec.ts | 27 +++- .../controllers/surveyGroup.controller.ts | 64 ++++++-- .../controllers/surveyMeta.controller.ts | 8 +- .../survey/dto/updateSurveyGroup.dto.ts | 4 + .../survey/services/surveyGroup.service.ts | 23 ++- .../survey/services/surveyMeta.service.ts | 145 +++++++++++++----- web/src/management/api/space.ts | 4 +- web/src/management/components/LeftMenu.vue | 2 +- .../pages/list/components/BaseList.vue | 9 ++ .../pages/list/components/ModifyDialog.vue | 4 +- .../pages/list/components/SliderBar.vue | 24 +-- web/src/management/pages/list/index.vue | 53 +++---- web/src/management/stores/workSpace.ts | 8 +- 14 files changed, 255 insertions(+), 124 deletions(-) create mode 100644 server/src/enums/surveyGroup.ts diff --git a/server/src/enums/surveyGroup.ts b/server/src/enums/surveyGroup.ts new file mode 100644 index 00000000..e1b7a2e2 --- /dev/null +++ b/server/src/enums/surveyGroup.ts @@ -0,0 +1,4 @@ +export enum GROUP_STATE { + ALL = 'all', + UNCLASSIFIED = 'unclassified', +} diff --git a/server/src/modules/survey/__test/surveyGroup.controller.spec.ts b/server/src/modules/survey/__test/surveyGroup.controller.spec.ts index 71ff64c8..84453a2e 100644 --- a/server/src/modules/survey/__test/surveyGroup.controller.spec.ts +++ b/server/src/modules/survey/__test/surveyGroup.controller.spec.ts @@ -84,7 +84,12 @@ describe('SurveyGroupController', () => { describe('findAll', () => { it('should return a list of survey groups', async () => { - const result = { total: 0, notTotal: 0, list: [], allList: [] }; + const result = { + total: 0, + unclassifiedSurveyTotal: 0, + list: [], + allList: [], + }; jest.spyOn(service, 'findAll').mockResolvedValue(result); const mockReq = { user: { _id: new ObjectId() } }; const mockQue = { curPage: 1, pageSize: 10, name: '' }; @@ -104,7 +109,15 @@ describe('SurveyGroupController', () => { const id = '1'; jest.spyOn(service, 'update').mockResolvedValue(updatedResult); - expect(await controller.updateOne(id, updatedFields)).toEqual({ + expect( + await controller.updateOne( + { + groupId: id, + name: 'xxx', + }, + { user: { _id: new ObjectId() } }, + ), + ).toEqual({ code: 200, ret: updatedResult, }); @@ -113,10 +126,12 @@ describe('SurveyGroupController', () => { it('should throw error on invalid parameter', async () => { const id = '1'; - const invalidFields: any = {}; - await expect(controller.updateOne(id, invalidFields)).rejects.toThrow( - HttpException, - ); + await expect( + controller.updateOne( + { groupId: id, name: '' }, + { user: { _id: new ObjectId() } }, + ), + ).rejects.toThrow(HttpException); }); }); diff --git a/server/src/modules/survey/controllers/surveyGroup.controller.ts b/server/src/modules/survey/controllers/surveyGroup.controller.ts index bb150c6d..714fde80 100644 --- a/server/src/modules/survey/controllers/surveyGroup.controller.ts +++ b/server/src/modules/survey/controllers/surveyGroup.controller.ts @@ -2,9 +2,7 @@ import { Controller, Get, Post, - Delete, Body, - Param, UseGuards, Request, HttpCode, @@ -23,16 +21,18 @@ import { EXCEPTION_CODE } from 'src/enums/exceptionCode'; import { CreateSurveyGroupDto } from '../dto/createSurveyGroup.dto'; import { UpdateSurveyGroupDto } from '../dto/updateSurveyGroup.dto'; import { GetGroupListDto } from '../dto/getGroupList.dto'; +import { CollaboratorService } from '../services/collaborator.service'; @ApiTags('surveyGroup') @ApiBearerAuth() @UseGuards(Authentication) -@Controller('api/surveyGroup') +@Controller('/api/surveyGroup') export class SurveyGroupController { constructor( private readonly surveyMetaService: SurveyMetaService, - private readonly SurveyGroupService: SurveyGroupService, + private readonly surveyGroupService: SurveyGroupService, private readonly logger: Logger, + private readonly collaboratorService: CollaboratorService, ) {} @Post() @HttpCode(200) @@ -48,7 +48,7 @@ export class SurveyGroupController { throw new HttpException('参数错误', EXCEPTION_CODE.PARAMETER_ERROR); } const userId = req.user._id.toString(); - const ret = await this.SurveyGroupService.create({ + const ret = await this.surveyGroupService.create({ name: value.name, ownerId: userId, }); @@ -75,7 +75,7 @@ export class SurveyGroupController { const curPage = Number(value.curPage); const pageSize = Number(value.pageSize); const skip = (curPage - 1) * pageSize; - const { total, list, allList } = await this.SurveyGroupService.findAll( + const { total, list, allList } = await this.surveyGroupService.findAll( userId, value.name, skip, @@ -95,10 +95,20 @@ export class SurveyGroupController { pre[cur] = total; return pre; }, {}); - const notTotal = await this.surveyMetaService.countSurveyMetaByGroupId({ - userId, - groupId: null, - }); + const unclassifiedSurveyTotal = + await this.surveyMetaService.countSurveyMetaByGroupId({ + userId, + groupId: null, + }); + const cooperationList = + await this.collaboratorService.getCollaboratorListByUserId({ userId }); + const surveyIdList = cooperationList.map((item) => item.surveyId); + const allSurveyTotal = + await this.surveyMetaService.countSurveyMetaByGroupId({ + userId, + surveyIdList, + groupId: 'all', + }); return { code: 200, data: { @@ -112,34 +122,54 @@ export class SurveyGroupController { }; }), allList, - notTotal, + unclassifiedSurveyTotal, + allSurveyTotal, }, }; } - @Post(':id') + @Post('/update') @HttpCode(200) async updateOne( - @Param('id') id: string, @Body() reqBody: UpdateSurveyGroupDto, + @Request() + req, ) { const { error, value } = UpdateSurveyGroupDto.validate(reqBody); if (error) { this.logger.error(`createSurveyGroup_parameter error: ${error.message}`); throw new HttpException('参数错误', EXCEPTION_CODE.PARAMETER_ERROR); } - const ret = await this.SurveyGroupService.update(id, value); + const group = await this.surveyGroupService.findOne(value.groupId); + if (group.ownerId !== req.user._id.toString()) { + throw new HttpException('没有权限', EXCEPTION_CODE.NO_PERMISSION); + } + const ret = await this.surveyGroupService.update(value.group, { + name: value.name, + }); return { code: 200, ret, }; } - @Delete(':id') + @Post('delete') @HttpCode(200) - async remove(@Param('id') id: string) { - await this.SurveyGroupService.remove(id); + async remove( + @Request() + req, + ) { + const groupId = req.body.groupId; + if (!groupId) { + this.logger.error(`deleteSurveyGroup_parameter error: ${groupId}`); + throw new HttpException('参数错误', EXCEPTION_CODE.PARAMETER_ERROR); + } + const group = await this.surveyGroupService.findOne(groupId); + if (group.ownerId !== req.user._id.toString()) { + throw new HttpException('没有权限', EXCEPTION_CODE.NO_PERMISSION); + } + await this.surveyGroupService.remove(groupId); return { code: 200, }; diff --git a/server/src/modules/survey/controllers/surveyMeta.controller.ts b/server/src/modules/survey/controllers/surveyMeta.controller.ts index d2481b0e..b6c66568 100644 --- a/server/src/modules/survey/controllers/surveyMeta.controller.ts +++ b/server/src/modules/survey/controllers/surveyMeta.controller.ts @@ -27,6 +27,7 @@ import { PERMISSION as WORKSPACE_PERMISSION } from 'src/enums/workspace'; import { GetSurveyListDto } from '../dto/getSurveyMetaList.dto'; import { CollaboratorService } from '../services/collaborator.service'; +import { GROUP_STATE } from 'src/enums/surveyGroup'; @ApiTags('survey') @Controller('/api/survey') @@ -107,8 +108,11 @@ export class SurveyMetaController { } } const userId = req.user._id.toString(); - const cooperationList = - await this.collaboratorService.getCollaboratorListByUserId({ userId }); + let cooperationList = []; + if (groupId === GROUP_STATE.ALL) { + cooperationList = + await this.collaboratorService.getCollaboratorListByUserId({ userId }); + } const cooperSurveyIdMap = cooperationList.reduce((pre, cur) => { pre[cur.surveyId] = cur; return pre; diff --git a/server/src/modules/survey/dto/updateSurveyGroup.dto.ts b/server/src/modules/survey/dto/updateSurveyGroup.dto.ts index a2e3b3aa..ad2085cf 100644 --- a/server/src/modules/survey/dto/updateSurveyGroup.dto.ts +++ b/server/src/modules/survey/dto/updateSurveyGroup.dto.ts @@ -2,11 +2,15 @@ import { ApiProperty } from '@nestjs/swagger'; import Joi from 'joi'; export class UpdateSurveyGroupDto { + @ApiProperty({ description: '分组id', required: true }) + groupId: string; + @ApiProperty({ description: '分组名称', required: true }) name: string; static validate(data) { return Joi.object({ + groupId: Joi.string().required(), name: Joi.string().required(), }).validate(data); } diff --git a/server/src/modules/survey/services/surveyGroup.service.ts b/server/src/modules/survey/services/surveyGroup.service.ts index 99953e28..194525dc 100644 --- a/server/src/modules/survey/services/surveyGroup.service.ts +++ b/server/src/modules/survey/services/surveyGroup.service.ts @@ -4,24 +4,25 @@ import { MongoRepository } from 'typeorm'; import { SurveyGroup } from 'src/models/surveyGroup.entity'; import { SurveyMeta } from 'src/models/surveyMeta.entity'; +import { ObjectId } from 'mongodb'; @Injectable() export class SurveyGroupService { constructor( @InjectRepository(SurveyGroup) - private readonly SurveyGroup: MongoRepository, + private readonly surveyGroupRepository: MongoRepository, @InjectRepository(SurveyMeta) private surveyMetaRepository: MongoRepository, ) {} create(params: { name: string; ownerId: string }) { - const newGroup = this.SurveyGroup.create({ + const newGroup = this.surveyGroupRepository.create({ ...params, }); - return this.SurveyGroup.save(newGroup); + return this.surveyGroupRepository.save(newGroup); } async findAll(userId: string, name: string, skip: number, pageSize: number) { - const [list, total] = await this.SurveyGroup.findAndCount({ + const [list, total] = await this.surveyGroupRepository.findAndCount({ skip: skip, take: pageSize, where: name @@ -31,7 +32,7 @@ export class SurveyGroupService { createdAt: -1, }, }); - const allList = await this.SurveyGroup.find({ + const allList = await this.surveyGroupRepository.find({ where: { ownerId: userId }, select: ['_id', 'name'], }); @@ -42,15 +43,23 @@ export class SurveyGroupService { }; } + async findOne(id: string) { + return this.surveyGroupRepository.findOne({ + where: { + _id: new ObjectId(id), + }, + }); + } + update(id: string, updatedFields: Partial) { updatedFields.updatedAt = new Date(); - return this.SurveyGroup.update(id, updatedFields); + return this.surveyGroupRepository.update(id, updatedFields); } async remove(id: string) { const query = { groupId: id }; const update = { $set: { groupId: null } }; await this.surveyMetaRepository.updateMany(query, update); - return this.SurveyGroup.delete(id); + return this.surveyGroupRepository.delete(id); } } diff --git a/server/src/modules/survey/services/surveyMeta.service.ts b/server/src/modules/survey/services/surveyMeta.service.ts index c18f4cdb..301aa4c9 100644 --- a/server/src/modules/survey/services/surveyMeta.service.ts +++ b/server/src/modules/survey/services/surveyMeta.service.ts @@ -1,12 +1,13 @@ import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; -import { MongoRepository, FindOptionsOrder } from 'typeorm'; +import { MongoRepository, FindOptionsOrder, ObjectLiteral } from 'typeorm'; import { SurveyMeta } from 'src/models/surveyMeta.entity'; import { RECORD_STATUS, RECORD_SUB_STATUS } from 'src/enums'; import { ObjectId } from 'mongodb'; import { HttpException } from 'src/exceptions/httpException'; import { EXCEPTION_CODE } from 'src/enums/exceptionCode'; import { PluginManager } from 'src/securityPlugin/pluginManager'; +import { GROUP_STATE } from 'src/enums/surveyGroup'; @Injectable() export class SurveyMetaService { @@ -153,14 +154,14 @@ export class SurveyMetaService { pageNum, pageSize, userId, - username, + // username, workspaceId, groupId, surveyIdList, } = condition; const skip = (pageNum - 1) * pageSize; try { - const query: Record = Object.assign( + const query: ObjectLiteral = Object.assign( { isDeleted: { $ne: true, @@ -168,40 +169,67 @@ export class SurveyMetaService { }, condition.filter, ); - if (condition.filter['curStatus.status']) { - query['subStatus.status'] = RECORD_SUB_STATUS.DEFAULT; + const otherQuery: ObjectLiteral = {}; + if (Array.isArray(surveyIdList) && surveyIdList.length > 0) { + query.$or = []; + query.$or.push({ + _id: { + $in: surveyIdList.map((item) => new ObjectId(item)), + }, + }); } - if (groupId && groupId !== 'all') { - query.groupId = - groupId === 'unclassified' - ? { - $exists: true, - $eq: null, - } - : groupId; + + if (condition.filter['curStatus.status']) { + otherQuery['subStatus.status'] = RECORD_SUB_STATUS.DEFAULT; } if (workspaceId) { - query.workspaceId = workspaceId; + otherQuery.workspaceId = workspaceId; } else { - query.workspaceId = { - $exists: false, - }; - // 引入空间之前,新建的问卷只有owner字段,引入空间之后,新建的问卷多了ownerId字段,使用owenrId字段进行关联更加合理,此处做了兼容 - query.$or = [ + otherQuery.$and = [ { - owner: username, + workspaceId: { $exists: false }, }, { - ownerId: userId, + workspaceId: null, }, ]; - if (Array.isArray(surveyIdList) && surveyIdList.length > 0) { - query.$or.push({ - _id: { - $in: surveyIdList.map((item) => new ObjectId(item)), - }, - }); + if (groupId && groupId !== GROUP_STATE.ALL) { + if (groupId === GROUP_STATE.UNCLASSIFIED) { + if (!otherQuery.$or) { + otherQuery.$or = []; + } + otherQuery.$or.push( + ...[ + { + groupId: { + $exists: false, + }, + }, + { + groupId: null, + }, + ], + ); + } else { + otherQuery.groupId = groupId; + } } + // 引入空间之前,新建的问卷只有owner字段,引入空间之后,新建的问卷多了ownerId字段,使用owenrId字段进行关联更加合理,此处做了兼容 + // query.$or = [ + // { + // owner: username, + // }, + // { + // ownerId: userId, + // }, + // ]; + otherQuery.ownerId = userId; + } + + if (Array.isArray(query.$or)) { + query.$or.push(otherQuery); + } else { + Object.assign(query, otherQuery); } const order = condition.order && Object.keys(condition.order).length > 0 @@ -248,22 +276,63 @@ export class SurveyMetaService { }); return total; } - async countSurveyMetaByGroupId({ groupId, userId = undefined }) { - const total = await this.surveyRepository.count({ + + async countSurveyMetaByGroupId({ + groupId, + userId, + surveyIdList, + }: { + groupId?: string; + userId: string; + surveyIdList?: Array; + }) { + const query: ObjectLiteral = {}; + if (Array.isArray(surveyIdList) && surveyIdList.length > 0) { + query.$or = []; + query.$or.push({ + _id: { + $in: surveyIdList.map((item) => new ObjectId(item)), + }, + }); + } + + const otherQuery: ObjectLiteral = { ownerId: userId, - groupId, - $or: [ - { workspaceId: { $exists: false } }, - { workspaceId: null }, - { workspaceId: '' }, - ], isDeleted: { $ne: true, }, - 'curStatus.status': { - $ne: RECORD_STATUS.REMOVED, + }; + otherQuery.$and = [ + { + workspaceId: { $exists: false }, }, - }); + { + workspaceId: null, + }, + ]; + if (groupId) { + if (groupId !== 'all') { + otherQuery.groupId = groupId; + } + } else { + otherQuery.$or = [ + { + groupId: null, + }, + { + groupId: { + $exists: false, + }, + }, + ]; + // otherQuery.groupId = null; + } + if (Array.isArray(query.$or)) { + query.$or.push(otherQuery); + } else { + Object.assign(query, otherQuery); + } + const total = await this.surveyRepository.count(query); return total; } } diff --git a/web/src/management/api/space.ts b/web/src/management/api/space.ts index 71794003..9e152e4d 100644 --- a/web/src/management/api/space.ts +++ b/web/src/management/api/space.ts @@ -84,7 +84,7 @@ export const createGroup = ({ name }: any) => { } export const updateGroup = ({ _id, name }: any) => { - return axios.post(`/surveyGroup/${_id}`, { name }) + return axios.post(`/surveyGroup/update`, { name, groupId: _id }) } export const getGroupList = (params: any) => { @@ -94,5 +94,5 @@ export const getGroupList = (params: any) => { } export const deleteGroup = (id: string) => { - return axios.delete(`/surveyGroup/${id}`) + return axios.post(`/surveyGroup/delete`, { groupId: id }) } diff --git a/web/src/management/components/LeftMenu.vue b/web/src/management/components/LeftMenu.vue index e388cb3a..e1dcd1d5 100644 --- a/web/src/management/components/LeftMenu.vue +++ b/web/src/management/components/LeftMenu.vue @@ -2,7 +2,7 @@