From a529a8b7e30bca1c4d3bd4e51a15913dfb6577dd Mon Sep 17 00:00:00 2001 From: lcj <2331845269@qq.com> Date: Thu, 3 Apr 2025 18:03:33 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=BD=E5=B7=A5=E4=BA=BA=E5=91=98=E4=B8=8B?= =?UTF-8?q?=E8=BD=BD=E6=89=B9=E9=87=8F=E5=AF=BC=E5=85=A5=E5=8E=8B=E7=BC=A9?= =?UTF-8?q?=E5=8C=85=E6=A8=A1=E7=89=88=E6=8E=A5=E5=8F=A3=EF=BC=8C=E4=B8=8A?= =?UTF-8?q?=E4=BC=A0=E5=8E=8B=E7=BC=A9=E5=8C=85=E6=89=B9=E9=87=8F=E5=AF=BC?= =?UTF-8?q?=E5=85=A5=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/core/utils/file/FileUtils.java | 31 +++ .../constant/ConstructionUserConstant.java | 14 + .../BusConstructionUserFileController.java | 22 ++ .../enums/ConstructionUserFileStatusEnum.java | 43 +++ .../domain/vo/BusConstructionUserExitVo.java | 11 +- .../domain/vo/BusConstructionUserVo.java | 7 + .../IBusConstructionUserExitService.java | 17 ++ .../IBusConstructionUserFileService.java | 18 ++ .../BusConstructionUserExitServiceImpl.java | 59 ++++- .../BusConstructionUserFileServiceImpl.java | 248 +++++++++++++++++- .../impl/BusConstructionUserServiceImpl.java | 18 ++ 11 files changed, 476 insertions(+), 12 deletions(-) create mode 100644 RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/constant/ConstructionUserConstant.java create mode 100644 RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/enums/ConstructionUserFileStatusEnum.java diff --git a/RuoYi-Vue-Plus/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/file/FileUtils.java b/RuoYi-Vue-Plus/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/file/FileUtils.java index 573b2073..1e5d1606 100644 --- a/RuoYi-Vue-Plus/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/file/FileUtils.java +++ b/RuoYi-Vue-Plus/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/file/FileUtils.java @@ -5,8 +5,14 @@ import jakarta.servlet.http.HttpServletResponse; import lombok.AccessLevel; import lombok.NoArgsConstructor; +import java.io.IOException; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; /** * 文件处理工具类 @@ -40,4 +46,29 @@ public class FileUtils extends FileUtil { String encode = URLEncoder.encode(s, StandardCharsets.UTF_8); return encode.replaceAll("\\+", "%20"); } + + /** + * 删除目录 + * + * @param path 路径 + * @throws IOException I/O异常 + */ + public static void deleteDirectory(Path path) throws IOException { + // walkFileTree会递归遍历path下所有文件和文件夹 + Files.walkFileTree(path, new SimpleFileVisitor<>() { + // 先删除文件 + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + Files.delete(file); + return FileVisitResult.CONTINUE; + } + + // 然后删除目录 + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { + Files.delete(dir); + return FileVisitResult.CONTINUE; + } + }); + } } diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/constant/ConstructionUserConstant.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/constant/ConstructionUserConstant.java new file mode 100644 index 00000000..d59140ce --- /dev/null +++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/constant/ConstructionUserConstant.java @@ -0,0 +1,14 @@ +package org.dromara.project.constant; + +/** + * @author lcj + * @date 2025/4/2 17:18 + */ +public interface ConstructionUserConstant { + + /** + * 施工人员文件类型字典 + */ + String USER_FILE_TYPE = "user_file_type"; + +} diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusConstructionUserFileController.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusConstructionUserFileController.java index f82134d9..420ab691 100644 --- a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusConstructionUserFileController.java +++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/controller/BusConstructionUserFileController.java @@ -15,6 +15,7 @@ import org.dromara.project.domain.vo.BusConstructionUserFileVo; import org.dromara.project.service.IBusConstructionUserFileService; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; import java.util.List; @@ -52,6 +53,27 @@ public class BusConstructionUserFileController extends BaseController { ExcelUtil.exportExcel(list, "施工人员文件存储", BusConstructionUserFileVo.class, response); } + /** + * 下载施工人员文件存储模板 + */ + @SaCheckPermission("project:constructionUserFile:export") + @Log(title = "施工人员文件存储", businessType = BusinessType.EXPORT) + @PostMapping("/exportFileTemplate") + public void exportFileTemplate(Long projectId, HttpServletResponse response) { + busConstructionUserFileService.downloadFileTemplate(projectId, response); + } + + /** + * 上传施工人员文件压缩包,批量导入存储施工人员文件 + */ + @SaCheckPermission("project:constructionUserFile:edit") + @Log(title = "施工人员文件存储", businessType = BusinessType.INSERT) + @PostMapping("/upload/zip") + public R uploadFileZip(@RequestParam("file") MultipartFile file) { + Boolean result = busConstructionUserFileService.batchUploadFileByZip(file); + return R.ok(result); + } + /** * 获取施工人员文件存储详细信息 * diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/enums/ConstructionUserFileStatusEnum.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/enums/ConstructionUserFileStatusEnum.java new file mode 100644 index 00000000..ee06b581 --- /dev/null +++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/enums/ConstructionUserFileStatusEnum.java @@ -0,0 +1,43 @@ +package org.dromara.project.domain.enums; + +import lombok.Getter; +import org.dromara.common.core.utils.ObjectUtils; + +/** + * @author lcj + * @date 2025/4/3 17:47 + */ +@Getter +public enum ConstructionUserFileStatusEnum { + + NOUPLOAD("未上传", "1"), + PARTUPLOAD("部分上传", "2"), + UPLOAD("已上传", "3"); + + private final String text; + + private final String value; + + ConstructionUserFileStatusEnum(String text, String value) { + this.text = text; + this.value = value; + } + + /** + * 根据 value 获取枚举 + * + * @param value 项目成员岗位枚举值 + * @return 项目成员岗位枚举 + */ + public static ConstructionUserFileStatusEnum getEnumByValue(String value) { + if (ObjectUtils.isEmpty(value)) { + return null; + } + for (ConstructionUserFileStatusEnum anEnum : ConstructionUserFileStatusEnum.values()) { + if (anEnum.value.equals(value)) { + return anEnum; + } + } + return null; + } +} diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/BusConstructionUserExitVo.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/BusConstructionUserExitVo.java index 4e3f2bc2..612805bd 100644 --- a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/BusConstructionUserExitVo.java +++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/BusConstructionUserExitVo.java @@ -8,6 +8,8 @@ import org.dromara.project.domain.BusConstructionUserExit; import java.io.Serial; import java.io.Serializable; +import java.util.Date; +import java.util.List; /** @@ -58,13 +60,13 @@ public class BusConstructionUserExitVo implements Serializable { * 入场时间 */ @ExcelProperty(value = "入场时间") - private String entryDate; + private Date entryDate; /** * 退场时间 */ @ExcelProperty(value = "退场时间") - private String leaveDate; + private Date leaveDate; /** * 退场文件 @@ -72,6 +74,11 @@ public class BusConstructionUserExitVo implements Serializable { @ExcelProperty(value = "退场文件") private String path; + /** + * 退场文件url + */ + private List pathUrl; + /** * 备注 */ diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/BusConstructionUserVo.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/BusConstructionUserVo.java index 5a35fd97..3141e05b 100644 --- a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/BusConstructionUserVo.java +++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/domain/vo/BusConstructionUserVo.java @@ -233,6 +233,13 @@ public class BusConstructionUserVo implements Serializable { @ExcelProperty(value = "薪水") private Long salary; + /** + * 文件上传状态 + */ + @ExcelProperty(value = "文件上传状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "user_file_status_type") + private String fileUploadStatus; + /** * 备注 */ diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusConstructionUserExitService.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusConstructionUserExitService.java index 0a435002..1cc6e6b1 100644 --- a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusConstructionUserExitService.java +++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusConstructionUserExitService.java @@ -1,6 +1,7 @@ package org.dromara.project.service; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.IService; import org.dromara.common.mybatis.core.page.PageQuery; import org.dromara.common.mybatis.core.page.TableDataInfo; @@ -43,6 +44,14 @@ public interface IBusConstructionUserExitService extends IService queryList(ConstructionUserExitQueryReq req); + /** + * 获取施工人员入场退场记录视图对象 + * + * @param constructionUserExit 施工人员入场退场记录对象 + * @return 施工人员入场退场记录视图对象 + */ + BusConstructionUserExitVo getVo(BusConstructionUserExit constructionUserExit); + /** * 获取施工人员入场退场记录信息查询条件封装 * @@ -51,4 +60,12 @@ public interface IBusConstructionUserExitService extends IService buildQueryWrapper(ConstructionUserExitQueryReq req); + /** + * 获取施工人员入场退场记录分页对象视图 + * + * @param constructionUserExitPage 施工人员入场退场记录分页对象 + * @return 施工人员入场退场记录分页对象视图 + */ + Page getVoPage(Page constructionUserExitPage); + } diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusConstructionUserFileService.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusConstructionUserFileService.java index 51ca1f9b..87cc1838 100644 --- a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusConstructionUserFileService.java +++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/IBusConstructionUserFileService.java @@ -2,10 +2,12 @@ package org.dromara.project.service; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.IService; +import jakarta.servlet.http.HttpServletResponse; import org.dromara.project.domain.BusConstructionUserFile; import org.dromara.project.domain.req.constructionuserfile.ConstructionUserFileQueryReq; import org.dromara.project.domain.req.constructionuserfile.ConstructionUserFileSaveReq; import org.dromara.project.domain.vo.BusConstructionUserFileVo; +import org.springframework.web.multipart.MultipartFile; import java.util.List; @@ -33,6 +35,22 @@ public interface IBusConstructionUserFileService extends IService queryList(ConstructionUserFileQueryReq req); + /** + * 导出施工人员文件模版zip + * + * @param projectId 项目id + * @param response 响应对象 + */ + void downloadFileTemplate(Long projectId, HttpServletResponse response); + + /** + * 通过zip文件批量上传施工人员文件 + * + * @param file zip文件 + * @return 是否上传成功 + */ + Boolean batchUploadFileByZip(MultipartFile file); + /** * 保存施工人员文件存储 * diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusConstructionUserExitServiceImpl.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusConstructionUserExitServiceImpl.java index 9a9508d9..52df3577 100644 --- a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusConstructionUserExitServiceImpl.java +++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusConstructionUserExitServiceImpl.java @@ -1,9 +1,11 @@ package org.dromara.project.service.impl; +import cn.hutool.core.collection.CollUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; import org.dromara.common.core.utils.ObjectUtils; import org.dromara.common.core.utils.StringUtils; import org.dromara.common.mybatis.core.page.PageQuery; @@ -13,8 +15,12 @@ import org.dromara.project.domain.req.constructionuserexit.ConstructionUserExitQ import org.dromara.project.domain.vo.BusConstructionUserExitVo; import org.dromara.project.mapper.BusConstructionUserExitMapper; import org.dromara.project.service.IBusConstructionUserExitService; +import org.dromara.system.domain.vo.SysOssVo; +import org.dromara.system.service.ISysOssService; +import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Service; +import java.util.Arrays; import java.util.List; /** @@ -27,6 +33,9 @@ import java.util.List; public class BusConstructionUserExitServiceImpl extends ServiceImpl implements IBusConstructionUserExitService { + @Resource + private ISysOssService ossService; + /** * 查询施工人员入场退场记录信息 * @@ -47,9 +56,8 @@ public class BusConstructionUserExitServiceImpl extends ServiceImpl queryPageList(ConstructionUserExitQueryReq req, PageQuery pageQuery) { - LambdaQueryWrapper lqw = buildQueryWrapper(req); - Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); - return TableDataInfo.build(result); + Page result = this.page(pageQuery.build(), buildQueryWrapper(req)); + return TableDataInfo.build(this.getVoPage(result)); } /** @@ -61,7 +69,29 @@ public class BusConstructionUserExitServiceImpl extends ServiceImpl queryList(ConstructionUserExitQueryReq req) { LambdaQueryWrapper lqw = buildQueryWrapper(req); - return baseMapper.selectVoList(lqw); + return this.list(lqw).stream().map(this::getVo).toList(); + } + + /** + * 获取施工人员入场退场记录视图对象 + * + * @param constructionUserExit 施工人员入场退场记录对象 + * @return 施工人员入场退场记录视图对象 + */ + @Override + public BusConstructionUserExitVo getVo(BusConstructionUserExit constructionUserExit) { + // 对象转封装类 + BusConstructionUserExitVo constructionUserExitVo = new BusConstructionUserExitVo(); + if (constructionUserExit == null) { + return constructionUserExitVo; + } + BeanUtils.copyProperties(constructionUserExit, constructionUserExitVo); + String path = constructionUserExitVo.getPath(); + if (StringUtils.isNotBlank(path)) { + List ossIdList = Arrays.stream(path.split(",")).map(Long::parseLong).toList(); + constructionUserExitVo.setPathUrl(ossService.listByIds(ossIdList).stream().map(SysOssVo::getUrl).toList()); + } + return constructionUserExitVo; } /** @@ -99,4 +129,25 @@ public class BusConstructionUserExitServiceImpl extends ServiceImpl getVoPage(Page constructionUserExitPage) { + List constructionUserExitList = constructionUserExitPage.getRecords(); + Page constructionUserExitVoPage = new Page<>( + constructionUserExitPage.getCurrent(), + constructionUserExitPage.getSize(), + constructionUserExitPage.getTotal()); + if (CollUtil.isEmpty(constructionUserExitList)) { + return constructionUserExitVoPage; + } + List constructionUserExitVoList = constructionUserExitList.stream().map(this::getVo).toList(); + constructionUserExitVoPage.setRecords(constructionUserExitVoList); + return constructionUserExitVoPage; + } + } diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusConstructionUserFileServiceImpl.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusConstructionUserFileServiceImpl.java index f3539344..c5ca03a1 100644 --- a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusConstructionUserFileServiceImpl.java +++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/project/service/impl/BusConstructionUserFileServiceImpl.java @@ -1,34 +1,57 @@ package org.dromara.project.service.impl; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.RandomUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.core.util.ZipUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; import lombok.extern.slf4j.Slf4j; import org.dromara.common.core.constant.HttpStatus; import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.DateUtils; import org.dromara.common.core.utils.ObjectUtils; import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.core.utils.file.FileUtils; import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.project.constant.ConstructionUserConstant; +import org.dromara.project.domain.BusConstructionBlacklist; import org.dromara.project.domain.BusConstructionUser; import org.dromara.project.domain.BusConstructionUserFile; +import org.dromara.project.domain.BusProject; import org.dromara.project.domain.req.constructionuserfile.ConstructionUserFileQueryReq; import org.dromara.project.domain.req.constructionuserfile.ConstructionUserFileReq; import org.dromara.project.domain.req.constructionuserfile.ConstructionUserFileSaveReq; import org.dromara.project.domain.vo.BusConstructionUserFileVo; import org.dromara.project.mapper.BusConstructionUserFileMapper; +import org.dromara.project.service.IBusConstructionBlacklistService; import org.dromara.project.service.IBusConstructionUserFileService; import org.dromara.project.service.IBusConstructionUserService; import org.dromara.project.service.IBusProjectService; +import org.dromara.system.domain.vo.SysDictDataVo; +import org.dromara.system.domain.vo.SysOssVo; +import org.dromara.system.service.ISysDictTypeService; +import org.dromara.system.service.ISysOssService; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.function.Function; import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; /** * 施工人员文件存储Service业务层处理 @@ -47,6 +70,15 @@ public class BusConstructionUserFileServiceImpl extends ServiceImpl blacklistUserIdList = constructionBlacklistService.lambdaQuery() + .eq(BusConstructionBlacklist::getProjectId, projectId) + .list().stream().map(BusConstructionBlacklist::getUserId).toList(); + // 3. 根据项目id获取对应施工人员 + List constructionUserList = constructionUserService.lambdaQuery() + .notIn(BusConstructionUser::getId, blacklistUserIdList) + .eq(BusConstructionUser::getProjectId, projectId).list(); + // 4. 根目录名称 + String randomString = project.getId() + "_" + RandomUtil.randomString(8); + String rootFolder = project.getShortName() + "_" + randomString + "/"; + // 6. 设置响应头 + response.setContentType("application/octet-stream"); + response.setHeader("Content-Disposition", "attachment;filename=\"" + randomString + ".zip\""); + // 7. 获取输出流,并封装为 ZipOutputStream + try (ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream())) { + // 8. 根目录下创建一个文件夹 + zipOut.putNextEntry(new ZipEntry(rootFolder)); + zipOut.closeEntry(); + // 9. 对每个人,创建其文件夹,再在其中创建子文件夹(如“三级安全教育”、“体检报告”...)及文件 + for (BusConstructionUser constructionUser : constructionUserList) { + String personFolder = rootFolder + constructionUser.getUserName() + "-" + constructionUser.getId() + "/"; + // 9.1. 写入个人文件夹条目 + zipOut.putNextEntry(new ZipEntry(personFolder)); + zipOut.closeEntry(); + // 9.2. 在个人文件夹下写几个子文件夹 + List dictDataList = dictTypeService.selectDictDataByType(ConstructionUserConstant.USER_FILE_TYPE); + for (SysDictDataVo dataVo : dictDataList) { + String subFolderPath = personFolder + dataVo.getDictValue() + "_" + dataVo.getDictLabel() + "/"; + zipOut.putNextEntry(new ZipEntry(subFolderPath)); + zipOut.closeEntry(); + } + } + zipOut.flush(); + response.flushBuffer(); // 确保数据全部写入响应流 + } catch (IOException e) { + throw new ServiceException("文件下载失败", HttpStatus.ERROR); + } + } + + /** + * 通过zip文件批量上传施工人员文件 + * + * @param multipartFile zip文件 + * @return 是否上传成功 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean batchUploadFileByZip(MultipartFile multipartFile) { + // 获取文件原始名字 + String originalFilename = multipartFile.getOriginalFilename(); + // 校验 + if (originalFilename == null) { + throw new ServiceException("文件不存在", HttpStatus.BAD_REQUEST); + } + // 校验是否为压缩包zip格式 + String suffix = FileUtil.getSuffix(originalFilename); + if (!suffix.equals("zip")) { + throw new ServiceException("请上传zip格式的文件", HttpStatus.BAD_REQUEST); + } + // 1. 获取项目id + String[] parts = originalFilename.split("_"); + long projectId = Long.parseLong(parts[1]); + // 压缩包临时文件路径 + String randomStr = RandomUtil.randomString(16); + File tempZipFile = null; + String tempZipFilePath = randomStr + "-" + originalFilename; + // 解压后的文件夹路径 + File destDir = null; + String basePath = "unzip_path"; + String destDirPath = basePath + "/" + DateUtils.getDate() + "/" + projectId + "/" + randomStr; + // 构建需要修改的对象 + List constructionUserFileList = new ArrayList<>(); + try { + // 2. 创建临时文件 + tempZipFile = File.createTempFile(tempZipFilePath, null); + multipartFile.transferTo(tempZipFile); + // 3. 解压 zip + destDir = new File(destDirPath); + ZipUtil.unzip(tempZipFile, destDir); + // 4. 遍历最外层文件夹 + File[] userFolders = destDir.listFiles(); + if (userFolders != null) { + for (File userFolder : userFolders) { + if (userFolder.isDirectory()) { + String userFolderName = userFolder.getName(); // 李四-1905161272755195006 + // 5. 解析 userId + long userId = Long.parseLong(userFolderName.substring(userFolderName.lastIndexOf("-") + 1)); + // 6. 继续遍历每个用户子文件夹里的 1_合同, 2_体检报告, ... + File[] docFolders = userFolder.listFiles(); + if (docFolders != null) { + for (File docFolder : docFolders) { + if (docFolder.isDirectory()) { + String docFolderName = docFolder.getName(); // 1_合同 + String[] docParts = docFolderName.split("_"); + String fileType = docParts[0]; + // 7. 获取该文件夹下所有文件 + File[] filesInDocFolder = docFolder.listFiles(); + String fileIdStr = null; + if (filesInDocFolder != null) { + // 遍历文件 + List fileIds = new ArrayList<>(); + for (File file : filesInDocFolder) { + if (file.isFile()) { + SysOssVo upload = ossService.upload(file); + if (upload != null) { + fileIds.add(upload.getOssId()); + } + } + } + // 跳过空文件 + if (fileIds.isEmpty()) { + continue; + } + fileIdStr = fileIds.stream() + .map(String::valueOf) + .collect(Collectors.joining(",")); + } + // 8. 创建 BusConstructionUserFile 对象 + BusConstructionUserFile constructionUserFile = new BusConstructionUserFile(); + constructionUserFile.setUserId(userId); + constructionUserFile.setFileType(fileType); + constructionUserFile.setPath(fileIdStr); + constructionUserFileList.add(constructionUserFile); + } + } + } + } + } + } + } catch (Exception e) { + throw new ServiceException("文件上传失败", HttpStatus.ERROR); + } finally { + if (tempZipFile != null) { + // 删除临时文件 + boolean delete = tempZipFile.delete(); + if (!delete) { + log.error("临时文件删除失败,路径:{}", tempZipFilePath); + } + } + if (destDir != null) { + Path dirPath = Paths.get(basePath); + try { + FileUtils.deleteDirectory(dirPath); + } catch (IOException e) { + log.error("解压文件删除失败,路径:{}", destDirPath, e); + } + } + } + if (CollUtil.isEmpty(constructionUserFileList)) { + return true; + } + // 9. 判断是否已经存在 + List userIdList = constructionUserFileList.stream().map(BusConstructionUserFile::getUserId).toList(); + List oldConstructionUserFileList = this.lambdaQuery() + .in(BusConstructionUserFile::getUserId, userIdList).list(); + // 10. 如果存在,则删除数据库对应记录和文件 + if (CollUtil.isNotEmpty(oldConstructionUserFileList)) { + // 待删除id + List deleteIds = oldConstructionUserFileList.stream().map(BusConstructionUserFile::getId).toList(); + // 待删除对象存储id + List deleteOssIds = new ArrayList<>(); + for (BusConstructionUserFile constructionUserFile : oldConstructionUserFileList) { + String path = constructionUserFile.getPath(); + if (StrUtil.isNotBlank(path)) { + String[] ossIds = path.split(","); + deleteOssIds.addAll(Arrays.stream(ossIds).map(Long::parseLong).toList()); + } + } + // 删除数据库记录 + boolean result = this.removeByIds(deleteIds); + if (!result) { + throw new ServiceException("数据库操作失败", HttpStatus.ERROR); + } + // 删除文件 + Boolean ossResult = ossService.deleteWithValidByIds(deleteOssIds, true); + if (!ossResult) { + throw new ServiceException("文件存储修改失败", HttpStatus.ERROR); + } + } + // 11. 保存 + boolean result = this.saveBatch(constructionUserFileList); + if (!result) { + throw new ServiceException("数据库操作失败", HttpStatus.ERROR); + } + return true; + } + /** * 保存施工人员文件存储 * @@ -124,12 +357,14 @@ public class BusConstructionUserFileServiceImpl extends ServiceImpl wage1 )); + int fileTypeSize = dictTypeService.selectDictDataByType(ConstructionUserConstant.USER_FILE_TYPE).size(); // 填充信息 List constructionUserVoList = constructionUserList.stream().map(constructionUser -> { BusConstructionUserVo constructionUserVo = new BusConstructionUserVo(); @@ -630,6 +637,17 @@ public class BusConstructionUserServiceImpl extends ServiceImpl constructionUserFileLqw = Wrappers.lambdaQuery(BusConstructionUserFile.class) + .eq(BusConstructionUserFile::getUserId, constructionUser.getId()); + long count = constructionUserFileService.count(constructionUserFileLqw); + if (count <= 0) { + constructionUserVo.setFileUploadStatus(ConstructionUserFileStatusEnum.NOUPLOAD.getValue()); + } else if (count < fileTypeSize) { + constructionUserVo.setFileUploadStatus(ConstructionUserFileStatusEnum.PARTUPLOAD.getValue()); + } else if (count == fileTypeSize) { + constructionUserVo.setFileUploadStatus(ConstructionUserFileStatusEnum.UPLOAD.getValue()); + } return constructionUserVo; }).toList(); constructionUserVoPage.setRecords(constructionUserVoList);