Просмотр исходного кода

小程序端:
- 上传逻辑重写
PC端:
- 增加临时文件夹,待增加删除临时文档和指定文件夹功能
双端:
- 补全异常国际化内容

Huanyi 3 месяцев назад
Родитель
Сommit
1732ef946a
36 измененных файлов с 384 добавлено и 154 удалено
  1. 0 3
      ruoyi-admin/src/main/java/com/yingpaipay/web/controller/AppletAuthController.java
  2. 1 1
      ruoyi-admin/src/main/java/com/yingpaipay/web/service/strategy/PasswordAppletAuthService.java
  3. 13 0
      ruoyi-admin/src/main/resources/i18n/messages_en_US.properties
  4. 13 0
      ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties
  5. 5 0
      ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/GlobalConstants.java
  6. 2 2
      ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/handler/GlobalExceptionHandler.java
  7. 2 0
      ruoyi-common/yingpaipay-common-document/src/main/java/com/yingpaipay/common/file/util/PdfUtils.java
  8. 1 1
      ruoyi-modules/ruoyi-system/src/main/java/com/yingpaipay/system/constant/UserAppletStatusConst.java
  9. 2 0
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysUserService.java
  10. 18 2
      ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java
  11. 5 0
      ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/controller/DocumentController.java
  12. 6 0
      ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/controller/applet/AppletMyInfoController.java
  13. 9 2
      ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/controller/applet/AppletScanController.java
  14. 2 0
      ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/domain/DocumentAuditLog.java
  15. 12 0
      ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/domain/bo/AppletMyInfoEditPasswordBo.java
  16. 8 0
      ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/domain/bo/AppletUploadBo.java
  17. 0 4
      ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/domain/bo/AppletUploadNewBo.java
  18. 0 4
      ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/domain/bo/AppletUploadOnSubmitBo.java
  19. 5 5
      ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/domain/bo/DocumentQcTaskBo.java
  20. 5 5
      ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/domain/bo/DocumentQcTaskDetailBo.java
  21. 5 5
      ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/domain/bo/FolderBo.java
  22. 5 5
      ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/domain/bo/ProjectBo.java
  23. 1 0
      ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/domain/dto/WpsGetVersionsDto.java
  24. 3 3
      ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/domain/dto/WpsR.java
  25. 1 0
      ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/domain/dto/WpsVersionControlDto.java
  26. 1 0
      ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/domain/dto/WpsVersionDto.java
  27. 1 1
      ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/domain/vo/DocumentVo.java
  28. 1 0
      ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/service/IDocumentQcTaskDetailService.java
  29. 4 0
      ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/service/IDocumentService.java
  30. 45 1
      ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/service/impl/CommonFolderService.java
  31. 1 0
      ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/service/impl/DocumentQcTaskDetailServiceImpl.java
  32. 2 6
      ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/service/impl/DocumentQcTaskServiceImpl.java
  33. 126 33
      ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/service/impl/DocumentServiceImpl.java
  34. 65 24
      ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/service/impl/FolderServiceImpl.java
  35. 6 20
      ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/service/impl/ProjectServiceImpl.java
  36. 8 27
      ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/service/impl/TextInServiceImpl.java

+ 0 - 3
ruoyi-admin/src/main/java/com/yingpaipay/web/controller/AppletAuthController.java

@@ -4,14 +4,11 @@ import cn.dev33.satoken.annotation.SaIgnore;
 import cn.dev33.satoken.stp.StpUtil;
 import com.yingpaipay.web.domain.bo.AppletLoginBo;
 import com.yingpaipay.web.domain.vo.AppletLoginVo;
-import com.yingpaipay.web.service.IAppletAuthService;
 import com.yingpaipay.web.service.factory.AppletAuthStrategyFactory;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.dromara.common.core.domain.R;
-import org.dromara.common.satoken.utils.LoginHelper;
 import org.dromara.common.web.core.BaseController;
-import org.dromara.web.domain.vo.LoginVo;
 import org.springframework.web.bind.annotation.*;
 
 /**

+ 1 - 1
ruoyi-admin/src/main/java/com/yingpaipay/web/service/strategy/PasswordAppletAuthService.java

@@ -5,7 +5,7 @@ import cn.dev33.satoken.stp.parameter.SaLoginParameter;
 import cn.hutool.core.lang.Dict;
 import cn.hutool.crypto.digest.BCrypt;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
-import com.yingpaipay.business.constant.UserAppletStatusConst;
+import com.yingpaipay.system.constant.UserAppletStatusConst;
 import com.yingpaipay.web.domain.bo.AppletLoginBo;
 import com.yingpaipay.web.domain.vo.AppletLoginVo;
 import com.yingpaipay.web.service.IAppletAuthService;

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

@@ -75,8 +75,21 @@ applet.auth.login.notexists=User is not exists.
 applet.auth.login.passworderror=Password incorrect.
 applet.auth.nostrategy=The method is not supported.
 
+applet.mine.myinfo.editpassword.passworderror=Old password error!
+
+applet.document.centerorcountrycannotbenull=For newly uploaded file, please specify the country or center.
+
 ## 文件夹管理
 document.folder.restrictionerror=The sum of the same level cannot exceed the maximum limit of the parent lavel.
 
 document.document.audit.documentnotfound=The document is not found.
 document.document.download.notfound=The document is not found.
+document.document.uploadempty=The document you upload should not be empty.
+document.document.cannotparseusablepdf=No valid PDF file was parsed.
+
+document.qc.taskdetail.notask=There are no tasks can schedule.
+
+search.temp=Temporary Folder
+
+textin.networkerror=Network error.
+textin.recognitionfail=Recognition failed.

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

@@ -75,8 +75,21 @@ applet.auth.login.notexists=用户不存在
 applet.auth.login.passworderror=密码错误
 applet.auth.nostrategy=该方式不支持
 
+applet.mine.myinfo.editpassword.passworderror=密码错误
+
+applet.document.centerorcountrycannotbenull=新上传的文件需指定国家或者中心
+
 ## 文件夹管理
 document.folder.restrictionerror=子层级最大层级数相加不得大于父级的最大层级数
 
 document.document.audit.documentnotfound=对应文档未找到
 document.document.download.notfound=所属文档未找到
+document.document.uploadempty=提交的文件列表为空
+document.document.cannotparseusablepdf=未解析到有效的 PDF 文件数据
+
+document.qc.taskdetail.notask=没有任务可以执行
+
+search.temp=临时文件夹
+
+textin.networkerror=网络异常
+textin.recognitionfail=识别失败

+ 5 - 0
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/GlobalConstants.java

@@ -31,4 +31,9 @@ public interface GlobalConstants {
      * 三方认证 redis key
      */
     String SOCIAL_AUTH_CODE_KEY = GLOBAL_REDIS_KEY + "social_auth_codes:";
+
+    /**
+     * 文件下载水印 reids key
+     */
+    String DOCUMENT_WATERMARK_KEY = "document_watermark:";
 }

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

@@ -62,8 +62,8 @@ public class GlobalExceptionHandler {
     }
 
     @ExceptionHandler(BusinessException.class)
