This commit is contained in:
zt
2025-04-29 17:45:42 +08:00
parent 2c15d26bcc
commit c982cbaa75
32 changed files with 936 additions and 370 deletions

View File

@ -15,7 +15,9 @@ import com.ruoyi.bgt.service.IBgtProjectRecruitService;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.enums.RecruitApplyStatus;
import com.ruoyi.common.util.MessageUtil;
import com.ruoyi.wgz.bo.req.WgzAppPersonalBasicInformationReq;
import com.ruoyi.wgz.bo.res.WgzAppPersonalBasicInformationRes;
import com.ruoyi.wgz.service.IWgzAttendanceService;
@ -53,6 +55,8 @@ public class AppBgtMessageController extends BaseController {
private final IBgtProjectRecruitService iBgtProjectRecruitService;
private final RedisCache redisCache;
@ApiOperation("未读消息统计")
@GetMapping("/countUnread")
public AjaxResult<BgtMessageCountVO> count() {
@ -74,10 +78,14 @@ public class AppBgtMessageController extends BaseController {
@ApiOperation("已读")
@PutMapping("/read/{id}")
public AjaxResult<Boolean> read(@PathVariable(value = "id") Long id) {
BgtMessage bgtMessage = new BgtMessage();
bgtMessage.setId(id);
bgtMessage.setReadStatus("1");
return AjaxResult.success(iBgtMessageService.updateById(bgtMessage));
BgtMessage bgtMessage = iBgtMessageService.getById(id);
boolean b = true;
if("0".equals(bgtMessage.getReadStatus())){
MessageUtil.readMessagePush(bgtMessage.getRecipientType(), bgtMessage.getRecipientId(), bgtMessage.getMessageLargeType(), bgtMessage.getReadStatus());
bgtMessage.setReadStatus("1");
b = iBgtMessageService.updateById(bgtMessage);
}
return AjaxResult.success(b);
}
@ApiOperation("已操作")

View File

@ -0,0 +1,47 @@
package com.ruoyi.web.controller.common;
import com.ruoyi.common.util.SseUtil;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
@RestController
@RequestMapping("/sse")
public class SseController {
/**
* 客户端订阅SSE连接适配2.4.7
*/
@GetMapping(path = "/subscribe", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public SseEmitter subscribe(String userId,String prefix) {
return SseUtil.subscribe(userId,prefix);
}
// /**
// * 触发消息数量推送适配2.4.7
// */
// @GetMapping("/push")
// public void pushMessageCount(String userId) {
// SseEmitter emitter = emitterMap.get(userId);
// if (emitter != null) {
// BgtMessageCountVO bgtMessageCountVO = new BgtMessageCountVO();
// bgtMessageCountVO.setTaskMessageCount(1);
// bgtMessageCountVO.setSettlementMessageCount(0);
// try {
// // 发送自定义事件(客户端通过事件名监听)
// emitter.send(SseEmitter.event()
// .id(String.valueOf(System.currentTimeMillis()))
// .name("messageCount")
// .data(JSONUtil.toJsonStr(bgtMessageCountVO))
// );
// } catch (IOException e) {
// emitter.completeWithError(e);
// emitterMap.remove(userId); // 异常时清理无效连接
// }
// }
// }
}

View File

@ -11,7 +11,6 @@ import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.BgtUser;
import com.ruoyi.common.domain.Annex;
import com.ruoyi.common.domain.AnnexRecord;
import com.ruoyi.common.exception.BaseException;
import com.ruoyi.common.service.IAnnexRecordService;
import com.ruoyi.common.service.IAnnexService;
@ -34,15 +33,16 @@ import java.nio.charset.Charset;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
/**
* 登录验证
*
* @author ruoyi
* 压缩文件上传控制器(整合路径收集与验证逻辑)
*/
@Api(value = "网页模板上传", tags = {"网页模板上传"})
@RequiredArgsConstructor(onConstructor_ = @Autowired)
@ -57,9 +57,9 @@ public class UploadZipController {
private final IBgtUserService bgtUserService;
private final IBgtProjectRecruitApplyService recruitApplyService;
private static final String TEMP_DIR = "ruoyi/uploadPath/temporaryZip"; //临时解压
private static final String SAVE_DIR = "ruoyi/uploadPath/recruit"; //保存目录
private static final String RECORD_DIR = "ruoyi/uploadPath/record"; //记录目录
private static final String TEMP_DIR = "ruoyi/uploadPath/temporaryZip"; // 临时解压目录
private static final String SAVE_DIR = "ruoyi/uploadPath/recruit"; // 最终保存目录
private static final String RECORD_DIR = "ruoyi/uploadPath/record"; // 记录目录
@ApiOperation("上传压缩文件")
@PostMapping("/upload-zip")
@ -71,14 +71,14 @@ public class UploadZipController {
}
String originalFilename = file.getOriginalFilename();
if (originalFilename == null || !originalFilename.toLowerCase().endsWith(".zip")) {
throw new BaseException("上传的文件不是有效的 ZIP 文件!");
}
String[] split = originalFilename.split("_");
if (split.length != 2 || !split[0].equals(recruitId.toString())) {
throw new BaseException("文件名与所选择招工不匹配");
}
// String[] split = originalFilename.split("_");
// if (split.length != 2 || !split[0].equals(recruitId.toString())) {
// throw new BaseException("文件名与所选择招工不匹配");
// }
BgtProjectRecruit recruit = recruitService.queryById(recruitId);
if (recruit == null) {
throw new BaseException("招工信息不存在!");
@ -90,79 +90,151 @@ public class UploadZipController {
}
String username = bgtUser.getUsername();
String firstLevelFolderName = "";
String firstLevelFolderName = recruitId + "_" + DigestUtil.md5Hex(recruit.getRecruitName());
try {
// 保存上传的压缩文件
String s = DigestUtil.md5Hex(recruit.getRecruitName());
firstLevelFolderName = recruitId + "_" + s;
// 保存并解压ZIP文件
File zipFile = new File(TEMP_DIR, firstLevelFolderName + ".zip");
ensureDirectoryExists(zipFile.getParentFile());
try (OutputStream os = new FileOutputStream(zipFile)) {
os.write(file.getBytes());
}
// 解压压缩文件
File extractDir = new File(TEMP_DIR, firstLevelFolderName);
ensureDirectoryExists(extractDir);
extractZipFile(zipFile, extractDir);
// 处理解压后的文件
processExtractedFolder(extractDir, recruitId);
// 收集目标路径仅BaoXian/HeTong目录下的最底层文件
// 收集路径返回Map和目录列表
Object[] paths = collectLeafPaths(extractDir);
Map<String, String> leafFileMap = (Map<String, String>) paths[0]; // 改为Map
List<String> targetDirPaths = (List<String>) paths[1];
// 将解压后的文件移动到 SAVE_DIR
moveFilesToSaveDir(extractDir, recruitId, username);
// 处理SAVE_DIR中已有文件的重命名关键新增逻辑
processExistingFilesInSaveDir(targetDirPaths, recruitId);
// 异步执行 RECORD_DIR 操作和删除临时文件操作
asyncProcessRecordAndDeleteTemp(extractDir, zipFile, recruitId, username, userId);
// 修改后(新调用方式)
processExtractedFolder(targetDirPaths, recruitId); // 传递收集的targetDirPaths
// 移动文件到SAVE_DIR使用收集的路径
moveFilesToSaveDir(extractDir, recruitId, username, leafFileMap);
// 异步清理临时文件(仅保留清理逻辑)
asyncDeleteTempFiles(extractDir, zipFile);
return AjaxResult.success("文件上传并处理成功");
} catch (Exception e) {
// 删除临时文件和文件夹
File extractDir = new File(TEMP_DIR, firstLevelFolderName);
deleteFolder(extractDir);
File zipFile = new File(TEMP_DIR, firstLevelFolderName + ".zip");
deleteFolder(zipFile);
deleteFolder(new File(TEMP_DIR, firstLevelFolderName));
deleteFolder(new File(TEMP_DIR, firstLevelFolderName + ".zip"));
e.printStackTrace();
return AjaxResult.error("文件处理过程中出现错误");
}
}
@Async
public CompletableFuture<Void> asyncProcessRecordAndDeleteTemp(File extractDir, File zipFile, Long recruitId, String username, Long userId) {
return CompletableFuture.runAsync(() -> {
try {
// 移动到 RECORD_DIR
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
String timeStamp = LocalDateTime.now().format(formatter);
BgtProjectRecruit recruit = recruitService.queryById(recruitId);
String s = DigestUtil.md5Hex(recruit.getRecruitName());
String firstLevelFolderName = recruitId + "_" + s;
File recordDestDir = new File(RECORD_DIR, firstLevelFolderName);
ensureDirectoryExists(recordDestDir);
/**
* 收集最底层文件路径仅BaoXian/HeTong目录下的文件
* @param extractDir 解压根目录
* @return [文件路径列表, 目录路径列表]
*/
private Object[] collectLeafPaths(File extractDir) {
Map<String, String> leafFileMap = new HashMap<>(); // key: 倒数第二层/倒数第一层/文件名value: 完整相对路径
List<String> targetDirPaths = new ArrayList<>();
collectLeafPathsRecursive(extractDir, extractDir, leafFileMap, targetDirPaths);
return new Object[]{leafFileMap, targetDirPaths};
}
List<AnnexRecord> annexRecordList = new ArrayList<>();
moveFilesToRecordDirRecursively(extractDir, recordDestDir, timeStamp, annexRecordList, recruitId, username, userId);
if (CollectionUtil.isNotEmpty(annexRecordList)) {
annexRecordService.saveBatch(annexRecordList);
}
/**
* 递归收集路径(核心逻辑:验证倒数第一层目录名)
*/
private void collectLeafPathsRecursive(File baseDir, File currentDir,
Map<String, String> leafFileMap, List<String> targetDirPaths) {
File[] files = currentDir.listFiles();
if (files == null || files.length == 0) return;
// 删除临时文件和文件夹
deleteFolder(extractDir);
if (!zipFile.delete()) {
System.err.println("无法删除压缩文件: " + zipFile.getAbsolutePath());
}
} catch (IOException e) {
e.printStackTrace();
boolean hasSubDir = false;
for (File file : files) {
if (file.isDirectory()) {
hasSubDir = true;
collectLeafPathsRecursive(baseDir, file, leafFileMap, targetDirPaths);
}
});
}
if (!hasSubDir) {
for (File file : files) {
if (file.isFile()) {
String relativePath = getRelativePath(file, baseDir); // 完整相对路径张三_123/BaoXian/文件.pdf
String[] pathParts = relativePath.split(Pattern.quote(File.separator));
if (pathParts.length >= 3) {
String secondLastDir = pathParts[pathParts.length - 3]; // 倒数第二层张三_123
String lastDir = pathParts[pathParts.length - 2]; // 倒数第一层BaoXian
String fileName = pathParts[pathParts.length - 1]; // 文件名(如:文件.pdf
if ("BaoXian".equals(lastDir) || "HeTong".equals(lastDir)) {
// 构造key倒数第二层/倒数第一层/文件名张三_123/BaoXian/文件.pdf
String key = secondLastDir + File.separator + lastDir + File.separator + fileName;
leafFileMap.put(key, relativePath); // 存入Map
// 收集目录路径(倒数第二层/倒数第一层/
String dirPath = secondLastDir + File.separator + lastDir + File.separator;
if (!targetDirPaths.contains(dirPath)) {
targetDirPaths.add(dirPath);
}
}
}
}
}
}
}
/**
* 处理SAVE_DIR中已有文件的重命名添加时间戳
*/
private void processExistingFilesInSaveDir(List<String> targetDirPaths, Long recruitId) throws IOException {
BgtProjectRecruit recruit = recruitService.queryById(recruitId);
String firstLevelFolder = recruitId + "_" + DigestUtil.md5Hex(recruit.getRecruitName());
File saveBaseDir = new File(SAVE_DIR, firstLevelFolder);
for (String dirPath : targetDirPaths) {
File targetDir = new File(saveBaseDir, dirPath);
if (targetDir.exists() && targetDir.isDirectory()) {
File[] existingFiles = targetDir.listFiles();
if (existingFiles != null) {
for (File existingFile : existingFiles) {
if (existingFile.isFile() && !isTimestampedFile(existingFile.getName())) {
String newFileName = addTimestampToFileName(existingFile.getName());
File newFile = new File(targetDir, newFileName);
if (!existingFile.renameTo(newFile)) {
throw new IOException("重命名失败: " + existingFile.getAbsolutePath());
}
}
}
}
}
}
}
/**
* 判断文件名是否已包含时间戳格式xxx_yyyyMMddHHmmss.xxx
*/
private boolean isTimestampedFile(String fileName) {
return fileName.matches("^.*_\\d{14}\\..*$");
}
/**
* 为文件名添加时间戳格式原文件名_yyyyMMddHHmmss.扩展名)
*/
private String addTimestampToFileName(String originalName) {
String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
int lastDotIndex = originalName.lastIndexOf('.');
if (lastDotIndex == -1) {
return originalName + "_" + timestamp;
}
return originalName.substring(0, lastDotIndex) + "_" + timestamp + originalName.substring(lastDotIndex);
}
private void ensureDirectoryExists(File directory) throws IOException {
if (!directory.exists()) {
if (!directory.mkdirs()) {
throw new IOException("无法创建目录: " + directory.getAbsolutePath());
}
if (!directory.exists() && !directory.mkdirs()) {
throw new IOException("无法创建目录: " + directory.getAbsolutePath());
}
}
@ -170,20 +242,12 @@ public class UploadZipController {
try (ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFile), Charset.forName("ISO-8859-15"))) {
ZipEntry zipEntry;
while ((zipEntry = zis.getNextEntry()) != null) {
File destFile = newFile(extractDir, zipEntry);
if (zipEntry.isDirectory()) {
// 是目录,不重命名,直接创建目录
File newDir = new File(extractDir, zipEntry.getName());
ensureDirectoryExists(newDir);
ensureDirectoryExists(destFile);
} else {
// 是文件,进行重命名
String originalFileName = zipEntry.getName();
String newFileName = renameFile(originalFileName);
File newFile = new File(extractDir, newFileName);
// 为文件创建父目录
ensureDirectoryExists(newFile.getParentFile());
// 写入文件内容
try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(newFile))) {
ensureDirectoryExists(destFile.getParentFile());
try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destFile))) {
byte[] bytesIn = new byte[4096];
int read;
while ((read = zis.read(bytesIn)) != -1) {
@ -193,277 +257,181 @@ public class UploadZipController {
}
}
}
}
private String renameFile(String originalFileName) {
int lastIndexOfSlash = originalFileName.lastIndexOf('/');
int lastIndexOfDot = originalFileName.lastIndexOf('.');
// 获取文件所在的目录路径
String directoryPath = lastIndexOfSlash != -1 ? originalFileName.substring(0, lastIndexOfSlash + 1) : "";
// 获取文件扩展名
String fileExtension = lastIndexOfDot != -1 ? originalFileName.substring(lastIndexOfDot) : "";
// 获取文件名(不包含扩展名)
String fileNameWithoutExtension = lastIndexOfSlash != -1 && lastIndexOfDot != -1 ?
originalFileName.substring(lastIndexOfSlash + 1, lastIndexOfDot) :
originalFileName;
// 将 MD5 值转换为一个整数
String s = DigestUtil.md5Hex(fileNameWithoutExtension);
return directoryPath + s + fileExtension;
originalFileName.substring(lastIndexOfSlash + 1, lastIndexOfDot) : originalFileName;
return directoryPath + DigestUtil.md5Hex(fileNameWithoutExtension) + fileExtension;
}
private File newFile(File destinationDir, ZipEntry zipEntry) throws IOException {
File destFile = new File(destinationDir, zipEntry.getName());
String destDirPath = destinationDir.getCanonicalPath();
String destFilePath = destFile.getCanonicalPath();
if (!destFilePath.startsWith(destDirPath + File.separator)) {
throw new IOException("Entry is outside of the target dir: " + zipEntry.getName());
}
return destFile;
}
private void processExtractedFolder(File extractDir, Long recruitId) {
File[] firstLevelFiles = extractDir.listFiles();
private void processExtractedFolder(List<String> targetDirPaths, Long recruitId) {
List<Long> insuranceUserIds = new ArrayList<>(); // 存储需要删除保险附件的用户ID
List<Long> contractUserIds = new ArrayList<>(); // 存储需要删除合同附件的用户ID
List<Long> recruitApplyIds = new ArrayList<>(); // 存储关联的招工申请ID
// 保险 2
List<Long> insurance = new ArrayList<>();
// 劳务合同 1
List<Long> contract = new ArrayList<>();
// 招工申请Id
List<Long> recruitApplyIds = new ArrayList<>();
if (firstLevelFiles != null) {
for (File firstLevelFile : firstLevelFiles) {
String firstLevelFolderName = firstLevelFile.getName();
System.out.println("第一层文件夹名称: " + firstLevelFolderName);
String[] split = firstLevelFolderName.split("_");
String card = split[1];
WgzUser wgzUser = wgzUserService.findByIdentityCard(card);
if (wgzUser == null) {
throw new BaseException("文件格式错误");
}
BgtProjectRecruitApply oneByUserIdAndRecruitId = recruitApplyService.getOneByUserIdAndRecruitId(wgzUser.getUserId(), recruitId);
if (oneByUserIdAndRecruitId == null) {
throw new BaseException("状态不对");
}
recruitApplyIds.add(oneByUserIdAndRecruitId.getId());
if (firstLevelFile.isDirectory()) {
File[] secondLevelFiles = firstLevelFile.listFiles();
if (secondLevelFiles != null) {
for (File secondLevelFile : secondLevelFiles) {
String secondLevelFolderName = secondLevelFile.getName();
System.out.println("第二层文件夹名称: " + secondLevelFolderName);
if (secondLevelFile.isDirectory()) {
File[] thirdLevelFiles = secondLevelFile.listFiles();
if (thirdLevelFiles != null && thirdLevelFiles.length > 0) {
// 删除数据库里的附件
if ("BaoXian".equals(secondLevelFolderName)) {
insurance.add(wgzUser.getUserId());
}
if ("HeTong".equals(secondLevelFolderName)) {
contract.add(wgzUser.getUserId());
}
}
}
}
}
}
// 遍历目标目录路径,解析关键信息
for (String dirPath : targetDirPaths) {
// dirPath格式示例"张三_110101199001011234/BaoXian/" 或 "李四_120101199002024567/HeTong/"
String[] pathParts = dirPath.split(Pattern.quote(File.separator));
if (pathParts.length < 2) {
throw new BaseException("目录路径格式异常: " + dirPath);
}
// 解析倒数第二层目录名字_身份证号和类型目录BaoXian/HeTong
String secondLastDir = pathParts[0]; // 格式名字_身份证号
String lastDir = pathParts[1]; // 格式BaoXian 或 HeTong末尾可能有斜杠需处理
lastDir = lastDir.replaceAll("/$", ""); // 移除末尾斜杠
// 验证类型目录是否合法
if (!"BaoXian".equals(lastDir) && !"HeTong".equals(lastDir)) {
continue; // 非目标类型目录,跳过
}
// 从"名字_身份证号"中提取身份证号
String[] nameIdCard = secondLastDir.split("_");
if (nameIdCard.length != 2) {
throw new BaseException("倒数第二层目录格式错误(需为'名字_身份证号': " + secondLastDir);
}
String idCard = nameIdCard[1];
// 根据身份证号查询用户
WgzUser wgzUser = wgzUserService.findByIdentityCard(idCard);
if (wgzUser == null) {
throw new BaseException("身份证号对应的用户不存在: " + idCard);
}
Long userId = wgzUser.getUserId();
// 查询用户对应的招工申请记录
BgtProjectRecruitApply apply = recruitApplyService.getOneByUserIdAndRecruitId(userId, recruitId);
if (apply == null) {
throw new BaseException("用户未参与当前招工或申请记录不存在: 用户ID=" + userId + ", 招工ID=" + recruitId);
}
Long applyId = apply.getId();
// 根据类型分类收集数据
if ("BaoXian".equals(lastDir)) {
insuranceUserIds.add(userId);
} else {
contractUserIds.add(userId);
}
recruitApplyIds.add(applyId);
}
if (CollectionUtil.isNotEmpty(insurance)) {
annexService.deleteByUserIdAndRecruitIdAndType(insurance, recruitId, "2", recruitApplyIds);
// 执行附件删除(与原逻辑一致,仅调整入参)
if (CollectionUtil.isNotEmpty(insuranceUserIds)) {
annexService.deleteByUserIdAndRecruitIdAndType(insuranceUserIds, recruitId, "2", recruitApplyIds);
}
if (CollectionUtil.isNotEmpty(contract)) {
annexService.deleteByUserIdAndRecruitIdAndType(contract, recruitId, "1", recruitApplyIds);
if (CollectionUtil.isNotEmpty(contractUserIds)) {
annexService.deleteByUserIdAndRecruitIdAndType(contractUserIds, recruitId, "1", recruitApplyIds);
}
}
private void moveFilesToSaveDir(File sourceDir, Long recruitId, String username) throws IOException {
// 移动到 SAVE_DIR
private void moveFilesToSaveDir(File sourceDir, Long recruitId, String username, Map<String, String> leafFileMap) throws IOException {
File saveDestDir = new File(SAVE_DIR);
ensureDirectoryExists(saveDestDir);
BgtProjectRecruit recruit = recruitService.queryById(recruitId);
String s = DigestUtil.md5Hex(recruit.getRecruitName());
String firstLevelFolderName = recruit.getId() + "_" + s;
String firstLevelFolderName = recruit.getId() + "_" + DigestUtil.md5Hex(recruit.getRecruitName());
File firstLevelDestDir = new File(saveDestDir, firstLevelFolderName);
ensureDirectoryExists(firstLevelDestDir);
File[] firstLevelFiles = sourceDir.listFiles();
List<Annex> annexList = new ArrayList<>();
if (firstLevelFiles != null) {
for (File firstLevelFile : firstLevelFiles) {
if (firstLevelFile.isDirectory()) {
for (Map.Entry<String, String> entry : leafFileMap.entrySet()) {
String key = entry.getKey(); // 格式:倒数第二层/倒数第一层/文件名张三_123/BaoXian/文件.pdf
String relativePath = entry.getValue(); // 完整相对路径张三_123/BaoXian/文件.pdf
String firstLevelName = firstLevelFile.getName(); //解压目录
File secondLevelDestDir = new File(firstLevelDestDir, firstLevelName); //保存目录
File[] secondLevelFiles = firstLevelFile.listFiles();
if (secondLevelFiles != null) {
for (File secondLevelfile : secondLevelFiles) {
if (secondLevelfile.isDirectory()) {
String secondLevelName = secondLevelfile.getName(); //解压目录
File thirdLevelDestDir = new File(secondLevelDestDir, secondLevelName); //保存目录
File[] thirdLevelFiles = secondLevelfile.listFiles();
if (thirdLevelFiles != null && thirdLevelFiles.length > 0) {
deleteFolder(thirdLevelDestDir);
}
}
}
}
moveFilesRecursively(firstLevelFile, firstLevelDestDir, annexList, recruitId, username);
// 原文件路径:解压目录 + 相对路径
File sourceFile = new File(sourceDir,relativePath);
if (!sourceFile.exists() || !sourceFile.isFile()) {
continue;
}
}
// 拆分原文件路径为目录部分和文件名部分
String originalFileName = sourceFile.getName(); // 原文件名(含扩展名)
String parentDirPath = key.substring(0, key.length() - originalFileName.length()); // 目录路径(如 "张三_123/BaoXian/"
// 分离文件名主体和扩展名(例如 "原文件" 和 ".pdf"
int lastDotIndex = originalFileName.lastIndexOf('.');
String fileNameWithoutExt = (lastDotIndex == -1) ? originalFileName : originalFileName.substring(0, lastDotIndex);
String fileExtension = (lastDotIndex == -1) ? "" : originalFileName.substring(lastDotIndex);
// 生成MD5文件名对文件名主体进行哈希保留扩展名
String md5FileName = DigestUtil.md5Hex(fileNameWithoutExt); // MD5哈希值
String newFileName = md5FileName + fileExtension; // 新文件名(如 "d41d8cd98f00b204e9800998ecf8427e.pdf"
// 构建目标文件路径(原目录结构 + MD5文件名
String newFilePath = parentDirPath + newFileName;
File destFile = new File(firstLevelDestDir, newFilePath);
ensureDirectoryExists(destFile.getParentFile());
// 复制文件到目标目录
try (InputStream in = new FileInputStream(sourceFile);
OutputStream out = new FileOutputStream(destFile)) {
byte[] buffer = new byte[4096];
int length;
while ((length = in.read(buffer)) > 0) {
out.write(buffer, 0, length);
}
}
// 记录附件信息更新文件名为MD5后的值
String newRelativePath = SAVE_DIR + File.separator + newFilePath;
newRelativePath = newRelativePath.replace("\\", "/").replace("ruoyi/uploadPath", "/profile");
String[] pathParts = relativePath.split(Pattern.quote(File.separator));
String parentName = pathParts[pathParts.length - 3]; // 倒数第二层目录名(用户标识)
String dirName = pathParts[pathParts.length - 2]; // 倒数第一层目录名BaoXian/HeTong
String[] userParts = parentName.split("_");
String card = userParts[1];
WgzUser wgzUser = wgzUserService.findByIdentityCard(card);
BgtProjectRecruitApply apply = recruitApplyService.getOneByUserIdAndRecruitId(wgzUser.getUserId(), recruitId);
Annex annex = new Annex();
annex.setAnnexName(newFileName);
annex.setAnnexUrl(newRelativePath);
annex.setAnnexType("BaoXian".equals(dirName) ? "2" : "1");
annex.setUserType(Constants.WGZ);
annex.setUserId(wgzUser.getUserId());
annex.setRecruitId(recruitId);
annex.setRecruitApplyId(apply.getId());
annex.setCreateBy(username);
annex.setUpdateBy(username);
annexList.add(annex);
}
if (CollectionUtil.isNotEmpty(annexList)) {
annexService.saveBatch(annexList);
}
}
private void moveFilesRecursively(File source, File destination, List<Annex> annexList, Long recruitId, String username) throws IOException {
if (source.isDirectory()) {
File newDir = new File(destination, source.getName());
ensureDirectoryExists(newDir);
File[] files = source.listFiles();
if (files != null) {
for (File file : files) {
moveFilesRecursively(file, newDir, annexList, recruitId, username);
@Async
public CompletableFuture<Void> asyncDeleteTempFiles(File extractDir, File zipFile) {
return CompletableFuture.runAsync(() -> {
try {
// 仅清理临时解压目录和ZIP文件
deleteFolder(extractDir);
if (!zipFile.delete()) {
System.err.println("无法删除压缩文件: " + zipFile.getAbsolutePath());
}
} catch (Exception e) {
e.printStackTrace();
}
} else {
File destFile = new File(destination, source.getName());
ensureDirectoryExists(destFile.getParentFile());
try (InputStream in = new FileInputStream(source);
OutputStream out = new FileOutputStream(destFile)) {
byte[] buffer = new byte[4096];
int length;
while ((length = in.read(buffer)) > 0) {
out.write(buffer, 0, length);
}
}
String relativePath = SAVE_DIR + File.separator + getRelativePath(source, new File(TEMP_DIR));
relativePath = relativePath.replace("\\", "/").replace("ruoyi/uploadPath", "/profile");
System.out.println("文件在项目里的相对目录: " + relativePath);
// 存到数据库
String parentName = destination.getParentFile().getName();
System.out.println("上上一级文件名: " + parentName);
String[] split = parentName.split("_");
String card = split[1];
WgzUser wgzUser = wgzUserService.findByIdentityCard(card);
BgtProjectRecruitApply oneByUserIdAndRecruitId = recruitApplyService.getOneByUserIdAndRecruitId(wgzUser.getUserId(), recruitId);
String name = destination.getName();
System.out.println("上一级文件名: " + name);
String type = "";
if ("BaoXian".equals(name)) {
type = "2";
}
if ("HeTong".equals(name)) {
type = "1";
}
Annex annex = new Annex();
annex.setAnnexName(destFile.getName());
annex.setAnnexUrl(relativePath);
annex.setAnnexType(type);
annex.setUserType(Constants.WGZ);
annex.setUserId(wgzUser.getUserId());
annex.setRecruitId(recruitId);
annex.setRecruitApplyId(oneByUserIdAndRecruitId.getId());
annex.setCreateBy(username);
annex.setUpdateBy(username);
annexList.add(annex);
}
}
private void moveFilesToRecordDirRecursively(File source, File destination, String timeStamp, List<AnnexRecord> annexRecordList, Long recruitId, String username, Long userId) throws IOException {
if (source.isDirectory()) {
String folderName = source.getName();
String[] parts = folderName.split("_");
if (parts.length > 0 && parts[0].matches("\\d+") && parts.length > 1 && parts[0].equals(recruitId.toString())) {
// 如果parts第一部分是数字并且长度大于1跳过这一级目录的创建直接处理下一级目录
File[] files = source.listFiles();
if (files != null) {
for (File file : files) {
moveFilesToRecordDirRecursively(file, destination, timeStamp, annexRecordList, recruitId, username, userId);
}
}
} else {
File newDir = new File(destination, folderName);
ensureDirectoryExists(newDir);
File[] files = source.listFiles();
if (files != null) {
for (File file : files) {
moveFilesToRecordDirRecursively(file, newDir, timeStamp, annexRecordList, recruitId, username, userId);
}
}
}
} else {
// 获取文件名和扩展名
String fileName = source.getName();
int dotIndex = fileName.lastIndexOf('.');
String nameWithoutExtension = dotIndex == -1 ? fileName : fileName.substring(0, dotIndex);
String extension = dotIndex == -1 ? "" : fileName.substring(dotIndex);
// 在文件名后面添加时间戳
String newFileName = nameWithoutExtension + "_" + timeStamp + extension;
File destFile = new File(destination, newFileName);
ensureDirectoryExists(destFile.getParentFile());
try (InputStream in = new FileInputStream(source);
OutputStream out = new FileOutputStream(destFile)) {
byte[] buffer = new byte[4096];
int length;
while ((length = in.read(buffer)) > 0) {
out.write(buffer, 0, length);
}
}
// 记录文件信息到数据库
String relativePath = RECORD_DIR + File.separator + getRelativePath(destFile, new File(RECORD_DIR));
relativePath = relativePath.replace("\\", "/").replace("ruoyi/uploadPath", "/profile");
String parentName = destination.getParentFile().getName();
String[] split = parentName.split("_");
String card = split[1];
WgzUser wgzUser = wgzUserService.findByIdentityCard(card);
BgtProjectRecruitApply oneByUserIdAndRecruitId = recruitApplyService.getOneByUserIdAndRecruitId(wgzUser.getUserId(), recruitId);
String name = destination.getName();
String type = "";
if ("BaoXian".equals(name)) {
type = "2";
}
if ("HeTong".equals(name)) {
type = "1";
}
AnnexRecord annexRecord = new AnnexRecord();
annexRecord.setAnnexName(newFileName);
annexRecord.setAnnexUrl(relativePath);
annexRecord.setAnnexType(type);
annexRecord.setUserType(Constants.WGZ);
annexRecord.setUserId(wgzUser.getUserId());
annexRecord.setRecruitId(recruitId);
annexRecord.setRecruitApplyId(oneByUserIdAndRecruitId.getId());
annexRecord.setCreateBy(username);
annexRecord.setUpdateBy(username);
annexRecord.setCreateUserId(userId);
annexRecord.setCreateUserType(Constants.BGT);
annexRecordList.add(annexRecord);
}
});
}
private String getRelativePath(File file, File baseDir) {

View File

@ -3,6 +3,8 @@ package com.ruoyi.web.controller.fbs;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.util.MessageUtil;
import com.ruoyi.fbs.domain.FbsMessage;
import com.ruoyi.fbs.domain.dto.FbsMessageDetailDTO;
import com.ruoyi.fbs.domain.dto.FbsMessageMyListDTO;
@ -29,7 +31,7 @@ import org.springframework.web.bind.annotation.*;
public class AppFbsMessageController extends BaseController {
private final IFbsMessageService iFbsMessageService;
private final RedisCache redisCache;
@ApiOperation("分包商未读消息统计")
@GetMapping("/countUnread")
public AjaxResult<FbsMessageCountVO> count() {
@ -54,10 +56,14 @@ public class AppFbsMessageController extends BaseController {
@ApiOperation("分包商消息已读")
@PutMapping("/read/{id}")
public AjaxResult<Boolean> read(@PathVariable(value = "id") Long id) {
FbsMessage fbsMessage = new FbsMessage();
fbsMessage.setId(id);
fbsMessage.setReadStatus("1");
return AjaxResult.success(iFbsMessageService.updateById(fbsMessage));
FbsMessage fbsMessage = iFbsMessageService.getById(id);
boolean b = true;
if("0".equals(fbsMessage.getReadStatus())){
MessageUtil.readMessagePush(fbsMessage.getRecipientType(), fbsMessage.getRecipientId(), fbsMessage.getMessageLargeType(), fbsMessage.getReadStatus());
fbsMessage.setReadStatus("1");
b = iFbsMessageService.updateById(fbsMessage);
}
return AjaxResult.success(b);
}
@ApiOperation("分包商消息已操作")
@ -69,4 +75,10 @@ public class AppFbsMessageController extends BaseController {
return AjaxResult.success(iFbsMessageService.updateById(fbsMessage));
}
@ApiOperation("消息详情")
@GetMapping("/detail/{id}")
public AjaxResult<FbsMessage> detail(@PathVariable(value = "id") Long id) {
return AjaxResult.success(iFbsMessageService.getById(id));
}
}

View File

@ -148,6 +148,15 @@
return AjaxResult.success(iWgzUserService.userPersonalBasicInformation(req));
}
/**
* 【我的】总收入
*/
@GetMapping("/grossIncome")
public AjaxResult<BigDecimal> grossIncome() {
return AjaxResult.success(iWgzPayCalculationService.grossIncome());
}
/**
* 【我的】【实名认证】实名认证
*/

View File

@ -3,6 +3,7 @@ package com.ruoyi.web.controller.zbf;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.util.MessageUtil;
import com.ruoyi.zbf.domain.ZbfMessage;
import com.ruoyi.zbf.domain.dto.ZbfMessageDetailDTO;
import com.ruoyi.zbf.domain.dto.ZbfMessageMyListDTO;
@ -29,7 +30,6 @@ import org.springframework.web.bind.annotation.*;
public class AppZbfMessageController extends BaseController {
private final IZbfMessageService iZbfMessageService;
/**
* 查询消息列表
*/
@ -55,10 +55,14 @@ public class AppZbfMessageController extends BaseController {
@ApiOperation("总包方消息已读")
@PutMapping("/read/{id}")
public AjaxResult<Boolean> read(@PathVariable(value = "id") Long id) {
ZbfMessage zbfMessage = new ZbfMessage();
zbfMessage.setId(id);
zbfMessage.setReadStatus("1");
return AjaxResult.success(iZbfMessageService.updateById(zbfMessage));
ZbfMessage zbfMessage = iZbfMessageService.getById(id);
boolean b= true;
if("0".equals(zbfMessage.getReadStatus())){
MessageUtil.readMessagePush(zbfMessage.getRecipientType(), zbfMessage.getRecipientId(), zbfMessage.getMessageLargeType(), zbfMessage.getReadStatus());
zbfMessage.setReadStatus("1");
iZbfMessageService.updateById(zbfMessage);
}
return AjaxResult.success(b);
}
@ApiOperation("总包方消息已操作")