Browse Source

- 项目成员关联调整回来
- 文件夹管理初步完成
- 成员与中心关联基本建立

Huanyi 1 day ago
parent
commit
b4920eccbb
31 changed files with 596 additions and 157 deletions
  1. 1 1
      ruoyi-admin/src/main/resources/application.yml
  2. 5 0
      ruoyi-admin/src/main/resources/i18n/messages_en_US.properties
  3. 5 0
      ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties
  4. 2 1
      ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/handler/GlobalExceptionHandler.java
  5. 3 16
      ruoyi-modules/ruoyi-system/src/main/java/com/yingpaipay/system/domain/SysUserFolder.java
  6. 7 0
      ruoyi-modules/ruoyi-system/src/main/java/com/yingpaipay/system/mapper/SysUserFolderMapper.java
  7. 0 14
      ruoyi-modules/ruoyi-system/src/main/java/com/yingpaipay/system/mapper/SysUserProjectMapper.java
  8. 0 5
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysUserController.java
  9. 5 1
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysUserService.java
  10. 19 26
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java
  11. 11 0
      ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/constant/FolderTypeConst.java
  12. 47 0
      ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/controller/FolderController.java
  13. 25 18
      ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/controller/ProjectController.java
  14. 3 2
      ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/domain/Folder.java
  15. 2 1
      ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/domain/bo/FolderBo.java
  16. 12 0
      ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/domain/bo/ProjectCenterListBo.java
  17. 14 0
      ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/domain/bo/ProjectCenterMemberListBo.java
  18. 14 0
      ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/domain/bo/ProjectInviteCenterMemberBo.java
  19. 18 0
      ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/domain/vo/FolderListVo.java
  20. 4 5
      ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/domain/vo/FolderVo.java
  21. 24 0
      ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/domain/vo/ProjectCenterListVo.java
  22. 10 0
      ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/domain/vo/ProjectCenterMemberListVo.java
  23. 0 1
      ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/domain/vo/ProjectListByNameVo.java
  24. 0 2
      ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/domain/vo/ProjectMemberListVo.java
  25. 16 0
      ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/domain/vo/ProjectMemberNotInCenterVo.java
  26. 27 0
      ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/service/IFolderService.java
  27. 6 11
      ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/service/IProjectService.java
  28. 14 0
      ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/service/impl/CommonFolderService.java
  29. 223 0
      ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/service/impl/FolderServiceImpl.java
  30. 76 40
      ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/service/impl/ProjectServiceImpl.java
  31. 3 13
      script/sql/business/create.sql

+ 1 - 1
ruoyi-admin/src/main/resources/application.yml

@@ -128,7 +128,7 @@ tenant:
         - sys_dict_type
         - applet_setting
         - sys_user_projects
-        - sys_user_project
+        - sys_user_folder
 
 # MyBatisPlus配置
 # https://baomidou.com/config/

+ 5 - 0
ruoyi-admin/src/main/resources/i18n/messages_en_US.properties

@@ -67,8 +67,13 @@ r.fail=Fail
 table.data.info.success=Query success.
 table.data.info.fail=Query fail.
 
+runtime.exception=Internal System Error
+
 ## 小程序
 # 登录
 applet.auth.login.notexists=User is not exists.
 applet.auth.login.passworderror=Password incorrect.
 applet.auth.nostrategy=The method is not supported.
+
+## 文件夹管理
+document.folder.restrictionerror=The sum of the same level cannot exceed the maximum limit of the parent lavel.

+ 5 - 0
ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties

@@ -67,8 +67,13 @@ r.fail=操作失败
 table.data.info.success=查询成功
 table.data.info.fail=查询失败
 
+runtime.exception=系统内部异常
+
 ## 小程序
 # 登录
 applet.auth.login.notexists=用户不存在
 applet.auth.login.passworderror=密码错误
 applet.auth.nostrategy=该方式不支持
+
+## 文件夹管理
+document.folder.restrictionerror=子层级最大层级数相加不得大于父级的最大层级数

+ 2 - 1
ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/handler/GlobalExceptionHandler.java

@@ -13,6 +13,7 @@ import org.dromara.common.core.exception.BusinessException;
 import org.dromara.common.core.exception.ServiceException;
 import org.dromara.common.core.exception.SseException;
 import org.dromara.common.core.exception.base.BaseException;
+import org.dromara.common.core.utils.MessageUtils;
 import org.dromara.common.core.utils.StreamUtils;
 import org.dromara.common.json.utils.JsonUtils;
 import org.springframework.context.support.DefaultMessageSourceResolvable;
@@ -154,7 +155,7 @@ public class GlobalExceptionHandler {
     public R<Void> handleRuntimeException(RuntimeException e, HttpServletRequest request) {
         String requestURI = request.getRequestURI();
         log.error("请求地址'{}',发生未知异常.", requestURI, e);
-        return R.fail(e.getMessage());
+        return R.fail(MessageUtils.message("runtime.exception"));
     }
 
     /**

+ 3 - 16
ruoyi-modules/ruoyi-system/src/main/java/com/yingpaipay/system/domain/SysUserProject.java → ruoyi-modules/ruoyi-system/src/main/java/com/yingpaipay/system/domain/SysUserFolder.java

@@ -5,26 +5,13 @@ import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
 import lombok.Data;
 
-import java.util.Date;
-
-/**
- * @Author: Huanyi
- * @CreateTime: 2025-12-09
- * @Description:
- * @Version: 1.0
- */
-
 @Data
-@TableName("sys_user_project")
-public class SysUserProject {
+@TableName("sys_user_folder")
+public class SysUserFolder {
 
     @TableId(type = IdType.INPUT)
     private Long userId;
 
-    private Long projectId;
-
-    private String note;
-
-    private Date joinTime;
+    private Long folderId;
 
 }

+ 7 - 0
ruoyi-modules/ruoyi-system/src/main/java/com/yingpaipay/system/mapper/SysUserFolderMapper.java

@@ -0,0 +1,7 @@
+package com.yingpaipay.system.mapper;
+
+import com.yingpaipay.system.domain.SysUserFolder;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+
+public interface SysUserFolderMapper extends BaseMapperPlus<SysUserFolder, SysUserFolder> {
+}

+ 0 - 14
ruoyi-modules/ruoyi-system/src/main/java/com/yingpaipay/system/mapper/SysUserProjectMapper.java

@@ -1,14 +0,0 @@
-package com.yingpaipay.system.mapper;
-
-import com.yingpaipay.system.domain.SysUserProject;
-import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
-
-/**
- * @Author: Huanyi
- * @CreateTime: 2025-12-09
- * @Description:
- * @Version: 1.0
- */
-
-public interface SysUserProjectMapper extends BaseMapperPlus<SysUserProject, SysUserProject> {
-}

+ 0 - 5
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysUserController.java

@@ -316,9 +316,4 @@ public class SysUserController extends BaseController {
         return R.ok(userService.selectUserListByDept(deptId));
     }
 
-    @GetMapping("/listOnNameNotJoinProject")
-    public TableDataInfo<SysUserListOnNameVo> listOnNameNotJoinProject(ListOnNameNotJoinProjectBo bo, PageQuery pageQuery) {
-        return userService.listOnNameNotJoinProject(bo, pageQuery);
-    }
-
 }

+ 5 - 1
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysUserService.java

@@ -1,8 +1,10 @@
 package org.dromara.system.service;
 
+import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.yingpaipay.system.domain.bo.ListOnNameNotJoinProjectBo;
 import org.dromara.common.mybatis.core.page.PageQuery;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.system.domain.SysUser;
 import org.dromara.system.domain.bo.SysUserBo;
 import org.dromara.system.domain.vo.SysUserExportVo;
 import org.dromara.system.domain.vo.SysUserListOnNameVo;
@@ -86,6 +88,8 @@ public interface ISysUserService {
      */
     List<SysUserVo> selectUserByIds(List<Long> userIds, Long deptId);
 
+    List<SysUserVo> selectUserByIds(List<Long> userIds);
+
     /**
      * 根据用户ID查询用户所属角色组
      *
@@ -233,5 +237,5 @@ public interface ISysUserService {
 
     int updateUserAppletStatus(Long userId, Integer appletStatus);
 
-    TableDataInfo<SysUserListOnNameVo> listOnNameNotJoinProject(ListOnNameNotJoinProjectBo bo, PageQuery pageQuery);
+    IPage<SysUser> selectPageByNameAndIds(String name, List<Long> userIds, PageQuery pageQuery);
 }

+ 19 - 26
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java

@@ -9,12 +9,11 @@ import com.baomidou.mybatisplus.core.conditions.Wrapper;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.yingpaipay.system.domain.SysUserProject;
 import com.yingpaipay.system.domain.SysUserProjects;
 import com.yingpaipay.system.domain.bo.ListOnNameNotJoinProjectBo;
-import com.yingpaipay.system.mapper.SysUserProjectMapper;
 import com.yingpaipay.system.mapper.SysUserProjectsMapper;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
@@ -59,7 +58,6 @@ public class SysUserServiceImpl implements ISysUserService, UserService {
     private final SysUserPostMapper userPostMapper;
     private final SysUserProjectsMapper userProjectsMapper;
     private final SysOssMapper ossMapper;
-    private final SysUserProjectMapper userProjectMapper;
 
     @Override
     public TableDataInfo<SysUserVo> selectPageUserList(SysUserBo user, PageQuery pageQuery) {
@@ -210,6 +208,17 @@ public class SysUserServiceImpl implements ISysUserService, UserService {
             .in(CollUtil.isNotEmpty(userIds), SysUser::getUserId, userIds));
     }
 
+    @Override
+    public List<SysUserVo> selectUserByIds(List<Long> userIds) {
+        if (userIds.isEmpty()) {
+            return List.of();
+        }
+        return baseMapper.selectUserList(new LambdaQueryWrapper<SysUser>()
+            .select(SysUser::getUserId, SysUser::getUserName, SysUser::getNickName)
+            .eq(SysUser::getStatus, SystemConstants.NORMAL)
+            .in(CollUtil.isNotEmpty(userIds), SysUser::getUserId, userIds));
+    }
+
     /**
      * 查询用户所属角色组
      *
@@ -611,32 +620,16 @@ public class SysUserServiceImpl implements ISysUserService, UserService {
     }
 
     @Override
-    public TableDataInfo<SysUserListOnNameVo> listOnNameNotJoinProject(ListOnNameNotJoinProjectBo bo, PageQuery pageQuery) {
-        List<Long> userIds = new ArrayList<>();
-        userProjectMapper.selectList(Wrappers.lambdaQuery(SysUserProject.class).eq(SysUserProject::getProjectId, bo.getId()))
-            .forEach(e -> userIds.add(e.getUserId()));
-        Page<SysUser> page = baseMapper.selectPage(
+    public IPage<SysUser> selectPageByNameAndIds(String name, List<Long> userIds, PageQuery pageQuery) {
+        if (userIds.isEmpty()) {
+            return new Page<>();
+        }
+        return baseMapper.selectPage(
             pageQuery.build(),
             Wrappers.lambdaQuery(SysUser.class)
-                .like(StringUtils.isNotBlank(bo.getName()), SysUser::getNickName, bo.getName())
-                .notIn(!userIds.isEmpty(), SysUser::getUserId, userIds)
-                .orderByDesc(SysUser::getUserId)
+                .like(StringUtils.isNotBlank(name), SysUser::getNickName, name)
+                .in(SysUser::getUserId, userIds)
         );
-        List<Long> deptIds = new ArrayList<>();
-        Map<Long, String> deptMap = new HashMap<>();
-        page.getRecords().forEach(e -> deptIds.add(e.getDeptId()));
-        if (!deptIds.isEmpty()) {
-            deptMapper.selectByIds(deptIds)
-                .forEach(e -> deptMap.put(e.getDeptId(), e.getDeptName()));
-        }
-        return TableDataInfo.build(page.convert(e -> {
-            SysUserListOnNameVo vo = new SysUserListOnNameVo();
-            vo.setId(e.getUserId());
-            vo.setName(e.getNickName());
-            vo.setDeptName(deptMap.get(e.getDeptId()));
-            vo.setPhoneNumber(e.getPhonenumber());
-            return vo;
-        }));
     }
 
     /**

+ 11 - 0
ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/constant/FolderTypeConst.java

@@ -0,0 +1,11 @@
+package com.yingpaipay.business.constant;
+
+public interface FolderTypeConst {
+
+    Integer NORMAL = 0;
+
+    Integer COUNTRY = 1;
+
+    Integer CENTER = 2;
+
+}

+ 47 - 0
ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/controller/FolderController.java

@@ -2,10 +2,21 @@ package com.yingpaipay.business.controller;
 
 
 import cn.dev33.satoken.annotation.SaCheckPermission;
+import com.yingpaipay.business.domain.bo.FolderBo;
 import com.yingpaipay.business.domain.bo.ProjectOnDocumentBo;
+import com.yingpaipay.business.domain.vo.FolderListVo;
+import com.yingpaipay.business.domain.vo.FolderVo;
 import com.yingpaipay.business.domain.vo.ProjectOnDocumentVo;
 import com.yingpaipay.business.service.IProjectService;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
 import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
 import org.dromara.common.mybatis.core.page.PageQuery;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
 import org.springframework.web.bind.annotation.*;
@@ -13,6 +24,8 @@ import org.springframework.validation.annotation.Validated;
 import org.dromara.common.web.core.BaseController;
 import com.yingpaipay.business.service.IFolderService;
 
+import java.util.List;
+
 /**
  * 文件夹管理
  *
@@ -34,6 +47,40 @@ public class FolderController extends BaseController {
         return projectService.listOnDocument(bo, pageQuery);
     }
 
+    @SaCheckPermission("document:folder:list")
+    @GetMapping("/list")
+    public R<List<FolderListVo>> list(Long projectId) {
+        return R.ok(folderService.selectList(projectId));
+    }
 
+    @SaCheckPermission("document:folder:add")
+    @Log(title = "文件夹管理", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping()
+    public R<Void> add(@Validated(AddGroup.class) @RequestBody FolderBo bo) {
+        return toAjax(folderService.insertByBo(bo));
+    }
+
+    @SaCheckPermission("document:folder:remove")
+    @Log(title = "文件夹管理", businessType = BusinessType.DELETE)
+    @RepeatSubmit()
+    @DeleteMapping("/{ids}")
+    public R<Void> remove(@NotEmpty(message = "不能为空") @PathVariable Long[] ids) {
+        return toAjax(folderService.deleteWithValidIds(List.of(ids), true));
+    }
+
+    @SaCheckPermission("document:folder:edit")
+    @Log(title = "文件夹管理", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PutMapping()
+    public R<Void> edit(@Validated(EditGroup.class) @RequestBody FolderBo bo) {
+        return toAjax(folderService.updateByBo(bo));
+    }
+
+    @SaCheckPermission("document:folder:query")
+    @GetMapping("/{id}")
+    public R<FolderVo> getInfo(@NotNull(message = "主键不能为空") @PathVariable Long id) {
+        return R.ok(folderService.queryById(id));
+    }
 
 }

+ 25 - 18
ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/controller/ProjectController.java

@@ -2,10 +2,9 @@ package com.yingpaipay.business.controller;
 
 import java.util.List;
 
-import com.yingpaipay.business.domain.bo.ProjectInviteProjectMemberBo;
-import com.yingpaipay.business.domain.bo.ProjectUpdateStatusBo;
-import com.yingpaipay.business.domain.vo.ProjectListByNameVo;
-import com.yingpaipay.business.domain.vo.ProjectMemberListVo;
+import com.yingpaipay.business.domain.bo.*;
+import com.yingpaipay.business.domain.vo.*;
+import com.yingpaipay.business.service.IFolderService;
 import lombok.RequiredArgsConstructor;
 import jakarta.servlet.http.HttpServletResponse;
 import jakarta.validation.constraints.*;
@@ -21,8 +20,6 @@ import org.dromara.common.core.validate.AddGroup;
 import org.dromara.common.core.validate.EditGroup;
 import org.dromara.common.log.enums.BusinessType;
 import org.dromara.common.excel.utils.ExcelUtil;
-import com.yingpaipay.business.domain.vo.ProjectVo;
-import com.yingpaipay.business.domain.bo.ProjectBo;
 import com.yingpaipay.business.service.IProjectService;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
 
@@ -39,6 +36,7 @@ import org.dromara.common.mybatis.core.page.TableDataInfo;
 public class ProjectController extends BaseController {
 
     private final IProjectService projectService;
+    private final IFolderService folderService;
 
     /**
      * 查询项目管理列表
@@ -108,7 +106,7 @@ public class ProjectController extends BaseController {
     }
 
     @GetMapping("/getByName")
-    public R<List<ProjectListByNameVo>> getListByName(@RequestParam("name") String name) {
+    public R<List<ProjectListByNameVo>> getListByName(String name) {
         return R.ok(projectService.getListByName(name));
     }
 
@@ -128,24 +126,33 @@ public class ProjectController extends BaseController {
     @SaCheckPermission("project:management:queryProjectMember")
     @Log(title = "项目管理", businessType = BusinessType.UPDATE)
     @GetMapping("/queryProjectMember")
-    public TableDataInfo<ProjectMemberListVo> queryProjectMember(@RequestParam("id") Long id, PageQuery pageQuery) {
+    public TableDataInfo<ProjectMemberListVo> queryProjectMember(Long id, PageQuery pageQuery) {
         return projectService.selectMemberListById(id, pageQuery);
     }
 
-    @SaCheckPermission("project:management:queryProjectMemberInviteMember")
+    @GetMapping("/queryMemberNotInCenter")
+    public TableDataInfo<ProjectMemberNotInCenterVo> queryMemberNotInCenter(@RequestParam("projectId") Long projectId, @RequestParam("folderId") Long folderId, @RequestParam("name") String name, PageQuery pageQuery) {
+        return projectService.queryMemberNotInCenter(projectId, folderId, name, pageQuery);
+    }
+
+    @SaCheckPermission("project:management:queryCenterInfo")
+    @GetMapping("/queryCenterInfo")
+    public TableDataInfo<ProjectCenterListVo> queryCenterInfo(ProjectCenterListBo bo, PageQuery pageQuery) {
+        return folderService.queryCenterInfo(bo, pageQuery);
+    }
+
+    @SaCheckPermission("project:management:queryCenterInfoInviteMember")
     @Log(title = "项目管理", businessType = BusinessType.INSERT)
     @RepeatSubmit()
-    @PostMapping("/queryProjectMemberInviteMember")
-    public R<Void> queryProjectMemberInviteMember(@RequestBody ProjectInviteProjectMemberBo bo) {
-        return toAjax(projectService.inviteProjectMember(bo));
+    @PostMapping("/queryCenterInfoInviteMember")
+    public R<Void> inviteCenterMember(@RequestBody ProjectInviteCenterMemberBo bo) {
+        return toAjax(projectService.inviteCenterMember(bo));
     }
 
-    @SaCheckPermission("project:management:queryProjectMemberRemove")
-    @Log(title = "项目管理", businessType = BusinessType.DELETE)
-    @RepeatSubmit()
-    @DeleteMapping("/queryProjectMemberRemove")
-    public R<Void> removeProjectMember(@RequestParam("projectId") Long projectId, @RequestParam("userId") Long userId) {
-        return toAjax(projectService.removeProjectMember(projectId, userId));
+    @SaCheckPermission("project:management:queryCenterMember")
+    @GetMapping("/queryCenterMember")
+    public TableDataInfo<ProjectCenterMemberListVo> queryCenterMember(ProjectCenterMemberListBo bo, PageQuery pageQuery) {
+        return folderService.queryCenterMember(bo, pageQuery);
     }
 
 }

+ 3 - 2
ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/domain/Folder.java

@@ -40,7 +40,7 @@ public class Folder extends TenantEntity {
     /**
      * 类型
      */
-    private Long type;
+    private Integer type;
 
     /**
      * 名称
@@ -50,7 +50,7 @@ public class Folder extends TenantEntity {
     /**
      * 状态
      */
-    private Long status;
+    private Integer status;
 
     /**
      * 备注
@@ -63,5 +63,6 @@ public class Folder extends TenantEntity {
     @TableLogic
     private String delFlag;
 
+    private Integer restrictionLevel;
 
 }

+ 2 - 1
ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/domain/bo/FolderBo.java

@@ -54,12 +54,13 @@ public class FolderBo extends BaseEntity {
      * 状态
      */
     @NotNull(message = "状态不能为空", groups = { AddGroup.class, EditGroup.class })
-    private Long status;
+    private Integer status;
 
     /**
      * 备注
      */
     private String note;
 
+    private Integer restrictionLevel;
 
 }

+ 12 - 0
ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/domain/bo/ProjectCenterListBo.java

@@ -0,0 +1,12 @@
+package com.yingpaipay.business.domain.bo;
+
+import lombok.Data;
+
+@Data
+public class ProjectCenterListBo {
+
+    private String name;
+
+    private Long projectId;
+
+}

+ 14 - 0
ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/domain/bo/ProjectCenterMemberListBo.java

@@ -0,0 +1,14 @@
+package com.yingpaipay.business.domain.bo;
+
+import lombok.Data;
+
+@Data
+public class ProjectCenterMemberListBo {
+
+    private String name;
+
+    private String center;
+
+    private Long projectId;
+
+}

+ 14 - 0
ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/domain/bo/ProjectInviteCenterMemberBo.java

@@ -0,0 +1,14 @@
+package com.yingpaipay.business.domain.bo;
+
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class ProjectInviteCenterMemberBo {
+
+    private List<Long> userIds;
+
+    private Long folderId;
+
+}

+ 18 - 0
ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/domain/vo/FolderListVo.java

@@ -0,0 +1,18 @@
+package com.yingpaipay.business.domain.vo;
+
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class FolderListVo {
+
+    private Long id;
+
+    private String name;
+
+    private Integer type;
+
+    private List<FolderListVo> children;
+
+}

+ 4 - 5
ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/domain/vo/FolderVo.java

@@ -3,8 +3,6 @@ package com.yingpaipay.business.domain.vo;
 import com.yingpaipay.business.domain.Folder;
 import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
 import cn.idev.excel.annotation.ExcelProperty;
-import org.dromara.common.excel.annotation.ExcelDictFormat;
-import org.dromara.common.excel.convert.ExcelDictConvert;
 import io.github.linpeilie.annotations.AutoMapper;
 import lombok.Data;
 
@@ -50,7 +48,7 @@ public class FolderVo implements Serializable {
      * 类型
      */
     @ExcelProperty(value = "类型")
-    private Long type;
+    private Integer type;
 
     /**
      * 名称
@@ -62,7 +60,7 @@ public class FolderVo implements Serializable {
      * 状态
      */
     @ExcelProperty(value = "状态")
-    private Long status;
+    private Integer status;
 
     /**
      * 创建时间
@@ -76,5 +74,6 @@ public class FolderVo implements Serializable {
     @ExcelProperty(value = "更新时间")
     private Date updateTime;
 
-
+    @ExcelProperty(value = "限制层级")
+    private Integer restrictionLevel;
 }

+ 24 - 0
ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/domain/vo/ProjectCenterListVo.java

@@ -0,0 +1,24 @@
+package com.yingpaipay.business.domain.vo;
+
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+public class ProjectCenterListVo {
+
+    private Long id;
+
+    private String name;
+
+    private Integer status;
+
+    private Date createTime;
+
+    private Date updateTime;
+
+    private String createBy;
+
+    private String updateBy;
+
+}

+ 10 - 0
ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/domain/vo/ProjectCenterMemberListVo.java

@@ -0,0 +1,10 @@
+package com.yingpaipay.business.domain.vo;
+
+import lombok.Data;
+
+@Data
+public class ProjectCenterMemberListVo extends ProjectMemberListVo {
+
+    private String centers;
+
+}

+ 0 - 1
ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/domain/vo/ProjectListByNameVo.java

@@ -5,7 +5,6 @@ import lombok.Data;
 /**
  * @Author: Huanyi
  * @CreateTime: 2025-12-08
- * @Description:
  * @Version: 1.0
  */
 

+ 0 - 2
ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/domain/vo/ProjectMemberListVo.java

@@ -24,6 +24,4 @@ public class ProjectMemberListVo {
 
     private Date time;
 
-    private String note;
-
 }

+ 16 - 0
ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/domain/vo/ProjectMemberNotInCenterVo.java

@@ -0,0 +1,16 @@
+package com.yingpaipay.business.domain.vo;
+
+import lombok.Data;
+
+@Data
+public class ProjectMemberNotInCenterVo {
+
+    private Long id;
+
+    private String name;
+
+    private String dept;
+
+    private String phoneNumber;
+
+}

+ 27 - 0
ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/service/IFolderService.java

@@ -1,5 +1,19 @@
 package com.yingpaipay.business.service;
 
+import com.yingpaipay.business.domain.bo.FolderBo;
+import com.yingpaipay.business.domain.bo.ProjectCenterListBo;
+import com.yingpaipay.business.domain.bo.ProjectCenterMemberListBo;
+import com.yingpaipay.business.domain.vo.FolderListVo;
+import com.yingpaipay.business.domain.vo.FolderVo;
+import com.yingpaipay.business.domain.vo.ProjectCenterListVo;
+import com.yingpaipay.business.domain.vo.ProjectCenterMemberListVo;
+import jakarta.validation.constraints.NotNull;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+
+import java.util.Collection;
+import java.util.List;
+
 /**
  * 文件夹管理Service接口
  *
@@ -8,4 +22,17 @@ package com.yingpaipay.business.service;
  */
 public interface IFolderService {
 
+    List<FolderListVo> selectList(Long projectId);
+
+    boolean insertByBo(FolderBo bo);
+
+    boolean deleteWithValidIds(Collection<Long> ids, Boolean isValid);
+
+    boolean updateByBo(FolderBo bo);
+
+    FolderVo queryById(Long id);
+
+    TableDataInfo<ProjectCenterListVo> queryCenterInfo(ProjectCenterListBo bo, PageQuery pageQuery);
+
+    TableDataInfo<ProjectCenterMemberListVo> queryCenterMember(ProjectCenterMemberListBo bo, PageQuery pageQuery);
 }

+ 6 - 11
ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/service/IProjectService.java

@@ -1,13 +1,7 @@
 package com.yingpaipay.business.service;
 
-import com.yingpaipay.business.domain.bo.ProjectInviteProjectMemberBo;
-import com.yingpaipay.business.domain.bo.ProjectOnDocumentBo;
-import com.yingpaipay.business.domain.bo.ProjectUpdateStatusBo;
-import com.yingpaipay.business.domain.vo.ProjectListByNameVo;
-import com.yingpaipay.business.domain.vo.ProjectMemberListVo;
-import com.yingpaipay.business.domain.vo.ProjectOnDocumentVo;
-import com.yingpaipay.business.domain.vo.ProjectVo;
-import com.yingpaipay.business.domain.bo.ProjectBo;
+import com.yingpaipay.business.domain.bo.*;
+import com.yingpaipay.business.domain.vo.*;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
 import org.dromara.common.mybatis.core.page.PageQuery;
 
@@ -80,9 +74,10 @@ public interface IProjectService {
 
     TableDataInfo<ProjectMemberListVo> selectMemberListById(Long id, PageQuery pageQuery);
 
-    boolean inviteProjectMember(ProjectInviteProjectMemberBo bo);
+    TableDataInfo<ProjectOnDocumentVo> listOnDocument(ProjectOnDocumentBo bo, PageQuery pageQuery);
 
-    int removeProjectMember(Long projectId, Long userId);
+    boolean inviteCenterMember(ProjectInviteCenterMemberBo bo);
+
+    TableDataInfo<ProjectMemberNotInCenterVo> queryMemberNotInCenter(Long projectId, Long folderId, String name, PageQuery pageQuery);
 
-    TableDataInfo<ProjectOnDocumentVo> listOnDocument(ProjectOnDocumentBo bo, PageQuery pageQuery);
 }

+ 14 - 0
ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/service/impl/CommonFolderService.java

@@ -0,0 +1,14 @@
+package com.yingpaipay.business.service.impl;
+
+import com.yingpaipay.business.mapper.FolderMapper;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+@Service
+@RequiredArgsConstructor
+public class CommonFolderService {
+
+    private final FolderMapper folderMapper;
+
+
+}

+ 223 - 0
ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/service/impl/FolderServiceImpl.java

@@ -1,10 +1,41 @@
 package com.yingpaipay.business.service.impl;
 
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.yingpaipay.business.constant.FolderTypeConst;
+import com.yingpaipay.business.domain.Folder;
+import com.yingpaipay.business.domain.Project;
+import com.yingpaipay.business.domain.bo.FolderBo;
+import com.yingpaipay.business.domain.bo.ProjectCenterListBo;
+import com.yingpaipay.business.domain.bo.ProjectCenterMemberListBo;
+import com.yingpaipay.business.domain.vo.FolderListVo;
+import com.yingpaipay.business.domain.vo.FolderVo;
+import com.yingpaipay.business.domain.vo.ProjectCenterListVo;
+import com.yingpaipay.business.domain.vo.ProjectCenterMemberListVo;
+import com.yingpaipay.system.domain.SysUserFolder;
+import com.yingpaipay.system.mapper.SysUserFolderMapper;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.exception.BusinessException;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.MessageUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.system.domain.SysUser;
+import org.dromara.system.service.ISysDeptService;
+import org.dromara.system.service.ISysUserService;
 import org.springframework.stereotype.Service;
 import com.yingpaipay.business.mapper.FolderMapper;
 import com.yingpaipay.business.service.IFolderService;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.sql.Wrapper;
+import java.util.*;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
 
 /**
  * 文件夹管理Service业务层处理
@@ -18,6 +49,198 @@ import com.yingpaipay.business.service.IFolderService;
 public class FolderServiceImpl implements IFolderService {
 
     private final FolderMapper baseMapper;
+    private final SysUserFolderMapper userFolderMapper;
+
+    private final ISysUserService userService;
+    private final ISysDeptService deptService;
+
+    @Override
+    public List<FolderListVo> selectList(Long projectId) {
+        List<Folder> folders = baseMapper.selectList(Wrappers.lambdaQuery(Folder.class).eq(Folder::getProjectId, projectId));
+        Map<Long, List<Folder>> childrenMap = folders.stream()
+            .filter(this::isNotRoot)
+            .collect(Collectors.groupingBy(Folder::getParentId));
+        List<Folder> roots = folders.stream().filter(this::isRoot).toList();
+        List<FolderListVo> vos = new ArrayList<>();
+        roots.forEach(e -> {
+            FolderListVo vo = new FolderListVo();
+            vo.setId(e.getId());
+            vo.setName(e.getName());
+            vo.setType(e.getType());
+            vo.setChildren(buildChildren(e, childrenMap));
+            vos.add(vo);
+        });
+        return vos;
+    }
+
+    private List<FolderListVo> buildChildren(Folder folder, Map<Long, List<Folder>> childrenMap) {
+        List<Folder> children = childrenMap.get(folder.getId());
+        if (children == null || children.isEmpty()) {
+            return Collections.emptyList();
+        }
+
+        return children.stream().map(childFolder -> {
+            FolderListVo vo = new FolderListVo();
+            vo.setId(childFolder.getId());
+            vo.setName(childFolder.getName());
+            vo.setType(childFolder.getType());
+            vo.setChildren(buildChildren(childFolder, childrenMap));
+            return vo;
+        }).toList();
+    }
+
+    private boolean isRoot(Folder folder) {
+        return folder.getParentId() == null;
+    }
+
+    private boolean isNotRoot(Folder folder) {
+        return !isRoot(folder);
+    }
+
+    @Override
+    public boolean insertByBo(FolderBo bo) {
+        Folder entity = MapstructUtils.convert(bo, Folder.class);
+        boolean flag = baseMapper.insert(entity) == 0;
+        if (flag) {
+            throw new RuntimeException("插入失败");
+        }
+        checkInsertIsValid(bo);
+        return true;
+    }
+
+    private void checkInsertIsValid(FolderBo bo) {
+        if (bo.getParentId() == null) {
+            return;
+        }
+        Folder parent = baseMapper.selectById(bo.getParentId());
+        if (parent.getRestrictionLevel().equals(-1)) {
+            return;
+        }
+        if (bo.getRestrictionLevel().equals(-1)) {
+            throw new BusinessException(MessageUtils.message("document.folder.restrictionerror"));
+        }
+        checkRestriction(parent.getId(), parent.getRestrictionLevel());
+    }
+
+    @Override
+    public boolean deleteWithValidIds(Collection<Long> ids, Boolean isValid) {
+        return baseMapper.deleteByIds(ids) > 0;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean updateByBo(FolderBo bo) {
+        Folder entity = MapstructUtils.convert(bo, Folder.class);
+        boolean flag = baseMapper.updateById(entity) == 0;
+        if (flag) {
+            throw new RuntimeException("更新操作失败");
+        }
+        checkInsertIsValid(bo);
+        checkUpdateIsValid(bo);
+        return true;
+    }
+
+    private void checkUpdateIsValid(FolderBo bo) {
+        checkRestriction(bo.getId(), bo.getRestrictionLevel());
+    }
+
+    private void checkRestriction(Long parentId, Integer restrictionLevel) {
+        if (restrictionLevel.equals(-1)) {
+            return;
+        }
+        AtomicInteger total = new AtomicInteger();
+        baseMapper.selectList(Wrappers.lambdaQuery(Folder.class).eq(Folder::getParentId, parentId))
+            .forEach(e -> {
+                log.debug("当前层次文件夹名称 : {}; 限制个数 : {}", e.getName(), e.getRestrictionLevel());
+                if (e.getRestrictionLevel().equals(-1)) {
+                    throw new BusinessException(MessageUtils.message("document.folder.restrictionerror"));
+                }
+                total.addAndGet(e.getRestrictionLevel());
+            });
+        if (total.get() > restrictionLevel) {
+            throw new BusinessException(MessageUtils.message("document.folder.restrictionerror"));
+        }
+    }
+
+    @Override
+    public FolderVo queryById(Long id) {
+        return baseMapper.selectVoById(id);
+    }
+
+    @Override
+    public TableDataInfo<ProjectCenterListVo> queryCenterInfo(ProjectCenterListBo bo, PageQuery pageQuery) {
+        LambdaQueryWrapper<Folder> wrapper = buildCenterQueryWrapper(bo);
+        IPage<Folder> page = baseMapper.selectPage(pageQuery.build(), wrapper);
+        List<Long> userIds = new ArrayList<>();
+        Map<Long, String> userMap = new HashMap<>();
+        page.getRecords().forEach(e -> {
+            userIds.add(e.getCreateBy());
+            userIds.add(e.getUpdateBy());
+        });
+        userService.selectUserByIds(userIds)
+            .forEach(e -> userMap.put(e.getUserId(), e.getNickName()));
+        return TableDataInfo.build(page.convert(e -> {
+            ProjectCenterListVo vo = new ProjectCenterListVo();
+            vo.setId(e.getId());
+            vo.setName(e.getName());
+            vo.setStatus(e.getStatus());
+            vo.setCreateTime(e.getCreateTime());
+            vo.setUpdateTime(e.getUpdateTime());
+            vo.setCreateBy(userMap.get(e.getCreateBy()));
+            vo.setUpdateBy(userMap.get(e.getUpdateBy()));
+            return vo;
+        }));
+    }
+
+    @Override
+    public TableDataInfo<ProjectCenterMemberListVo> queryCenterMember(ProjectCenterMemberListBo bo, PageQuery pageQuery) {
+        List<Long> folderIds = new ArrayList<>();
+        Map<Long, String> folderMap = new HashMap<>();
+        baseMapper.selectList(Wrappers.lambdaQuery(Folder.class)
+                .like(StringUtils.isNotBlank(bo.getCenter()), Folder::getName, bo.getCenter())
+                .eq(Folder::getProjectId, bo.getProjectId())
+            ).forEach(e -> {
+                folderIds.add(e.getId());
+                folderMap.put(e.getId(), e.getName());
+        });
+        if (folderIds.isEmpty()) {
+            return TableDataInfo.build();
+        }
+        List<SysUserFolder> userFolders = userFolderMapper.selectList(
+            Wrappers.lambdaQuery(SysUserFolder.class).
+                in(SysUserFolder::getFolderId, folderIds)
+        );
+        List<Long> userIds = new ArrayList<>();
+        userFolders.forEach(e -> userIds.add(e.getUserId()));
+        IPage<SysUser> page = userService.selectPageByNameAndIds(bo.getName(), userIds, pageQuery);
+        List<Long> deptIds = new ArrayList<>();
+        Map<Long, String> deptMap = new HashMap<>();
+        page.getRecords().forEach(e -> deptIds.add(e.getDeptId()));
+        if (!deptIds.isEmpty()) {
+            deptService.selectDeptByIds(deptIds).forEach(e -> deptMap.put(e.getDeptId(), e.getDeptName()));
+        }
+        return TableDataInfo.build(page.convert(e -> {
+            ProjectCenterMemberListVo vo = new ProjectCenterMemberListVo();
+            StringBuilder centers = new StringBuilder();
+            userFolders.stream()
+                .filter(entity -> entity.getUserId().equals(e.getUserId()))
+                .forEach(entity -> centers.append(folderMap.get(entity.getFolderId())).append(","));
+            vo.setCenters(centers.toString());
+            vo.setId(e.getUserId());
+            vo.setName(e.getNickName());
+            vo.setPhoneNumber(e.getPhonenumber());
+            vo.setDept(deptMap.get(e.getDeptId()));
+            vo.setTime(e.getCreateTime());
+            return vo;
+        }));
+    }
 
+    private LambdaQueryWrapper<Folder> buildCenterQueryWrapper(ProjectCenterListBo bo) {
+        return Wrappers.lambdaQuery(Folder.class)
+            .eq(Folder::getType, FolderTypeConst.CENTER)
+            .eq(Folder::getProjectId, bo.getProjectId())
+            .like(StringUtils.isNotBlank(bo.getName()), Folder::getName, bo.getName())
+            .orderByDesc(Folder::getId);
+    }
 
 }

+ 76 - 40
ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/service/impl/ProjectServiceImpl.java

@@ -1,15 +1,14 @@
 package com.yingpaipay.business.service.impl;
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.yingpaipay.business.constant.DictTypeConst;
+import com.yingpaipay.business.domain.Folder;
 import com.yingpaipay.business.domain.bo.*;
-import com.yingpaipay.business.domain.vo.ProjectOnDocumentVo;
+import com.yingpaipay.business.domain.vo.*;
 import com.yingpaipay.business.enumeration.ProjectStatusEnum;
-import com.yingpaipay.system.domain.SysUserProject;
-import com.yingpaipay.business.domain.vo.ProjectListByNameVo;
-import com.yingpaipay.business.domain.vo.ProjectMemberListVo;
+import com.yingpaipay.business.mapper.FolderMapper;
+import com.yingpaipay.system.domain.SysUserFolder;
 import com.yingpaipay.system.domain.SysUserProjects;
-import com.yingpaipay.system.mapper.SysUserProjectMapper;
+import com.yingpaipay.system.mapper.SysUserFolderMapper;
 import com.yingpaipay.system.mapper.SysUserProjectsMapper;
 import org.dromara.common.core.utils.MapstructUtils;
 import org.dromara.common.core.utils.StringUtils;
@@ -20,6 +19,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.mybatis.helper.DataBaseHelper;
 import org.dromara.common.satoken.utils.LoginHelper;
 import org.dromara.system.domain.SysUser;
 import org.dromara.system.mapper.SysUserMapper;
@@ -27,7 +27,6 @@ import org.dromara.system.service.ISysDeptService;
 import org.dromara.system.service.ISysDictTypeService;
 import org.dromara.system.service.ISysOssService;
 import org.springframework.stereotype.Service;
-import com.yingpaipay.business.domain.vo.ProjectVo;
 import com.yingpaipay.business.domain.Project;
 import com.yingpaipay.business.mapper.ProjectMapper;
 import com.yingpaipay.business.service.IProjectService;
@@ -47,12 +46,11 @@ public class ProjectServiceImpl implements IProjectService {
 
     private final ProjectMapper baseMapper;
     private final SysUserProjectsMapper userProjectsMapper;
-    private final SysUserProjectMapper userProjectMapper;
     private final SysUserMapper userMapper;
+    private final SysUserFolderMapper userFolderMapper;
 
     private final ISysOssService ossService;
     private final ISysDeptService deptService;
-    private final ISysDictTypeService dictTypeService;
 
     /**
      * 查询项目管理
@@ -230,11 +228,14 @@ public class ProjectServiceImpl implements IProjectService {
     @Override
     public TableDataInfo<ProjectMemberListVo> selectMemberListById(Long id, PageQuery pageQuery) {
         List<Long> userIds = new ArrayList<>();
-        Page<SysUserProject> page = userProjectMapper.selectPage(
+        Page<SysUserProjects> page = userProjectsMapper.selectPage(
             pageQuery.build(),
-            Wrappers.lambdaQuery(SysUserProject.class)
-                .eq(SysUserProject::getProjectId, id)
-                .orderByDesc(SysUserProject::getJoinTime)
+            Wrappers.lambdaQuery(SysUserProjects.class)
+                .and(wrapper -> wrapper
+                    .eq(SysUserProjects::getProjects, "*")
+                    .or()
+                    .apply(DataBaseHelper.findInSet(id, "projects")))
+                .orderByDesc(SysUserProjects::getUserId)
         );
         page.getRecords().forEach(e -> userIds.add(e.getUserId()));
         if (userIds.isEmpty()) {
@@ -262,37 +263,11 @@ public class ProjectServiceImpl implements IProjectService {
             vo.setName(user.getNickName());
             vo.setPhoneNumber(user.getPhonenumber());
             vo.setDept(deptMap.get(user.getDeptId()));
-            vo.setNote(e.getNote());
-            vo.setTime(e.getJoinTime());
+            vo.setTime(user.getCreateTime());
             return vo;
         }));
     }
 
-    @Override
-    public boolean inviteProjectMember(ProjectInviteProjectMemberBo bo) {
-        if (bo.getUsers().isEmpty()) {
-            return true;
-        }
-        List<SysUserProject> userProjectList = new ArrayList<>();
-        List<ProjectInviteMemberBo> users = bo.getUsers();
-        for (ProjectInviteMemberBo user : users) {
-            SysUserProject entity = new SysUserProject();
-            entity.setUserId(user.getId());
-            entity.setNote(user.getNote());
-            entity.setProjectId(bo.getProjectId());
-            userProjectList.add(entity);
-        }
-        return userProjectMapper.insertBatch(userProjectList);
-    }
-
-    @Override
-    public int removeProjectMember(Long projectId, Long userId) {
-        return userProjectMapper.delete(
-            Wrappers.lambdaQuery(SysUserProject.class)
-                .eq(SysUserProject::getUserId, userId)
-                .eq(SysUserProject::getProjectId, projectId)
-        );
-    }
 
     @Override
     public TableDataInfo<ProjectOnDocumentVo> listOnDocument(ProjectOnDocumentBo bo, PageQuery pageQuery) {
@@ -314,6 +289,67 @@ public class ProjectServiceImpl implements IProjectService {
         }));
     }
 
+    @Override
+    public boolean inviteCenterMember(ProjectInviteCenterMemberBo bo) {
+        List<SysUserFolder> userFolder = new ArrayList<>();
+        bo.getUserIds().forEach(e -> {
+            SysUserFolder entity = new SysUserFolder();
+            entity.setUserId(e);
+            entity.setFolderId(bo.getFolderId());
+            userFolder.add(entity);
+        });
+        return userFolderMapper.insertBatch(userFolder);
+    }
+
+    @Override
+    public TableDataInfo<ProjectMemberNotInCenterVo> queryMemberNotInCenter(Long projectId, Long folderId, String name, PageQuery pageQuery) {
+        // TODO 排除已在中心中的人
+        List<Long> userIdsInFolder = new ArrayList<>();
+        // TODO 只能是项目中的人
+        List<Long> userIdsInProject = new ArrayList<>();
+        userProjectsMapper.selectList(
+            Wrappers.lambdaQuery(SysUserProjects.class)
+                .and(wrapper -> wrapper
+                    .eq(SysUserProjects::getProjects, "*")
+                    .or()
+                    .apply(DataBaseHelper.findInSet(projectId, "projects")))
+                .orderByDesc(SysUserProjects::getUserId)
+        ).forEach(e -> userIdsInProject.add(e.getUserId()));
+        if (userIdsInProject.isEmpty()) {
+            return TableDataInfo.build();
+        }
+        userFolderMapper.selectList(Wrappers.lambdaQuery(SysUserFolder.class).eq(SysUserFolder::getFolderId, folderId))
+            .forEach(e -> userIdsInFolder.add(e.getUserId()));
+        IPage<SysUser> page = userMapper.selectPage(
+            pageQuery.build(),
+            Wrappers.lambdaQuery(SysUser.class)
+                .notIn(!userIdsInFolder.isEmpty(), SysUser::getUserId, userIdsInFolder)
+                .in(SysUser::getUserId, userIdsInProject)
+                .like(StringUtils.isNotBlank(name), SysUser::getNickName, name)
+        );
+        if (page.getRecords().isEmpty()) {
+            return TableDataInfo.build();
+        }
+        List<Long> deptIds = new ArrayList<>();
+        Map<Long, String> deptMap = new HashMap<>();
+        page.getRecords().forEach(e -> deptIds.add(e.getDeptId()));
+        deptService.selectDeptByIds(deptIds).forEach(e -> deptMap.put(e.getDeptId(), e.getDeptName()));
+        return TableDataInfo.build(page.convert(e -> {
+            ProjectMemberNotInCenterVo vo = new ProjectMemberNotInCenterVo();
+            vo.setId(e.getUserId());
+            vo.setName(e.getNickName());
+            vo.setDept(deptMap.get(e.getDeptId()));
+            vo.setPhoneNumber(e.getPhonenumber());
+            return vo;
+        }));
+    }
+
+    private LambdaQueryWrapper<Folder> buildQueryProjectCenterWrapper(ProjectCenterListBo bo) {
+        return Wrappers.lambdaQuery(Folder.class)
+            .like(StringUtils.isNotEmpty(bo.getName()), Folder::getName, bo.getName())
+            .orderByDesc(Folder::getId);
+    }
+
     private LambdaQueryWrapper<Project> buildQueryOnDocumentWrapper(ProjectOnDocumentBo bo) {
         Map<String, Object> params = bo.getParams();
         LambdaQueryWrapper<Project> lqw = Wrappers.lambdaQuery();

+ 3 - 13
script/sql/business/create.sql

@@ -32,21 +32,11 @@ CREATE TABLE `sys_user_projects`
 ) ENGINE = InnoDB
   DEFAULT CHARSET = utf8mb4 COMMENT ='用户项目数据权限表';
 
-CREATE TABLE `sys_user_project`
-(
-    `user_id`   bigint NOT NULL COMMENT '用户ID',
-    `project_id` bigint NOT NULL COMMENT '项目ID',
-    `note`      varchar(255) COMMENT '备注',
-    `join_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '加入时间',
-    PRIMARY KEY (`user_id`, `project_id`)
-) ENGINE = InnoDB
-  DEFAULT CHARSET = utf8mb4 COMMENT ='用户项目关联表';
-
 CREATE TABLE `sys_user_center`
 (
-    `user_id`   bigint NOT NULL PRIMARY KEY COMMENT '用户ID',
-    `center_id`  bigint NOT NULL PRIMARY KEY COMMENT '中心ID',
-    `join_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '加入时间'
+    `user_id`   bigint NOT NULL COMMENT '用户ID',
+    `folder_id`    bigint NOT NULL COMMENT '文件夹ID',
+    PRIMARY KEY (`user_id`, `folder_id`)
 ) ENGINE = InnoDB
   DEFAULT CHARSET = utf8mb4 COMMENT ='用户中心关联表';