Commit d75d7647 authored by huyuchen's avatar huyuchen

huych-入职确认信息编辑提交

parent 2b68dc4a
......@@ -136,25 +136,6 @@ public class TElectronicArchiveTaskController {
return R.ok(task);
}
/**
* 手动触发异步处理(用于重试)
*
* @param taskId 任务ID
* @return R
*/
@Operation(summary = "手动触发异步处理", description = "手动触发异步处理任务(用于重试失败的任务)")
@PostMapping("/retryProcess/{taskId}")
public R<?> retryProcess(@PathVariable("taskId") String taskId) {
TElectronicArchiveTask task = tElectronicArchiveTaskService.getById(taskId);
if (task == null) {
return R.failed("任务不存在");
}
// 只有生成中或失败的任务才能重试
// 这里可以根据需要增加失败状态
return importService.asyncProcessUpload(taskId);
}
/**
* 单个新增人员附件
* 前端先调用 /fileUpload/uploadArchiveFile 接口上传文件获取附件ID列表
......
......@@ -35,9 +35,8 @@ public interface ElectronicArchiveImportService {
* 第三步:异步处理上传
*
* @param taskId 任务ID
* @return 处理结果
*/
R<?> asyncProcessUpload(String taskId);
void asyncProcessUpload(String taskId);
/**
* 生成任务编号
......
......@@ -33,9 +33,11 @@ import com.yifu.cloud.plus.v1.yifu.common.security.util.SecurityUtils;
import com.yifu.cloud.plus.v1.yifu.insurances.constants.InsurancesConstants;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.support.SimpleValueWrapper;
import org.springframework.context.annotation.Lazy;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
......@@ -70,14 +72,22 @@ public class ElectronicArchiveImportServiceImpl implements ElectronicArchiveImpo
private final ArchivesDaprUtil archivesDaprUtil;
private final CacheManager cacheManager;
private final OSSUtil ossUtil;
private final SysConfigLimitMapper configLimitMapper;
/**
* 自注入代理对象,用于解决@Async注解在类内部调用时失效的问题
*
* @Lazy 延迟加载,避免循环依赖
*/
@Autowired
@Lazy
private ElectronicArchiveImportService self;
//初始化zip导入上限值
private int maxLimit = 1;
private AtomicInteger atomicInteger = new AtomicInteger(0);
private final SysConfigLimitMapper configLimitMapper;
/**
* 第一步:导入Excel模板文件
......@@ -95,7 +105,7 @@ public class ElectronicArchiveImportServiceImpl implements ElectronicArchiveImpo
ExcelUtil<ArchiveImportVO> util = new ExcelUtil<>(ArchiveImportVO.class);
List<ErrorMessage<ArchiveImportVO>> errorMessageList = new ArrayList<>();
// 将输入流转换为字节数组,以便后续上传到OSS
byte[] fileBytes;
try {
......@@ -104,7 +114,7 @@ public class ElectronicArchiveImportServiceImpl implements ElectronicArchiveImpo
log.error("读取文件流失败", e);
return R.failed("读取文件失败:" + e.getMessage());
}
try {
// 使用字节数组创建新的输入流用于Excel读取
InputStream excelInputStream = new java.io.ByteArrayInputStream(fileBytes);
......@@ -163,15 +173,15 @@ public class ElectronicArchiveImportServiceImpl implements ElectronicArchiveImpo
taskService.save(task);
// 保存任务表附件
saveTaskAttachment(task.getId(), fileName, inputStream, "task_file"+"/" + task.getId() + "_" + fileName);
saveTaskAttachment(task.getId(), fileName, inputStream, "task_file" + "/" + task.getId() + "_" + fileName);
// 上传文件到阿里云OSS根目录
uploadFileToOSS("task_file"+"/" + task.getId() + "_" + fileName, fileBytes);
uploadFileToOSS("task_file" + "/" + task.getId() + "_" + fileName, fileBytes);
// 建立任务和档案详情的关联关系
createTaskArchiveRelations(task.getId(), successList);
return R.ok(task.getId(),"全部校验通过");
return R.ok(task.getId(), "全部校验通过");
} catch (Exception e) {
log.error("导入Excel文件失败", e);
......@@ -188,7 +198,7 @@ public class ElectronicArchiveImportServiceImpl implements ElectronicArchiveImpo
TEmployeeInfo empInfo;
TSettleDomainSelectVo settleResult;
R<TEmployeeInfo> empResult;
Map<String,String> map = new HashMap<>();
Map<String, String> map = new HashMap<>();
List<String> deptNoList = new ArrayList<>();
......@@ -210,7 +220,7 @@ public class ElectronicArchiveImportServiceImpl implements ElectronicArchiveImpo
if (Common.isNotNull(user) && isCheck) {
if (Common.isEmpty(deptNoList) || !deptNoList.contains(data.getDeptNo())) {
ErrorMessage<ArchiveImportVO> errorMessage = new ErrorMessage<>(data.getRowIndex()
,InsurancesConstants.DEPT_NO_NOT_IN_USER_DEPT_LIST,data);
, InsurancesConstants.DEPT_NO_NOT_IN_USER_DEPT_LIST, data);
errorMessageList.add(errorMessage);
continue;
}
......@@ -219,7 +229,7 @@ public class ElectronicArchiveImportServiceImpl implements ElectronicArchiveImpo
String uniqueKey = data.getEmpIdcard() + "_" + data.getEmpName();
if (null != map.get(uniqueKey)) {
ErrorMessage<ArchiveImportVO> errorMessage = new ErrorMessage<>(data.getRowIndex()
,"第" + data.getRowIndex() + "行:姓名和身份证信息存在重复数据",data);
, "第" + data.getRowIndex() + "行:姓名和身份证信息存在重复数据", data);
errorMessageList.add(errorMessage);
continue;
} else {
......@@ -230,7 +240,7 @@ public class ElectronicArchiveImportServiceImpl implements ElectronicArchiveImpo
settleResult = archivesDaprUtil.selectDeptByNo(data.getDeptNo());
if (Common.isEmpty(settleResult) || Common.isEmpty(settleResult.getCustomerCode())) {
ErrorMessage<ArchiveImportVO> errorMessage = new ErrorMessage<>(data.getRowIndex()
,"第" + data.getRowIndex() + "行:项目编码[" + data.getDeptNo() + "]信息不存在",data);
, "第" + data.getRowIndex() + "行:项目编码[" + data.getDeptNo() + "]信息不存在", data);
errorMessageList.add(errorMessage);
continue;
}
......@@ -242,7 +252,7 @@ public class ElectronicArchiveImportServiceImpl implements ElectronicArchiveImpo
empResult = archivesDaprUtil.getTEmployeeInfoByIdcardAndName(vo);
if (empResult == null || empResult.getData() == null) {
ErrorMessage<ArchiveImportVO> errorMessage = new ErrorMessage<>(data.getRowIndex()
,"第" + data.getRowIndex() + "行:人员档案信息不存在",data);
, "第" + data.getRowIndex() + "行:人员档案信息不存在", data);
errorMessageList.add(errorMessage);
continue;
}
......@@ -271,12 +281,12 @@ public class ElectronicArchiveImportServiceImpl implements ElectronicArchiveImpo
detail.setStatus(ArchiveConstants.DETAIL_STATUS_DISABLED);
detail.setDeleteFlag(CommonConstants.ZERO_STRING);
// 设置档案所在地(需要从empInfo中获取)
detail.setFileProvince(empInfo.getFileProvince());
detail.setFileCity(empInfo.getFileCity());
detail.setFileTown(empInfo.getFileTown());
detail.setFileAddress(buildFileAddress(empInfo.getFileProvince(), empInfo.getFileCity(), empInfo.getFileTown()));
detailService.save(detail);
// 设置档案所在地(需要从empInfo中获取)
detail.setFileProvince(empInfo.getFileProvince());
detail.setFileCity(empInfo.getFileCity());
detail.setFileTown(empInfo.getFileTown());
detail.setFileAddress(buildFileAddress(empInfo.getFileProvince(), empInfo.getFileCity(), empInfo.getFileTown()));
detailService.save(detail);
}
successList.add(data);
......@@ -289,7 +299,7 @@ public class ElectronicArchiveImportServiceImpl implements ElectronicArchiveImpo
/**
* 保存任务表附件
*/
private void saveTaskAttachment(String taskId, String fileName, InputStream inputStream,String filePath) {
private void saveTaskAttachment(String taskId, String fileName, InputStream inputStream, String filePath) {
try {
TAttaInfo attaInfo = new TAttaInfo();
attaInfo.setAttaName(fileName);
......@@ -307,16 +317,16 @@ public class ElectronicArchiveImportServiceImpl implements ElectronicArchiveImpo
/**
* 上传文件到阿里云OSS
*
* @param fileName 文件名
*
* @param fileName 文件名
* @param fileBytes 文件字节数组
*/
private void uploadFileToOSS(String fileName, byte[] fileBytes) {
try {
// 使用字节数组创建输入流
InputStream ossInputStream = new java.io.ByteArrayInputStream(fileBytes);
// 上传到OSS根目录
ossUtil.uploadFileByStream(ossInputStream, fileName, "yf-hr-efile-source");
......@@ -328,22 +338,22 @@ public class ElectronicArchiveImportServiceImpl implements ElectronicArchiveImpo
/**
* 获取项目权限
*
* @author huych
* @param userId
* @return {@link List< String>}
* @author huych
*/
public List<String> getDeptNoList(String userId){
public List<String> getDeptNoList(String userId) {
List<String> deptList = new ArrayList<>(16);
try{
try {
R<TSettleDomainListVo> settleDomainList = archivesDaprUtil.getSettleDomainIdsByUserId(userId);
if(Common.isNotNull(settleDomainList) && settleDomainList.getCode() == CommonConstants.SUCCESS){
if (Common.isNotNull(settleDomainList) && settleDomainList.getCode() == CommonConstants.SUCCESS) {
TSettleDomainListVo data = settleDomainList.getData();
if (Optional.ofNullable(data).isPresent()){
if (Optional.ofNullable(data).isPresent()) {
deptList = data.getDeptNos();
}
}
}catch (Exception e){
log.error("查询项目信息出错:"+e);
} catch (Exception e) {
log.error("查询项目信息出错:" + e);
}
return deptList;
}
......@@ -359,7 +369,7 @@ public class ElectronicArchiveImportServiceImpl implements ElectronicArchiveImpo
String uniqueKey = data.getEmpIdcard() + "_" + data.getEmpName() + "_" + data.getDeptNo();
uniqueMap.put(uniqueKey, data);
}
// 为每个唯一的人员创建关联关系
for (ArchiveImportVO data : uniqueMap.values()) {
// 查找对应的电子档案明细
......@@ -370,7 +380,7 @@ public class ElectronicArchiveImportServiceImpl implements ElectronicArchiveImpo
.eq(TElectronicArchiveDetail::getDeleteFlag, CommonConstants.ZERO_STRING)
.last(CommonConstants.LAST_ONE_SQL);
TElectronicArchiveDetail detail = detailService.getOne(wrapper);
if (detail != null) {
// 创建关联记录
TTaskArchiveRelation relation = new TTaskArchiveRelation();
......@@ -420,7 +430,7 @@ public class ElectronicArchiveImportServiceImpl implements ElectronicArchiveImpo
// 3. 校验同时上传任务数
maxLimit = configLimitMapper.getSysConfigLimitByKey("UPDOLOAD_MAX_LIMIT");
if (atomicInteger.incrementAndGet() > maxLimit){
if (atomicInteger.incrementAndGet() > maxLimit) {
atomicInteger.decrementAndGet();
return R.failed("有其他客服正在上传中,请5分钟后重试");
}
......@@ -436,7 +446,7 @@ public class ElectronicArchiveImportServiceImpl implements ElectronicArchiveImpo
if (!tempDir.exists() && !tempDir.mkdirs()) {
throw new IOException("Failed to create directory: " + tempDirPath);
}
tempZipFile = new File(tempDir, file.getOriginalFilename());
file.transferTo(tempZipFile);
......@@ -451,8 +461,8 @@ public class ElectronicArchiveImportServiceImpl implements ElectronicArchiveImpo
zipAtta.setAttaSrc(tempZipFile.getAbsolutePath()); // 临时存储文件路径
attaInfoService.save(zipAtta);
// 调用异步处理
asyncProcessUpload(taskId);
// 调用异步处理(通过self代理对象调用,使@Async生效)
self.asyncProcessUpload(taskId);
return R.ok("ZIP文件提交成功,正在处理中");
......@@ -475,7 +485,7 @@ public class ElectronicArchiveImportServiceImpl implements ElectronicArchiveImpo
*/
@Override
@Async
public R<?> asyncProcessUpload(String taskId) {
public void asyncProcessUpload(String taskId) {
List<ArchiveFeedbackVO> feedbackList = new ArrayList<>();
File tempDir = null;
......@@ -485,7 +495,8 @@ public class ElectronicArchiveImportServiceImpl implements ElectronicArchiveImpo
// 查询任务及关联的明细
TElectronicArchiveTask task = taskService.getById(taskId);
if (task == null) {
return R.failed("任务不存在");
log.error("任务不存在,任务ID:{}", taskId);
return;
}
// 查询ZIP附件(从附件导入中获取)
......@@ -495,21 +506,24 @@ public class ElectronicArchiveImportServiceImpl implements ElectronicArchiveImpo
if (CollUtil.isEmpty(zipAttas)) {
updateTaskStatus(task, ArchiveConstants.TASK_STATUS_NOT_UPLOADED);
return R.failed("ZIP附件不存在");
log.error("ZIP附件不存在,任务ID:{}", taskId);
return;
}
TAttaInfo zipAtta = zipAttas.get(0);
// 从附件记录中获取ZIP文件路径
if (StrUtil.isBlank(zipAtta.getAttaSrc())) {
updateTaskStatus(task, ArchiveConstants.TASK_STATUS_NOT_UPLOADED);
return R.failed("ZIP文件路径为空");
log.error("ZIP文件路径为空,任务ID:{}", taskId);
return;
}
zipSourceFile = new File(zipAtta.getAttaSrc());
if (!zipSourceFile.exists()) {
updateTaskStatus(task, ArchiveConstants.TASK_STATUS_NOT_UPLOADED);
return R.failed("ZIP文件不存在");
log.error("ZIP文件不存在,任务ID:{},文件路径:{}", taskId, zipAtta.getAttaSrc());
return;
}
// 获取任务关联的明细
......@@ -518,7 +532,8 @@ public class ElectronicArchiveImportServiceImpl implements ElectronicArchiveImpo
if (CollUtil.isEmpty(relations)) {
updateTaskStatus(task, ArchiveConstants.TASK_STATUS_NOT_UPLOADED);
return R.failed("任务没有关联的明细数据");
log.error("任务没有关联的明细数据,任务ID:{}", taskId);
return;
}
List<String> detailIds = relations.stream()
......@@ -527,138 +542,139 @@ public class ElectronicArchiveImportServiceImpl implements ElectronicArchiveImpo
List<TElectronicArchiveDetail> details = detailService.listByIds(detailIds);
// 创建临时目录用于解压ZIP文件
String tempDirPath = System.getProperty("java.io.tmpdir") + File.separator + "archive_file" + File.separator
+ System.currentTimeMillis() + File.separator;
tempDir = new File(tempDirPath);
if (!tempDir.exists() && !tempDir.mkdirs()) {
updateTaskStatus(task, ArchiveConstants.TASK_STATUS_NOT_UPLOADED);
return R.failed("创建临时目录失败");
}
// 解压ZIP文件
try {
// 验证ZIP文件是否可读
if (!zipSourceFile.canRead()) {
log.error("ZIP文件不可读,路径:{}", zipSourceFile.getAbsolutePath());
// 创建临时目录用于解压ZIP文件
String tempDirPath = System.getProperty("java.io.tmpdir") + File.separator + "archive_file" + File.separator
+ System.currentTimeMillis() + File.separator;
tempDir = new File(tempDirPath);
if (!tempDir.exists() && !tempDir.mkdirs()) {
updateTaskStatus(task, ArchiveConstants.TASK_STATUS_NOT_UPLOADED);
return R.failed("ZIP文件不可读");
log.error("创建临时目录失败,任务ID:{},目录路径:{}", taskId, tempDirPath);
return;
}
// 使用指定字符集解压(支持中文文件名)
// Windows系统通常使用GBK编码,Linux使用UTF-8
// 解压ZIP文件
try {
ZipUtil.unzip(zipSourceFile, tempDir, java.nio.charset.Charset.forName("GBK"));
} catch (Exception e1) {
// 如果GBK失败,尝试UTF-8
ZipUtil.unzip(zipSourceFile, tempDir, java.nio.charset.StandardCharsets.UTF_8);
// 验证ZIP文件是否可读
if (!zipSourceFile.canRead()) {
log.error("ZIP文件不可读,路径:{}", zipSourceFile.getAbsolutePath());
updateTaskStatus(task, ArchiveConstants.TASK_STATUS_NOT_UPLOADED);
return;
}
// 使用指定字符集解压(支持中文文件名)
// Windows系统通常使用GBK编码,Linux使用UTF-8
try {
ZipUtil.unzip(zipSourceFile, tempDir, java.nio.charset.Charset.forName("GBK"));
} catch (Exception e1) {
// 如果GBK失败,尝试UTF-8
ZipUtil.unzip(zipSourceFile, tempDir, java.nio.charset.StandardCharsets.UTF_8);
}
} catch (Exception e) {
log.error("解压ZIP文件失败,任务ID:{},ZIP路径:{},临时目录:{}",
taskId, zipSourceFile.getAbsolutePath(), tempDirPath, e);
updateTaskStatus(task, ArchiveConstants.TASK_STATUS_NOT_UPLOADED);
return;
}
} catch (Exception e) {
log.error("解压ZIP文件失败,任务ID:{},ZIP路径:{},临时目录:{}",
taskId, zipSourceFile.getAbsolutePath(), tempDirPath, e);
updateTaskStatus(task, ArchiveConstants.TASK_STATUS_NOT_UPLOADED);
return R.failed("解压ZIP文件失败:" + e.getMessage() + ",请检查ZIP文件是否完整且格式正确");
}
// 获取ZIP包的根目录(第一级目录,身份证+姓名目录)
File[] zipRootDirs = tempDir.listFiles(File::isDirectory);
Map<String, List<File>> zipDirMap = new HashMap<>();
if (zipRootDirs != null && zipRootDirs.length > 0) {
// 将ZIP中的目录按照 身份证_姓名 建立映射,支持同一个人有多个文件夹
for (File personDir : zipRootDirs) {
String dirName = personDir.getName();
Map<String, String> idNameMap = parseIdCardAndName(dirName);
if (!idNameMap.isEmpty() && idNameMap.containsKey("idCard") && idNameMap.containsKey("name")) {
String uniqueKey = idNameMap.get("idCard") + "_" + idNameMap.get("name");
// 使用List存储,支持同一个人有多个文件夹
zipDirMap.computeIfAbsent(uniqueKey, k -> new ArrayList<>()).add(personDir);
// 获取ZIP包的根目录(第一级目录,身份证+姓名目录)
File[] zipRootDirs = tempDir.listFiles(File::isDirectory);
Map<String, List<File>> zipDirMap = new HashMap<>();
if (zipRootDirs != null && zipRootDirs.length > 0) {
// 将ZIP中的目录按照 身份证_姓名 建立映射,支持同一个人有多个文件夹
for (File personDir : zipRootDirs) {
String dirName = personDir.getName();
Map<String, String> idNameMap = parseIdCardAndName(dirName);
if (!idNameMap.isEmpty() && idNameMap.containsKey("idCard") && idNameMap.containsKey("name")) {
String uniqueKey = idNameMap.get("idCard") + "_" + idNameMap.get("name");
// 使用List存储,支持同一个人有多个文件夹
zipDirMap.computeIfAbsent(uniqueKey, k -> new ArrayList<>()).add(personDir);
}
}
}
}
// 按照第一步Excel导入的明细列表生成反馈表
// 用于记录每个人员的处理结果(一个人可能有多个资料类型)
Map<String, List<String>> personMaterialTypesMap = new HashMap<>();
Map<String, String> personProcessResultMap = new HashMap<>();
Map<String, String> personFailReasonMap = new HashMap<>();
// 遍历第一步导入的所有明细
for (TElectronicArchiveDetail detail : details) {
String uniqueKey = detail.getEmpIdcard() + "_" + detail.getEmpName();
// 检查ZIP中是否存在该人员的目录
List<File> personDirs = zipDirMap.get(uniqueKey);
if (personDirs == null || personDirs.isEmpty()) {
// ZIP中没有该人员的文件夹,记录为跳过
personProcessResultMap.put(uniqueKey, ArchiveConstants.PROCESS_RESULT_SKIP);
personFailReasonMap.put(uniqueKey, "压缩包中未找到对应文件夹,跳过处理");
personMaterialTypesMap.put(uniqueKey, new ArrayList<>());
} else {
// ZIP中存在该人员的文件夹,处理其附件(可能有多个文件夹)
List<String> materialTypes = new ArrayList<>();
List<String> failReasons = new ArrayList<>();
// 遍历该人员的所有文件夹
for (File personDir : personDirs) {
processPersonDirectoryWithResult(personDir, detail, materialTypes, failReasons, taskId);
}
personMaterialTypesMap.put(uniqueKey, materialTypes);
// 判断处理结果
if (materialTypes.isEmpty()) {
// 没有成功上传任何资料类型,记录为失败
personProcessResultMap.put(uniqueKey, ArchiveConstants.PROCESS_RESULT_FAILED);
if (failReasons.isEmpty()) {
personFailReasonMap.put(uniqueKey, "文件夹为空或格式不符");
} else {
personFailReasonMap.put(uniqueKey, String.join(";", failReasons));
}
// 按照第一步Excel导入的明细列表生成反馈表
// 用于记录每个人员的处理结果(一个人可能有多个资料类型)
Map<String, List<String>> personMaterialTypesMap = new HashMap<>();
Map<String, String> personProcessResultMap = new HashMap<>();
Map<String, String> personFailReasonMap = new HashMap<>();
// 遍历第一步导入的所有明细
for (TElectronicArchiveDetail detail : details) {
String uniqueKey = detail.getEmpIdcard() + "_" + detail.getEmpName();
// 检查ZIP中是否存在该人员的目录
List<File> personDirs = zipDirMap.get(uniqueKey);
if (personDirs == null || personDirs.isEmpty()) {
// ZIP中没有该人员的文件夹,记录为跳过
personProcessResultMap.put(uniqueKey, ArchiveConstants.PROCESS_RESULT_SKIP);
personFailReasonMap.put(uniqueKey, "压缩包中未找到对应文件夹,跳过处理");
personMaterialTypesMap.put(uniqueKey, new ArrayList<>());
} else {
// 有成功上传的资料类型
if (failReasons.isEmpty()) {
personProcessResultMap.put(uniqueKey, ArchiveConstants.PROCESS_RESULT_SUCCESS);
personFailReasonMap.put(uniqueKey, "");
} else {
// 部分成功,部分失败
// ZIP中存在该人员的文件夹,处理其附件(可能有多个文件夹)
List<String> materialTypes = new ArrayList<>();
List<String> failReasons = new ArrayList<>();
// 遍历该人员的所有文件夹
for (File personDir : personDirs) {
processPersonDirectoryWithResult(personDir, detail, materialTypes, failReasons, taskId);
}
personMaterialTypesMap.put(uniqueKey, materialTypes);
// 判断处理结果
if (materialTypes.isEmpty()) {
// 没有成功上传任何资料类型,记录为失败
personProcessResultMap.put(uniqueKey, ArchiveConstants.PROCESS_RESULT_FAILED);
personFailReasonMap.put(uniqueKey, String.join(";", failReasons));
if (failReasons.isEmpty()) {
personFailReasonMap.put(uniqueKey, "文件夹为空或格式不符");
} else {
personFailReasonMap.put(uniqueKey, String.join(";", failReasons));
}
} else {
// 有成功上传的资料类型
if (failReasons.isEmpty()) {
personProcessResultMap.put(uniqueKey, ArchiveConstants.PROCESS_RESULT_SUCCESS);
personFailReasonMap.put(uniqueKey, "");
} else {
// 部分成功,部分失败
personProcessResultMap.put(uniqueKey, ArchiveConstants.PROCESS_RESULT_FAILED);
personFailReasonMap.put(uniqueKey, String.join(";", failReasons));
}
}
}
}
}
// 按照第一步Excel的顺序生成反馈表
for (TElectronicArchiveDetail detail : details) {
String uniqueKey = detail.getEmpIdcard() + "_" + detail.getEmpName();
ArchiveFeedbackVO feedback = new ArchiveFeedbackVO();
feedback.setEmpName(detail.getEmpName());
feedback.setEmpIdcard(detail.getEmpIdcard());
feedback.setDeptNo(detail.getDeptNo());
feedback.setDeptName(detail.getDeptName());
// 设置资料类型(多个用逗号拼接)
List<String> materialTypes = personMaterialTypesMap.get(uniqueKey);
if (materialTypes != null && !materialTypes.isEmpty()) {
feedback.setMaterialType(String.join(",", materialTypes));
} else {
feedback.setMaterialType("");
// 按照第一步Excel的顺序生成反馈表
for (TElectronicArchiveDetail detail : details) {
String uniqueKey = detail.getEmpIdcard() + "_" + detail.getEmpName();
ArchiveFeedbackVO feedback = new ArchiveFeedbackVO();
feedback.setEmpName(detail.getEmpName());
feedback.setEmpIdcard(detail.getEmpIdcard());
feedback.setDeptNo(detail.getDeptNo());
feedback.setDeptName(detail.getDeptName());
// 设置资料类型(多个用逗号拼接)
List<String> materialTypes = personMaterialTypesMap.get(uniqueKey);
if (materialTypes != null && !materialTypes.isEmpty()) {
feedback.setMaterialType(String.join(",", materialTypes));
} else {
feedback.setMaterialType("");
}
feedback.setProcessResult(personProcessResultMap.get(uniqueKey));
feedback.setFailReason(personFailReasonMap.get(uniqueKey));
feedbackList.add(feedback);
}
feedback.setProcessResult(personProcessResultMap.get(uniqueKey));
feedback.setFailReason(personFailReasonMap.get(uniqueKey));
feedbackList.add(feedback);
}
// 处理完成,更新任务状态
task.setStatus(ArchiveConstants.TASK_STATUS_GENERATED);
taskService.updateById(task);
// 处理完成,更新任务状态
task.setStatus(ArchiveConstants.TASK_STATUS_GENERATED);
taskService.updateById(task);
// 生成反馈表
generateFeedbackExcel(task, feedbackList);
return R.ok("处理完成");
// 生成反馈表
generateFeedbackExcel(task, feedbackList);
log.info("异步任务处理完成,任务ID:{}", taskId);
} catch (Exception e) {
log.error("异步处理任务失败,任务ID:{}", taskId, e);
......@@ -667,7 +683,6 @@ public class ElectronicArchiveImportServiceImpl implements ElectronicArchiveImpo
if (task != null) {
updateTaskStatus(task, ArchiveConstants.TASK_STATUS_NOT_UPLOADED);
}
return R.failed("处理失败:" + e.getMessage());
} finally {
// 清理临时解压目录
if (tempDir != null && tempDir.exists()) {
......@@ -676,7 +691,7 @@ public class ElectronicArchiveImportServiceImpl implements ElectronicArchiveImpo
} catch (Exception e) {
}
}
// 清理上传的ZIP文件
if (zipSourceFile != null && zipSourceFile.exists()) {
try {
......@@ -823,15 +838,15 @@ public class ElectronicArchiveImportServiceImpl implements ElectronicArchiveImpo
/**
* 处理单个人员目录(返回处理结果,用于按Excel顺序生成反馈表)
*
* @param personDir 人员目录
* @param detail 电子档案明细
*
* @param personDir 人员目录
* @param detail 电子档案明细
* @param materialTypes 成功处理的资料类型列表(输出参数)
* @param failReasons 失败原因列表(输出参数)
* @param taskId 任务ID
* @param failReasons 失败原因列表(输出参数)
* @param taskId 任务ID
*/
private void processPersonDirectoryWithResult(File personDir, TElectronicArchiveDetail detail,
List<String> materialTypes, List<String> failReasons, String taskId) {
List<String> materialTypes, List<String> failReasons, String taskId) {
// 处理第三级目录(资料类型或直接是文件)
File[] subFiles = personDir.listFiles();
if (subFiles == null || subFiles.length == 0) {
......@@ -842,7 +857,7 @@ public class ElectronicArchiveImportServiceImpl implements ElectronicArchiveImpo
// 用于记录该人员的所有资料类型
Set<String> materialTypesSet = new HashSet<>();
// 收集直接文件(作为存量类型处理)
List<File> stockFiles = new ArrayList<>();
......@@ -866,7 +881,7 @@ public class ElectronicArchiveImportServiceImpl implements ElectronicArchiveImpo
// 不是有效的资料类型,跳过
continue;
}
// 按资料类型分组处理目录下的所有文件
String result = processMaterialTypeDirectoryWithResult(subFile, detail, materialType, taskId);
if ("success".equals(result)) {
......@@ -879,7 +894,7 @@ public class ElectronicArchiveImportServiceImpl implements ElectronicArchiveImpo
stockFiles.add(subFile);
}
}
// 统一处理所有直接文件(存量类型)
if (!stockFiles.isEmpty()) {
String result = processMaterialTypeFilesWithResult(stockFiles, detail, ArchiveConstants.MATERIAL_TYPE_STOCK, taskId);
......@@ -902,31 +917,31 @@ public class ElectronicArchiveImportServiceImpl implements ElectronicArchiveImpo
* 同一资料类型下的所有文件作为一个整体处理:先验证所有文件,全部通过后才统一上传
*/
private void processMaterialTypeDirectory(File directory, TElectronicArchiveDetail detail,
String materialType, List<ArchiveFeedbackVO> feedbackList,
Set<String> materialTypes, String taskId) {
String materialType, List<ArchiveFeedbackVO> feedbackList,
Set<String> materialTypes, String taskId) {
// 收集该资料类型目录下的所有文件(递归收集子目录中的文件)
List<File> allFiles = new ArrayList<>();
collectAllFiles(directory, allFiles);
if (allFiles.isEmpty()) {
// 文件夹为空
ArchiveFeedbackVO feedback = createFeedbackVO(detail, materialType,
ArchiveFeedbackVO feedback = createFeedbackVO(detail, materialType,
ArchiveConstants.PROCESS_RESULT_FAILED, "文件夹为空");
feedbackList.add(feedback);
return;
}
// 统一处理该资料类型下的所有文件
processMaterialTypeFiles(allFiles, detail, materialType, feedbackList, materialTypes, taskId);
}
/**
* 按资料类型处理目录下的所有文件(返回处理结果)
*
* @param directory 资料类型目录
* @param detail 电子档案明细
*
* @param directory 资料类型目录
* @param detail 电子档案明细
* @param materialType 资料类型
* @param taskId 任务ID
* @param taskId 任务ID
* @return "success" 表示成功,其他表示失败原因
*/
private String processMaterialTypeDirectoryWithResult(File directory, TElectronicArchiveDetail detail,
......@@ -934,15 +949,15 @@ public class ElectronicArchiveImportServiceImpl implements ElectronicArchiveImpo
// 收集该资料类型目录下的所有文件(递归收集子目录中的文件)
List<File> allFiles = new ArrayList<>();
collectAllFiles(directory, allFiles);
if (allFiles.isEmpty()) {
return "文件夹为空";
}
// 统一处理该资料类型下的所有文件
return processMaterialTypeFilesWithResult(allFiles, detail, materialType, taskId);
}
/**
* 递归收集目录下的所有文件
*/
......@@ -951,7 +966,7 @@ public class ElectronicArchiveImportServiceImpl implements ElectronicArchiveImpo
if (files == null || files.length == 0) {
return;
}
for (File file : files) {
if (file.isDirectory()) {
// 递归收集子目录中的文件
......@@ -961,7 +976,7 @@ public class ElectronicArchiveImportServiceImpl implements ElectronicArchiveImpo
}
}
}
/**
* 统一处理同一资料类型下的所有文件
* 1. 先验证所有文件格式,如果有一个失败则整体失败
......@@ -969,68 +984,68 @@ public class ElectronicArchiveImportServiceImpl implements ElectronicArchiveImpo
* 3. 只生成一条反馈记录
*/
private void processMaterialTypeFiles(List<File> files, TElectronicArchiveDetail detail,
String materialType, List<ArchiveFeedbackVO> feedbackList,
Set<String> materialTypes, String taskId) {
String materialType, List<ArchiveFeedbackVO> feedbackList,
Set<String> materialTypes, String taskId) {
// 第一步:验证所有文件格式
for (File file : files) {
String fileName = file.getName();
if (checkFileFormat(fileName)) {
// 有文件格式不符,整体失败,不再处理后续文件
ArchiveFeedbackVO feedback = createFeedbackVO(detail, materialType,
ArchiveConstants.PROCESS_RESULT_FAILED,
ArchiveFeedbackVO feedback = createFeedbackVO(detail, materialType,
ArchiveConstants.PROCESS_RESULT_FAILED,
"文件格式不符,文件格式需为gif|jpg|jpeg|png|bmp|xls|xlsx|csv|pdf|docx|doc|m4a|mp3|zip|rar|txt:" + fileName);
feedbackList.add(feedback);
return;
}
}
// 第二步:所有文件格式验证通过,统一上传到阿里云
try {
// 构建OSS目录路径
String ossDirectory = buildOssDirectory(detail, materialType);
// 依次上传每个文件
for (File file : files) {
String fileName = file.getName();
// 转换为MultipartFile
MultipartFile multipartFile = fileToMultipartFile(file);
if (multipartFile == null) {
// 文件转换失败,整体失败
ArchiveFeedbackVO feedback = createFeedbackVO(detail, materialType,
ArchiveFeedbackVO feedback = createFeedbackVO(detail, materialType,
ArchiveConstants.PROCESS_RESULT_FAILED, "文件转换失败:" + fileName);
feedbackList.add(feedback);
return;
}
// 上传文件到阿里云OSS,uploadFileReturnAtta会自动生成TAttaInfo记录
R<TAttaInfo> uploadResult = fileUploadService.uploadFileReturnAtta(
multipartFile,
multipartFile,
ossDirectory,
CommonConstants.FOUR_STRING,
detail.getId(),
taskId
);
if (!R.isSuccess(uploadResult)) {
// 上传失败,整体失败
ArchiveFeedbackVO feedback = createFeedbackVO(detail, materialType,
ArchiveConstants.PROCESS_RESULT_FAILED,
ArchiveFeedbackVO feedback = createFeedbackVO(detail, materialType,
ArchiveConstants.PROCESS_RESULT_FAILED,
"文件上传失败:" + fileName + ",原因:" + (uploadResult != null ? uploadResult.getMsg() : "未知错误"));
feedbackList.add(feedback);
return;
}
}
// 第三步:所有文件上传成功,记录资料类型并生成成功反馈
materialTypes.add(materialType);
ArchiveFeedbackVO feedback = createFeedbackVO(detail, materialType,
ArchiveFeedbackVO feedback = createFeedbackVO(detail, materialType,
ArchiveConstants.PROCESS_RESULT_SUCCESS, "");
feedbackList.add(feedback);
} catch (Exception e) {
log.error("上传文件失败,资料类型:{},电子档案详情ID:{},任务ID:{}", materialType, detail.getId(), taskId, e);
ArchiveFeedbackVO feedback = createFeedbackVO(detail, materialType,
ArchiveFeedbackVO feedback = createFeedbackVO(detail, materialType,
ArchiveConstants.PROCESS_RESULT_FAILED, "文件上传异常,原因:" + e.getMessage());
feedbackList.add(feedback);
}
......@@ -1038,11 +1053,11 @@ public class ElectronicArchiveImportServiceImpl implements ElectronicArchiveImpo
/**
* 统一处理同一资料类型下的所有文件(返回处理结果)
*
* @param files 文件列表
* @param detail 电子档案明细
*
* @param files 文件列表
* @param detail 电子档案明细
* @param materialType 资料类型
* @param taskId 任务ID
* @param taskId 任务ID
* @return "success" 表示成功,其他表示失败原因
*/
private String processMaterialTypeFilesWithResult(List<File> files, TElectronicArchiveDetail detail,
......@@ -1055,41 +1070,41 @@ public class ElectronicArchiveImportServiceImpl implements ElectronicArchiveImpo
return "文件格式不符,文件格式需为gif|jpg|jpeg|png|bmp|xls|xlsx|csv|pdf|docx|doc|m4a|mp3|zip|rar|txt:" + fileName;
}
}
// 第二步:所有文件格式验证通过,统一上传到阿里云
try {
// 构建OSS目录路径
String ossDirectory = buildOssDirectory(detail, materialType);
// 依次上传每个文件
for (File file : files) {
String fileName = file.getName();
// 转换为MultipartFile
MultipartFile multipartFile = fileToMultipartFile(file);
if (multipartFile == null) {
// 文件转换失败,整体失败
return "文件转换失败:" + fileName;
}
// 上传文件到阿里云OSS,uploadFileReturnAtta会自动生成TAttaInfo记录
R<TAttaInfo> uploadResult = fileUploadService.uploadFileReturnAtta(
multipartFile,
multipartFile,
ossDirectory,
CommonConstants.FOUR_STRING,
detail.getId(),
taskId
);
if (!R.isSuccess(uploadResult)) {
// 上传失败,整体失败
return "文件上传失败:" + fileName + ",原因:" + (uploadResult != null ? uploadResult.getMsg() : "未知错误");
}
}
// 第三步:所有文件上传成功
return "success";
} catch (Exception e) {
log.error("上传文件失败,资料类型:{},电子档案详情ID:{},任务ID:{}", materialType, detail.getId(), taskId, e);
return "文件上传异常,原因:" + e.getMessage();
......@@ -1102,7 +1117,7 @@ public class ElectronicArchiveImportServiceImpl implements ElectronicArchiveImpo
*/
private String buildOssDirectory(TElectronicArchiveDetail detail, String materialType) {
// 目录格式:项目编码-姓名-身份证号/资料类型
return detail.getDeptNo() + "-" + detail.getEmpName() + "-" + detail.getEmpIdcard() +
return detail.getDeptNo() + "-" + detail.getEmpName() + "-" + detail.getEmpIdcard() +
"/" + materialType;
}
......@@ -1194,7 +1209,7 @@ public class ElectronicArchiveImportServiceImpl implements ElectronicArchiveImpo
try {
// 创建临时文件
String tempFilePath = System.getProperty("java.io.tmpdir") + File.separator +
String tempFilePath = System.getProperty("java.io.tmpdir") + File.separator +
task.getTaskCode() + "结果反馈表" + ".xlsx";
File feedbackFile = new File(tempFilePath);
......@@ -1534,13 +1549,13 @@ public class ElectronicArchiveImportServiceImpl implements ElectronicArchiveImpo
detail.setMaterialType(materialType);
detail.setStatus(ArchiveConstants.DETAIL_STATUS_ENABLED);
detail.setDeleteFlag(CommonConstants.ZERO_STRING);
detail.setFileProvince(empInfo.getFileProvince());
detail.setFileCity(empInfo.getFileCity());
detail.setFileTown(empInfo.getFileTown());
detail.setFileAddress(buildFileAddress(empInfo.getFileProvince(), empInfo.getFileCity(), empInfo.getFileTown()));
detailService.save(detail);
detail.setFileProvince(empInfo.getFileProvince());
detail.setFileCity(empInfo.getFileCity());
detail.setFileTown(empInfo.getFileTown());
detail.setFileAddress(buildFileAddress(empInfo.getFileProvince(), empInfo.getFileCity(), empInfo.getFileTown()));
detailService.save(detail);
} else {
} else {
// 存在则更新资料类型(追加)
Set<String> existTypes = new HashSet<>();
if (StrUtil.isNotBlank(detail.getMaterialType())) {
......@@ -1611,10 +1626,10 @@ public class ElectronicArchiveImportServiceImpl implements ElectronicArchiveImpo
/**
* 构建档案所在地地址字符串
* 格式:安徽省/合肥市 或 安徽省/合肥市/庐阳区
*
*
* @param provinceCode 省代码
* @param cityCode 市代码
* @param townCode 区代码
* @param cityCode 市代码
* @param townCode 区代码
* @return 档案所在地地址字符串
*/
private String buildFileAddress(Integer provinceCode, Integer cityCode, Integer townCode) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment