From 7c336e2320eedde6ee936c36132f726fe1d1e0a8 Mon Sep 17 00:00:00 2001 From: Ken <66313154+HeHasGun@users.noreply.github.com> Date: Mon, 15 Jul 2024 18:30:50 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=A9=BA=E9=97=B4=E5=88=97=E8=A1=A8?= =?UTF-8?q?=E5=88=86=E9=A1=B5=E5=92=8C=E6=90=9C=E7=B4=A2=E5=8F=8A=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=88=97=E8=A1=A8=E4=BC=98=E5=8C=96=20(#344)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1、fix: 修复因滚动条宽度影响皮肤标签的问题 2、feat: 空间列表分页和搜索及数据列表样式优化 3、feat: 对部分代码进行了优化 --- .../_test/workspace.controller.spec.ts | 17 +++- .../controllers/workspace.controller.ts | 30 +++++- .../workspace/dto/getWorkspaceList.dto.ts | 21 ++++ .../workspace/services/workspace.service.ts | 58 +++++++++-- web/src/management/api/space.ts | 8 +- web/src/management/config/listConfig.js | 12 ++- .../pages/analysis/components/DataTable.vue | 10 +- .../pages/edit/components/ModuleNavbar.vue | 15 ++- .../settingModule/skin/CatalogPanel.vue | 4 + .../pages/list/components/SpaceList.vue | 96 ++++++++++++++++--- .../pages/list/components/TextSearch.vue | 2 +- web/src/management/pages/list/index.vue | 77 +++++++++------ web/src/management/store/list/index.js | 13 ++- 13 files changed, 294 insertions(+), 69 deletions(-) create mode 100644 server/src/modules/workspace/dto/getWorkspaceList.dto.ts diff --git a/server/src/modules/workspace/_test/workspace.controller.spec.ts b/server/src/modules/workspace/_test/workspace.controller.spec.ts index 3a5b2733..23c393d9 100644 --- a/server/src/modules/workspace/_test/workspace.controller.spec.ts +++ b/server/src/modules/workspace/_test/workspace.controller.spec.ts @@ -32,6 +32,7 @@ describe('WorkspaceController', () => { useValue: { create: jest.fn(), findAllById: jest.fn(), + findAllByIdWithPagination: jest.fn(), update: jest.fn(), delete: jest.fn(), }, @@ -145,20 +146,28 @@ describe('WorkspaceController', () => { jest .spyOn(workspaceMemberService, 'findAllByUserId') .mockResolvedValue(memberList as unknown as Array); + jest - .spyOn(workspaceService, 'findAllById') - .mockResolvedValue(workspaces as Array); + .spyOn(workspaceService, 'findAllByIdWithPagination') + .mockResolvedValue({ + list: workspaces as Array, + count: workspaces.length, + }); + jest.spyOn(userService, 'getUserListByIds').mockResolvedValue([]); - const result = await controller.findAll(req); + const result = await controller.findAll(req, {curPage:1,pageSize:10}); expect(result.code).toEqual(200); expect(workspaceMemberService.findAllByUserId).toHaveBeenCalledWith({ userId: req.user._id.toString(), }); - expect(workspaceService.findAllById).toHaveBeenCalledWith({ + expect(workspaceService.findAllByIdWithPagination).toHaveBeenCalledWith({ workspaceIdList: memberList.map((item) => item.workspaceId), + page: 1, + limit: 10, + name: undefined }); }); }); diff --git a/server/src/modules/workspace/controllers/workspace.controller.ts b/server/src/modules/workspace/controllers/workspace.controller.ts index 81196830..87669803 100644 --- a/server/src/modules/workspace/controllers/workspace.controller.ts +++ b/server/src/modules/workspace/controllers/workspace.controller.ts @@ -9,6 +9,7 @@ import { Request, SetMetadata, HttpCode, + Query, } from '@nestjs/common'; import { ApiTags, ApiBearerAuth } from '@nestjs/swagger'; import moment from 'moment'; @@ -31,6 +32,7 @@ import { splitMembers } from '../utils/splitMember'; import { UserService } from 'src/modules/auth/services/user.service'; import { SurveyMetaService } from 'src/modules/survey/services/surveyMeta.service'; import { Logger } from 'src/logger'; +import { GetWorkspaceListDto } from '../dto/getWorkspaceList.dto'; @ApiTags('workspace') @ApiBearerAuth() @@ -128,8 +130,21 @@ export class WorkspaceController { @Get() @HttpCode(200) - async findAll(@Request() req) { + async findAll(@Request() req, @Query() queryInfo: GetWorkspaceListDto) { + const { value, error } = GetWorkspaceListDto.validate(queryInfo); + if (error) { + this.logger.error( + `GetWorkspaceListDto validate failed: ${error.message}`, + { req }, + ); + throw new HttpException( + `参数错误: 请联系管理员`, + EXCEPTION_CODE.PARAMETER_ERROR, + ); + } const userId = req.user._id.toString(); + const curPage = Number(value.curPage); + const pageSize = Number(value.pageSize); // 查询当前用户参与的空间 const workspaceInfoList = await this.workspaceMemberService.findAllByUserId( { userId }, @@ -139,9 +154,16 @@ export class WorkspaceController { pre[cur.workspaceId] = cur; return pre; }, {}); + // 查询当前用户的空间列表 - const list = await this.workspaceService.findAllById({ workspaceIdList }); - const ownerIdList = list.map((item) => item.ownerId); + const { list, count } = + await this.workspaceService.findAllByIdWithPagination({ + workspaceIdList, + page: curPage, + limit: pageSize, + name: queryInfo.name, + }); + const ownerIdList = list.map((item: { ownerId: any }) => item.ownerId); const userList = await this.userService.getUserListByIds({ idList: ownerIdList, }); @@ -150,6 +172,7 @@ export class WorkspaceController { pre[id] = cur; return pre; }, {}); + const surveyTotalList = await Promise.all( workspaceIdList.map((item) => { return this.surveyMetaService.countSurveyMetaByWorkspaceId({ @@ -193,6 +216,7 @@ export class WorkspaceController { memberTotal: memberTotalMap[workspaceId] || 0, }; }), + count, }, }; } diff --git a/server/src/modules/workspace/dto/getWorkspaceList.dto.ts b/server/src/modules/workspace/dto/getWorkspaceList.dto.ts new file mode 100644 index 00000000..5990ff82 --- /dev/null +++ b/server/src/modules/workspace/dto/getWorkspaceList.dto.ts @@ -0,0 +1,21 @@ +import { ApiProperty } from '@nestjs/swagger'; +import Joi from 'joi'; + +export class GetWorkspaceListDto { + @ApiProperty({ description: '当前页码', required: true }) + curPage: number; + + @ApiProperty({ description: '分页', required: false }) + pageSize: number; + + @ApiProperty({ description: '空间名称', required: false }) + name?: string; + + static validate(data: Partial): Joi.ValidationResult { + return Joi.object({ + curPage: Joi.number().required(), + pageSize: Joi.number().allow(null).default(10), + name: Joi.string().allow(null, '').optional(), + }).validate(data); + } +} diff --git a/server/src/modules/workspace/services/workspace.service.ts b/server/src/modules/workspace/services/workspace.service.ts index aaf37f69..4607cb1f 100644 --- a/server/src/modules/workspace/services/workspace.service.ts +++ b/server/src/modules/workspace/services/workspace.service.ts @@ -8,6 +8,17 @@ import { SurveyMeta } from 'src/models/surveyMeta.entity'; import { ObjectId } from 'mongodb'; import { RECORD_STATUS } from 'src/enums'; +interface FindAllByIdWithPaginationParams { + workspaceIdList: string[]; + page: number; + limit: number; + name?: string; +} +interface FindAllByIdWithPaginationResult { + list: Workspace[]; + count: number; +} + @Injectable() export class WorkspaceService { constructor( @@ -41,15 +52,17 @@ export class WorkspaceService { }: { workspaceIdList: string[]; }): Promise { - return this.workspaceRepository.find({ - where: { - _id: { - $in: workspaceIdList.map((item) => new ObjectId(item)), - }, - 'curStatus.status': { - $ne: RECORD_STATUS.REMOVED, - }, + const query = { + _id: { + $in: workspaceIdList.map((item) => new ObjectId(item)), }, + 'curStatus.status': { + $ne: RECORD_STATUS.REMOVED, + }, + }; + + return this.workspaceRepository.find({ + where: query, order: { _id: -1, }, @@ -64,6 +77,35 @@ export class WorkspaceService { }); } + async findAllByIdWithPagination({ + workspaceIdList, + page, + limit, + name, + }: FindAllByIdWithPaginationParams): Promise { + const skip = (page - 1) * limit; + if (!Array.isArray(workspaceIdList) || workspaceIdList.length === 0) { + return { list: [], count: 0 }; + } + const query = { + _id: { + $in: workspaceIdList.map((m) => new ObjectId(m)), + }, + 'curStatus.status': { + $ne: RECORD_STATUS.REMOVED, + }, + }; + if (name) { + query['name'] = { $regex: name, $options: 'i' }; + } + const [data, count] = await this.workspaceRepository.findAndCount({ + where: query, + skip, + take: limit, + }); + return { list: data, count }; + } + update(id: string, workspace: Partial) { return this.workspaceRepository.update(id, workspace); } diff --git a/web/src/management/api/space.ts b/web/src/management/api/space.ts index b0aadda9..83f76ff8 100644 --- a/web/src/management/api/space.ts +++ b/web/src/management/api/space.ts @@ -8,8 +8,10 @@ export const updateSpace = ({ workspaceId, name, description, members }: any) => return axios.post(`/workspace/${workspaceId}`, { name, description, members }) } -export const getSpaceList = () => { - return axios.get('/workspace') +export const getSpaceList = (params: any) => { + return axios.get('/workspace', { + params + }) } export const getSpaceDetail = (workspaceId: string) => { @@ -71,4 +73,4 @@ export const getCollaboratorPermissions = (surveyId: string) => { surveyId } }) -} \ No newline at end of file +} diff --git a/web/src/management/config/listConfig.js b/web/src/management/config/listConfig.js index 5576d50a..8a558651 100644 --- a/web/src/management/config/listConfig.js +++ b/web/src/management/config/listConfig.js @@ -9,7 +9,7 @@ export const spaceListConfig = { name: { title: '空间名称', key: 'name', - width: 300 + width: 200 }, surveyTotal: { title: '问卷数', @@ -82,6 +82,16 @@ export const noListDataConfig = { img: '/imgs/icons/list-empty.webp' } +export const noSpaceDataConfig = { + title: '您还没有创建团队空间', + desc: '赶快点击右上角立即创建团队空间吧!', + img: '/imgs/icons/list-empty.webp' +} +export const noSpaceSearchDataConfig = { + title: '没有满足该查询条件的团队空间哦', + desc: '可以更换条件查询试试', + img: '/imgs/icons/list-empty.webp' +} export const noSearchDataConfig = { title: '没有满足该查询条件的问卷哦', desc: '可以更换条件查询试试', diff --git a/web/src/management/pages/analysis/components/DataTable.vue b/web/src/management/pages/analysis/components/DataTable.vue index 5c0e047d..d5df1d29 100644 --- a/web/src/management/pages/analysis/components/DataTable.vue +++ b/web/src/management/pages/analysis/components/DataTable.vue @@ -42,7 +42,7 @@ { } const onPopoverRefOver = (scope, type) => { let popoverContent - if (type == 'head') { + if (type === 'head') { popoverVirtualRef.value = popoverRefMap.value[scope.column.id] popoverContent = scope.column.label.replace(/ /g, '') } - if (type == 'content') { + if (type === 'content') { popoverVirtualRef.value = popoverRefMap.value[scope.$index + scope.column.property] popoverContent = getContent(scope.row[scope.column.property]) } @@ -99,7 +99,6 @@ const onPopoverRefOver = (scope, type) => { .data-table-wrapper { position: relative; width: 100%; - padding-bottom: 20px; min-height: v-bind('tableMinHeight'); background: #fff; padding: 10px 20px; @@ -132,4 +131,7 @@ const onPopoverRefOver = (scope, type) => { /* 显示省略号 */ } } +:deep(.el-table td.el-table__cell div) { + font-size: 13px; +} diff --git a/web/src/management/pages/edit/components/ModuleNavbar.vue b/web/src/management/pages/edit/components/ModuleNavbar.vue index 9949b348..d1484a5f 100644 --- a/web/src/management/pages/edit/components/ModuleNavbar.vue +++ b/web/src/management/pages/edit/components/ModuleNavbar.vue @@ -8,7 +8,14 @@
- + + + @@ -34,6 +41,12 @@ const store = useStore() const title = computed(() => _get(store.state, 'edit.schema.metaData.title'))