Commit 4338a7a0 authored by huyuchen's avatar huyuchen

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

parent 36892b58
......@@ -55,11 +55,11 @@ public class TAttaInfo extends BaseEntity {
@Schema(description = "资源类型")
private String attaType;
/**
* 关系类型 1 任务表附件 2 zip附件 3反馈表附件
* 关系类型 1 任务表附件 2 zip附件 3反馈表附件 4人员文件
*/
@NotBlank(message = "关系类型不能为空")
@Length(max = 20, message = "关系类型不能超过20个字符")
@Schema(description = "关系类型 1 任务表附件 2 zip附件 3反馈表附件")
@Schema(description = "关系类型 1 任务表附件 2 zip附件 3反馈表附件 4人员文件")
private String relationType;
/**
* 实体id和关系类型共同确定附件所属
......
......@@ -132,7 +132,6 @@ public class TElectronicArchiveDetail extends BaseEntity {
@Schema(description = "是否删除 0否/1是")
private String deleteFlag;
/**
* 附件Id
*/
......
......@@ -2,6 +2,7 @@ package com.yifu.cloud.plus.v1.batch.entity;
import com.alibaba.excel.annotation.ExcelProperty;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.yifu.cloud.plus.v1.yifu.common.core.constant.ExcelAttribute;
......@@ -62,4 +63,8 @@ public class TElectronicArchiveTask extends BaseEntity {
@Schema(description = "是否删除 0否/1是")
private String deleteFlag;
@Schema(description = "反馈表附件名称")
@TableField(exist = false)
private String backAttaName;
}
package com.yifu.cloud.plus.v1.batch.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import java.io.Serializable;
import java.util.List;
/**
* 单个新增人员档案附件请求VO
*
* @author huych
* @date 2025-12-31
*/
@Data
@Schema(description = "单个新增人员档案附件请求VO")
public class SingleArchiveUploadVO implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 身份证号
*/
@NotBlank(message = "身份证号不能为空")
@Schema(description = "身份证号")
private String empIdcard;
/**
* 姓名
*/
@NotBlank(message = "姓名不能为空")
@Schema(description = "姓名")
private String empName;
/**
* 项目编码
*/
@NotBlank(message = "项目编码不能为空")
@Schema(description = "项目编码")
private String deptNo;
/**
* 项目名称
*/
@NotBlank(message = "项目名称不能为空")
@Schema(description = "项目名称")
private String deptName;
/**
* 资料类型(存量、新签、续签、离职)
*/
@NotBlank(message = "资料类型不能为空")
@Schema(description = "资料类型(存量、新签、续签、离职)")
private String materialType;
/**
* 附件ID列表
*/
@NotEmpty(message = "附件ID列表不能为空")
@Schema(description = "附件ID列表")
private List<String> attaIdList;
}
......@@ -8,7 +8,6 @@ import com.yifu.cloud.plus.v1.yifu.common.core.constant.CommonConstants;
import com.yifu.cloud.plus.v1.yifu.common.core.util.Common;
import com.yifu.cloud.plus.v1.yifu.common.core.util.OSSUtil;
import com.yifu.cloud.plus.v1.yifu.common.core.util.R;
import com.yifu.cloud.plus.v1.yifu.common.log.annotation.SysLog;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
......@@ -84,7 +83,6 @@ public class FileUploadController {
* @return
**/
@Operation(description = "附件删除")
@SysLog("附件删除")
@PostMapping("/ossFileDelete/deleteByIds")
public R<Boolean> ossFileDelete(@RequestBody List<String> Ids) {
if (Common.isNotNull(Ids)) {
......@@ -95,7 +93,7 @@ public class FileUploadController {
return R.failed("无对应附件信息");
}
if (tAttaInfoService.removeById(id)) {
ossUtil.deleteObject(null, attaInfo.getAttaSrc());
ossUtil.deleteObject("yf-hr-efile-source", attaInfo.getAttaSrc());
return R.ok(null, "删除成功!");
}
}
......@@ -125,10 +123,147 @@ public class FileUploadController {
return new R<>(attas);
}
for (TAttaInfo atta:attas){
URL url = ossUtil.getObjectUrl(null, atta.getAttaSrc());
URL url = ossUtil.getObjectUrl("yf-hr-efile-source", atta.getAttaSrc());
atta.setAttaUrl(url.toString().replace("http","https"));
}
return new R<>(attas);
}
/**
* 获取附件下载地址
*
* @param id
* @return
* @Author fxj
* @Date 2019-08-16
* @param id domainId
**/
@Operation(description = "附件预览下载地址 根据ID和附件类型")
@PostMapping("/overrideOssFileUrl")
public R<List<TAttaInfo>> ossFileUrl(@RequestParam String id,@RequestParam String type) {
List<TAttaInfo> attas = tAttaInfoService.list(Wrappers.<TAttaInfo>query().lambda()
.eq(TAttaInfo::getDomainId,id)
.eq(TAttaInfo::getRelationType,type));
if (Common.isEmpty(attas)) {
return new R<>(attas);
}
for (TAttaInfo atta:attas){
URL url = ossUtil.getObjectUrl("yf-hr-efile-source", atta.getAttaSrc());
atta.setAttaUrl(url.toString().replace("http","https"));
}
return new R<>(attas);
}
/**
* 电子档案单个新增-附件上传接口
* 前端先调用此接口上传文件到阿里云OSS,如果文件名重复则自动添加后缀
*
* @param file 文件
* @param filePath 文件路径
* @param type 关系类型 4 人员文件
* @return R<TAttaInfo> 返回附件信息,包含附件ID
* @Author huych
* @Date 2025-12-31
*/
@Operation(description = "电子档案单个新增-附件上传接口,上传文件到OSS并返回附件ID")
@PostMapping(value = "/uploadArchiveFile")
public R<TAttaInfo> uploadArchiveFile(@RequestBody MultipartFile file, String filePath, String type) throws IOException {
if (file == null || file.isEmpty()) {
return R.failed("文件不能为空");
}
String fileName = file.getOriginalFilename();
if (fileName == null || Common.isEmpty(fileName)) {
return R.failed("文件名不能为空");
}
if (fileName.length() > 100) {
return R.failed("文件名不能超过100个字符");
}
// 默认关系类型为4(人员文件)
if (Common.isEmpty(type)) {
type = CommonConstants.FOUR_STRING;
}
// 构建OSS文件路径,如果文件名重复则添加后缀
String key = buildUniqueFilePath(filePath, fileName);
// 校验文件类型
if (!Common.checkFile(key)) {
return R.failed("非法上传类型:" + fileName);
}
try {
// 上传文件到OSS
boolean uploadSuccess = ossUtil.uploadFileByStream(file.getInputStream(), key, "yf-hr-efile-source");
if (!uploadSuccess) {
return R.failed("文件上传失败");
}
// 创建附件信息记录,domainId暂时为空,后续调用uploadSingleArchive接口时更新
TAttaInfo attaInfo = new TAttaInfo();
attaInfo.setAttaName(fileName);
attaInfo.setAttaSrc(key);
attaInfo.setAttaSize(file.getSize());
// 提取文件扩展名
int lastDotIndex = key.lastIndexOf('.');
if (lastDotIndex >= 0) {
attaInfo.setAttaType(key.substring(lastDotIndex));
}
attaInfo.setRelationType(type);
attaInfo.setDomainId(CommonConstants.ZERO_STRING); // 临时设置为"0",后续更新
attaInfo.setStatus(CommonConstants.ZERO_STRING); // 0可用
// 保存附件信息到数据库
tAttaInfoService.save(attaInfo);
// 获取附件URL
URL url = ossUtil.getObjectUrl("yf-hr-efile-source", attaInfo.getAttaSrc());
attaInfo.setAttaUrl(url.toString().replace("http", "https"));
return R.ok(attaInfo, "文件上传成功");
} catch (Exception e) {
log.error("附件上传异常:", e);
// 上传失败,删除OSS文件
try {
ossUtil.deleteObject("yf-hr-efile-source", key);
} catch (Exception ex) {
log.error("删除OSS文件失败:", ex);
}
return R.failed("上传异常:" + e.getMessage());
}
}
/**
* 构建唯一的文件路径,如果文件名重复则添加后缀
*
* @param filePath 文件路径
* @param fileName 文件名
* @return 唯一的文件路径
*/
private String buildUniqueFilePath(String filePath, String fileName) {
// 检查文件是否存在
if (!fileUploadService.checkFileExists(filePath+ "/" + fileName)) {
return filePath+ "/" + fileName;
}
// 文件存在,添加后缀
int lastDotIndex = fileName.lastIndexOf('.');
String nameWithoutExt;
String extension;
if (lastDotIndex > 0) {
nameWithoutExt = fileName.substring(0, lastDotIndex);
extension = fileName.substring(lastDotIndex);
} else {
nameWithoutExt = fileName;
extension = "";
}
return filePath + "/" + nameWithoutExt + "_" + System.currentTimeMillis() + extension;
}
}
......@@ -170,4 +170,26 @@ public class TElectronicArchiveDetailController {
tElectronicArchiveDetailService.exportArchivesByCondition(searchVo, response);
}
/**
* 删除电子档案明细表
* <p>
* 功能说明:
* 1. 单条删除电子档案明细表记录
* 2. 同步删除该明细下所有关联的附件信息
* 3. 将明细状态更新为不可用(逻辑删除)
* 4. 将附件删除
* 5. 同时删除OSS上的附件文件
* </p>
*
* @param id 明细ID
* @return 删除结果
* @author huych
* @date 2025-12-30
*/
@Operation(summary = "删除电子档案明细表", description = "删除电子档案明细表,同步删除所有关联的附件信息")
@DeleteMapping("/{id}")
public R<String> deleteDetail(@PathVariable("id") String id) {
return tElectronicArchiveDetailService.deleteArchiveDetail(id);
}
}
......@@ -2,16 +2,17 @@ package com.yifu.cloud.plus.v1.batch.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yifu.cloud.plus.v1.batch.entity.TElectronicArchiveDetail;
import com.yifu.cloud.plus.v1.batch.entity.TElectronicArchiveTask;
import com.yifu.cloud.plus.v1.batch.service.ElectronicArchiveImportService;
import com.yifu.cloud.plus.v1.batch.service.TElectronicArchiveTaskService;
import com.yifu.cloud.plus.v1.batch.vo.SingleArchiveUploadVO;
import com.yifu.cloud.plus.v1.batch.vo.TElectronicArchiveTaskSearchVo;
import com.yifu.cloud.plus.v1.yifu.common.core.util.R;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
......@@ -156,22 +157,22 @@ public class TElectronicArchiveTaskController {
/**
* 单个新增人员附件
* 前端先调用 /fileUpload/uploadArchiveFile 接口上传文件获取附件ID列表
* 然后调用此接口传入人员信息和附件ID列表,更新附件的domainId
*
* @param detail 人员信息
* @param files 附件文件列表
* @param vo 人员信息,包含身份证号、姓名、项目编码、项目名称、资料类型、附件ID列表
* @return R
*/
@Operation(summary = "单个新增人员附件", description = "单个新增人员档案附件,包含身份证号、姓名、项目编码、项目名称、资料类型和多个附件")
@Operation(summary = "单个新增人员附件", description = "单个新增人员档案附件,前端先上传文件获取附件ID,再调用此接口更新domainId")
@PostMapping("/uploadSingleArchive")
public R<?> uploadSingleArchive(@RequestBody TElectronicArchiveDetail detail,
@RequestParam("files") MultipartFile[] files) {
// 参数校验
if (files == null || files.length == 0) {
return R.failed("附件不能为空");
}
return importService.uploadSinglePersonArchive(detail.getEmpIdcard(), detail.getEmpName()
, detail.getDeptNo(), detail.getDeptName(), detail.getMaterialType(),files);
public R<?> uploadSingleArchive(@Validated @RequestBody SingleArchiveUploadVO vo) {
return importService.uploadSinglePersonArchiveByAttaIds(
vo.getEmpIdcard(),
vo.getEmpName(),
vo.getDeptNo(),
vo.getDeptName(),
vo.getMaterialType(),
vo.getAttaIdList()
);
}
}
......@@ -47,7 +47,7 @@ public interface ElectronicArchiveImportService {
String generateTaskCode();
/**
* 单个新增人员附件
* 单个新增人员附件(旧方法,保留用于兼容)
*
* @param empIdcard 身份证号
* @param empName 姓名
......@@ -59,5 +59,20 @@ public interface ElectronicArchiveImportService {
*/
R<?> uploadSinglePersonArchive(String empIdcard, String empName, String deptNo,
String deptName, String materialType, MultipartFile[] files);
/**
* 单个新增人员附件(通过附件ID列表)
* 前端先调用文件上传接口获取附件ID列表,再调用此方法更新附件的domainId
*
* @param empIdcard 身份证号
* @param empName 姓名
* @param deptNo 项目编码
* @param deptName 项目名称
* @param materialType 资料类型
* @param attaIdList 附件ID列表
* @return 上传结果
*/
R<?> uploadSinglePersonArchiveByAttaIds(String empIdcard, String empName, String deptNo,
String deptName, String materialType, java.util.List<String> attaIdList);
}
......@@ -62,4 +62,11 @@ public interface TElectronicArchiveDetailService extends IService<TElectronicArc
*/
void exportArchivesByCondition(TElectronicArchiveDetailSearchVo searchVo, HttpServletResponse response);
/**
* 删除电子档案明细表
* @param id 明细ID
* @return 删除结果
*/
R<String> deleteArchiveDetail(String id);
}
......@@ -67,6 +67,7 @@ public class ElectronicArchiveImportServiceImpl implements ElectronicArchiveImpo
private final FileUploadService fileUploadService;
private final ArchivesDaprUtil archivesDaprUtil;
private final CacheManager cacheManager;
private final OSSUtil ossUtil;
//初始化zip导入上限值
private int maxLimit = 1;
......@@ -92,8 +93,20 @@ public class ElectronicArchiveImportServiceImpl implements ElectronicArchiveImpo
ExcelUtil<ArchiveImportVO> util = new ExcelUtil<>(ArchiveImportVO.class);
List<ErrorMessage<ArchiveImportVO>> errorMessageList = new ArrayList<>();
// 将输入流转换为字节数组,以便后续上传到OSS
byte[] fileBytes;
try {
EasyExcel.read(inputStream, ArchiveImportVO.class, new ReadListener<ArchiveImportVO>() {
fileBytes = cn.hutool.core.io.IoUtil.readBytes(inputStream);
} catch (Exception e) {
log.error("读取文件流失败", e);
return R.failed("读取文件失败:" + e.getMessage());
}
try {
// 使用字节数组创建新的输入流用于Excel读取
InputStream excelInputStream = new java.io.ByteArrayInputStream(fileBytes);
EasyExcel.read(excelInputStream, ArchiveImportVO.class, new ReadListener<ArchiveImportVO>() {
public static final int BATCH_COUNT = CommonConstants.BATCH_COUNT;
private List<ArchiveImportVO> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
......@@ -148,12 +161,15 @@ public class ElectronicArchiveImportServiceImpl implements ElectronicArchiveImpo
taskService.save(task);
// 保存任务表附件
saveTaskAttachment(task.getId(), fileName, inputStream, user);
saveTaskAttachment(task.getId(), fileName, inputStream, "task_file"+"/" + task.getId() + "_" + fileName);
// 上传文件到阿里云OSS根目录
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);
......@@ -259,12 +275,14 @@ public class ElectronicArchiveImportServiceImpl implements ElectronicArchiveImpo
/**
* 保存任务表附件
*/
private void saveTaskAttachment(String taskId, String fileName, InputStream inputStream, YifuUser user) {
private void saveTaskAttachment(String taskId, String fileName, InputStream inputStream,String filePath) {
try {
TAttaInfo attaInfo = new TAttaInfo();
attaInfo.setAttaName(fileName);
attaInfo.setRelationType(ArchiveConstants.ATTA_RELATION_TYPE_TASK);
attaInfo.setDomainId(taskId);
attaInfo.setAttaSrc(filePath);
attaInfo.setAttaType(fileName.substring(fileName.lastIndexOf('.')));
attaInfo.setStatus(ArchiveConstants.ATTA_STATUS_ENABLED);
attaInfoService.save(attaInfo);
} catch (Exception e) {
......@@ -272,6 +290,26 @@ public class ElectronicArchiveImportServiceImpl implements ElectronicArchiveImpo
}
}
/**
* 上传文件到阿里云OSS
*
* @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");
} catch (Exception e) {
log.error("上传文件到阿里云OSS异常,文件名:{},异常信息:{}", fileName, e.getMessage(), e);
}
}
/**
* 获取项目权限
*
......@@ -759,8 +797,8 @@ public class ElectronicArchiveImportServiceImpl implements ElectronicArchiveImpo
// domainId为电子档案详情表的id(detail.getId())
R<TAttaInfo> uploadResult = fileUploadService.uploadFileReturnAtta(
multipartFile,
ossDirectory,
getMaterialTypeCode(materialType),
ossDirectory,
CommonConstants.FOUR_STRING,
detail.getId()
);
......@@ -772,9 +810,6 @@ public class ElectronicArchiveImportServiceImpl implements ElectronicArchiveImpo
return;
}
// 上传成功,记录附件信息
TAttaInfo attaInfo = uploadResult.getData();
// 记录该人员的资料类型
materialTypes.add(materialType);
......@@ -889,7 +924,7 @@ public class ElectronicArchiveImportServiceImpl implements ElectronicArchiveImpo
try {
// 创建临时文件
String tempFilePath = System.getProperty("java.io.tmpdir") + File.separator +
"feedback_" + taskId + "_" + System.currentTimeMillis() + ".xlsx";
"feedback_" + System.currentTimeMillis() + ".xlsx";
File feedbackFile = new File(tempFilePath);
// 使用EasyExcel生成反馈表
......@@ -982,22 +1017,6 @@ public class ElectronicArchiveImportServiceImpl implements ElectronicArchiveImpo
return false;
}
/**
* 资料类型名称转换为编码
*/
private String getMaterialTypeCode(String typeName) {
if (ArchiveConstants.MATERIAL_TYPE_STOCK.equals(typeName)) {
return ArchiveConstants.MATERIAL_TYPE_CODE_STOCK;
} else if (ArchiveConstants.MATERIAL_TYPE_NEW.equals(typeName)) {
return ArchiveConstants.MATERIAL_TYPE_CODE_NEW;
} else if (ArchiveConstants.MATERIAL_TYPE_RENEW.equals(typeName)) {
return ArchiveConstants.MATERIAL_TYPE_CODE_RENEW;
} else if (ArchiveConstants.MATERIAL_TYPE_LEAVE.equals(typeName)) {
return ArchiveConstants.MATERIAL_TYPE_CODE_LEAVE;
}
return ArchiveConstants.MATERIAL_TYPE_CODE_STOCK; // 默认存量
}
/**
* 单个新增人员附件
*/
......@@ -1095,12 +1114,12 @@ public class ElectronicArchiveImportServiceImpl implements ElectronicArchiveImpo
continue;
}
// 校验文件大小
if (file.getSize() > ArchiveConstants.SINGLE_FILE_MAX_SIZE) {
failCount++;
failReasons.append(file.getOriginalFilename()).append(":文件大小超过15M;");
continue;
}
// // 校验文件大小
// if (file.getSize() > ArchiveConstants.SINGLE_FILE_MAX_SIZE) {
// failCount++;
// failReasons.append(file.getOriginalFilename()).append(":文件大小超过15M;");
// continue;
// }
// 校验文件格式
String fileName = file.getOriginalFilename();
......@@ -1118,7 +1137,7 @@ public class ElectronicArchiveImportServiceImpl implements ElectronicArchiveImpo
R<TAttaInfo> uploadResult = fileUploadService.uploadFileReturnAtta(
file,
ossDirectory,
getMaterialTypeCode(materialType),
CommonConstants.FOUR_STRING,
detail.getId()
);
......@@ -1148,5 +1167,143 @@ public class ElectronicArchiveImportServiceImpl implements ElectronicArchiveImpo
return R.failed("处理失败:" + e.getMessage());
}
}
/**
* 单个新增人员附件(通过附件ID列表)
* 前端先调用文件上传接口获取附件ID列表,再调用此方法更新附件的domainId
*/
@Override
@Transactional(rollbackFor = Exception.class)
public R<?> uploadSinglePersonArchiveByAttaIds(String empIdcard, String empName, String deptNo,
String deptName, String materialType, List<String> attaIdList) {
YifuUser user = SecurityUtils.getUser();
if (null == user) {
return R.failed("用户未登录");
}
// 参数校验
if (StrUtil.isBlank(empIdcard) || StrUtil.isBlank(empName) || StrUtil.isBlank(deptNo) ||
StrUtil.isBlank(deptName) || StrUtil.isBlank(materialType)) {
return R.failed("参数不能为空");
}
// 校验附件ID列表
if (attaIdList == null || attaIdList.isEmpty()) {
return R.failed("附件ID列表不能为空");
}
// 校验资料类型是否有效
if (!isValidMaterialType(materialType)) {
return R.failed("资料类型不正确,必须为:存量、新签、续签、离职");
}
// 校验身份证格式
if (!empIdcard.matches("\\d{18}")) {
return R.failed("身份证号格式不正确");
}
try {
// 1. 查询项目信息获取客户信息
TSettleDomainSelectVo settleResult = archivesDaprUtil.selectDeptByNo(deptNo);
if (settleResult == null) {
return R.failed("项目编码[" + deptNo + "]信息不存在");
}
// 2. 查询人员档案信息获取档案所在地
IdNameNoVo vo = new IdNameNoVo();
vo.setName(empName);
vo.setNo(empIdcard);
R<TEmployeeInfo> empResult = archivesDaprUtil.getTEmployeeInfoByIdcardAndName(vo);
if (empResult == null || empResult.getData() == null) {
return R.failed("人员档案信息不存在");
}
TEmployeeInfo empInfo = empResult.getData();
// 3. 查找是否存在相同的电子档案明细
LambdaQueryWrapper<TElectronicArchiveDetail> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(TElectronicArchiveDetail::getEmpIdcard, empIdcard)
.eq(TElectronicArchiveDetail::getEmpName, empName)
.eq(TElectronicArchiveDetail::getDeptNo, deptNo)
.eq(TElectronicArchiveDetail::getStatus, ArchiveConstants.DETAIL_STATUS_ENABLED)
.eq(TElectronicArchiveDetail::getDeleteFlag, CommonConstants.ZERO_STRING)
.last(CommonConstants.LAST_ONE_SQL);
TElectronicArchiveDetail detail = detailService.getOne(wrapper);
// 4. 如果不存在,创建新的明细
if (detail == null) {
detail = new TElectronicArchiveDetail();
detail.setEmpName(empName);
detail.setEmpIdcard(empIdcard);
detail.setDeptNo(deptNo);
detail.setDeptName(deptName);
detail.setCustomerName(settleResult.getCustomerName());
detail.setCustomerCode(settleResult.getCustomerCode());
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());
detailService.save(detail);
} else {
// 存在则更新资料类型(追加)
Set<String> existTypes = new HashSet<>();
if (StrUtil.isNotBlank(detail.getMaterialType())) {
existTypes.addAll(Arrays.asList(detail.getMaterialType().split(",")));
}
existTypes.add(materialType);
detail.setMaterialType(String.join(",", existTypes));
detailService.updateById(detail);
}
// 5. 更新附件的domainId
int successCount = 0;
int failCount = 0;
StringBuilder failReasons = new StringBuilder();
for (String attaId : attaIdList) {
if (StrUtil.isBlank(attaId)) {
continue;
}
try {
// 查询附件信息
TAttaInfo attaInfo = attaInfoService.getById(attaId);
if (attaInfo == null) {
failCount++;
failReasons.append("附件ID[").append(attaId).append("]不存在;");
continue;
}
// 更新domainId
attaInfo.setDomainId(detail.getId());
boolean updateSuccess = attaInfoService.updateById(attaInfo);
if (updateSuccess) {
successCount++;
} else {
failCount++;
failReasons.append("附件ID[").append(attaId).append("]更新失败;");
}
} catch (Exception e) {
log.error("更新附件domainId失败,附件ID:{}", attaId, e);
failCount++;
failReasons.append("附件ID[").append(attaId).append("]更新异常;");
}
}
// 6. 返回处理结果
String resultMsg = String.format("处理完成,成功:%d个,失败:%d个", successCount, failCount);
if (failCount > 0) {
resultMsg += "。失败原因:" + failReasons.toString();
}
return R.ok(detail.getId(), resultMsg);
} catch (Exception e) {
log.error("单个新增人员附件失败", e);
return R.failed("处理失败:" + e.getMessage());
}
}
}
......@@ -6,12 +6,12 @@ import com.yifu.cloud.plus.v1.batch.service.FileUploadService;
import com.yifu.cloud.plus.v1.batch.service.TAttaInfoService;
import com.yifu.cloud.plus.v1.yifu.common.core.constant.CommonConstants;
import com.yifu.cloud.plus.v1.yifu.common.core.constant.ResultConstants;
import com.yifu.cloud.plus.v1.yifu.common.core.constant.SecurityConstants;
import com.yifu.cloud.plus.v1.yifu.common.core.util.Common;
import com.yifu.cloud.plus.v1.yifu.common.core.util.OSSUtil;
import com.yifu.cloud.plus.v1.yifu.common.core.util.R;
import com.yifu.cloud.plus.v1.yifu.common.core.vo.FileVo;
import com.yifu.cloud.plus.v1.yifu.common.core.vo.YifuUser;
import com.yifu.cloud.plus.v1.yifu.common.security.util.SecurityUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.GrantedAuthority;
......@@ -58,18 +58,34 @@ public class FileUploadServiceImpl implements FileUploadService {
//jpg,jpeg,png,bmp
String key = "";
if (Common.isNotNull(filePath)) {
key = filePath + "/" + System.currentTimeMillis() + fileName;
key = filePath + "/" + fileName;
} else {
key = System.currentTimeMillis() + fileName;
}
if (!Common.checkFile(key)) {
return R.failed("非法上传类型:"+fileName);
}
boolean flag = ossUtil.uploadFileByStream(file.getInputStream(), key, null);
//判断是否存在此文件,存在的话,加后缀
if (ossUtil.doesObjectExist("yf-hr-efile-source", key,CommonConstants.ZERO_INT)) {
// 文件存在,添加后缀
int lastDotIndex = fileName.lastIndexOf('.');
String nameWithoutExt;
String extension;
if (lastDotIndex > 0) {
nameWithoutExt = fileName.substring(0, lastDotIndex);
extension = fileName.substring(lastDotIndex);
} else {
nameWithoutExt = fileName;
extension = "";
}
key = filePath + "/" + nameWithoutExt + "_" + System.currentTimeMillis() + extension;
}
boolean flag = ossUtil.uploadFileByStream(file.getInputStream(), key, "yf-hr-efile-source");
TAttaInfo attaInfo;
URL url;
if (flag) {
log.info("文件:" + fileName + "上传到存储空间" + ossUtil.getBucketName() + "成功!");
attaInfo = initUnitAttaForInsert(fileName, key, file.getSize());
attaInfo.setRelationType(type);
try {
......@@ -78,22 +94,16 @@ public class FileUploadServiceImpl implements FileUploadService {
Set<String> dbAuthsSet = new HashSet<>();
Collection<? extends GrantedAuthority> authorities = AuthorityUtils
.createAuthorityList(dbAuthsSet.toArray(new String[0]));
YifuUser user = new YifuUser("8", 1L, "", "电子档案上传",
"电子档案上传", "0", SecurityConstants.BCRYPT + "123456",
"12345678911", true, true, true,
true,
"1", authorities, "1",
null, null,
null,null);
YifuUser user = SecurityUtils.getUser();
attaInfo.setCreateBy(user.getId());
attaInfo.setCreateName(user.getNickname());
attaInfo = tAttaInfoService.add(attaInfo);
} catch (Exception e) {
log.error("OSS文件上传异常:" + e.getMessage());
ossUtil.deleteObject(null, key);
ossUtil.deleteObject("yf-hr-efile-source", key);
return R.failed("上传异常:" + e.getMessage());
}
url = ossUtil.getObjectUrl(null, attaInfo.getAttaSrc());
url = ossUtil.getObjectUrl("yf-hr-efile-source", attaInfo.getAttaSrc());
attaInfo.setAttaUrl(String.valueOf(url));
return R.ok(attaInfo);
} else {
......@@ -124,12 +134,11 @@ public class FileUploadServiceImpl implements FileUploadService {
if (!Common.checkFile(key)) {
return R.failed("非法上传类型!");
}
boolean flag = ossUtil.uploadFileByStream(file.getInputStream(), key, null);
boolean flag = ossUtil.uploadFileByStream(file.getInputStream(), key, "yf-hr-efile-source");
FileVo fileVo;
TAttaInfo attaInfo;
URL url;
if (flag) {
log.info("文件:" + fileName + "上传至存储空间" + ossUtil.getBucketName() + "成功!");
attaInfo = initUnitAttaForInsert(fileName, key, file.getSize());
attaInfo.setRelationType(type);
try {
......@@ -137,16 +146,16 @@ public class FileUploadServiceImpl implements FileUploadService {
attaInfo = tAttaInfoService.add(attaInfo);
} catch (Exception e) {
log.error("OSS文件上传接口异常:" + e.getMessage());
ossUtil.deleteObject(null, key);
ossUtil.deleteObject("yf-hr-efile-source", key);
return R.failed("fail:" + e.getMessage());
}
//有实体id则插入关系,用于编辑
if (Common.isNotNull(domain)) {
url = ossUtil.getObjectUrl(null, attaInfo.getAttaSrc());
url = ossUtil.getObjectUrl("yf-hr-efile-source", attaInfo.getAttaSrc());
fileVo = new FileVo(attaInfo.getId(), attaInfo.getAttaName(), url.toString());
return R.ok(fileVo, "success");
}
url = ossUtil.getObjectUrl(null, attaInfo.getAttaSrc());
url = ossUtil.getObjectUrl("yf-hr-efile-source", attaInfo.getAttaSrc());
fileVo = new FileVo(attaInfo.getId(), attaInfo.getAttaName(), url.toString());
return R.ok(fileVo, "success");
} else {
......@@ -216,7 +225,7 @@ public class FileUploadServiceImpl implements FileUploadService {
@Override
public boolean checkFileExists(String filePath) {
try {
return ossUtil.doesObjectExist(null, filePath);
return ossUtil.doesObjectExist("yf-hr-efile-source", filePath,CommonConstants.ZERO_INT);
} catch (Exception e) {
log.error("检查文件是否存在失败:{}", filePath, e);
return false;
......
......@@ -111,7 +111,7 @@ public class TElectronicArchiveDetailServiceImpl extends ServiceImpl<TElectronic
// 查询该任务上传的附件(domainId为明细ID,附件是在处理ZIP时关联到明细的)
List<TAttaInfo> taskAttachments = attaInfoService.list(Wrappers.<TAttaInfo>lambdaQuery()
.eq(TAttaInfo::getDomainId, id)
.eq(TAttaInfo::getRelationType, ArchiveConstants.ATTA_RELATION_TYPE_ZIP)
.eq(TAttaInfo::getRelationType, ArchiveConstants.ATTA_RELATION_TYPE_PER)
.eq(TAttaInfo::getStatus, ArchiveConstants.ATTA_STATUS_ENABLED));
if (CollUtil.isEmpty(taskAttachments)) {
......@@ -620,9 +620,7 @@ public class TElectronicArchiveDetailServiceImpl extends ServiceImpl<TElectronic
for (TAttaInfo atta : attachments) {
try {
// 更新附件状态为不可用
atta.setStatus(ArchiveConstants.ATTA_STATUS_DISABLED);
boolean updated = attaInfoService.updateById(atta);
boolean updated = attaInfoService.removeById(atta);
if (updated) {
// 删除OSS文件
......@@ -1321,4 +1319,101 @@ public class TElectronicArchiveDetailServiceImpl extends ServiceImpl<TElectronic
}
}
}
/**
* 删除电子档案明细表
* <p>
* 功能说明:
* 1. 校验明细是否存在
* 2. 查询该明细下所有关联的附件
* 3. 将明细状态更新为不可用(逻辑删除)
* 4. 将所有附件删除
* 5. 同时删除OSS上的附件文件
* 6. 删除任务与档案的关联关系
* </p>
*
* @param id 明细ID
* @return 删除结果
* @author huych
* @date 2025-12-30
*/
@Override
public R<String> deleteArchiveDetail(String id) {
try {
// 1. 校验明细是否存在
TElectronicArchiveDetail detail = baseMapper.selectById(id);
if (Common.isEmpty(detail)) {
return R.failed("电子档案明细不存在");
}
// 2. 查询该明细下所有的附件(包括可用和不可用的)
List<TAttaInfo> attachments = attaInfoService.list(Wrappers.<TAttaInfo>lambdaQuery()
.eq(TAttaInfo::getDomainId, id)
.eq(TAttaInfo::getRelationType, ArchiveConstants.ATTA_RELATION_TYPE_ZIP));
// 3. 删除所有附件并删除OSS文件
int attachmentSuccessCount = 0;
int attachmentFailCount = 0;
if (CollUtil.isNotEmpty(attachments)) {
for (TAttaInfo atta : attachments) {
try {
boolean updated = attaInfoService.removeById(atta);
if (updated) {
// 删除OSS文件
try {
ossUtil.deleteObject("yf-hr-efile-source", atta.getAttaSrc());
attachmentSuccessCount++;
} catch (Exception e) {
log.error("删除OSS文件失败,附件ID:{},路径:{}", atta.getId(), atta.getAttaSrc(), e);
// OSS删除失败不影响整体流程,已经逻辑删除了
attachmentSuccessCount++;
}
} else {
attachmentFailCount++;
log.error("更新附件状态失败,附件ID:{}", atta.getId());
}
} catch (Exception e) {
attachmentFailCount++;
log.error("删除附件失败,附件ID:{}", atta.getId(), e);
}
}
}
// 5. 删除任务与档案的关联关系
try {
relationService.remove(Wrappers.<TTaskArchiveRelation>lambdaQuery()
.eq(TTaskArchiveRelation::getArchiveDetailId, id));
} catch (Exception e) {
log.error("删除任务档案关联关系失败,明细ID:{}", id, e);
// 关联关系删除失败不影响主流程
}
// 6. 逻辑删除明细(更新状态为不可用,deleteFlag设为1)
detail.setStatus(ArchiveConstants.DETAIL_STATUS_DISABLED);
detail.setDeleteFlag(CommonConstants.ONE_STRING);
boolean detailUpdated = baseMapper.updateById(detail) > 0;
if (!detailUpdated) {
return R.failed("删除电子档案明细失败");
}
// 7. 构建返回消息
YifuUser user = SecurityUtils.getUser();
String resultMsg = String.format("删除成功。明细:%s-%s-%s,附件删除成功:%d个",
detail.getDeptNo(), detail.getEmpName(), detail.getEmpIdcard(), attachmentSuccessCount);
if (attachmentFailCount > 0) {
resultMsg += String.format(",附件删除失败:%d个", attachmentFailCount);
}
return R.ok(null, resultMsg);
} catch (Exception e) {
log.error("删除电子档案明细失败,明细ID:{}", id, e);
return R.failed("删除失败:" + e.getMessage());
}
}
}
......@@ -95,13 +95,14 @@
</if>
</sql>
<!--tElectronicArchiveDetail简单分页查询-->
<select id="getTElectronicArchiveDetailPage" resultMap="tElectronicArchiveDetailMap">
SELECT
<include refid="Base_Column_List"/>
FROM t_electronic_archive_detail a
<where>
<select id="getTElectronicArchiveDetailPage" resultMap="tElectronicArchiveDetailMap">
SELECT
<include refid="Base_Column_List"/>
FROM t_electronic_archive_detail a
<where>
a.DELETE_FLAG = '0'
<include refid="tElectronicArchiveDetail_where"/>
</where>
</select>
<include refid="tElectronicArchiveDetail_where"/>
</where>
ORDER BY a.CREATE_TIME DESC
</select>
</mapper>
......@@ -16,6 +16,7 @@
<result property="createTime" column="CREATE_TIME"/>
<result property="updateBy" column="UPDATE_BY"/>
<result property="updateTime" column="UPDATE_TIME"/>
<result property="backAttaName" column="backAttaName"/>
</resultMap>
<sql id="Base_Column_List">
a.ID,
......@@ -65,10 +66,14 @@
<select id="getTElectronicArchiveTaskPage" resultMap="tElectronicArchiveTaskMap">
SELECT
<include refid="Base_Column_List"/>
,c.ATTA_NAME as backAttaName
FROM t_electronic_archive_task a
left join t_atta_info c on a.id = c.DOMAIN_ID and c.RELATION_TYPE = '3'
<where>
a.DELETE_FLAG = '0'
<include refid="tElectronicArchiveTask_where"/>
</where>
group by a.ID
ORDER BY a.CREATE_TIME DESC
</select>
</mapper>
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