Commit 071845e2 authored by huyuchen's avatar huyuchen

huych-电子档案批量导入第三次提交

parent 20ef390d
......@@ -141,4 +141,33 @@ public class TElectronicArchiveDetailController {
tElectronicArchiveDetailService.selectedExportArchives(requestList, response);
}
/**
* 根据查询条件导出电子档案
* <p>
* 功能说明:
* 1. 根据查询条件(姓名、身份证、项目编码、项目名称、客户名称、客户编码、资料类型、档案所在地等)查询电子档案明细
* 2. 导出查询结果中所有人员的电子档案附件
* 3. 导出格式与批量下载功能保持一致
* 4. 一级文件夹:项目编码-姓名-身份证
* 5. 二级文件夹:资料类型,该文件夹下为具体附件
* 6. 压缩包命名规则为:电子档案条件导出_时间戳.zip
* 7. 压缩包中包含:所有人员的项目编码-姓名-身份证号的文件夹 和 一个结果反馈表(同级)
* 8. 只导出TAttaInfo表中status为可用(0)的附件
* </p>
*
* @param searchVo 查询条件
* @param response HTTP响应
* @author huych
* @date 2025-12-30
*/
@Operation(summary = "根据查询条件导出电子档案", description = "根据查询条件导出电子档案,支持姓名、身份证、项目、客户、资料类型等条件")
@PostMapping("/exportByCondition")
public void exportArchivesByCondition(
@RequestBody TElectronicArchiveDetailSearchVo searchVo,
HttpServletResponse response) {
YifuUser user = SecurityUtils.getUser();
menuUtil.setAuthSql(user, searchVo);
tElectronicArchiveDetailService.exportArchivesByCondition(searchVo, response);
}
}
......@@ -55,4 +55,11 @@ public interface TElectronicArchiveDetailService extends IService<TElectronicArc
*/
void selectedExportArchives(List<ArchiveSelectedExportRequestVO> requestList, HttpServletResponse response);
/**
* 根据查询条件导出电子档案
* @param searchVo 查询条件
* @param response HTTP响应
*/
void exportArchivesByCondition(TElectronicArchiveDetailSearchVo searchVo, HttpServletResponse response);
}
......@@ -1019,4 +1019,306 @@ public class TElectronicArchiveDetailServiceImpl extends ServiceImpl<TElectronic
}
return false;
}
/**
* 根据查询条件导出电子档案
* <p>
* 功能说明:
* 1. 根据查询条件查询符合条件的电子档案明细列表
* 2. 导出所有查询结果的电子档案附件
* 3. 导出格式与批量下载功能保持一致
* 4. 一级文件夹:项目编码-姓名-身份证
* 5. 二级文件夹:资料类型,该文件夹下为具体附件
* 6. 压缩包命名规则为:电子档案条件导出_时间戳.zip
* 7. 只导出status为可用(1)的明细和可用(0)的附件
* </p>
*
* @param searchVo 查询条件
* @param response HTTP响应
* @author huych
* @date 2025-12-30
*/
@Override
public void exportArchivesByCondition(TElectronicArchiveDetailSearchVo searchVo, HttpServletResponse response) {
// 反馈列表
List<ArchiveDownloadFeedbackVO> feedbackList = new ArrayList<>();
// 用于存储需要导出的档案及其附件
Map<String, ArchiveDownloadInfo> downloadMap = new LinkedHashMap<>();
try {
// 1. 根据查询条件查询电子档案明细列表
initSearchVo(searchVo);
// 构建查询条件
LambdaQueryWrapper<TElectronicArchiveDetail> wrapper = buildQueryWrapper(searchVo);
// 查询符合条件的档案明细列表
List<TElectronicArchiveDetail> detailList = baseMapper.selectList(wrapper);
// 2. 检查是否有查询结果
if (CollUtil.isEmpty(detailList)) {
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write("{\"code\":1,\"msg\":\"未找到符合条件的电子档案\"}");
return;
}
log.info("根据查询条件找到{}条电子档案明细,开始准备导出", detailList.size());
// 3. 遍历每个明细,准备下载信息
for (TElectronicArchiveDetail detail : detailList) {
try {
prepareExportByDetail(detail, downloadMap, feedbackList);
} catch (Exception e) {
log.error("准备导出档案失败,明细ID:{},姓名:{},身份证:{}",
detail.getId(), detail.getEmpName(), detail.getEmpIdcard(), e);
feedbackList.add(createExportFeedbackVO(detail, "系统异常:" + e.getMessage()));
}
}
// 4. 检查是否有可导出的档案
if (downloadMap.isEmpty()) {
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write("{\"code\":1,\"msg\":\"没有可导出的档案附件\"}");
return;
}
// 5. 设置响应头
String fileName = "电子档案条件导出_" +
LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) + ".zip";
response.setContentType("application/zip");
response.setCharacterEncoding("UTF-8");
response.setHeader(CommonConstants.CONTENT_DISPOSITION,
"attachment; filename=" + URLEncoder.encode(fileName, "UTF-8"));
// 6. 创建ZIP输出流
try (ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream())) {
// 7. 下载并打包档案文件
for (Map.Entry<String, ArchiveDownloadInfo> entry : downloadMap.entrySet()) {
String folderName = entry.getKey();
ArchiveDownloadInfo downloadInfo = entry.getValue();
try {
downloadArchiveFiles(zipOut, folderName, downloadInfo);
// 更新反馈状态为成功
updateExportFeedbackStatus(feedbackList, downloadInfo, "成功", "");
} catch (Exception e) {
log.error("导出档案文件失败,文件夹:{}", folderName, e);
// 更新反馈状态为失败
updateExportFeedbackStatus(feedbackList, downloadInfo, "失败", "导出文件失败:" + e.getMessage());
}
}
// 8. 生成并添加反馈Excel表
addFeedbackExcel(zipOut, feedbackList);
zipOut.finish();
}
} catch (Exception e) {
log.error("根据查询条件导出电子档案失败", e);
}
}
/**
* 构建查询条件
*
* @param searchVo 查询VO
* @return 查询条件
*/
private LambdaQueryWrapper<TElectronicArchiveDetail> buildQueryWrapper(TElectronicArchiveDetailSearchVo searchVo) {
LambdaQueryWrapper<TElectronicArchiveDetail> wrapper = Wrappers.<TElectronicArchiveDetail>lambdaQuery()
.eq(TElectronicArchiveDetail::getDeleteFlag, CommonConstants.ZERO_STRING)
.eq(TElectronicArchiveDetail::getStatus, ArchiveConstants.DETAIL_STATUS_ENABLED);
// 姓名(模糊查询)
if (StrUtil.isNotBlank(searchVo.getEmpName())) {
wrapper.like(TElectronicArchiveDetail::getEmpName, searchVo.getEmpName());
}
// 身份证号(精确查询)
if (StrUtil.isNotBlank(searchVo.getEmpIdcard())) {
wrapper.eq(TElectronicArchiveDetail::getEmpIdcard, searchVo.getEmpIdcard());
}
// 项目编码(精确查询)
if (StrUtil.isNotBlank(searchVo.getDeptNo())) {
wrapper.eq(TElectronicArchiveDetail::getDeptNo, searchVo.getDeptNo());
}
// 项目名称(模糊查询)
if (StrUtil.isNotBlank(searchVo.getDeptName())) {
wrapper.like(TElectronicArchiveDetail::getDeptName, searchVo.getDeptName());
}
// 客户名称(模糊查询)
if (StrUtil.isNotBlank(searchVo.getCustomerName())) {
wrapper.like(TElectronicArchiveDetail::getCustomerName, searchVo.getCustomerName());
}
// 客户编码(精确查询)
if (StrUtil.isNotBlank(searchVo.getCustomerCode())) {
wrapper.eq(TElectronicArchiveDetail::getCustomerCode, searchVo.getCustomerCode());
}
// 资料类型(IN查询)
if (CollUtil.isNotEmpty(searchVo.getTypeList())) {
wrapper.and(w -> {
for (String type : searchVo.getTypeList()) {
w.or().like(TElectronicArchiveDetail::getMaterialType, type);
}
});
}
// 档案所在地-省
if (searchVo.getFileProvince() != null) {
wrapper.eq(TElectronicArchiveDetail::getFileProvince, searchVo.getFileProvince());
}
// 档案所在地-市
if (searchVo.getFileCity() != null) {
wrapper.eq(TElectronicArchiveDetail::getFileCity, searchVo.getFileCity());
}
// 档案所在地-县
if (searchVo.getFileTown() != null) {
wrapper.eq(TElectronicArchiveDetail::getFileTown, searchVo.getFileTown());
}
// 创建人
if (StrUtil.isNotBlank(searchVo.getCreateBy())) {
wrapper.eq(TElectronicArchiveDetail::getCreateBy, searchVo.getCreateBy());
}
// 创建时间区间
if (searchVo.getCreateTimes() != null && searchVo.getCreateTimes().length == 2) {
if (searchVo.getCreateTimes()[0] != null) {
wrapper.ge(TElectronicArchiveDetail::getCreateTime, searchVo.getCreateTimes()[0]);
}
if (searchVo.getCreateTimes()[1] != null) {
wrapper.le(TElectronicArchiveDetail::getCreateTime, searchVo.getCreateTimes()[1]);
}
}
return wrapper;
}
/**
* 准备单个明细的导出信息
*
* @param detail 档案明细
* @param downloadMap 下载信息Map
* @param feedbackList 反馈列表
*/
private void prepareExportByDetail(TElectronicArchiveDetail detail,
Map<String, ArchiveDownloadInfo> downloadMap,
List<ArchiveDownloadFeedbackVO> feedbackList) {
// 1. 查询该明细下所有可用附件
List<TAttaInfo> allAttaList = attaInfoService.list(Wrappers.<TAttaInfo>lambdaQuery()
.eq(TAttaInfo::getDomainId, detail.getId())
.eq(TAttaInfo::getRelationType, ArchiveConstants.ATTA_RELATION_TYPE_ZIP)
.eq(TAttaInfo::getStatus, ArchiveConstants.ATTA_STATUS_ENABLED));
// 2. 如果没有附件,添加失败反馈
if (CollUtil.isEmpty(allAttaList)) {
feedbackList.add(createExportFeedbackVO(detail, "该人员在此项目下没有可用的附件"));
return;
}
// 3. 构建文件夹名称:项目编码-姓名-身份证
String folderName = detail.getDeptNo() + "-" + detail.getEmpName() + "-" + detail.getEmpIdcard();
// 4. 按资料类型分组附件
Map<String, List<TAttaInfo>> materialTypeAttaMap = new LinkedHashMap<>();
for (TAttaInfo atta : allAttaList) {
String materialType = extractMaterialTypeFromPath(atta.getAttaSrc());
if (StrUtil.isBlank(materialType)) {
materialType = "其他";
}
materialTypeAttaMap.computeIfAbsent(materialType, k -> new ArrayList<>()).add(atta);
}
// 5. 添加到下载Map
ArchiveDownloadInfo downloadInfo = downloadMap.get(folderName);
if (downloadInfo == null) {
downloadInfo = new ArchiveDownloadInfo();
downloadInfo.setDetail(detail);
downloadInfo.setMaterialTypeAttaMap(materialTypeAttaMap);
downloadMap.put(folderName, downloadInfo);
} else {
// 合并资料类型附件(理论上不会出现重复的folderName,但为了安全起见)
downloadInfo.getMaterialTypeAttaMap().putAll(materialTypeAttaMap);
}
downloadInfo.setMaterialType(String.join(",", materialTypeAttaMap.keySet()));
// 6. 添加成功的反馈(状态暂时为"处理中",实际导出完成后更新)
feedbackList.add(createExportSuccessFeedbackVO(detail, materialTypeAttaMap.keySet()));
}
/**
* 创建导出失败反馈VO
*
* @param detail 档案明细
* @param failReason 失败原因
* @return 反馈VO
*/
private ArchiveDownloadFeedbackVO createExportFeedbackVO(TElectronicArchiveDetail detail, String failReason) {
ArchiveDownloadFeedbackVO feedback = new ArchiveDownloadFeedbackVO();
feedback.setEmpName(detail.getEmpName());
feedback.setEmpIdcard(detail.getEmpIdcard());
feedback.setDeptNo(detail.getDeptNo());
feedback.setDeptName(detail.getDeptName());
feedback.setMaterialType(detail.getMaterialType());
feedback.setDownloadStatus("失败");
feedback.setFailReason(failReason);
return feedback;
}
/**
* 创建导出成功反馈VO
*
* @param detail 档案明细
* @param materialTypes 资料类型集合
* @return 反馈VO
*/
private ArchiveDownloadFeedbackVO createExportSuccessFeedbackVO(TElectronicArchiveDetail detail,
Set<String> materialTypes) {
ArchiveDownloadFeedbackVO feedback = new ArchiveDownloadFeedbackVO();
feedback.setEmpName(detail.getEmpName());
feedback.setEmpIdcard(detail.getEmpIdcard());
feedback.setDeptNo(detail.getDeptNo());
feedback.setDeptName(detail.getDeptName());
feedback.setMaterialType(String.join(",", materialTypes));
feedback.setDownloadStatus("处理中");
feedback.setFailReason("");
return feedback;
}
/**
* 更新导出反馈状态
*
* @param feedbackList 反馈列表
* @param downloadInfo 下载信息
* @param status 状态
* @param failReason 失败原因
*/
private void updateExportFeedbackStatus(List<ArchiveDownloadFeedbackVO> feedbackList,
ArchiveDownloadInfo downloadInfo,
String status,
String failReason) {
TElectronicArchiveDetail detail = downloadInfo.getDetail();
for (ArchiveDownloadFeedbackVO feedback : feedbackList) {
if (feedback.getEmpName().equals(detail.getEmpName()) &&
feedback.getEmpIdcard().equals(detail.getEmpIdcard()) &&
feedback.getDeptNo().equals(detail.getDeptNo())) {
feedback.setDownloadStatus(status);
feedback.setFailReason(failReason);
}
}
}
}
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