-    public R<Void> handleBusinessException(BusinessException e, HttpServletRequest request) {
-        log.error(e.getMessage());
+    public R<Void> handleBusinessException(BusinessException e) {
+        log.error("业务异常 : ", e);
         return R.fail(e.getCode(), e.getMessage());
     }
 

+ 2 - 0
ruoyi-common/yingpaipay-common-document/src/main/java/com/yingpaipay/common/file/util/PdfUtils.java

@@ -14,6 +14,8 @@ import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 
 public class PdfUtils {
 

+ 1 - 1
ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/constant/UserAppletStatusConst.java → ruoyi-modules/ruoyi-system/src/main/java/com/yingpaipay/system/constant/UserAppletStatusConst.java

@@ -1,4 +1,4 @@
-package com.yingpaipay.business.constant;
+package com.yingpaipay.system.constant;
 
 /**
  * @Author: Huanyi

+ 2 - 0
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysUserService.java

@@ -256,4 +256,6 @@ public interface ISysUserService {
     SysUserVo getById(Long id);
 
     boolean updateOnProject(Long id, String nickname, String phoneNumber, String email, String password);
+
+    boolean updatePassword(String oldPassword, String newPassword);
 }

+ 18 - 2
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java

@@ -13,6 +13,7 @@ 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.constant.UserAppletStatusConst;
 import com.yingpaipay.system.domain.SysUserFolders;
 import com.yingpaipay.system.domain.SysUserProjects;
 import com.yingpaipay.system.domain.bo.ListOnNameNotJoinProjectBo;
@@ -25,6 +26,7 @@ import lombok.extern.slf4j.Slf4j;
 import org.dromara.common.core.constant.CacheNames;
 import org.dromara.common.core.constant.SystemConstants;
 import org.dromara.common.core.domain.dto.UserDTO;
+import org.dromara.common.core.exception.BusinessException;
 import org.dromara.common.core.exception.ServiceException;
 import org.dromara.common.core.service.UserService;
 import org.dromara.common.core.utils.*;
@@ -220,8 +222,12 @@ public class SysUserServiceImpl implements ISysUserService, UserService {
             return List.of();
         }
         return baseMapper.selectVoList(new LambdaQueryWrapper<SysUser>()
-//            .select(SysUser::getUserId, SysUser::getUserName, SysUser::getNickName)
-            .eq(SysUser::getStatus, SystemConstants.NORMAL)
+                .and(wrapper -> {
+                    wrapper.eq(SysUser::getStatus, SystemConstants.NORMAL)
+                        .or()
+                        .eq(SysUser::getAppletStatus, UserAppletStatusConst.NORMAL);
+                })
+
             .in(CollUtil.isNotEmpty(userIds), SysUser::getUserId, userIds));
     }
 
@@ -711,6 +717,16 @@ public class SysUserServiceImpl implements ISysUserService, UserService {
         ) > 0;
     }
 
+    @Override
+    public boolean updatePassword(String oldPassword, String newPassword) {
+        SysUser user = baseMapper.selectById(LoginHelper.getUserId());
+        if (!BCrypt.checkpw(oldPassword, user.getPassword())) {
+            throw new BusinessException(MessageUtils.message("applet.mine.myinfo.editpassword.passworderror"));
+        }
+        user.setPassword(BCrypt.hashpw(newPassword));
+        return baseMapper.updateById(user) > 0;
+    }
+
     /**
      * 通过用户ID查询用户账户
      *

+ 5 - 0
ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/controller/DocumentController.java

@@ -151,4 +151,9 @@ public class DocumentController extends BaseController {
         documentService.download(ossId, response);
     }
 
+    @GetMapping("/countTemp")
+    public R<Long> countTemp(@RequestParam Long projectId) {
+        return R.ok(documentService.countTemp(projectId));
+    }
+
 }

+ 6 - 0
ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/controller/applet/AppletMyInfoController.java

@@ -3,6 +3,7 @@ package com.yingpaipay.business.controller.applet;
 import com.yingpaipay.business.domain.bo.AppletMyInfoEditAvatarBo;
 import com.yingpaipay.business.domain.bo.AppletMyInfoEditGenderBo;
 import com.yingpaipay.business.domain.bo.AppletMyInfoEditNicknameBo;
+import com.yingpaipay.business.domain.bo.AppletMyInfoEditPasswordBo;
 import lombok.RequiredArgsConstructor;
 import org.dromara.common.core.domain.R;
 import org.dromara.common.web.core.BaseController;
@@ -34,4 +35,9 @@ public class AppletMyInfoController extends BaseController {
         return toAjax(userService.updateAvatar(bo.getAvatar()));
     }
 
+    @PutMapping("/edit/password")
+    public R<Void> editPassword(@RequestBody AppletMyInfoEditPasswordBo bo) {
+        return toAjax(userService.updatePassword(bo.getOldPassword(), bo.getNewPassword()));
+    }
+
 }

+ 9 - 2
ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/controller/applet/AppletScanController.java

@@ -41,7 +41,7 @@ public class AppletScanController extends BaseController {
     }
 
     @PostMapping("/uploadOnSubmit")
-    public R<Void> uploadOnSubmit(@Validated @RequestBody AppletUploadOnSubmitBo bo) {
+    public R<Void> uploadOnSubmit(@RequestBody AppletUploadOnSubmitBo bo) {
         return toAjax(documentService.uploadOnSubmit(bo));
     }
 
@@ -55,14 +55,21 @@ public class AppletScanController extends BaseController {
         return R.ok(folderService.selectList(projectId));
     }
 
+    @Deprecated
     @GetMapping("/listFolderPermission")
     public R<FolderPermissionVo> listFolderPermission(@RequestParam("projectId") Long projectId) {
         return R.ok(userService.selectUserFolderPermissionByProjectId(projectId));
     }
 
+    @Deprecated
     @PostMapping("/uploadNew")
-    public R<Void> uploadNew(@Validated @RequestBody AppletUploadNewBo bo) {
+    public R<Void> uploadNew(@RequestBody AppletUploadNewBo bo) {
         return toAjax(documentService.uploadNew(bo));
     }
 
+    @PostMapping("/upload")
+    public R<Void> upload(@RequestBody AppletUploadBo bo) {
+        return toAjax(documentService.upload(bo));
+    }
+
 }

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

@@ -34,4 +34,6 @@ public class DocumentAuditLog extends TenantEntity {
 
     private Date auditTime;
 
+    private Long submitter;
+
 }

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

@@ -0,0 +1,12 @@
+package com.yingpaipay.business.domain.bo;
+
+import lombok.Data;
+
+@Data
+public class AppletMyInfoEditPasswordBo {
+
+    private String oldPassword;
+
+    private String newPassword;
+
+}

+ 8 - 0
ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/domain/bo/AppletUploadBo.java

@@ -7,6 +7,14 @@ import java.util.List;
 @Data
 public class AppletUploadBo {
 
+    private Long projectId;
+
+    private Long country;
+
+    private Long center;
+
+    private String name;
+
     private List<String> files;
 
 }

+ 0 - 4
ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/domain/bo/AppletUploadNewBo.java

@@ -10,18 +10,14 @@ import java.util.List;
 @Data
 public class AppletUploadNewBo {
 
-    @NotNull
     private Long folderId;
 
-    @NotBlank
     private String fileName;
 
-    @NotNull
     private Long projectId;
 
     private String note;
 
-    @NotEmpty
     private List<String> files;
 
 }

+ 0 - 4
ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/domain/bo/AppletUploadOnSubmitBo.java

@@ -1,7 +1,5 @@
 package com.yingpaipay.business.domain.bo;
 
-import jakarta.validation.constraints.NotEmpty;
-import jakarta.validation.constraints.NotNull;
 import lombok.Data;
 
 import java.util.List;
@@ -9,10 +7,8 @@ import java.util.List;
 @Data
 public class AppletUploadOnSubmitBo {
 
-    @NotNull
     private Long documentId;
 
-    @NotEmpty
     private List<String> fileBase64List;
 
 }

+ 5 - 5
ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/domain/bo/DocumentQcTaskBo.java

@@ -25,31 +25,31 @@ public class DocumentQcTaskBo extends BaseEntity {
     /**
      * 序号
      */
-    @NotNull(message = "序号不能为空", groups = { EditGroup.class })
+//    @NotNull(message = "序号不能为空", groups = { EditGroup.class })
     private Long id;
 
     /**
      * 质控名称
      */
-    @NotBlank(message = "质控名称不能为空", groups = { AddGroup.class, EditGroup.class })
+//    @NotBlank(message = "质控名称不能为空", groups = { AddGroup.class, EditGroup.class })
     private String name;
 
     /**
      * 发起人
      */
-    @NotNull(message = "发起人不能为空", groups = { AddGroup.class, EditGroup.class })
+//    @NotNull(message = "发起人不能为空", groups = { AddGroup.class, EditGroup.class })
     private Long initiator;
 
     /**
      * 质控项目
      */
-    @NotNull(message = "质控项目不能为空", groups = { AddGroup.class, EditGroup.class })
+//    @NotNull(message = "质控项目不能为空", groups = { AddGroup.class, EditGroup.class })
     private Long projectId;
 
     /**
      * 截止时间
      */
-    @NotNull(message = "截止时间不能为空", groups = { AddGroup.class, EditGroup.class })
+//    @NotNull(message = "截止时间不能为空", groups = { AddGroup.class, EditGroup.class })
     private Date deadline;
 
     /**

+ 5 - 5
ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/domain/bo/DocumentQcTaskDetailBo.java

@@ -23,28 +23,28 @@ public class DocumentQcTaskDetailBo extends BaseEntity {
     /**
      * 序号
      */
-    @NotNull(message = "序号不能为空", groups = { EditGroup.class })
+//    @NotNull(message = "序号不能为空", groups = { EditGroup.class })
     private Long id;
 
     /**
      * 所属任务
      */
-    @NotNull(message = "所属任务不能为空", groups = { AddGroup.class, EditGroup.class })
+//    @NotNull(message = "所属任务不能为空", groups = { AddGroup.class, EditGroup.class })
     private Long taskId;
 
     /**
      * 质控文件
      */
-    @NotNull(message = "质控文件不能为空", groups = { AddGroup.class, EditGroup.class })
+//    @NotNull(message = "质控文件不能为空", groups = { AddGroup.class, EditGroup.class })
     private Long documentId;
 
     /**
      * 计划执行人
      */
-    @NotNull(message = "计划执行人不能为空", groups = { AddGroup.class, EditGroup.class })
+//    @NotNull(message = "计划执行人不能为空", groups = { AddGroup.class, EditGroup.class })
     private Long executor;
 
-    @NotNull(message = "指控项目不能为空", groups = { AddGroup.class, EditGroup.class })
+//    @NotNull(message = "指控项目不能为空", groups = { AddGroup.class, EditGroup.class })
     private Long projectId;
 
     /**

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

@@ -23,13 +23,13 @@ public class FolderBo extends BaseEntity {
     /**
      * 序号
      */
-    @NotNull(message = "序号不能为空", groups = { EditGroup.class })
+//    @NotNull(message = "序号不能为空", groups = { EditGroup.class })
     private Long id;
 
     /**
      * 所属项目
      */
-    @NotNull(message = "所属项目不能为空", groups = { AddGroup.class, EditGroup.class })
+//    @NotNull(message = "所属项目不能为空", groups = { AddGroup.class, EditGroup.class })
     private Long projectId;
 
     /**
@@ -41,19 +41,19 @@ public class FolderBo extends BaseEntity {
     /**
      * 类型
      */
-    @NotNull(message = "类型不能为空", groups = { AddGroup.class, EditGroup.class })
+//    @NotNull(message = "类型不能为空", groups = { AddGroup.class, EditGroup.class })
     private Long type;
 
     /**
      * 名称
      */
-    @NotBlank(message = "名称不能为空", groups = { AddGroup.class, EditGroup.class })
+//    @NotBlank(message = "名称不能为空", groups = { AddGroup.class, EditGroup.class })
     private String name;
 
     /**
      * 状态
      */
-    @NotNull(message = "状态不能为空", groups = { AddGroup.class, EditGroup.class })
+//    @NotNull(message = "状态不能为空", groups = { AddGroup.class, EditGroup.class })
     private Integer status;
 
     /**

+ 5 - 5
ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/domain/bo/ProjectBo.java

@@ -27,19 +27,19 @@ public class ProjectBo extends BaseEntity {
     /**
      * 序号
      */
-    @NotNull(message = "序号不能为空", groups = { EditGroup.class })
+//    @NotNull(message = "序号不能为空", groups = { EditGroup.class })
     private Long id;
 
     /**
      * 项目编号
      */
-    @NotBlank(message = "项目编号不能为空", groups = { AddGroup.class, EditGroup.class })
+//    @NotBlank(message = "项目编号不能为空", groups = { AddGroup.class, EditGroup.class })
     private String code;
 
     /**
      * 名称
      */
-    @NotBlank(message = "名称不能为空", groups = { AddGroup.class, EditGroup.class })
+//    @NotBlank(message = "名称不能为空", groups = { AddGroup.class, EditGroup.class })
     private String name;
 
     /**
@@ -50,13 +50,13 @@ public class ProjectBo extends BaseEntity {
     /**
      * 项目语言
      */
-    @NotBlank(message = "项目语言不能为空", groups = { AddGroup.class, EditGroup.class })
+//    @NotBlank(message = "项目语言不能为空", groups = { AddGroup.class, EditGroup.class })
     private String language;
 
     /**
      * 项目类型
      */
-    @NotBlank(message = "项目类型不能为空", groups = { AddGroup.class, EditGroup.class })
+//    @NotBlank(message = "项目类型不能为空", groups = { AddGroup.class, EditGroup.class })
     private String type;
 
     /**

+ 1 - 0
ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/domain/dto/WpsGetVersionsDto.java

@@ -3,6 +3,7 @@ package com.yingpaipay.business.domain.dto;
 import lombok.AllArgsConstructor;
 import lombok.Data;
 
+@Deprecated
 @Data
 @AllArgsConstructor
 public class WpsGetVersionsDto {

+ 3 - 3
ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/domain/dto/WpsR.java

@@ -1,12 +1,12 @@
 package com.yingpaipay.business.domain.dto;
 
-import lombok.AllArgsConstructor;
+import lombok.AccessLevel;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 
+@Deprecated
 @Data
-@NoArgsConstructor
-@AllArgsConstructor
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
 public class WpsR<E> {
 
     private Integer code;

+ 1 - 0
ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/domain/dto/WpsVersionControlDto.java

@@ -4,6 +4,7 @@ import lombok.Data;
 
 import java.util.List;
 
+@Deprecated
 @Data
 public class WpsVersionControlDto {
 

+ 1 - 0
ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/domain/dto/WpsVersionDto.java

@@ -5,6 +5,7 @@ import lombok.Data;
 
 import java.util.Date;
 
+@Deprecated
 @Data
 @AllArgsConstructor
 public class WpsVersionDto {

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

@@ -107,7 +107,7 @@ public class DocumentVo implements Serializable {
     private Date updateTime;
 
     @ExcelProperty(value = "递交人")
-//    @Translation(type = TransConstant.USER_ID_TO_NICKNAME, mapper = "submitter")
+    @Translation(type = TransConstant.USER_ID_TO_NICKNAME, mapper = "submitter")
     private String submitterName;
     private Long submitter;
 

+ 1 - 0
ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/service/IDocumentQcTaskDetailService.java

@@ -16,6 +16,7 @@ import java.util.List;
  */
 public interface IDocumentQcTaskDetailService {
 
+    @Deprecated
     List<DocumentQcGenerateVo> generate(Long projectId);
 
     TableDataInfo<DocumentQcTaskDetailListVo> listPage(DocumentQcTaskDetailListBo bo, PageQuery pageQuery);

+ 4 - 0
ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/service/IDocumentService.java

@@ -105,4 +105,8 @@ public interface IDocumentService {
     boolean uploadNew(AppletUploadNewBo bo);
 
     AppletGetRejectionVo getRejection(Long documentId);
+
+    boolean upload(AppletUploadBo bo);
+
+    long countTemp(Long projectId);
 }

+ 45 - 1
ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/service/impl/CommonFolderService.java

@@ -1,5 +1,6 @@
 package com.yingpaipay.business.service.impl;
 
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.yingpaipay.business.constant.DocumentTypeConst;
 import com.yingpaipay.business.constant.FolderTypeConst;
@@ -149,9 +150,52 @@ public class CommonFolderService {
         if (projectIds.isEmpty()) {
             return Collections.emptyList();
         }
-        return baseMapper.selectList(
+        List<Folder> folders = baseMapper.selectList(
             Wrappers.lambdaQuery(Folder.class)
                 .in(Folder::getProjectId, projectIds)
         );
+        Map<Long, String> userFolderMap = new HashMap<>();
+        userFoldersMapper.selectList(
+            Wrappers.lambdaQuery(SysUserFolders.class)
+                .eq(SysUserFolders::getUserId, LoginHelper.getUserId())
+                .in(SysUserFolders::getProjectId, projectIds)
+        ).forEach(e -> userFolderMap.put(e.getProjectId(), e.getFolders()));
+
+        Map<Long, List<Folder>> folderProjectMap = folders.stream().collect(Collectors.groupingBy(Folder::getProjectId));
+
+        return buildFinalFolders(folderProjectMap, userFolderMap);
+    }
+
+    private List<Folder> buildFinalFolders(Map<Long, List<Folder>> folderProjectMap, Map<Long, String> userFolderMap) {
+        List<Folder> folders = new ArrayList<>();
+
+        folderProjectMap.forEach((projectId, folderList) -> {
+            String permission = userFolderMap.get(projectId);
+            if (StringUtils.isBlank(permission)) {
+                return;
+            }
+            if (permission.equals("*")) {
+                folders.addAll(folderList);
+            } else {
+                Map<Long, List<Folder>> childrenMap = folderList.stream().filter(e -> e.getParentId() != null).collect(Collectors.groupingBy(Folder::getParentId));
+                Map<Long, Folder> folderMap = new HashMap<>();
+                folderList.forEach(e -> folderMap.put(e.getId(), e));
+                List<Long> folderIds = Arrays.stream(permission.split(",")).map(Long::valueOf).toList();
+                for (Long folderId : folderIds) {
+                    buildFolders(folderMap.get(folderId), folders, childrenMap);
+                }
+            }
+        });
+
+        return folders;
+    }
+
+    private void buildFolders(Folder folder, List<Folder> folders, Map<Long, List<Folder>> childrenMap) {
+        folders.add(folder);
+        List<Folder> children = childrenMap.get(folder.getId());
+        if (children == null || children.isEmpty()) {
+            return;
+        }
+        children.forEach(e -> buildFolders(e, folders, childrenMap));
     }
 }

+ 1 - 0
ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/service/impl/DocumentQcTaskDetailServiceImpl.java

@@ -13,6 +13,7 @@ import com.yingpaipay.business.domain.vo.DocumentQcTaskDetailListVo;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.dromara.common.core.exception.BusinessException;
+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;

+ 2 - 6
ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/service/impl/DocumentQcTaskServiceImpl.java

@@ -14,6 +14,7 @@ import com.yingpaipay.business.domain.vo.DocumentQcTaskVo;
 import com.yingpaipay.business.mapper.DocumentQcTaskDetailMapper;
 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.SpringUtils;
 import org.dromara.common.core.utils.StringUtils;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
@@ -194,7 +195,7 @@ public class DocumentQcTaskServiceImpl implements IDocumentQcTaskService {
                 .filter(e -> !historyIds.contains(e.getId()))
                 .collect(Collectors.toList());
             if (selectedDocuments.isEmpty()) {
-                throw new BusinessException("无任务进行");
+                throw new BusinessException(MessageUtils.message("document.qc.taskdetail.notask"));
             }
             Collections.shuffle(selectedDocuments, new Random((long) documents.size() * bo.getProportion() / 100));
 
@@ -206,11 +207,6 @@ public class DocumentQcTaskServiceImpl implements IDocumentQcTaskService {
                 detail.setExecutor(LoginHelper.getUserId());
                 detail.setProjectId(bo.getProjectId());
                 detail.setTenantId(TenantHelper.getTenantId());
-                detail.setCreateDept(LoginHelper.getDeptId());
-                detail.setCreateBy(LoginHelper.getUserId());
-                detail.setCreateTime(new Date());
-                detail.setUpdateBy(LoginHelper.getUserId());
-                detail.setUpdateTime(new Date());
                 details.add(detail);
             });
 

+ 126 - 33
ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/service/impl/DocumentServiceImpl.java

@@ -1,21 +1,17 @@
 package com.yingpaipay.business.service.impl;
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.yingpaipay.business.constant.DictTypeConst;
-import com.yingpaipay.business.constant.DocumentAuditorTypeConst;
-import com.yingpaipay.business.constant.DocumentStatusConst;
-import com.yingpaipay.business.constant.DocumentTypeConst;
+import com.yingpaipay.business.constant.*;
 import com.yingpaipay.business.domain.DocumentAuditLog;
 import com.yingpaipay.business.domain.Folder;
-import com.yingpaipay.business.domain.Project;
 import com.yingpaipay.business.domain.bo.*;
 import com.yingpaipay.business.domain.vo.*;
 import com.yingpaipay.business.mapper.DocumentAuditLogMapper;
 import com.yingpaipay.common.file.util.PdfUtils;
 import jakarta.servlet.http.HttpServletResponse;
 import org.apache.commons.io.FilenameUtils;
+import org.dromara.common.core.constant.GlobalConstants;
 import org.dromara.common.core.exception.BusinessException;
-import org.dromara.common.core.exception.ServiceException;
 import org.dromara.common.core.utils.MapstructUtils;
 import org.dromara.common.core.utils.MessageUtils;
 import org.dromara.common.core.utils.StringUtils;
@@ -29,6 +25,7 @@ import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.dromara.common.oss.core.OssClient;
 import org.dromara.common.oss.factory.OssFactory;
+import org.dromara.common.redis.utils.RedisUtils;
 import org.dromara.common.satoken.utils.LoginHelper;
 import org.dromara.common.tenant.helper.TenantHelper;
 import org.dromara.system.domain.vo.SysOssVo;
@@ -45,8 +42,9 @@ import org.springframework.transaction.annotation.Transactional;
 import java.io.*;
 import java.nio.file.Files;
 import java.nio.file.Path;
-import java.nio.file.Paths;
 import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
 
 /**
  * 文档Service业务层处理
@@ -68,6 +66,11 @@ public class DocumentServiceImpl implements IDocumentService {
     private final CommonFolderService folderService;
     private final CommonProjectService projectService;
 
+    /**
+     * 水印的锁
+     */
+    private static final Map<Long, Object> WATERMARK_LOCK = new ConcurrentHashMap<>();
+
     /**
      * 查询文档
      *
@@ -100,16 +103,7 @@ public class DocumentServiceImpl implements IDocumentService {
         List<Long> folderIds = new ArrayList<>();
         Map<Long, String> folderMap = new HashMap<>();
         List<Long> userIds = new ArrayList<>();
-        Map<String, String> planDocumentTypeMap = new HashMap<>();
-        Map<String, String> centerFileSpecificationMap = new HashMap<>();
-        Map<String, String> projectFileSpecificationMap = new HashMap<>();
         Map<Long, String> userMap = new HashMap<>();
-        dictTypeService.selectDictDataByType(DictTypeConst.PLAN_DOCUMENT_TYPE)
-            .forEach(e -> planDocumentTypeMap.put(e.getDictValue(), e.getDictLabel()));
-        dictTypeService.selectDictDataByType(DictTypeConst.CENTER_FILE_SPECIFICATION)
-            .forEach(e -> centerFileSpecificationMap.put(e.getDictValue(), e.getDictLabel()));
-        dictTypeService.selectDictDataByType(DictTypeConst.PROJECT_FILE_SPECIFICATION)
-            .forEach(e -> projectFileSpecificationMap.put(e.getDictValue(), e.getDictLabel()));
         documents.forEach(e -> {
             ossIds.add(e.getOssId());
             folderIds.add(e.getFolderId());
@@ -126,7 +120,8 @@ public class DocumentServiceImpl implements IDocumentService {
             }
             e.setSubmitterName(userMap.get(e.getSubmitter()));
             e.setPlanSubmitterName(userMap.get(e.getPlanSubmitter()));
-            e.setFolderName(folderMap.get(e.getFolderId()));
+            String folderName = folderMap.get(e.getFolderId());
+            e.setFolderName(StringUtils.isNotBlank(folderName) ? folderName : MessageUtils.message("search.temp"));
         });
     }
 
@@ -377,7 +372,7 @@ public class DocumentServiceImpl implements IDocumentService {
     public void download(Long ossId, HttpServletResponse response) throws IOException {
         SysOssVo sysOss = ossService.getById(ossId);
         if (sysOss == null) {
-            throw new ServiceException("文件数据不存在!");
+            throw new BusinessException(MessageUtils.message("document.document.download.notfound"));
         }
 
         String originalExt = FilenameUtils.getExtension(sysOss.getOriginalName());
@@ -417,6 +412,7 @@ public class DocumentServiceImpl implements IDocumentService {
 
     private String buildRemark(Long ossId) {
         Document document = baseMapper.selectOne(Wrappers.lambdaQuery(Document.class).eq(Document::getOssId, ossId));
+        // 也有可能直接下载审核版本
         if (document == null) {
             DocumentAuditLog log = auditLogMapper.selectOne(
                 Wrappers.lambdaQuery(DocumentAuditLog.class)
@@ -427,8 +423,20 @@ public class DocumentServiceImpl implements IDocumentService {
             }
             document = baseMapper.selectById(log.getDocumentId());
         }
-        Project project = projectService.queryById(document.getProjectId());
-        return project.getCode() + ":" + document.getId();
+
+        Object lock = WATERMARK_LOCK.computeIfAbsent(document.getId(), id -> new Object());
+        String key = GlobalConstants.DOCUMENT_WATERMARK_KEY + document.getId();
+        synchronized (lock) {
+            int count;
+            if (RedisUtils.hasKey(key)) {
+                count = RedisUtils.getCacheObject(key);
+                count++;
+            } else {
+                count = 1;
+            }
+            RedisUtils.setCacheObject(key, count);
+            return document.getId() + ":" + String.format("%06d", count);
+        }
     }
 
     @Override
@@ -494,7 +502,7 @@ public class DocumentServiceImpl implements IDocumentService {
         AppletMineCountVo vo = new AppletMineCountVo();
         List<Document> documentList = baseMapper.selectList(
             Wrappers.lambdaQuery(Document.class)
-                .eq(Document::getSubmitter, LoginHelper.getUserId())
+                .eq(Document::getPlanSubmitter, LoginHelper.getUserId())
                 .in(Document::getStatus, List.of(DocumentStatusConst.UN_UPLOAD, DocumentStatusConst.UN_AUDIT, DocumentStatusConst.AUDIT_REJECT))
         );
         vo.setToSubmit(
@@ -539,7 +547,7 @@ public class DocumentServiceImpl implements IDocumentService {
         IPage<Document> page = baseMapper.selectPage(
             pageQuery.build(),
             Wrappers.lambdaQuery(Document.class)
-                .eq(Document::getSubmitter, LoginHelper.getUserId())
+                .eq(Document::getPlanSubmitter, LoginHelper.getUserId())
                 .eq(bo.getStatus() != null, Document::getStatus, bo.getStatus())
                 .like(StringUtils.isNotBlank(bo.getName()), Document::getName, bo.getName())
                 .orderByDesc(Document::getId)
@@ -562,7 +570,7 @@ public class DocumentServiceImpl implements IDocumentService {
         IPage<Document> page = baseMapper.selectPage(
             pageQuery.build(),
             Wrappers.lambdaQuery(Document.class)
-                .eq(Document::getSubmitter, LoginHelper.getUserId())
+                .eq(Document::getPlanSubmitter, LoginHelper.getUserId())
                 .in(Document::getStatus, List.of(DocumentStatusConst.UN_UPLOAD, DocumentStatusConst.AUDIT_REJECT))
                 .like(StringUtils.isNotBlank(bo.getName()), Document::getName, bo.getName())
                 .orderByDesc(Document::getId)
@@ -571,10 +579,17 @@ public class DocumentServiceImpl implements IDocumentService {
         Map<Long, Folder> folderMap = new HashMap<>();
         Map<Long, String> projectMap = new HashMap<>();
 
-        page.getRecords().forEach(e -> projectIds.add(e.getProjectId()));
+        page.getRecords().forEach(e -> {
+            if (!projectIds.contains(e.getProjectId())) {
+                projectIds.add(e.getProjectId());
+            }
+        });
         projectService.queryByIds(projectIds).forEach(e -> projectMap.put(e.getId(), e.getName()));
         List<Folder> folderList = folderService.queryByProjectIds(projectIds);
-        folderList.forEach(e -> folderMap.put(e.getId(), e));
+//        folderList.forEach(e -> folderMap.put(e.getId(), e));
+        for (Folder folder : folderList) {
+            folderMap.put(folder.getId(), folder);
+        }
 
         return TableDataInfo.build(page.convert(e -> {
             AppletDocumentScanSubmitVo vo = new AppletDocumentScanSubmitVo();
@@ -607,7 +622,7 @@ public class DocumentServiceImpl implements IDocumentService {
         List<String> fileBase64List = bo.getFileBase64List();
 
         if (fileBase64List == null || fileBase64List.isEmpty()) {
-            throw new BusinessException("提交的文件列表为空");
+            throw new BusinessException(MessageUtils.message("document.document.uploadempty"));
         }
 
         File file;
@@ -623,6 +638,7 @@ public class DocumentServiceImpl implements IDocumentService {
                 .eq(Document::getId, bo.getDocumentId())
                 .set(Document::getOssId, ossVo.getOssId())
                 .set(Document::getStatus, DocumentStatusConst.UN_AUDIT)
+                .set(Document::getSubmitter, LoginHelper.getUserId())
                 .set(Document::getSubmitTime, new Date())
         ) > 0;
     }
@@ -652,7 +668,7 @@ public class DocumentServiceImpl implements IDocumentService {
         }
 
         if (files.isEmpty()) {
-            throw new BusinessException("未解析到有效的 PDF 文件数据");
+            throw new BusinessException(MessageUtils.message("document.document.cannotparseusablepdf"));
         }
 
         finalFile = PdfUtils.merge(files, fileName);
@@ -667,7 +683,7 @@ public class DocumentServiceImpl implements IDocumentService {
         List<String> fileBase64List = bo.getFiles();
 
         if (fileBase64List == null || fileBase64List.isEmpty()) {
-            throw new BusinessException("提交的文件列表为空");
+            throw new BusinessException(MessageUtils.message("document.document.uploadempty"));
         }
 
         File file;
@@ -691,11 +707,6 @@ public class DocumentServiceImpl implements IDocumentService {
         document.setSendFlag(false);
         document.setSendStatus(false);
         document.setTenantId(TenantHelper.getTenantId());
-        document.setCreateDept(LoginHelper.getDeptId());
-        document.setCreateBy(LoginHelper.getUserId());
-        document.setCreateTime(new Date());
-        document.setUpdateBy(LoginHelper.getUserId());
-        document.setUpdateTime(new Date());
 
         return baseMapper.insert(document) > 0;
     }
@@ -712,6 +723,87 @@ public class DocumentServiceImpl implements IDocumentService {
         );
     }
 
+    /**
+     * 文件上传和插入数据库并非原子操作,因此无需使用事务控制
+     */
+    @Override
+    public boolean upload(AppletUploadBo bo) {
+
+        List<String> fileBase64List = bo.getFiles();
+
+        if (fileBase64List == null || fileBase64List.isEmpty()) {
+            throw new BusinessException(MessageUtils.message("document.document.uploadempty"));
+        }
+
+        File file;
+        try {
+            file = convertToFile(fileBase64List, bo.getName());
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+        SysOssVo ossVo = ossService.upload(file);
+
+        List<Folder> folders = folderService.queryByProjectIds(List.of(bo.getProjectId()));
+        Map<Long, Folder> folderMap = new HashMap<>();
+            folders.forEach(e -> folderMap.put(e.getId(), e));
+        Map<Long, List<Folder>> childrenMap = folders.stream().filter(e -> e.getParentId() != null).collect(Collectors.groupingBy(Folder::getParentId));
+        List<Long> selected = new ArrayList<>();
+        if (bo.getCenter() != 0L) {
+            buildFolders(selected, folderMap.get(bo.getCenter()), childrenMap);
+        } else {
+            if (bo.getCountry() != 0L) {
+                buildFolders(selected, folderMap.get(bo.getCountry()), childrenMap);
+            } else {
+                selected = folders.stream().map(Folder::getId).toList();
+            }
+        }
+        List<Document> documents = baseMapper.selectList(
+            Wrappers.lambdaQuery(Document.class)
+                .in(Document::getFolderId, selected)
+        );
+        for (Document document : documents) {
+            if (document.getName().equals(bo.getName())) {
+                document.setOssId(ossVo.getOssId());
+                document.setSubmitter(LoginHelper.getUserId());
+                document.setSubmitTime(new Date());
+                document.setStatus(DocumentStatusConst.UN_AUDIT);
+                return baseMapper.updateById(document) > 0;
+            }
+        }
+
+        Document document = new Document();
+        document.setFolderId(bo.getCenter() != 0L ? bo.getCenter() : bo.getCountry());
+        document.setName(bo.getName());
+        document.setStatus(DocumentStatusConst.UN_AUDIT);
+        document.setOssId(ossVo.getOssId());
+        document.setType(DocumentTypeConst.NOT_PLAN);
+        document.setSubmitter(LoginHelper.getUserId());
+        document.setSubmitTime(new Date());
+        document.setProjectId(bo.getProjectId());
+        document.setSpecificationType(bo.getCenter() != 0L ? SpecificationTypeConst.CENTER : SpecificationTypeConst.PROJECT);
+        document.setTenantId(TenantHelper.getTenantId());
+
+        return baseMapper.insert(document) > 0;
+    }
+
+    @Override
+    public long countTemp(Long projectId) {
+        return baseMapper.selectCount(
+            Wrappers.lambdaQuery(Document.class)
+                .eq(Document::getProjectId, projectId)
+                .eq(Document::getFolderId, 0)
+        );
+    }
+
+    private void buildFolders(List<Long> selected, Folder folder, Map<Long, List<Folder>> childrenMap) {
+        selected.add(folder.getId());
+        List<Folder> childrens = childrenMap.get(folder.getId());
+        if (childrens == null || childrens.isEmpty()) {
+            return;
+        }
+        childrens.forEach(e -> buildFolders(selected, e, childrenMap));
+    }
+
     private LambdaQueryWrapper<Document> buildFilingListWrapper(TaskCenterFilingListBo bo, List<Long> folderIds) {
         return Wrappers.lambdaQuery(Document.class)
             .like(StringUtils.isNotBlank(bo.getName()), Document::getName, bo.getName())
@@ -768,6 +860,7 @@ public class DocumentServiceImpl implements IDocumentService {
         log.setCreateTime(new Date());
         log.setUpdateBy(LoginHelper.getUserId());
         log.setUpdateTime(new Date());
+        log.setSubmitter(document.getSubmitter());
         return log;
     }
 }

+ 65 - 24
ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/service/impl/FolderServiceImpl.java

@@ -4,6 +4,7 @@ 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.DocumentTypeConst;
 import com.yingpaipay.business.constant.FolderTypeConst;
 import com.yingpaipay.business.domain.Folder;
 import com.yingpaipay.business.domain.bo.FolderBo;
@@ -294,13 +295,35 @@ public class FolderServiceImpl implements IFolderService {
 
     @Override
     public TableDataInfo<ProjectCenterMemberListVo> queryCenterMember(ProjectCenterMemberListBo bo, PageQuery pageQuery) {
+        List<Long> centerIds = new ArrayList<>();
+        Map<Long, Folder> folderMap = new HashMap<>();
+        List<Folder> folderList = new ArrayList<>();
+        baseMapper.selectList(Wrappers.lambdaQuery(Folder.class).eq(Folder::getProjectId, bo.getProjectId()))
+            .forEach(e -> {
+                folderList.add(e);
+                folderMap.put(e.getId(), e);
+            });
+        Map<Long, List<Folder>> childerMap = folderList.stream().filter(e -> e.getParentId() != null).collect(Collectors.groupingBy(Folder::getParentId));
+        for (Folder folder : folderList) {
+            if (folder.getType().equals(FolderTypeConst.CENTER)) {
+                centerIds.add(folder.getId());
+            } else if (folder.getType().equals(FolderTypeConst.COUNTRY)) {
+                List<Folder> childrens = childerMap.getOrDefault(folder.getId(), Collections.emptyList());
+                if (childrens.stream().anyMatch(e -> e.getType().equals(FolderTypeConst.CENTER))) {
+                    centerIds.add(folder.getId());
+                }
+            }
+        }
+
         IPage<SysUserFolders> page = userFoldersMapper.selectPage(
             pageQuery.build(),
             Wrappers.lambdaQuery(SysUserFolders.class)
                 .eq(SysUserFolders::getProjectId, bo.getProjectId())
                 .and(wrapper -> {
                         wrapper.eq(SysUserFolders::getFolders, "*");
-
+                        for (Long centerId : centerIds) {
+                            wrapper.or().apply(DataBaseHelper.findInSet(centerId, "folders"));
+                        }
                     }
                 )
                 .orderByDesc(SysUserFolders::getUserId)
@@ -309,38 +332,66 @@ public class FolderServiceImpl implements IFolderService {
         List<Long> deptIds = new ArrayList<>();
         Map<Long, SysUserVo> userMap = new HashMap<>();
         Map<Long, String> deptMap = new HashMap<>();
-        Map<Long, Folder> folderMap = new HashMap<>();
         page.getRecords().forEach(e -> userIds.add(e.getUserId()));
         userService.selectUserVoByIds(userIds).forEach(e -> {
             userMap.put(e.getUserId(), e);
             deptIds.add(e.getDeptId());
         });
         deptService.selectDeptByIds(deptIds).forEach(e -> deptMap.put(e.getDeptId(), e.getDeptName()));
-        List<Folder> folderList = baseMapper.selectList(Wrappers.lambdaQuery(Folder.class).eq(Folder::getProjectId, bo.getProjectId()).eq(Folder::getType, FolderTypeConst.CENTER));
-        folderList.forEach(e -> folderMap.put(e.getId(), e));
-        Map<Long, List<Folder>> childerMap = folderList.stream().collect(Collectors.groupingBy(Folder::getParentId));
+        List<Folder> roots = folderList.stream().filter(folder -> folder.getParentId() == null).toList();
         return TableDataInfo.build(page.convert(e -> {
 
             SysUserVo user = userMap.get(e.getUserId());
             ProjectCenterMemberListVo vo = new ProjectCenterMemberListVo();
-            Set<Folder> centers= new HashSet<>();
+
+            Set<Folder> centers = new HashSet<>();
             if (e.getFolders().equals("*")) {
-                folderMap.forEach((k, v) -> {
-                    if (v.getType().equals(FolderTypeConst.CENTER)) {
-                        centers.add(v);
+                for (Folder root : roots) {
+                    if (root.getType().equals(FolderTypeConst.CENTER)) {
+                        centers.add(root);
+                        continue;
+                    }
+                    List<Folder> childrens = childerMap.getOrDefault(root.getId(), Collections.emptyList());
+                    for (Folder children : childrens) {
+                        if (children.getType().equals(FolderTypeConst.CENTER)) {
+                            centers.add(children);
+                        }
                     }
-                });
+                }
             } else {
                 Long[] folderIds = Arrays.stream(e.getFolders().split(",")).map(Long::valueOf).toArray(Long[]::new);
                 for (Long folderId : folderIds) {
-                    Folder folder = folderMap.get(folderId);
-                    if (folder != null) {
-                        buildCenters(folder, childerMap, centers);
+                    Folder current = folderMap.get(folderId);
+                    if (current.getType().equals(FolderTypeConst.CENTER)) {
+                        centers.add(current);
+                    } else if (current.getType().equals(FolderTypeConst.COUNTRY)) {
+                        // 国家就看有没有子中心
+                        List<Folder> folders = childerMap.getOrDefault(current.getId(), Collections.emptyList());
+                        for (Folder folder : folders) {
+                            if (folder.getType().equals(FolderTypeConst.CENTER)) {
+                                centers.add(folder);
+                            }
+                        }
+                    } else {
+                        // 如果该成员拥有某一中心的某个文件夹的任意权限,那么他也属于该中心
+                        if (current.getParentId() == null) {
+                            continue;
+                        }
+                        Folder parent = folderMap.get(current.getParentId());
+                        while (parent.getType().equals(FolderTypeConst.NORMAL)) {
+                            if (parent.getType().equals(FolderTypeConst.CENTER) || parent.getParentId() == null) {
+                                break;
+                            }
+                            parent = folderMap.get(parent.getParentId());
+                        }
+                        if (parent.getType().equals(FolderTypeConst.CENTER)) {
+                            centers.add(parent);
+                        }
                     }
                 }
             }
-
             vo.setCenters(String.join(",", new TreeSet<>(centers.stream().map(Folder::getName).collect(Collectors.toSet()))));
+
             if (user != null) {
                 vo.setId(user.getUserId());
                 vo.setName(user.getNickName());
@@ -352,16 +403,6 @@ public class FolderServiceImpl implements IFolderService {
         }));
     }
 
-    private void buildCenters(Folder current, Map<Long, List<Folder>> childrenMap, Set<Folder> result) {
-        result.add(current);
-        List<Folder> childrens = childrenMap.get(current.getId());
-        if (childrens != null) {
-            for (Folder children : childrens) {
-                buildCenters(children, childrenMap, result);
-            }
-        }
-    }
-
     private LambdaQueryWrapper<Folder> buildCenterQueryWrapper(ProjectCenterListBo bo) {
         return Wrappers.lambdaQuery(Folder.class)
             .eq(Folder::getType, FolderTypeConst.CENTER)

+ 6 - 20
ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/service/impl/ProjectServiceImpl.java

@@ -3,12 +3,11 @@ package com.yingpaipay.business.service.impl;
 import cn.hutool.crypto.digest.BCrypt;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.yingpaipay.business.constant.DocumentTypeConst;
-import com.yingpaipay.business.constant.UserAppletStatusConst;
+import com.yingpaipay.system.constant.UserAppletStatusConst;
 import com.yingpaipay.business.domain.Document;
 import com.yingpaipay.business.domain.bo.*;
 import com.yingpaipay.business.domain.vo.*;
 import com.yingpaipay.business.enumeration.ProjectStatusEnum;
-import com.yingpaipay.business.mapper.DocumentMapper;
 import com.yingpaipay.system.domain.SysUserFolders;
 import com.yingpaipay.system.domain.SysUserProjects;
 import com.yingpaipay.system.mapper.SysUserFoldersMapper;
@@ -360,13 +359,13 @@ public class ProjectServiceImpl implements IProjectService {
             vo.setId(e.getId());
             vo.setCode(e.getCode());
             vo.setName(e.getName());
-            long total = 0L, onTimeSubmit = 0L, lateSubmit = 0L, notSubmit = 0L;
+            long total = 1L, onTimeSubmit = 0L, lateSubmit = 0L, notSubmit = 0L;
             if (documentList != null) {
                 total = documentList.size();
                 List<Document> planDocuments = documentList.stream()
                     .filter(item -> item.getType().equals(DocumentTypeConst.PLAN))
                     .toList();
-                if (total > 0) {
+                if (total > 0L) {
                     onTimeSubmit = planDocuments.stream()
                         .filter(item -> item.getOssId() != null && item.getSubmitTime().before(item.getSubmitDeadline()))
                         .count();
@@ -380,17 +379,9 @@ public class ProjectServiceImpl implements IProjectService {
                         .count();
                 }
             }
-//            long onTimeSubmit = planDocuments.stream()
-//                .filter(item -> item.getOssId() != null && item.getSubmitTime().before(item.getSubmitDeadline()))
-//                .count();
-//            long lateSubmit = planDocuments.stream()
-//                .filter(item -> item.getOssId() != null)
-//                .filter(item -> item.getSubmitDeadline().before(item.getSubmitTime()))
-//                .count();
-//            long notSubmit = planDocuments.stream()
-//                .filter(item -> item.getOssId() == null)
-//                .filter(item -> item.getSubmitDeadline().before(new Date()))
-//                .count();
+
+            // TODO 如果 total == 0 , 那么计算两个比例的时候就会变为 NaN
+            total = total > 0L ? total : 1L;
             vo.setOnTimeSubmissionRate(Double.valueOf(String.format("%.2f", (double) onTimeSubmit / total * 100L)));
             vo.setLateSubmissionCount(lateSubmit);
             vo.setSubmissionProgress(Double.valueOf(String.format("%.2f", (double) notSubmit / total * 100L)));
@@ -472,11 +463,6 @@ public class ProjectServiceImpl implements IProjectService {
         user.setAppletStatus(UserAppletStatusConst.NORMAL);
         user.setRoleIds(bo.getRoleIds());
         user.setProjects(bo.getProjectId().toString());
-        user.setCreateDept(LoginHelper.getDeptId());
-        user.setCreateBy(LoginHelper.getUserId());
-        user.setCreateTime(new Date());
-        user.setUpdateBy(LoginHelper.getUserId());
-        user.setUpdateTime(new Date());
         return user;
     }
 

+ 8 - 27
ruoyi-modules/yingpaipay-business/src/main/java/com/yingpaipay/business/service/impl/TextInServiceImpl.java

@@ -10,7 +10,10 @@ import com.yingpaipay.common.file.config.TextInConfig;
 import com.yingpaipay.setting.domain.vo.TextinSettingVo;
 import com.yingpaipay.setting.service.ITextinSettingService;
 import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.logging.log4j.message.Message;
 import org.dromara.common.core.exception.BusinessException;
+import org.dromara.common.core.utils.MessageUtils;
 import org.dromara.common.json.utils.JsonUtils;
 import org.jspecify.annotations.NonNull;
 import org.springframework.http.MediaType;
@@ -25,11 +28,9 @@ import java.util.zip.ZipInputStream;
 
 @Service
 @RequiredArgsConstructor
+@Slf4j
 public class TextInServiceImpl implements ITextInService {
 
-    private static final String APP_ID = "efb7393aac470f5af564ad91b2a79d2e";
-    private static final String SECRET_CODE = "027e0c7ceedf5c8b583ec53debbe9420";
-
     private final TextInConfig config;
 
     private final ITextinSettingService settingService;
@@ -57,16 +58,15 @@ public class TextInServiceImpl implements ITextInService {
 
     private static @NonNull TextInR getR(HttpResponse response) {
         if (response.getStatus() != 200) {
-            throw new BusinessException("网络异常");
+            throw new BusinessException(MessageUtils.message("textin.networkerror"));
         }
         String body = response.body();
         TextInR result = JsonUtils.parseObject(body, TextInR.class);
         if (result == null) {
-            throw new BusinessException("识别失败");
+            throw new BusinessException(MessageUtils.message("textin.recognitionfail"));
         }
-
         if (result.getCode() != 200) {
-            throw new BusinessException(result.getMessage());
+            throw new RuntimeException(result.getMessage());
         }
         return result;
     }
@@ -74,12 +74,6 @@ public class TextInServiceImpl implements ITextInService {
     @Override
     public String imageToWord(String image) {
 
-//        HttpResponse response = HttpRequest.post(config.getImageToWord())
-//            .header("x-ti-app-id", APP_ID)
-//            .header("x-ti-secret-code", SECRET_CODE)
-//            .header(Header.CONTENT_TYPE, MediaType.APPLICATION_OCTET_STREAM_VALUE)
-//            .body(Base64.getDecoder().decode(image))
-//            .execute();
         HttpResponse response = getResponse(
             HttpRequest.post(config.getImageToWord())
                 .header(Header.CONTENT_TYPE, MediaType.APPLICATION_OCTET_STREAM_VALUE)
@@ -94,13 +88,6 @@ public class TextInServiceImpl implements ITextInService {
     @Override
     public String wordToImage(String docx) {
 
-//        HttpResponse response = HttpRequest.post(config.getWordToImage())
-//            .header("x-ti-app-id", APP_ID)
-//            .header("x-ti-secret-code", SECRET_CODE)
-//            .header(Header.CONTENT_TYPE, MediaType.APPLICATION_OCTET_STREAM_VALUE)
-//            .body(docx)
-//            .execute();
-
         HttpResponse response = getResponse(
             HttpRequest.post(config.getWordToImage())
                 .header(Header.CONTENT_TYPE, MediaType.APPLICATION_OCTET_STREAM_VALUE)
@@ -145,7 +132,7 @@ public class TextInServiceImpl implements ITextInService {
             }
 
         } catch (IllegalArgumentException e) {
-            throw new RuntimeException("Base64 格式无效", e);
+            throw new RuntimeException("BASE64 格式无效", e);
         } catch (IOException e) {
             throw new RuntimeException("解压失败", e);
         }
@@ -156,12 +143,6 @@ public class TextInServiceImpl implements ITextInService {
     @Override
     public String wordToPdf(String docx) {
 
-//        HttpResponse response = HttpRequest.post(config.getWordToPdf())
-//            .header("x-ti-app-id", APP_ID)
-//            .header("x-ti-secret-code", SECRET_CODE)
-//            .header(Header.CONTENT_TYPE, MediaType.APPLICATION_OCTET_STREAM_VALUE)
-//            .body(Base64.getDecoder().decode(docx))
-//            .execute();
         HttpResponse response = getResponse(
             HttpRequest.post(config.getWordToPdf())
                 .header(Header.CONTENT_TYPE, MediaType.APPLICATION_OCTET_STREAM_VALUE)