用户文件批量上传

This commit is contained in:
lcj
2025-11-19 17:11:18 +08:00
parent 72c775b1e3
commit 1902ba9d59
4 changed files with 67 additions and 41 deletions

View File

@ -53,4 +53,9 @@ public class SubConstructionUserFileTemplateReq implements Serializable {
*/ */
private List<Long> userIdList; private List<Long> userIdList;
/**
* 用户角色
*/
private String userRole;
} }

View File

@ -2,6 +2,7 @@ package org.dromara.contractor.service.impl;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil; import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdcardUtil;
import cn.hutool.core.util.RandomUtil; import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.ZipUtil; import cn.hutool.core.util.ZipUtil;
@ -17,6 +18,7 @@ import org.dromara.common.core.utils.DateUtils;
import org.dromara.common.core.utils.ObjectUtils; import org.dromara.common.core.utils.ObjectUtils;
import org.dromara.common.core.utils.StringUtils; import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.core.utils.file.FileUtils; import org.dromara.common.core.utils.file.FileUtils;
import org.dromara.common.utils.IdCardEncryptorUtil;
import org.dromara.contractor.constant.SubConstructionUserConstant; import org.dromara.contractor.constant.SubConstructionUserConstant;
import org.dromara.contractor.domain.SubConstructionUser; import org.dromara.contractor.domain.SubConstructionUser;
import org.dromara.contractor.domain.SubConstructionUserFile; import org.dromara.contractor.domain.SubConstructionUserFile;
@ -32,7 +34,6 @@ import org.dromara.project.domain.BusConstructionBlacklist;
import org.dromara.project.domain.BusProject; import org.dromara.project.domain.BusProject;
import org.dromara.project.service.IBusConstructionBlacklistService; import org.dromara.project.service.IBusConstructionBlacklistService;
import org.dromara.project.service.IBusProjectService; import org.dromara.project.service.IBusProjectService;
import org.dromara.safety.service.IWgzQuestionSavePdfService;
import org.dromara.system.domain.vo.SysDictDataVo; import org.dromara.system.domain.vo.SysDictDataVo;
import org.dromara.system.domain.vo.SysOssVo; import org.dromara.system.domain.vo.SysOssVo;
import org.dromara.system.service.ISysDictTypeService; import org.dromara.system.service.ISysDictTypeService;
@ -79,7 +80,7 @@ public class SubConstructionUserFileServiceImpl extends ServiceImpl<SubConstruct
private ISysOssService ossService; private ISysOssService ossService;
@Resource @Resource
private IWgzQuestionSavePdfService wgzQuestionSavePdfService; private IdCardEncryptorUtil idCardEncryptorUtil;
/** /**
* 查询施工人员文件存储 * 查询施工人员文件存储
@ -150,6 +151,7 @@ public class SubConstructionUserFileServiceImpl extends ServiceImpl<SubConstruct
throw new ServiceException("项目不存在", HttpStatus.BAD_REQUEST); throw new ServiceException("项目不存在", HttpStatus.BAD_REQUEST);
} }
// 2. 查询施工人员列表 // 2. 查询施工人员列表
req.setUserRole("0");
List<SubConstructionUser> constructionUserList = constructionUserService.list(this.buildTemplateQueryWrapper(req)); List<SubConstructionUser> constructionUserList = constructionUserService.list(this.buildTemplateQueryWrapper(req));
// 3. 根目录名称 // 3. 根目录名称
String randomString = project.getId() + "_" + RandomUtil.randomString(8); String randomString = project.getId() + "_" + RandomUtil.randomString(8);
@ -164,7 +166,11 @@ public class SubConstructionUserFileServiceImpl extends ServiceImpl<SubConstruct
zipOut.closeEntry(); zipOut.closeEntry();
// 7. 对每个人,创建其文件夹,再在其中创建子文件夹(如“三级安全教育”、“体检报告”...)及文件 // 7. 对每个人,创建其文件夹,再在其中创建子文件夹(如“三级安全教育”、“体检报告”...)及文件
for (SubConstructionUser constructionUser : constructionUserList) { for (SubConstructionUser constructionUser : constructionUserList) {
String personFolder = rootFolder + constructionUser.getUserName() + "-" + constructionUser.getSysUserId() + "/"; // 获取身份证信息
String sfzNumber = constructionUser.getSfzNumber();
// 解密
String decrypt = idCardEncryptorUtil.decrypt(sfzNumber);
String personFolder = rootFolder + constructionUser.getUserName() + "-" + decrypt + "/";
// 7.1. 写入个人文件夹条目 // 7.1. 写入个人文件夹条目
zipOut.putNextEntry(new ZipEntry(personFolder)); zipOut.putNextEntry(new ZipEntry(personFolder));
zipOut.closeEntry(); zipOut.closeEntry();
@ -220,6 +226,22 @@ public class SubConstructionUserFileServiceImpl extends ServiceImpl<SubConstruct
String destDirPath = basePath + "/" + DateUtils.getDate() + "/" + projectId + "/" + randomStr; String destDirPath = basePath + "/" + DateUtils.getDate() + "/" + projectId + "/" + randomStr;
// 构建需要修改的对象 // 构建需要修改的对象
List<SubConstructionUserFile> constructionUserFileList = new ArrayList<>(); List<SubConstructionUserFile> constructionUserFileList = new ArrayList<>();
// 获取所有身份证对应的用户信息
List<SubConstructionUser> allUserList = constructionUserService.lambdaQuery()
.select(SubConstructionUser::getId, SubConstructionUser::getSysUserId,
SubConstructionUser::getUserName, SubConstructionUser::getSfzNumber)
.eq(SubConstructionUser::getProjectId, projectId)
.eq( SubConstructionUser::getUserRole, "0")
.list();
if (CollUtil.isEmpty(allUserList)) {
throw new ServiceException("项目下无施工人员");
}
Map<String, Long> userMap = allUserList.stream()
.collect(Collectors.toMap(
SubConstructionUser::getSfzNumber,
SubConstructionUser::getSysUserId,
(oldV, newV) -> newV
));
try { try {
// 2. 创建临时文件 // 2. 创建临时文件
tempZipFile = File.createTempFile(tempZipFilePath, null); tempZipFile = File.createTempFile(tempZipFilePath, null);
@ -228,7 +250,7 @@ public class SubConstructionUserFileServiceImpl extends ServiceImpl<SubConstruct
destDir = new File(destDirPath); destDir = new File(destDirPath);
ZipUtil.unzip(tempZipFile, destDir); ZipUtil.unzip(tempZipFile, destDir);
// 4. 递归扫描目录 // 4. 递归扫描目录
scanUserFolders(destDir, constructionUserFileList); scanUserFolders(destDir, userMap, constructionUserFileList);
} catch (Exception e) { } catch (Exception e) {
throw new ServiceException("文件上传失败", HttpStatus.ERROR); throw new ServiceException("文件上传失败", HttpStatus.ERROR);
} finally { } finally {
@ -403,6 +425,7 @@ public class SubConstructionUserFileServiceImpl extends ServiceImpl<SubConstruct
String typeOfWork = req.getTypeOfWork(); String typeOfWork = req.getTypeOfWork();
String clock = req.getClock(); String clock = req.getClock();
List<Long> userIdList = req.getUserIdList(); List<Long> userIdList = req.getUserIdList();
String userRole = req.getUserRole();
// 模糊查询 // 模糊查询
lqw.like(StringUtils.isNotBlank(userName), SubConstructionUser::getUserName, userName); lqw.like(StringUtils.isNotBlank(userName), SubConstructionUser::getUserName, userName);
// 精确查询 // 精确查询
@ -411,9 +434,8 @@ public class SubConstructionUserFileServiceImpl extends ServiceImpl<SubConstruct
lqw.eq(ObjectUtils.isNotEmpty(teamId), SubConstructionUser::getTeamId, teamId); lqw.eq(ObjectUtils.isNotEmpty(teamId), SubConstructionUser::getTeamId, teamId);
lqw.eq(StringUtils.isNotBlank(typeOfWork), SubConstructionUser::getTypeOfWork, typeOfWork); lqw.eq(StringUtils.isNotBlank(typeOfWork), SubConstructionUser::getTypeOfWork, typeOfWork);
lqw.eq(StringUtils.isNotBlank(clock), SubConstructionUser::getClock, clock); lqw.eq(StringUtils.isNotBlank(clock), SubConstructionUser::getClock, clock);
if (CollUtil.isNotEmpty(userIdList)) { lqw.in(CollUtil.isNotEmpty(userIdList), SubConstructionUser::getId, userIdList);
lqw.in(SubConstructionUser::getId, userIdList); lqw.eq(StringUtils.isNotBlank(userRole), SubConstructionUser::getUserRole, userRole);
}
// 根据项目id获取黑名单施工人员 // 根据项目id获取黑名单施工人员
List<Long> blacklistUserIdList = constructionBlacklistService.lambdaQuery() List<Long> blacklistUserIdList = constructionBlacklistService.lambdaQuery()
.eq(BusConstructionBlacklist::getProjectId, projectId) .eq(BusConstructionBlacklist::getProjectId, projectId)
@ -451,28 +473,32 @@ public class SubConstructionUserFileServiceImpl extends ServiceImpl<SubConstruct
/** /**
* 递归扫描指定目录,找到 “姓名-Id” 格式的文件夹并解析 * 递归扫描指定目录,找到 “姓名-Id” 格式的文件夹并解析
*/ */
public void scanUserFolders(File root, List<SubConstructionUserFile> resultList) { public void scanUserFolders(File root, Map<String, Long> userMap, List<SubConstructionUserFile> resultList) {
if (root == null || !root.exists()) { if (root == null || !root.exists()) {
return; return;
} }
File[] files = root.listFiles(); File[] files = root.listFiles();
if (files == null) return; if (files == null) return;
for (File file : files) { for (File file : files) {
if (file.isDirectory()) { if (file.isDirectory()) {
// 判断是否为 “姓名-身份证号” 格式
// 判断是否符合 “姓名-数字ID” 格式 String folderName = file.getName();
if (file.getName().matches(".+-\\d+")) { int idx = folderName.lastIndexOf("-");
// 解析 UserId if (idx > 0) {
long userId = Long.parseLong(file.getName().replaceAll(".*-", "")); String idCard = folderName.substring(idx + 1);
parseUserDocFolder(file, userId, resultList); // 校验身份证
if (IdcardUtil.isValidCard(idCard)) {
// 根据身份证获取用户id
String encrypt = idCardEncryptorUtil.encrypt(idCard);
if (userMap.containsKey(encrypt)) {
Long userId = userMap.get(encrypt);
parseUserDocFolder(file, userId, resultList);
} else {
log.warn("未找到身份证为 {} 的施工人员", idCard);
}
}
} else { } else {
// 目录不是目标,继续递归查找 scanUserFolders(file, userMap, resultList);
scanUserFolders(file, resultList);
} }
} }
} }

View File

@ -3,10 +3,7 @@ package org.dromara.progress.controller;
import cn.dev33.satoken.annotation.SaIgnore; import cn.dev33.satoken.annotation.SaIgnore;
import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.LocalDateTimeUtil; import cn.hutool.core.date.LocalDateTimeUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.poi.ss.usermodel.*; import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.ss.util.CellRangeAddress;
@ -14,7 +11,6 @@ import org.apache.poi.ss.util.RegionUtil;
import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.dromara.common.core.domain.R; import org.dromara.common.core.domain.R;
import org.dromara.common.core.enums.FormatsType; import org.dromara.common.core.enums.FormatsType;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.DateUtils; import org.dromara.common.core.utils.DateUtils;
import org.dromara.common.core.utils.StringUtils; import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.web.core.BaseController; import org.dromara.common.web.core.BaseController;
@ -31,7 +27,6 @@ import org.dromara.progress.domain.vo.progresscategory.PgsProgressCategoryDayTot
import org.dromara.progress.domain.vo.progresscategory.PgsProgressCategoryDetailByDayVo; import org.dromara.progress.domain.vo.progresscategory.PgsProgressCategoryDetailByDayVo;
import org.dromara.progress.service.IPgsProcessDailyReportService; import org.dromara.progress.service.IPgsProcessDailyReportService;
import org.dromara.progress.service.IPgsProgressCategoryService; import org.dromara.progress.service.IPgsProgressCategoryService;
import org.dromara.progress.service.IPgsProgressPlanService;
import org.dromara.project.domain.BusProject; import org.dromara.project.domain.BusProject;
import org.dromara.project.service.IBusProjectService; import org.dromara.project.service.IBusProjectService;
import org.dromara.quality.domain.QltQualityInspection; import org.dromara.quality.domain.QltQualityInspection;
@ -40,19 +35,20 @@ import org.dromara.safety.domain.HseSafetyInspection;
import org.dromara.safety.service.IHseSafetyInspectionService; import org.dromara.safety.service.IHseSafetyInspectionService;
import org.dromara.system.domain.vo.SysOssVo; import org.dromara.system.domain.vo.SysOssVo;
import org.dromara.system.service.ISysOssService; import org.dromara.system.service.ISysOssService;
import org.springframework.scheduling.annotation.Async;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
import java.io.*; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL; import java.net.URL;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.*; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@Validated @Validated
@ -85,7 +81,7 @@ public class PgsReportExportController extends BaseController {
@SaIgnore @SaIgnore
@GetMapping("/dayReport") @GetMapping("/dayReport")
public R<String> getStreamData(ReportExportDto dto) { public R<String> getStreamData(ReportExportDto dto) {
String url = ""; String url;
LocalDate localDate = DateUtils.parseLocalDateTime(FormatsType.YYYY_MM_DD, dto.getDate()); LocalDate localDate = DateUtils.parseLocalDateTime(FormatsType.YYYY_MM_DD, dto.getDate());
PgsProcessDailyReport one = dailyReportService.lambdaQuery() PgsProcessDailyReport one = dailyReportService.lambdaQuery()
.eq(PgsProcessDailyReport::getReportDate, localDate) .eq(PgsProcessDailyReport::getReportDate, localDate)
@ -130,7 +126,7 @@ public class PgsReportExportController extends BaseController {
} }
} }
return R.ok(url); return R.ok("操作成功", url);
} }

View File

@ -1,22 +1,17 @@
package org.dromara.progress.domain.vo; package org.dromara.progress.domain.vo;
import java.time.LocalDate;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.dromara.progress.domain.PgsProcessDailyReport;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.annotation.ExcelProperty;
import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import io.github.linpeilie.annotations.AutoMapper; import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data; import lombok.Data;
import org.dromara.progress.domain.PgsProcessDailyReport;
import java.io.Serial; import java.io.Serial;
import java.io.Serializable; import java.io.Serializable;
import java.time.LocalDate;
import java.util.Date; import java.util.Date;
/** /**
* 进度日报视图对象 pgs_process_daily_report * 进度日报视图对象 pgs_process_daily_report
* *
@ -63,5 +58,9 @@ public class PgsProcessDailyReportVo implements Serializable {
@ExcelProperty(value = "下载路径") @ExcelProperty(value = "下载路径")
private String url; private String url;
/**
* 创建时间
*/
private Date createTime;
} }