优化
This commit is contained in:
		| @ -15,7 +15,9 @@ import com.ruoyi.bgt.service.IBgtProjectRecruitService; | |||||||
| import com.ruoyi.common.core.controller.BaseController; | import com.ruoyi.common.core.controller.BaseController; | ||||||
| import com.ruoyi.common.core.domain.AjaxResult; | import com.ruoyi.common.core.domain.AjaxResult; | ||||||
| import com.ruoyi.common.core.page.TableDataInfo; | import com.ruoyi.common.core.page.TableDataInfo; | ||||||
|  | import com.ruoyi.common.core.redis.RedisCache; | ||||||
| import com.ruoyi.common.enums.RecruitApplyStatus; | import com.ruoyi.common.enums.RecruitApplyStatus; | ||||||
|  | import com.ruoyi.common.util.MessageUtil; | ||||||
| import com.ruoyi.wgz.bo.req.WgzAppPersonalBasicInformationReq; | import com.ruoyi.wgz.bo.req.WgzAppPersonalBasicInformationReq; | ||||||
| import com.ruoyi.wgz.bo.res.WgzAppPersonalBasicInformationRes; | import com.ruoyi.wgz.bo.res.WgzAppPersonalBasicInformationRes; | ||||||
| import com.ruoyi.wgz.service.IWgzAttendanceService; | import com.ruoyi.wgz.service.IWgzAttendanceService; | ||||||
| @ -53,6 +55,8 @@ public class AppBgtMessageController extends BaseController { | |||||||
|  |  | ||||||
| 	private final IBgtProjectRecruitService iBgtProjectRecruitService; | 	private final IBgtProjectRecruitService iBgtProjectRecruitService; | ||||||
|  |  | ||||||
|  | 	private final RedisCache redisCache; | ||||||
|  |  | ||||||
| 	@ApiOperation("未读消息统计") | 	@ApiOperation("未读消息统计") | ||||||
| 	@GetMapping("/countUnread") | 	@GetMapping("/countUnread") | ||||||
| 	public AjaxResult<BgtMessageCountVO> count() { | 	public AjaxResult<BgtMessageCountVO> count() { | ||||||
| @ -74,10 +78,14 @@ public class AppBgtMessageController extends BaseController { | |||||||
| 	@ApiOperation("已读") | 	@ApiOperation("已读") | ||||||
| 	@PutMapping("/read/{id}") | 	@PutMapping("/read/{id}") | ||||||
| 	public AjaxResult<Boolean> read(@PathVariable(value = "id") Long id) { | 	public AjaxResult<Boolean> read(@PathVariable(value = "id") Long id) { | ||||||
| 		BgtMessage bgtMessage = new BgtMessage(); | 		BgtMessage bgtMessage = iBgtMessageService.getById(id); | ||||||
| 		bgtMessage.setId(id); | 		boolean b = true; | ||||||
|  | 		if("0".equals(bgtMessage.getReadStatus())){ | ||||||
|  | 			MessageUtil.readMessagePush(bgtMessage.getRecipientType(), bgtMessage.getRecipientId(), bgtMessage.getMessageLargeType(), bgtMessage.getReadStatus()); | ||||||
| 			bgtMessage.setReadStatus("1"); | 			bgtMessage.setReadStatus("1"); | ||||||
| 		return AjaxResult.success(iBgtMessageService.updateById(bgtMessage)); | 			b = iBgtMessageService.updateById(bgtMessage); | ||||||
|  | 		} | ||||||
|  | 		return AjaxResult.success(b); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	@ApiOperation("已操作") | 	@ApiOperation("已操作") | ||||||
|  | |||||||
| @ -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);  // 异常时清理无效连接 | ||||||
|  | //			} | ||||||
|  | //		} | ||||||
|  | //	} | ||||||
|  | } | ||||||
|  |  | ||||||
| @ -11,7 +11,6 @@ import com.ruoyi.common.constant.Constants; | |||||||
| import com.ruoyi.common.core.domain.AjaxResult; | import com.ruoyi.common.core.domain.AjaxResult; | ||||||
| import com.ruoyi.common.core.domain.entity.BgtUser; | import com.ruoyi.common.core.domain.entity.BgtUser; | ||||||
| import com.ruoyi.common.domain.Annex; | import com.ruoyi.common.domain.Annex; | ||||||
| import com.ruoyi.common.domain.AnnexRecord; |  | ||||||
| import com.ruoyi.common.exception.BaseException; | import com.ruoyi.common.exception.BaseException; | ||||||
| import com.ruoyi.common.service.IAnnexRecordService; | import com.ruoyi.common.service.IAnnexRecordService; | ||||||
| import com.ruoyi.common.service.IAnnexService; | import com.ruoyi.common.service.IAnnexService; | ||||||
| @ -34,15 +33,16 @@ import java.nio.charset.Charset; | |||||||
| import java.time.LocalDateTime; | import java.time.LocalDateTime; | ||||||
| import java.time.format.DateTimeFormatter; | import java.time.format.DateTimeFormatter; | ||||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||||
|  | import java.util.HashMap; | ||||||
| import java.util.List; | import java.util.List; | ||||||
|  | import java.util.Map; | ||||||
| import java.util.concurrent.CompletableFuture; | import java.util.concurrent.CompletableFuture; | ||||||
|  | import java.util.regex.Pattern; | ||||||
| import java.util.zip.ZipEntry; | import java.util.zip.ZipEntry; | ||||||
| import java.util.zip.ZipInputStream; | import java.util.zip.ZipInputStream; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * 登录验证 |  * 压缩文件上传控制器(整合路径收集与验证逻辑) | ||||||
|  * |  | ||||||
|  * @author ruoyi |  | ||||||
|  */ |  */ | ||||||
| @Api(value = "网页模板上传", tags = {"网页模板上传"}) | @Api(value = "网页模板上传", tags = {"网页模板上传"}) | ||||||
| @RequiredArgsConstructor(onConstructor_ = @Autowired) | @RequiredArgsConstructor(onConstructor_ = @Autowired) | ||||||
| @ -57,8 +57,8 @@ public class UploadZipController { | |||||||
| 	private final IBgtUserService bgtUserService; | 	private final IBgtUserService bgtUserService; | ||||||
| 	private final IBgtProjectRecruitApplyService recruitApplyService; | 	private final IBgtProjectRecruitApplyService recruitApplyService; | ||||||
|  |  | ||||||
| 	private static final String TEMP_DIR = "ruoyi/uploadPath/temporaryZip";  //临时解压 | 	private static final String TEMP_DIR = "ruoyi/uploadPath/temporaryZip";  // 临时解压目录 | ||||||
| 	private static final String SAVE_DIR = "ruoyi/uploadPath/recruit";        //保存目录 | 	private static final String SAVE_DIR = "ruoyi/uploadPath/recruit";        // 最终保存目录 | ||||||
| 	private static final String RECORD_DIR = "ruoyi/uploadPath/record";        // 记录目录 | 	private static final String RECORD_DIR = "ruoyi/uploadPath/record";        // 记录目录 | ||||||
|  |  | ||||||
| 	@ApiOperation("上传压缩文件") | 	@ApiOperation("上传压缩文件") | ||||||
| @ -71,14 +71,14 @@ public class UploadZipController { | |||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		String originalFilename = file.getOriginalFilename(); | 		String originalFilename = file.getOriginalFilename(); | ||||||
|  |  | ||||||
| 		if (originalFilename == null || !originalFilename.toLowerCase().endsWith(".zip")) { | 		if (originalFilename == null || !originalFilename.toLowerCase().endsWith(".zip")) { | ||||||
| 			throw new BaseException("上传的文件不是有效的 ZIP 文件!"); | 			throw new BaseException("上传的文件不是有效的 ZIP 文件!"); | ||||||
| 		} | 		} | ||||||
| 		String[] split = originalFilename.split("_"); | //		String[] split = originalFilename.split("_"); | ||||||
| 		if (split.length != 2 || !split[0].equals(recruitId.toString())) { | //		if (split.length != 2 || !split[0].equals(recruitId.toString())) { | ||||||
| 			throw new BaseException("文件名与所选择招工不匹配"); | //			throw new BaseException("文件名与所选择招工不匹配"); | ||||||
| 		} | //		} | ||||||
|  |  | ||||||
| 		BgtProjectRecruit recruit = recruitService.queryById(recruitId); | 		BgtProjectRecruit recruit = recruitService.queryById(recruitId); | ||||||
| 		if (recruit == null) { | 		if (recruit == null) { | ||||||
| 			throw new BaseException("招工信息不存在!"); | 			throw new BaseException("招工信息不存在!"); | ||||||
| @ -90,100 +90,164 @@ public class UploadZipController { | |||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		String username = bgtUser.getUsername(); | 		String username = bgtUser.getUsername(); | ||||||
| 		String firstLevelFolderName = ""; | 		String firstLevelFolderName = recruitId + "_" + DigestUtil.md5Hex(recruit.getRecruitName()); | ||||||
| 		try { | 		try { | ||||||
| 			// 保存上传的压缩文件 | 			// 保存并解压ZIP文件 | ||||||
| 			String s = DigestUtil.md5Hex(recruit.getRecruitName()); |  | ||||||
| 			firstLevelFolderName = recruitId + "_" + s; |  | ||||||
| 			File zipFile = new File(TEMP_DIR, firstLevelFolderName + ".zip"); | 			File zipFile = new File(TEMP_DIR, firstLevelFolderName + ".zip"); | ||||||
| 			ensureDirectoryExists(zipFile.getParentFile()); | 			ensureDirectoryExists(zipFile.getParentFile()); | ||||||
| 			try (OutputStream os = new FileOutputStream(zipFile)) { | 			try (OutputStream os = new FileOutputStream(zipFile)) { | ||||||
| 				os.write(file.getBytes()); | 				os.write(file.getBytes()); | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			// 解压压缩文件 |  | ||||||
| 			File extractDir = new File(TEMP_DIR, firstLevelFolderName); | 			File extractDir = new File(TEMP_DIR, firstLevelFolderName); | ||||||
| 			ensureDirectoryExists(extractDir); | 			ensureDirectoryExists(extractDir); | ||||||
| 			extractZipFile(zipFile, extractDir); | 			extractZipFile(zipFile, extractDir); | ||||||
|  |  | ||||||
| 			// 处理解压后的文件夹 | 			// 收集目标路径(仅BaoXian/HeTong目录下的最底层文件) | ||||||
| 			processExtractedFolder(extractDir, recruitId); | 			// 收集路径(返回Map和目录列表) | ||||||
|  | 			Object[] paths = collectLeafPaths(extractDir); | ||||||
|  | 			Map<String, String> leafFileMap = (Map<String, String>) paths[0];  // 改为Map | ||||||
|  | 			List<String> targetDirPaths = (List<String>) paths[1]; | ||||||
|  |  | ||||||
| 			// 将解压后的文件移动到 SAVE_DIR | 			// 处理SAVE_DIR中已有文件的重命名(关键新增逻辑) | ||||||
| 			moveFilesToSaveDir(extractDir, recruitId, username); | 			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("文件上传并处理成功"); | 			return AjaxResult.success("文件上传并处理成功"); | ||||||
| 		} catch (Exception e) { | 		} catch (Exception e) { | ||||||
| 			// 删除临时文件和文件夹 | 			deleteFolder(new File(TEMP_DIR, firstLevelFolderName)); | ||||||
| 			File extractDir = new File(TEMP_DIR, firstLevelFolderName); | 			deleteFolder(new File(TEMP_DIR, firstLevelFolderName + ".zip")); | ||||||
| 			deleteFolder(extractDir); |  | ||||||
| 			File zipFile = new File(TEMP_DIR, firstLevelFolderName + ".zip"); |  | ||||||
| 			deleteFolder(zipFile); |  | ||||||
| 			e.printStackTrace(); | 			e.printStackTrace(); | ||||||
| 			return AjaxResult.error("文件处理过程中出现错误"); | 			return AjaxResult.error("文件处理过程中出现错误"); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	@Async | 	/** | ||||||
| 	public CompletableFuture<Void> asyncProcessRecordAndDeleteTemp(File extractDir, File zipFile, Long recruitId, String username, Long userId) { | 	 * 收集最底层文件路径(仅BaoXian/HeTong目录下的文件) | ||||||
| 		return CompletableFuture.runAsync(() -> { | 	 * @param extractDir 解压根目录 | ||||||
| 			try { | 	 * @return [文件路径列表, 目录路径列表] | ||||||
| 				// 移动到 RECORD_DIR | 	 */ | ||||||
| 				DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss"); | 	private Object[] collectLeafPaths(File extractDir) { | ||||||
| 				String timeStamp = LocalDateTime.now().format(formatter); | 		Map<String, String> leafFileMap = new HashMap<>();  // key: 倒数第二层/倒数第一层/文件名,value: 完整相对路径 | ||||||
|  | 		List<String> targetDirPaths = new ArrayList<>(); | ||||||
|  | 		collectLeafPathsRecursive(extractDir, extractDir, leafFileMap, targetDirPaths); | ||||||
|  | 		return new Object[]{leafFileMap, targetDirPaths}; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * 递归收集路径(核心逻辑:验证倒数第一层目录名) | ||||||
|  | 	 */ | ||||||
|  | 	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; | ||||||
|  |  | ||||||
|  | 		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); | 		BgtProjectRecruit recruit = recruitService.queryById(recruitId); | ||||||
| 				String s = DigestUtil.md5Hex(recruit.getRecruitName()); | 		String firstLevelFolder = recruitId + "_" + DigestUtil.md5Hex(recruit.getRecruitName()); | ||||||
| 				String firstLevelFolderName = recruitId + "_" + s; | 		File saveBaseDir = new File(SAVE_DIR, firstLevelFolder); | ||||||
| 				File recordDestDir = new File(RECORD_DIR, firstLevelFolderName); |  | ||||||
| 				ensureDirectoryExists(recordDestDir); |  | ||||||
|  |  | ||||||
| 				List<AnnexRecord> annexRecordList = new ArrayList<>(); | 		for (String dirPath : targetDirPaths) { | ||||||
| 				moveFilesToRecordDirRecursively(extractDir, recordDestDir, timeStamp, annexRecordList, recruitId, username, userId); | 			File targetDir = new File(saveBaseDir, dirPath); | ||||||
|  | 			if (targetDir.exists() && targetDir.isDirectory()) { | ||||||
| 				if (CollectionUtil.isNotEmpty(annexRecordList)) { | 				File[] existingFiles = targetDir.listFiles(); | ||||||
| 					annexRecordService.saveBatch(annexRecordList); | 				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()); | ||||||
|  | 							} | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 				// 删除临时文件和文件夹 | 	/** | ||||||
| 				deleteFolder(extractDir); | 	 * 判断文件名是否已包含时间戳(格式:xxx_yyyyMMddHHmmss.xxx) | ||||||
| 				if (!zipFile.delete()) { | 	 */ | ||||||
| 					System.err.println("无法删除压缩文件: " + zipFile.getAbsolutePath()); | 	private boolean isTimestampedFile(String fileName) { | ||||||
|  | 		return fileName.matches("^.*_\\d{14}\\..*$"); | ||||||
| 	} | 	} | ||||||
| 			} catch (IOException e) { |  | ||||||
| 				e.printStackTrace(); | 	/** | ||||||
|  | 	 * 为文件名添加时间戳(格式:原文件名_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 { | 	private void ensureDirectoryExists(File directory) throws IOException { | ||||||
| 		if (!directory.exists()) { | 		if (!directory.exists() && !directory.mkdirs()) { | ||||||
| 			if (!directory.mkdirs()) { |  | ||||||
| 			throw new IOException("无法创建目录: " + directory.getAbsolutePath()); | 			throw new IOException("无法创建目录: " + directory.getAbsolutePath()); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	private void extractZipFile(File zipFile, File extractDir) throws IOException { | 	private void extractZipFile(File zipFile, File extractDir) throws IOException { | ||||||
| 		try (ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFile), Charset.forName("ISO-8859-15"))) { | 		try (ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFile), Charset.forName("ISO-8859-15"))) { | ||||||
| 			ZipEntry zipEntry; | 			ZipEntry zipEntry; | ||||||
| 			while ((zipEntry = zis.getNextEntry()) != null) { | 			while ((zipEntry = zis.getNextEntry()) != null) { | ||||||
|  | 				File destFile = newFile(extractDir, zipEntry); | ||||||
| 				if (zipEntry.isDirectory()) { | 				if (zipEntry.isDirectory()) { | ||||||
| 					// 是目录,不重命名,直接创建目录 | 					ensureDirectoryExists(destFile); | ||||||
| 					File newDir = new File(extractDir, zipEntry.getName()); |  | ||||||
| 					ensureDirectoryExists(newDir); |  | ||||||
| 				} else { | 				} else { | ||||||
| 					// 是文件,进行重命名 | 					ensureDirectoryExists(destFile.getParentFile()); | ||||||
| 					String originalFileName = zipEntry.getName(); | 					try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destFile))) { | ||||||
| 					String newFileName = renameFile(originalFileName); |  | ||||||
| 					File newFile = new File(extractDir, newFileName); |  | ||||||
| 					// 为文件创建父目录 |  | ||||||
| 					ensureDirectoryExists(newFile.getParentFile()); |  | ||||||
|  |  | ||||||
| 					// 写入文件内容 |  | ||||||
| 					try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(newFile))) { |  | ||||||
| 						byte[] bytesIn = new byte[4096]; | 						byte[] bytesIn = new byte[4096]; | ||||||
| 						int read; | 						int read; | ||||||
| 						while ((read = zis.read(bytesIn)) != -1) { | 						while ((read = zis.read(bytesIn)) != -1) { | ||||||
| @ -193,277 +257,181 @@ public class UploadZipController { | |||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	private String renameFile(String originalFileName) { | 	private String renameFile(String originalFileName) { | ||||||
| 		int lastIndexOfSlash = originalFileName.lastIndexOf('/'); | 		int lastIndexOfSlash = originalFileName.lastIndexOf('/'); | ||||||
| 		int lastIndexOfDot = originalFileName.lastIndexOf('.'); | 		int lastIndexOfDot = originalFileName.lastIndexOf('.'); | ||||||
|  |  | ||||||
| 		// 获取文件所在的目录路径 |  | ||||||
| 		String directoryPath = lastIndexOfSlash != -1 ? originalFileName.substring(0, lastIndexOfSlash + 1) : ""; | 		String directoryPath = lastIndexOfSlash != -1 ? originalFileName.substring(0, lastIndexOfSlash + 1) : ""; | ||||||
| 		// 获取文件扩展名 |  | ||||||
| 		String fileExtension = lastIndexOfDot != -1 ? originalFileName.substring(lastIndexOfDot) : ""; | 		String fileExtension = lastIndexOfDot != -1 ? originalFileName.substring(lastIndexOfDot) : ""; | ||||||
| 		// 获取文件名(不包含扩展名) |  | ||||||
| 		String fileNameWithoutExtension = lastIndexOfSlash != -1 && lastIndexOfDot != -1 ? | 		String fileNameWithoutExtension = lastIndexOfSlash != -1 && lastIndexOfDot != -1 ? | ||||||
| 			originalFileName.substring(lastIndexOfSlash + 1, lastIndexOfDot) : | 			originalFileName.substring(lastIndexOfSlash + 1, lastIndexOfDot) : originalFileName; | ||||||
| 			originalFileName; | 		return directoryPath + DigestUtil.md5Hex(fileNameWithoutExtension) + fileExtension; | ||||||
|  |  | ||||||
| 		// 将 MD5 值转换为一个整数 |  | ||||||
| 		String s = DigestUtil.md5Hex(fileNameWithoutExtension); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 		return directoryPath + s + fileExtension; |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	private File newFile(File destinationDir, ZipEntry zipEntry) throws IOException { | 	private File newFile(File destinationDir, ZipEntry zipEntry) throws IOException { | ||||||
| 		File destFile = new File(destinationDir, zipEntry.getName()); | 		File destFile = new File(destinationDir, zipEntry.getName()); | ||||||
|  |  | ||||||
| 		String destDirPath = destinationDir.getCanonicalPath(); | 		String destDirPath = destinationDir.getCanonicalPath(); | ||||||
| 		String destFilePath = destFile.getCanonicalPath(); | 		String destFilePath = destFile.getCanonicalPath(); | ||||||
|  |  | ||||||
| 		if (!destFilePath.startsWith(destDirPath + File.separator)) { | 		if (!destFilePath.startsWith(destDirPath + File.separator)) { | ||||||
| 			throw new IOException("Entry is outside of the target dir: " + zipEntry.getName()); | 			throw new IOException("Entry is outside of the target dir: " + zipEntry.getName()); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		return destFile; | 		return destFile; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	private void processExtractedFolder(File extractDir, Long recruitId) { | 	private void processExtractedFolder(List<String> targetDirPaths, Long recruitId) { | ||||||
| 		File[] firstLevelFiles = extractDir.listFiles(); | 		List<Long> insuranceUserIds = new ArrayList<>();   // 存储需要删除保险附件的用户ID | ||||||
|  | 		List<Long> contractUserIds = new ArrayList<>();    // 存储需要删除合同附件的用户ID | ||||||
|  | 		List<Long> recruitApplyIds = new ArrayList<>();    // 存储关联的招工申请ID | ||||||
|  |  | ||||||
| 		// 保险 2 | 		// 遍历目标目录路径,解析关键信息 | ||||||
| 		List<Long> insurance = new ArrayList<>(); | 		for (String dirPath : targetDirPaths) { | ||||||
| 		// 劳务合同 1 | 			// dirPath格式示例:"张三_110101199001011234/BaoXian/" 或 "李四_120101199002024567/HeTong/" | ||||||
| 		List<Long> contract = new ArrayList<>(); | 			String[] pathParts = dirPath.split(Pattern.quote(File.separator)); | ||||||
| 		// 招工申请Id | 			if (pathParts.length < 2) { | ||||||
| 		List<Long> recruitApplyIds = new ArrayList<>(); | 				throw new BaseException("目录路径格式异常: " + dirPath); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			// 解析倒数第二层目录(名字_身份证号)和类型目录(BaoXian/HeTong) | ||||||
|  | 			String secondLastDir = pathParts[0];  // 格式:名字_身份证号 | ||||||
|  | 			String lastDir = pathParts[1];         // 格式:BaoXian 或 HeTong(末尾可能有斜杠,需处理) | ||||||
|  | 			lastDir = lastDir.replaceAll("/$", ""); // 移除末尾斜杠 | ||||||
|  |  | ||||||
| 		if (firstLevelFiles != null) { | 			// 验证类型目录是否合法 | ||||||
| 			for (File firstLevelFile : firstLevelFiles) { | 			if (!"BaoXian".equals(lastDir) && !"HeTong".equals(lastDir)) { | ||||||
| 				String firstLevelFolderName = firstLevelFile.getName(); | 				continue; // 非目标类型目录,跳过 | ||||||
| 				System.out.println("第一层文件夹名称: " + firstLevelFolderName); | 			} | ||||||
| 				String[] split = firstLevelFolderName.split("_"); |  | ||||||
| 				String card = split[1]; | 			// 从"名字_身份证号"中提取身份证号 | ||||||
| 				WgzUser wgzUser = wgzUserService.findByIdentityCard(card); | 			String[] nameIdCard = secondLastDir.split("_"); | ||||||
|  | 			if (nameIdCard.length != 2) { | ||||||
|  | 				throw new BaseException("倒数第二层目录格式错误(需为'名字_身份证号'): " + secondLastDir); | ||||||
|  | 			} | ||||||
|  | 			String idCard = nameIdCard[1]; | ||||||
|  |  | ||||||
|  | 			// 根据身份证号查询用户 | ||||||
|  | 			WgzUser wgzUser = wgzUserService.findByIdentityCard(idCard); | ||||||
| 			if (wgzUser == null) { | 			if (wgzUser == null) { | ||||||
| 					throw new BaseException("文件格式错误"); | 				throw new BaseException("身份证号对应的用户不存在: " + idCard); | ||||||
| 			} | 			} | ||||||
| 				BgtProjectRecruitApply oneByUserIdAndRecruitId = recruitApplyService.getOneByUserIdAndRecruitId(wgzUser.getUserId(), recruitId); | 			Long userId = wgzUser.getUserId(); | ||||||
| 				if (oneByUserIdAndRecruitId == null) { |  | ||||||
| 					throw new BaseException("状态不对"); | 			// 查询用户对应的招工申请记录 | ||||||
|  | 			BgtProjectRecruitApply apply = recruitApplyService.getOneByUserIdAndRecruitId(userId, recruitId); | ||||||
|  | 			if (apply == null) { | ||||||
|  | 				throw new BaseException("用户未参与当前招工或申请记录不存在: 用户ID=" + userId + ", 招工ID=" + recruitId); | ||||||
| 			} | 			} | ||||||
| 				recruitApplyIds.add(oneByUserIdAndRecruitId.getId()); | 			Long applyId = apply.getId(); | ||||||
| 				if (firstLevelFile.isDirectory()) { |  | ||||||
| 					File[] secondLevelFiles = firstLevelFile.listFiles(); | 			// 根据类型分类收集数据 | ||||||
| 					if (secondLevelFiles != null) { | 			if ("BaoXian".equals(lastDir)) { | ||||||
| 						for (File secondLevelFile : secondLevelFiles) { | 				insuranceUserIds.add(userId); | ||||||
| 							String secondLevelFolderName = secondLevelFile.getName(); | 			} else { | ||||||
| 							System.out.println("第二层文件夹名称: " + secondLevelFolderName); | 				contractUserIds.add(userId); | ||||||
| 							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)) { | 			recruitApplyIds.add(applyId); | ||||||
| 										contract.add(wgzUser.getUserId()); |  | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | 		// 执行附件删除(与原逻辑一致,仅调整入参) | ||||||
|  | 		if (CollectionUtil.isNotEmpty(insuranceUserIds)) { | ||||||
|  | 			annexService.deleteByUserIdAndRecruitIdAndType(insuranceUserIds, recruitId, "2", recruitApplyIds); | ||||||
| 		} | 		} | ||||||
| 							} | 		if (CollectionUtil.isNotEmpty(contractUserIds)) { | ||||||
| 						} | 			annexService.deleteByUserIdAndRecruitIdAndType(contractUserIds, recruitId, "1", recruitApplyIds); | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		if (CollectionUtil.isNotEmpty(insurance)) { |  | ||||||
| 			annexService.deleteByUserIdAndRecruitIdAndType(insurance, recruitId, "2", recruitApplyIds); |  | ||||||
| 		} |  | ||||||
| 		if (CollectionUtil.isNotEmpty(contract)) { |  | ||||||
| 			annexService.deleteByUserIdAndRecruitIdAndType(contract, recruitId, "1", recruitApplyIds); |  | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	private void moveFilesToSaveDir(File sourceDir, Long recruitId, String username) throws IOException { | 	private void moveFilesToSaveDir(File sourceDir, Long recruitId, String username, Map<String, String> leafFileMap) throws IOException { | ||||||
| 		// 移动到 SAVE_DIR |  | ||||||
| 		File saveDestDir = new File(SAVE_DIR); | 		File saveDestDir = new File(SAVE_DIR); | ||||||
| 		ensureDirectoryExists(saveDestDir); | 		ensureDirectoryExists(saveDestDir); | ||||||
|  |  | ||||||
| 		BgtProjectRecruit recruit = recruitService.queryById(recruitId); | 		BgtProjectRecruit recruit = recruitService.queryById(recruitId); | ||||||
| 		String s = DigestUtil.md5Hex(recruit.getRecruitName()); | 		String firstLevelFolderName = recruit.getId() + "_" + DigestUtil.md5Hex(recruit.getRecruitName()); | ||||||
| 		String firstLevelFolderName = recruit.getId() + "_" + s; |  | ||||||
| 		File firstLevelDestDir = new File(saveDestDir, firstLevelFolderName); | 		File firstLevelDestDir = new File(saveDestDir, firstLevelFolderName); | ||||||
| 		ensureDirectoryExists(firstLevelDestDir); | 		ensureDirectoryExists(firstLevelDestDir); | ||||||
|  |  | ||||||
| 		File[] firstLevelFiles = sourceDir.listFiles(); |  | ||||||
| 		List<Annex> annexList = new ArrayList<>(); | 		List<Annex> annexList = new ArrayList<>(); | ||||||
| 		if (firstLevelFiles != null) { | 			for (Map.Entry<String, String> entry : leafFileMap.entrySet()) { | ||||||
| 			for (File firstLevelFile : firstLevelFiles) { | 				String key = entry.getKey();        // 格式:倒数第二层/倒数第一层/文件名(如:张三_123/BaoXian/文件.pdf) | ||||||
| 				if (firstLevelFile.isDirectory()) { | 				String relativePath = entry.getValue();  // 完整相对路径(如:张三_123/BaoXian/文件.pdf) | ||||||
|  |  | ||||||
| 					String firstLevelName = firstLevelFile.getName();  //解压目录 | 				// 原文件路径:解压目录 + 相对路径 | ||||||
| 					File secondLevelDestDir = new File(firstLevelDestDir, firstLevelName);    //保存目录 | 				File sourceFile = new File(sourceDir,relativePath); | ||||||
|  | 				if (!sourceFile.exists() || !sourceFile.isFile()) { | ||||||
| 					File[] secondLevelFiles = firstLevelFile.listFiles(); | 					continue; | ||||||
| 					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); |  | ||||||
| 				} | 				} | ||||||
|  |  | ||||||
|  | 				// 拆分原文件路径为目录部分和文件名部分 | ||||||
|  | 				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); | ||||||
| 		} | 		} | ||||||
| 					moveFilesRecursively(firstLevelFile, firstLevelDestDir, annexList, recruitId, username); |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		if (CollectionUtil.isNotEmpty(annexList)) { | 		if (CollectionUtil.isNotEmpty(annexList)) { | ||||||
| 			annexService.saveBatch(annexList); | 			annexService.saveBatch(annexList); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	private void moveFilesRecursively(File source, File destination, List<Annex> annexList, Long recruitId, String username) throws IOException { | 	@Async | ||||||
| 		if (source.isDirectory()) { | 	public CompletableFuture<Void> asyncDeleteTempFiles(File extractDir, File zipFile) { | ||||||
| 			File newDir = new File(destination, source.getName()); | 		return CompletableFuture.runAsync(() -> { | ||||||
| 			ensureDirectoryExists(newDir); | 			try { | ||||||
| 			File[] files = source.listFiles(); | 				// 仅清理临时解压目录和ZIP文件 | ||||||
| 			if (files != null) { | 				deleteFolder(extractDir); | ||||||
| 				for (File file : files) { | 				if (!zipFile.delete()) { | ||||||
| 					moveFilesRecursively(file, newDir, annexList, recruitId, username); | 					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) { | 	private String getRelativePath(File file, File baseDir) { | ||||||
|  | |||||||
| @ -3,6 +3,8 @@ package com.ruoyi.web.controller.fbs; | |||||||
| import com.ruoyi.common.core.controller.BaseController; | import com.ruoyi.common.core.controller.BaseController; | ||||||
| import com.ruoyi.common.core.domain.AjaxResult; | import com.ruoyi.common.core.domain.AjaxResult; | ||||||
| import com.ruoyi.common.core.page.TableDataInfo; | 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.FbsMessage; | ||||||
| import com.ruoyi.fbs.domain.dto.FbsMessageDetailDTO; | import com.ruoyi.fbs.domain.dto.FbsMessageDetailDTO; | ||||||
| import com.ruoyi.fbs.domain.dto.FbsMessageMyListDTO; | import com.ruoyi.fbs.domain.dto.FbsMessageMyListDTO; | ||||||
| @ -29,7 +31,7 @@ import org.springframework.web.bind.annotation.*; | |||||||
| public class AppFbsMessageController extends BaseController { | public class AppFbsMessageController extends BaseController { | ||||||
|  |  | ||||||
|     private final IFbsMessageService iFbsMessageService; |     private final IFbsMessageService iFbsMessageService; | ||||||
|  | 	private final RedisCache redisCache; | ||||||
| 	@ApiOperation("分包商未读消息统计") | 	@ApiOperation("分包商未读消息统计") | ||||||
| 	@GetMapping("/countUnread") | 	@GetMapping("/countUnread") | ||||||
| 	public AjaxResult<FbsMessageCountVO> count() { | 	public AjaxResult<FbsMessageCountVO> count() { | ||||||
| @ -54,10 +56,14 @@ public class AppFbsMessageController extends BaseController { | |||||||
| 	@ApiOperation("分包商消息已读") | 	@ApiOperation("分包商消息已读") | ||||||
| 	@PutMapping("/read/{id}") | 	@PutMapping("/read/{id}") | ||||||
| 	public AjaxResult<Boolean> read(@PathVariable(value = "id") Long id) { | 	public AjaxResult<Boolean> read(@PathVariable(value = "id") Long id) { | ||||||
| 		FbsMessage fbsMessage = new FbsMessage(); | 		FbsMessage fbsMessage = iFbsMessageService.getById(id); | ||||||
| 		fbsMessage.setId(id); | 		boolean b = true; | ||||||
|  | 		if("0".equals(fbsMessage.getReadStatus())){ | ||||||
|  | 			MessageUtil.readMessagePush(fbsMessage.getRecipientType(), fbsMessage.getRecipientId(), fbsMessage.getMessageLargeType(), fbsMessage.getReadStatus()); | ||||||
| 			fbsMessage.setReadStatus("1"); | 			fbsMessage.setReadStatus("1"); | ||||||
| 		return AjaxResult.success(iFbsMessageService.updateById(fbsMessage)); | 			b = iFbsMessageService.updateById(fbsMessage); | ||||||
|  | 		} | ||||||
|  | 		return AjaxResult.success(b); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	@ApiOperation("分包商消息已操作") | 	@ApiOperation("分包商消息已操作") | ||||||
| @ -69,4 +75,10 @@ public class AppFbsMessageController extends BaseController { | |||||||
| 		return AjaxResult.success(iFbsMessageService.updateById(fbsMessage)); | 		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)); | ||||||
|  | 	} | ||||||
|  |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -148,6 +148,15 @@ | |||||||
| 			return AjaxResult.success(iWgzUserService.userPersonalBasicInformation(req)); | 			return AjaxResult.success(iWgzUserService.userPersonalBasicInformation(req)); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | 		/** | ||||||
|  | 		 * 【我的】总收入 | ||||||
|  | 		 */ | ||||||
|  | 		@GetMapping("/grossIncome") | ||||||
|  | 		public AjaxResult<BigDecimal> grossIncome() { | ||||||
|  | 			return AjaxResult.success(iWgzPayCalculationService.grossIncome()); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  |  | ||||||
| 		/** | 		/** | ||||||
| 		 * 【我的】【实名认证】实名认证 | 		 * 【我的】【实名认证】实名认证 | ||||||
| 		 */ | 		 */ | ||||||
|  | |||||||
| @ -3,6 +3,7 @@ package com.ruoyi.web.controller.zbf; | |||||||
| import com.ruoyi.common.core.controller.BaseController; | import com.ruoyi.common.core.controller.BaseController; | ||||||
| import com.ruoyi.common.core.domain.AjaxResult; | import com.ruoyi.common.core.domain.AjaxResult; | ||||||
| import com.ruoyi.common.core.page.TableDataInfo; | import com.ruoyi.common.core.page.TableDataInfo; | ||||||
|  | import com.ruoyi.common.util.MessageUtil; | ||||||
| import com.ruoyi.zbf.domain.ZbfMessage; | import com.ruoyi.zbf.domain.ZbfMessage; | ||||||
| import com.ruoyi.zbf.domain.dto.ZbfMessageDetailDTO; | import com.ruoyi.zbf.domain.dto.ZbfMessageDetailDTO; | ||||||
| import com.ruoyi.zbf.domain.dto.ZbfMessageMyListDTO; | import com.ruoyi.zbf.domain.dto.ZbfMessageMyListDTO; | ||||||
| @ -29,7 +30,6 @@ import org.springframework.web.bind.annotation.*; | |||||||
| public class AppZbfMessageController extends BaseController { | public class AppZbfMessageController extends BaseController { | ||||||
|  |  | ||||||
| 	private final IZbfMessageService iZbfMessageService; | 	private final IZbfMessageService iZbfMessageService; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 查询消息列表 |      * 查询消息列表 | ||||||
|      */ |      */ | ||||||
| @ -55,10 +55,14 @@ public class AppZbfMessageController extends BaseController { | |||||||
| 	@ApiOperation("总包方消息已读") | 	@ApiOperation("总包方消息已读") | ||||||
| 	@PutMapping("/read/{id}") | 	@PutMapping("/read/{id}") | ||||||
| 	public AjaxResult<Boolean> read(@PathVariable(value = "id") Long id) { | 	public AjaxResult<Boolean> read(@PathVariable(value = "id") Long id) { | ||||||
| 		ZbfMessage zbfMessage =  new ZbfMessage(); | 		ZbfMessage zbfMessage =  iZbfMessageService.getById(id); | ||||||
| 		zbfMessage.setId(id); | 		boolean b= true; | ||||||
|  | 		if("0".equals(zbfMessage.getReadStatus())){ | ||||||
|  | 			MessageUtil.readMessagePush(zbfMessage.getRecipientType(), zbfMessage.getRecipientId(), zbfMessage.getMessageLargeType(), zbfMessage.getReadStatus()); | ||||||
| 			zbfMessage.setReadStatus("1"); | 			zbfMessage.setReadStatus("1"); | ||||||
| 		return AjaxResult.success(iZbfMessageService.updateById(zbfMessage)); | 			iZbfMessageService.updateById(zbfMessage); | ||||||
|  | 		} | ||||||
|  | 		return AjaxResult.success(b); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	@ApiOperation("总包方消息已操作") | 	@ApiOperation("总包方消息已操作") | ||||||
|  | |||||||
| @ -86,7 +86,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter | |||||||
|      * hasRole             |   如果有参数,参数表示角色,则其角色可以访问 |      * hasRole             |   如果有参数,参数表示角色,则其角色可以访问 | ||||||
|      * permitAll           |   用户可以任意访问 |      * permitAll           |   用户可以任意访问 | ||||||
|      * rememberMe          |   允许通过remember-me登录的用户访问 |      * rememberMe          |   允许通过remember-me登录的用户访问 | ||||||
|      * authenticated       |   用户登录后可访问 |      * authenticated       |   用户登录后可访问 "/sse/subscribe", | ||||||
|      */ |      */ | ||||||
|     @Override |     @Override | ||||||
|     protected void configure(HttpSecurity httpSecurity) throws Exception |     protected void configure(HttpSecurity httpSecurity) throws Exception | ||||||
|  | |||||||
| @ -17,12 +17,12 @@ import com.ruoyi.bgt.domain.vo.BgtMessageDetailVO; | |||||||
| import com.ruoyi.bgt.domain.vo.BgtMessageVO; | import com.ruoyi.bgt.domain.vo.BgtMessageVO; | ||||||
| import com.ruoyi.bgt.mapper.BgtMessageMapper; | import com.ruoyi.bgt.mapper.BgtMessageMapper; | ||||||
| import com.ruoyi.bgt.service.IBgtMessageService; | import com.ruoyi.bgt.service.IBgtMessageService; | ||||||
| import com.ruoyi.bgt.service.IBgtProjectRecruitApplyService; |  | ||||||
| import com.ruoyi.bgt.service.IBgtProjectRecruitService; |  | ||||||
| import com.ruoyi.bgt.service.IBgtWageApplicationService; | import com.ruoyi.bgt.service.IBgtWageApplicationService; | ||||||
| import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl; | import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl; | ||||||
| import com.ruoyi.common.core.page.TableDataInfo; | import com.ruoyi.common.core.page.TableDataInfo; | ||||||
|  | import com.ruoyi.common.core.redis.RedisCache; | ||||||
| import com.ruoyi.common.enums.BgtMessageType; | import com.ruoyi.common.enums.BgtMessageType; | ||||||
|  | import com.ruoyi.common.util.MessageUtil; | ||||||
| import com.ruoyi.common.utils.PageUtils; | import com.ruoyi.common.utils.PageUtils; | ||||||
| import com.ruoyi.common.utils.SecurityUtils; | import com.ruoyi.common.utils.SecurityUtils; | ||||||
| import com.ruoyi.fbs.domain.FbsProjectTask; | import com.ruoyi.fbs.domain.FbsProjectTask; | ||||||
| @ -32,7 +32,10 @@ import com.ruoyi.fbs.service.IFbsProjectTaskService; | |||||||
| import com.ruoyi.wgz.domain.WgzDailyClock; | import com.ruoyi.wgz.domain.WgzDailyClock; | ||||||
| import com.ruoyi.wgz.domain.WgzLeave; | import com.ruoyi.wgz.domain.WgzLeave; | ||||||
| import com.ruoyi.wgz.domain.WgzReissueacard; | import com.ruoyi.wgz.domain.WgzReissueacard; | ||||||
| import com.ruoyi.wgz.service.*; | import com.ruoyi.wgz.service.IWgzDailyClockService; | ||||||
|  | import com.ruoyi.wgz.service.IWgzLeaveService; | ||||||
|  | import com.ruoyi.wgz.service.IWgzReissueacardService; | ||||||
|  | import com.ruoyi.wgz.service.IWgzUserService; | ||||||
| import org.springframework.beans.factory.annotation.Autowired; | import org.springframework.beans.factory.annotation.Autowired; | ||||||
| import org.springframework.context.annotation.Lazy; | import org.springframework.context.annotation.Lazy; | ||||||
| import org.springframework.stereotype.Service; | import org.springframework.stereotype.Service; | ||||||
| @ -59,15 +62,7 @@ import static com.ruoyi.common.constants.WgzAndBgtMessageConstant.OPERATION_NEED | |||||||
| public class BgtMessageServiceImpl extends ServicePlusImpl<BgtMessageMapper, BgtMessage> implements IBgtMessageService { | public class BgtMessageServiceImpl extends ServicePlusImpl<BgtMessageMapper, BgtMessage> implements IBgtMessageService { | ||||||
|  |  | ||||||
| 	@Autowired | 	@Autowired | ||||||
| 	@Lazy | 	private RedisCache redisCache; | ||||||
| 	private IBgtProjectRecruitApplyService recruitApplyService; |  | ||||||
|  |  | ||||||
| 	@Autowired |  | ||||||
| 	private IBgtProjectRecruitService recruitService; |  | ||||||
|  |  | ||||||
| 	@Autowired |  | ||||||
| 	@Lazy |  | ||||||
| 	private IWgzPayCalculationService payCalculationService; |  | ||||||
|  |  | ||||||
| 	@Autowired | 	@Autowired | ||||||
| 	@Lazy | 	@Lazy | ||||||
| @ -170,11 +165,14 @@ public class BgtMessageServiceImpl extends ServicePlusImpl<BgtMessageMapper, Bgt | |||||||
| 	@Override | 	@Override | ||||||
| 	@Transactional | 	@Transactional | ||||||
| 	public Boolean sendAMessage(BgtMessage bo) { | 	public Boolean sendAMessage(BgtMessage bo) { | ||||||
| 		return save(bo); | 		boolean save = save(bo); | ||||||
|  | 		MessageUtil.saveMessagePush(bo.getRecipientType(), bo.getRecipientId(), bo.getMessageLargeType(), bo.getIsOperation()); | ||||||
|  | 		return save; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	@Override | 	@Override | ||||||
| 	public BgtMessageCountVO countUnread() { | 	public BgtMessageCountVO countUnread() { | ||||||
|  | //		Object cacheObject = redisCache.getCacheObject(REIDS_KEY + SecurityUtils.getAppUserId()); | ||||||
| 		List<BgtMessage> bgtMessages = baseMapper.selectList(Wrappers.<BgtMessage>lambdaQuery() | 		List<BgtMessage> bgtMessages = baseMapper.selectList(Wrappers.<BgtMessage>lambdaQuery() | ||||||
| 			.eq(BgtMessage::getRecipientId, SecurityUtils.getAppUserId()) | 			.eq(BgtMessage::getRecipientId, SecurityUtils.getAppUserId()) | ||||||
| 			.eq(BgtMessage::getReadStatus, "0")); | 			.eq(BgtMessage::getReadStatus, "0")); | ||||||
| @ -189,6 +187,7 @@ public class BgtMessageServiceImpl extends ServicePlusImpl<BgtMessageMapper, Bgt | |||||||
| 			.eq(BgtMessage::getRecipientId, SecurityUtils.getAppUserId()) | 			.eq(BgtMessage::getRecipientId, SecurityUtils.getAppUserId()) | ||||||
| 			.eq(BgtMessage::getIsOperation, OPERATION_NEED)); | 			.eq(BgtMessage::getIsOperation, OPERATION_NEED)); | ||||||
| 		bgtMessageCountVO.setHandleMessageCount(handle); | 		bgtMessageCountVO.setHandleMessageCount(handle); | ||||||
|  | 		redisCache.setCacheObject(REDIS_KEY+SecurityUtils.getAppUserId(), bgtMessageCountVO); | ||||||
| 		return bgtMessageCountVO; | 		return bgtMessageCountVO; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @ -283,6 +282,7 @@ public class BgtMessageServiceImpl extends ServicePlusImpl<BgtMessageMapper, Bgt | |||||||
| 		wrapper.eq(BgtMessage::getTableName, tableName); | 		wrapper.eq(BgtMessage::getTableName, tableName); | ||||||
| 		wrapper.set(BgtMessage::getIsOperation, OPERATION_ALREADY); | 		wrapper.set(BgtMessage::getIsOperation, OPERATION_ALREADY); | ||||||
| 		update(wrapper); | 		update(wrapper); | ||||||
|  | 		MessageUtil.operationMessagePush(recipientType, recipientId, 1); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | |||||||
| @ -611,7 +611,7 @@ public class BgtProjectRecruitApplyServiceImpl extends ServicePlusImpl<BgtProjec | |||||||
| 					.setRecipientId(vo.getUserId()) | 					.setRecipientId(vo.getUserId()) | ||||||
| 					.setHeadline(map.get(HEADLINE)) | 					.setHeadline(map.get(HEADLINE)) | ||||||
| 					.setSubheading(map.get(SUBHEADING)) | 					.setSubheading(map.get(SUBHEADING)) | ||||||
| 					.setTableId(vo.getRecruitId()) | 					.setTableId(vo.getId()) | ||||||
| 					.setTableName(SqlHelper.table(BgtProjectRecruitApply.class).getTableName()) | 					.setTableName(SqlHelper.table(BgtProjectRecruitApply.class).getTableName()) | ||||||
| 					.setMessageLargeType(LARGE_OTHER) | 					.setMessageLargeType(LARGE_OTHER) | ||||||
| 					.setMessageSmallType(SMALL_EXIT); | 					.setMessageSmallType(SMALL_EXIT); | ||||||
| @ -741,7 +741,7 @@ public class BgtProjectRecruitApplyServiceImpl extends ServicePlusImpl<BgtProjec | |||||||
| 			throw new RuntimeException("修改招工申请信息失败!"); | 			throw new RuntimeException("修改招工申请信息失败!"); | ||||||
| 		} | 		} | ||||||
| 		//3-2、修改消息 | 		//3-2、修改消息 | ||||||
| 		boolean b = iWgzMessageService.updateById(new WgzMessage().setId(req.getMessageId()).setIsOperation("2")); | 		boolean b = iWgzMessageService.updateOperationStatus(req.getMessageId()); | ||||||
| 		if (!b) { | 		if (!b) { | ||||||
| 			throw new RuntimeException("修改消息失败!"); | 			throw new RuntimeException("修改消息失败!"); | ||||||
| 		} | 		} | ||||||
|  | |||||||
| @ -9,17 +9,19 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | |||||||
| import com.baomidou.mybatisplus.extension.toolkit.SqlHelper; | import com.baomidou.mybatisplus.extension.toolkit.SqlHelper; | ||||||
| import com.ruoyi.bgt.bo.BgtProjectTaskProgressQueryBo; | import com.ruoyi.bgt.bo.BgtProjectTaskProgressQueryBo; | ||||||
| import com.ruoyi.bgt.domain.BgtMessage; | import com.ruoyi.bgt.domain.BgtMessage; | ||||||
|  | import com.ruoyi.bgt.domain.BgtProjectRecruit; | ||||||
| import com.ruoyi.bgt.domain.BgtProjectTaskProgress; | import com.ruoyi.bgt.domain.BgtProjectTaskProgress; | ||||||
| import com.ruoyi.bgt.domain.dto.BgtProjectTaskProgressQueryDTO; | import com.ruoyi.bgt.domain.dto.BgtProjectTaskProgressQueryDTO; | ||||||
| import com.ruoyi.bgt.domain.vo.BgtProjectTaskProgressDetailVO; | import com.ruoyi.bgt.domain.vo.BgtProjectTaskProgressDetailVO; | ||||||
| import com.ruoyi.bgt.domain.vo.BgtProjectTaskProgressVO; | import com.ruoyi.bgt.domain.vo.BgtProjectTaskProgressVO; | ||||||
| import com.ruoyi.bgt.mapper.BgtProjectTaskProgressMapper; | import com.ruoyi.bgt.mapper.BgtProjectTaskProgressMapper; | ||||||
| import com.ruoyi.bgt.service.IBgtMessageService; | import com.ruoyi.bgt.service.IBgtMessageService; | ||||||
| import com.ruoyi.bgt.service.IBgtProjectRecruitApplyService; | import com.ruoyi.bgt.service.IBgtProjectRecruitService; | ||||||
| import com.ruoyi.bgt.service.IBgtProjectTaskProgressService; | import com.ruoyi.bgt.service.IBgtProjectTaskProgressService; | ||||||
| import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl; | import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl; | ||||||
| import com.ruoyi.common.core.page.TableDataInfo; | import com.ruoyi.common.core.page.TableDataInfo; | ||||||
| import com.ruoyi.common.enums.AuditStatus; | import com.ruoyi.common.enums.AuditStatus; | ||||||
|  | import com.ruoyi.common.enums.RecruitStatus; | ||||||
| import com.ruoyi.common.exception.BaseException; | import com.ruoyi.common.exception.BaseException; | ||||||
| import com.ruoyi.common.utils.PageUtils; | import com.ruoyi.common.utils.PageUtils; | ||||||
| import com.ruoyi.common.utils.SecurityUtils; | import com.ruoyi.common.utils.SecurityUtils; | ||||||
| @ -55,7 +57,7 @@ public class BgtProjectTaskProgressServiceImpl extends ServicePlusImpl<BgtProjec | |||||||
| 	@Autowired | 	@Autowired | ||||||
| 	private IBgtMessageService bgtMessageService; | 	private IBgtMessageService bgtMessageService; | ||||||
| 	@Autowired | 	@Autowired | ||||||
| 	private IBgtProjectRecruitApplyService recruitApplyService; | 	private IBgtProjectRecruitService recruitService; | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public BgtProjectTaskProgress queryById(Long id){ |     public BgtProjectTaskProgress queryById(Long id){ | ||||||
| @ -159,6 +161,16 @@ public class BgtProjectTaskProgressServiceImpl extends ServicePlusImpl<BgtProjec | |||||||
| 		if(lastProgress>=entity.getProgress()){ | 		if(lastProgress>=entity.getProgress()){ | ||||||
| 			throw new BaseException("当前进度不能小于等于上一个进度"); | 			throw new BaseException("当前进度不能小于等于上一个进度"); | ||||||
| 		} | 		} | ||||||
|  | 		if(entity.getProgress()==100){ | ||||||
|  | 			List<BgtProjectRecruit> recruitList = recruitService.list(Wrappers.<BgtProjectRecruit>lambdaQuery() | ||||||
|  | 				.eq(BgtProjectRecruit::getTaskId, entity.getTaskId()) | ||||||
|  | 				.ne(BgtProjectRecruit::getStatus, RecruitStatus.OVERDUE.getCode()) | ||||||
|  | 			); | ||||||
|  | 			if(CollectionUtil.isNotEmpty(recruitList)){ | ||||||
|  | 				throw new BaseException("招工结束前不能完成任务"); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 		} | ||||||
|  |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | |||||||
| @ -7,6 +7,7 @@ import java.util.Map; | |||||||
|  |  | ||||||
| public class BgtMessageConstant { | public class BgtMessageConstant { | ||||||
| 	// 公共常量 | 	// 公共常量 | ||||||
|  | 	public static final String REDIS_KEY = "messageCount:bgt:"; | ||||||
|  |  | ||||||
| 	public static final String BGT_LARGE_TASK = "1";                 //大类型-任务 | 	public static final String BGT_LARGE_TASK = "1";                 //大类型-任务 | ||||||
| 	public static final String BGT_LARGE_SETTLEMENT = "2";           //大类型-结算 | 	public static final String BGT_LARGE_SETTLEMENT = "2";           //大类型-结算 | ||||||
|  | |||||||
| @ -10,6 +10,7 @@ import static com.ruoyi.common.constants.BgtMessageConstant.SUBHEADING; | |||||||
|  |  | ||||||
| public class FbsMessageConstant { | public class FbsMessageConstant { | ||||||
| 	// 公共常量 | 	// 公共常量 | ||||||
|  | 	public static final String REDIS_KEY = "messageCount:fbs:"; | ||||||
|  |  | ||||||
| 	public static final String FBS_LARGE_TASK = "1";                 //大类型-项目 | 	public static final String FBS_LARGE_TASK = "1";                 //大类型-项目 | ||||||
| 	public static final String FBS_LARGE_SETTLEMENT = "2";           //大类型-结算 | 	public static final String FBS_LARGE_SETTLEMENT = "2";           //大类型-结算 | ||||||
|  | |||||||
| @ -3,12 +3,14 @@ package com.ruoyi.common.constants; | |||||||
| import java.util.Map; | import java.util.Map; | ||||||
|  |  | ||||||
| public class WgzAndBgtMessageConstant { | public class WgzAndBgtMessageConstant { | ||||||
|  |  | ||||||
|  | 	public static final String REDIS_KEY = "messageCount:wgz:"; | ||||||
| 	// 公共常量 | 	// 公共常量 | ||||||
| 	public static final  String USERTYPE_SYSTEM = "0"; //系统 | 	public static final  String USERTYPE_SYSTEM = "0"; //系统 | ||||||
| 	public static final  String USERTYPE_WGZ = "1"; //务工者 | 	public static final  String USERTYPE_WGZ = "1"; //务工者 | ||||||
| 	public static final  String USERTYPE_BGT = "2";	//包工头 | 	public static final  String USERTYPE_BGT = "2";	//包工头 | ||||||
| 	public static final String USERTYPE_FBS = "3"; //分包商 | 	public static final String USERTYPE_FBS = "3"; //分包商 | ||||||
| 	public static final String USERTYPE_ZBF = "4"; //分包商 | 	public static final String USERTYPE_ZBF = "4"; //总包方 | ||||||
|  |  | ||||||
| 	//系统ID | 	//系统ID | ||||||
| 	public static final Long SYSTEM_ID = 0L; | 	public static final Long SYSTEM_ID = 0L; | ||||||
|  | |||||||
| @ -11,6 +11,8 @@ import static com.ruoyi.common.constants.BgtMessageConstant.SUBHEADING; | |||||||
| public class ZbfMessageConstant { | public class ZbfMessageConstant { | ||||||
| 	// 公共常量 | 	// 公共常量 | ||||||
|  |  | ||||||
|  | 	public static final String REDIS_KEY = "messageCount:zbf:"; | ||||||
|  |  | ||||||
| 	public static final String ZBF_LARGE_TASK = "1";                 //大类型-任务 | 	public static final String ZBF_LARGE_TASK = "1";                 //大类型-任务 | ||||||
| 	public static final String ZBF_LARGE_SETTLEMENT = "2";           //大类型-结算 | 	public static final String ZBF_LARGE_SETTLEMENT = "2";           //大类型-结算 | ||||||
| 	public static final String ZBF_LARGE_OTHER = "3";                //大类型-其它 | 	public static final String ZBF_LARGE_OTHER = "3";                //大类型-其它 | ||||||
|  | |||||||
| @ -64,4 +64,6 @@ public class CompanyAuthenticateDTO { | |||||||
| 	@ApiModelProperty("资质与荣誉") | 	@ApiModelProperty("资质与荣誉") | ||||||
| 	private String url; | 	private String url; | ||||||
|  |  | ||||||
|  | 	@ApiModelProperty("备注") | ||||||
|  | 	private String remark; | ||||||
| } | } | ||||||
|  | |||||||
| @ -0,0 +1,297 @@ | |||||||
|  | package com.ruoyi.common.util; | ||||||
|  |  | ||||||
|  | import cn.hutool.core.util.StrUtil; | ||||||
|  | import cn.hutool.json.JSONUtil; | ||||||
|  | import com.ruoyi.bgt.domain.vo.BgtMessageCountVO; | ||||||
|  | import com.ruoyi.common.constants.BgtMessageConstant; | ||||||
|  | import com.ruoyi.common.constants.FbsMessageConstant; | ||||||
|  | import com.ruoyi.common.constants.WgzAndBgtMessageConstant; | ||||||
|  | import com.ruoyi.common.constants.ZbfMessageConstant; | ||||||
|  | import com.ruoyi.common.core.redis.RedisCache; | ||||||
|  | import com.ruoyi.common.utils.spring.SpringUtils; | ||||||
|  | import com.ruoyi.fbs.domain.vo.FbsMessageCountVO; | ||||||
|  | import com.ruoyi.wgz.bo.res.WgzAppMessageTypeStatisticsRes; | ||||||
|  | import com.ruoyi.zbf.domain.vo.ZbfMessageCountVO; | ||||||
|  | import org.slf4j.Logger; | ||||||
|  | import org.slf4j.LoggerFactory; | ||||||
|  |  | ||||||
|  | import java.util.Map; | ||||||
|  |  | ||||||
|  | import static com.ruoyi.common.constants.BgtMessageConstant.*; | ||||||
|  | import static com.ruoyi.common.constants.FbsMessageConstant.*; | ||||||
|  | import static com.ruoyi.common.constants.WgzAndBgtMessageConstant.OPERATION_NEED; | ||||||
|  | import static com.ruoyi.common.constants.ZbfMessageConstant.*; | ||||||
|  |  | ||||||
|  | public class MessageUtil { | ||||||
|  |  | ||||||
|  | 	//获取日志 | ||||||
|  | 	public static final Logger log = LoggerFactory.getLogger(MessageUtil.class); | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * 保存消息是像客户端发送消息 | ||||||
|  | 	 * | ||||||
|  | 	 * @param recipientType    用户类型 | ||||||
|  | 	 * @param recipientId      用户ID | ||||||
|  | 	 * @param messageLargeType 消息大类型 | ||||||
|  | 	 * @param isOperation      操作类型 | ||||||
|  | 	 */ | ||||||
|  | 	public static void saveMessagePush(String recipientType, Long recipientId, String messageLargeType, String isOperation) { | ||||||
|  | 		try { | ||||||
|  | 			String messageKey = ""; | ||||||
|  | 			String data = ""; | ||||||
|  | 			String redisKey = ""; | ||||||
|  | 			Object cacheObject; | ||||||
|  | 			RedisCache redisCache = SpringUtils.getBean(RedisCache.class); | ||||||
|  | 			switch (recipientType) { | ||||||
|  | 				case WgzAndBgtMessageConstant.USERTYPE_WGZ: | ||||||
|  | 					redisKey = WgzAndBgtMessageConstant.REDIS_KEY + recipientId; | ||||||
|  | 					messageKey = SseUtil.WGZ_PREFIX + recipientId; | ||||||
|  | 					cacheObject = redisCache.getCacheObject(redisKey); | ||||||
|  | 					if (cacheObject != null) { | ||||||
|  | 						WgzAppMessageTypeStatisticsRes res = (WgzAppMessageTypeStatisticsRes) cacheObject; | ||||||
|  | 						Map<String, Integer> mp = res.getMp(); | ||||||
|  | 						if ("0".equals(messageLargeType)) { | ||||||
|  | 							mp.put("0", mp.get("0") + 1); | ||||||
|  | 						} else if ("1".equals(messageLargeType)) { | ||||||
|  | 							mp.put("1", mp.get("1") + 1); | ||||||
|  | 						} else if ("2".equals(messageLargeType)) { | ||||||
|  | 							mp.put("2", mp.get("2") + 1); | ||||||
|  | 						} | ||||||
|  | 						if (OPERATION_NEED.equals(isOperation)) { | ||||||
|  | 							mp.put("3", mp.get("3") + 1); | ||||||
|  | 						} | ||||||
|  | 						redisCache.setCacheObject(redisKey, res); | ||||||
|  | 						data = JSONUtil.toJsonStr(res); | ||||||
|  | 					} | ||||||
|  | 					break; | ||||||
|  | 				case WgzAndBgtMessageConstant.USERTYPE_BGT: | ||||||
|  | 					redisKey = BgtMessageConstant.REDIS_KEY + recipientId; | ||||||
|  | 					messageKey = SseUtil.BGT_PREFIX + recipientId; | ||||||
|  | 					cacheObject = redisCache.getCacheObject(redisKey); | ||||||
|  | 					if (cacheObject != null) { | ||||||
|  | 						BgtMessageCountVO bgtMessageCountVO = (BgtMessageCountVO) cacheObject; | ||||||
|  | 						if (BGT_LARGE_TASK.equals(messageLargeType)) { | ||||||
|  | 							bgtMessageCountVO.setTaskMessageCount(bgtMessageCountVO.getTaskMessageCount() + 1); | ||||||
|  | 						} else if (BGT_LARGE_SETTLEMENT.equals(messageLargeType)) { | ||||||
|  | 							bgtMessageCountVO.setSettlementMessageCount(bgtMessageCountVO.getSettlementMessageCount() + 1); | ||||||
|  | 						} else if (BGT_LARGE_OTHER.equals(messageLargeType)) { | ||||||
|  | 							bgtMessageCountVO.setOtherMessageCount(bgtMessageCountVO.getOtherMessageCount() + 1); | ||||||
|  | 						} | ||||||
|  | 						if (OPERATION_NEED.equals(isOperation)) { | ||||||
|  | 							bgtMessageCountVO.setHandleMessageCount(bgtMessageCountVO.getHandleMessageCount() + 1); | ||||||
|  | 						} | ||||||
|  | 						redisCache.setCacheObject(redisKey, bgtMessageCountVO); | ||||||
|  | 						data = JSONUtil.toJsonStr(bgtMessageCountVO); | ||||||
|  | 					} | ||||||
|  | 					break; | ||||||
|  | 				case WgzAndBgtMessageConstant.USERTYPE_FBS: | ||||||
|  | 					redisKey = FbsMessageConstant.REDIS_KEY + recipientId; | ||||||
|  | 					messageKey = SseUtil.FBS_PREFIX + recipientId; | ||||||
|  | 					cacheObject = redisCache.getCacheObject(redisKey); | ||||||
|  | 					if (cacheObject != null) { | ||||||
|  | 						FbsMessageCountVO fbsMessageCountVO = (FbsMessageCountVO) cacheObject; | ||||||
|  | 						if (FBS_LARGE_TASK.equals(messageLargeType)) { | ||||||
|  | 							fbsMessageCountVO.setTaskMessageCount(fbsMessageCountVO.getTaskMessageCount() + 1); | ||||||
|  | 						} else if (FBS_LARGE_SETTLEMENT.equals(messageLargeType)) { | ||||||
|  | 							fbsMessageCountVO.setSettlementMessageCount(fbsMessageCountVO.getSettlementMessageCount() + 1); | ||||||
|  | 						} else if (FBS_LARGE_OTHER.equals(messageLargeType)) { | ||||||
|  | 							fbsMessageCountVO.setOtherMessageCount(fbsMessageCountVO.getOtherMessageCount() + 1); | ||||||
|  | 						} | ||||||
|  | 						if (OPERATION_NEED.equals(isOperation)) { | ||||||
|  | 							fbsMessageCountVO.setHandleMessageCount(fbsMessageCountVO.getHandleMessageCount() + 1); | ||||||
|  | 						} | ||||||
|  | 						redisCache.setCacheObject(redisKey, fbsMessageCountVO); | ||||||
|  | 						data = JSONUtil.toJsonStr(fbsMessageCountVO); | ||||||
|  | 					} | ||||||
|  | 					break; | ||||||
|  | 				case WgzAndBgtMessageConstant.USERTYPE_ZBF: | ||||||
|  | 					redisKey = ZbfMessageConstant.REDIS_KEY + recipientId; | ||||||
|  | 					messageKey = SseUtil.ZBF_PREFIX + recipientId; | ||||||
|  | 					cacheObject = redisCache.getCacheObject(redisKey); | ||||||
|  | 					if (cacheObject != null) { | ||||||
|  | 						ZbfMessageCountVO zbfMessageCountVO = (ZbfMessageCountVO) cacheObject; | ||||||
|  | 						if (ZBF_LARGE_TASK.equals(messageLargeType)) { | ||||||
|  | 							zbfMessageCountVO.setTaskMessageCount(zbfMessageCountVO.getTaskMessageCount() + 1); | ||||||
|  | 						} else if (ZBF_LARGE_SETTLEMENT.equals(messageLargeType)) { | ||||||
|  | 							zbfMessageCountVO.setSettlementMessageCount(zbfMessageCountVO.getSettlementMessageCount() + 1); | ||||||
|  | 						} else if (ZBF_LARGE_OTHER.equals(messageLargeType)) { | ||||||
|  | 							zbfMessageCountVO.setOtherMessageCount(zbfMessageCountVO.getOtherMessageCount() + 1); | ||||||
|  | 						} | ||||||
|  | 						if (OPERATION_NEED.equals(isOperation)) { | ||||||
|  | 							zbfMessageCountVO.setHandleMessageCount(zbfMessageCountVO.getHandleMessageCount() + 1); | ||||||
|  | 						} | ||||||
|  | 						redisCache.setCacheObject(redisKey, zbfMessageCountVO); | ||||||
|  | 						data = JSONUtil.toJsonStr(zbfMessageCountVO); | ||||||
|  | 					} | ||||||
|  | 					break; | ||||||
|  | 				default: | ||||||
|  | 					break; | ||||||
|  | 			} | ||||||
|  | 			if(StrUtil.isNotBlank(data)){ | ||||||
|  | 				SseUtil.pushMessage(messageKey, data); | ||||||
|  | 			} | ||||||
|  | 		} catch (Exception e) { | ||||||
|  | 			log.error("sse推送异常", e); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	public static void readMessagePush(String recipientType, Long recipientId, String messageLargeType, String readStatus) { | ||||||
|  | 		try { | ||||||
|  | 			String messageKey = ""; | ||||||
|  | 			String data = ""; | ||||||
|  | 			String redisKey; | ||||||
|  | 			Object cacheObject; | ||||||
|  | 			RedisCache redisCache = SpringUtils.getBean(RedisCache.class); | ||||||
|  | 			switch (recipientType) { | ||||||
|  | 				case WgzAndBgtMessageConstant.USERTYPE_WGZ: | ||||||
|  | 					redisKey = WgzAndBgtMessageConstant.REDIS_KEY + recipientId; | ||||||
|  | 					messageKey = SseUtil.WGZ_PREFIX + recipientId; | ||||||
|  |  | ||||||
|  | 					cacheObject = redisCache.getCacheObject(redisKey); | ||||||
|  | 					if (cacheObject != null && "0".equals(readStatus)) { | ||||||
|  | 						WgzAppMessageTypeStatisticsRes res = (WgzAppMessageTypeStatisticsRes) cacheObject; | ||||||
|  | 						Map<String, Integer> mp = res.getMp(); | ||||||
|  | 						if ("0".equals(messageLargeType)) { | ||||||
|  | 							mp.put("0", mp.get("0") - 1); | ||||||
|  | 						} else if ("1".equals(messageLargeType)) { | ||||||
|  | 							mp.put("1", mp.get("1") - 1); | ||||||
|  | 						} else if ("2".equals(messageLargeType)) { | ||||||
|  | 							mp.put("2", mp.get("2") - 1); | ||||||
|  | 						} | ||||||
|  | 						redisCache.setCacheObject(redisKey, res); | ||||||
|  | 						data = JSONUtil.toJsonStr(res); | ||||||
|  | 					} | ||||||
|  | 					break; | ||||||
|  | 				case WgzAndBgtMessageConstant.USERTYPE_BGT: | ||||||
|  | 					redisKey = BgtMessageConstant.REDIS_KEY + recipientId; | ||||||
|  | 					messageKey = SseUtil.BGT_PREFIX + recipientId; | ||||||
|  |  | ||||||
|  | 					cacheObject = redisCache.getCacheObject(redisKey); | ||||||
|  | 					if (cacheObject != null && "0".equals(readStatus)) { | ||||||
|  | 						BgtMessageCountVO bgtMessageCountVO = (BgtMessageCountVO) cacheObject; | ||||||
|  | 						if (BGT_LARGE_TASK.equals(messageLargeType)) { | ||||||
|  | 							bgtMessageCountVO.setTaskMessageCount(bgtMessageCountVO.getTaskMessageCount() - 1); | ||||||
|  | 						} else if (BGT_LARGE_SETTLEMENT.equals(messageLargeType)) { | ||||||
|  | 							bgtMessageCountVO.setSettlementMessageCount(bgtMessageCountVO.getSettlementMessageCount() - 1); | ||||||
|  | 						} else if (BGT_LARGE_OTHER.equals(messageLargeType)) { | ||||||
|  | 							bgtMessageCountVO.setOtherMessageCount(bgtMessageCountVO.getOtherMessageCount() - 1); | ||||||
|  | 						} | ||||||
|  | 						redisCache.setCacheObject(redisKey, bgtMessageCountVO); | ||||||
|  | 						data = JSONUtil.toJsonStr(bgtMessageCountVO); | ||||||
|  | 					} | ||||||
|  |  | ||||||
|  | 					break; | ||||||
|  | 				case WgzAndBgtMessageConstant.USERTYPE_FBS: | ||||||
|  | 					redisKey = FbsMessageConstant.REDIS_KEY + recipientId; | ||||||
|  | 					messageKey = SseUtil.FBS_PREFIX + recipientId; | ||||||
|  |  | ||||||
|  | 					cacheObject = redisCache.getCacheObject(redisKey); | ||||||
|  | 					if (cacheObject != null && "0".equals(readStatus)) { | ||||||
|  | 						FbsMessageCountVO fbsMessageCountVO = (FbsMessageCountVO) cacheObject; | ||||||
|  | 						if (FBS_LARGE_TASK.equals(messageLargeType)) { | ||||||
|  | 							fbsMessageCountVO.setTaskMessageCount(fbsMessageCountVO.getTaskMessageCount() - 1); | ||||||
|  | 						} else if (FBS_LARGE_SETTLEMENT.equals(messageLargeType)) { | ||||||
|  | 							fbsMessageCountVO.setSettlementMessageCount(fbsMessageCountVO.getSettlementMessageCount() - 1); | ||||||
|  | 						} else if (FBS_LARGE_OTHER.equals(messageLargeType)) { | ||||||
|  | 							fbsMessageCountVO.setOtherMessageCount(fbsMessageCountVO.getOtherMessageCount() - 1); | ||||||
|  | 						} | ||||||
|  | 						redisCache.setCacheObject(redisKey, fbsMessageCountVO); | ||||||
|  | 						data = JSONUtil.toJsonStr(fbsMessageCountVO); | ||||||
|  | 					} | ||||||
|  | 					break; | ||||||
|  | 				case WgzAndBgtMessageConstant.USERTYPE_ZBF: | ||||||
|  | 					redisKey = ZbfMessageConstant.REDIS_KEY + recipientId; | ||||||
|  | 					messageKey = SseUtil.ZBF_PREFIX + recipientId; | ||||||
|  |  | ||||||
|  | 					cacheObject = redisCache.getCacheObject(redisKey); | ||||||
|  | 					if (cacheObject != null && "0".equals(readStatus)) { | ||||||
|  | 						ZbfMessageCountVO zbfMessageCountVO = (ZbfMessageCountVO) cacheObject; | ||||||
|  | 						if (ZBF_LARGE_TASK.equals(messageLargeType)) { | ||||||
|  | 							zbfMessageCountVO.setTaskMessageCount(zbfMessageCountVO.getTaskMessageCount() - 1); | ||||||
|  | 						} else if (ZBF_LARGE_SETTLEMENT.equals(messageLargeType)) { | ||||||
|  | 							zbfMessageCountVO.setSettlementMessageCount(zbfMessageCountVO.getSettlementMessageCount() - 1); | ||||||
|  | 						} else if (ZBF_LARGE_OTHER.equals(messageLargeType)) { | ||||||
|  | 							zbfMessageCountVO.setOtherMessageCount(zbfMessageCountVO.getOtherMessageCount() - 1); | ||||||
|  | 						} | ||||||
|  | 						redisCache.setCacheObject(redisKey, zbfMessageCountVO); | ||||||
|  | 						data = JSONUtil.toJsonStr(zbfMessageCountVO); | ||||||
|  | 					} | ||||||
|  | 					break; | ||||||
|  | 				default: | ||||||
|  | 					break; | ||||||
|  | 			} | ||||||
|  | 			if(StrUtil.isNotBlank(data)){ | ||||||
|  | 				SseUtil.pushMessage(messageKey, data); | ||||||
|  | 			} | ||||||
|  | 		} catch (Exception e) { | ||||||
|  | 			log.error("sse推送异常", e); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static void operationMessagePush(String recipientType, Long recipientId, Integer num) { | ||||||
|  | 		try { | ||||||
|  | 			String messageKey = ""; | ||||||
|  | 			String data = ""; | ||||||
|  | 			String redisKey; | ||||||
|  | 			Object cacheObject; | ||||||
|  | 			RedisCache redisCache = SpringUtils.getBean(RedisCache.class); | ||||||
|  | 			switch (recipientType) { | ||||||
|  | 				case WgzAndBgtMessageConstant.USERTYPE_WGZ: | ||||||
|  | 					redisKey = WgzAndBgtMessageConstant.REDIS_KEY + recipientId; | ||||||
|  | 					messageKey = SseUtil.WGZ_PREFIX + recipientId; | ||||||
|  | 					cacheObject = redisCache.getCacheObject(redisKey); | ||||||
|  | 					if (cacheObject != null) { | ||||||
|  | 						WgzAppMessageTypeStatisticsRes res = (WgzAppMessageTypeStatisticsRes) cacheObject; | ||||||
|  | 						Map<String, Integer> mp = res.getMp(); | ||||||
|  | 						mp.put("3", mp.get("3") - num); | ||||||
|  | 						redisCache.setCacheObject(redisKey, res); | ||||||
|  | 						data = JSONUtil.toJsonStr(res); | ||||||
|  | 					} | ||||||
|  | 					break; | ||||||
|  | 				case WgzAndBgtMessageConstant.USERTYPE_BGT: | ||||||
|  | 					redisKey = BgtMessageConstant.REDIS_KEY + recipientId; | ||||||
|  | 					messageKey = SseUtil.BGT_PREFIX + recipientId; | ||||||
|  | 					cacheObject = redisCache.getCacheObject(redisKey); | ||||||
|  | 					if (cacheObject != null) { | ||||||
|  | 						BgtMessageCountVO bgtMessageCountVO = (BgtMessageCountVO) cacheObject; | ||||||
|  | 						bgtMessageCountVO.setHandleMessageCount(bgtMessageCountVO.getHandleMessageCount() - num); | ||||||
|  | 						redisCache.setCacheObject(redisKey, bgtMessageCountVO); | ||||||
|  | 						data = JSONUtil.toJsonStr(bgtMessageCountVO); | ||||||
|  | 					} | ||||||
|  |  | ||||||
|  | 					break; | ||||||
|  | 				case WgzAndBgtMessageConstant.USERTYPE_FBS: | ||||||
|  | 					redisKey = FbsMessageConstant.REDIS_KEY + recipientId; | ||||||
|  | 					messageKey = SseUtil.FBS_PREFIX + recipientId; | ||||||
|  | 					cacheObject = redisCache.getCacheObject(redisKey); | ||||||
|  | 					if (cacheObject != null) { | ||||||
|  | 						FbsMessageCountVO fbsMessageCountVO = (FbsMessageCountVO) cacheObject; | ||||||
|  | 						fbsMessageCountVO.setHandleMessageCount(fbsMessageCountVO.getHandleMessageCount() - num); | ||||||
|  | 						redisCache.setCacheObject(redisKey, fbsMessageCountVO); | ||||||
|  | 						data = JSONUtil.toJsonStr(fbsMessageCountVO); | ||||||
|  | 					} | ||||||
|  |  | ||||||
|  | 					break; | ||||||
|  | 				case WgzAndBgtMessageConstant.USERTYPE_ZBF: | ||||||
|  | 					redisKey = ZbfMessageConstant.REDIS_KEY + recipientId; | ||||||
|  | 					messageKey = SseUtil.ZBF_PREFIX + recipientId; | ||||||
|  | 					cacheObject = redisCache.getCacheObject(redisKey); | ||||||
|  | 					if (cacheObject != null) { | ||||||
|  | 						ZbfMessageCountVO zbfMessageCountVO = (ZbfMessageCountVO) cacheObject; | ||||||
|  | 						zbfMessageCountVO.setHandleMessageCount(zbfMessageCountVO.getHandleMessageCount() - num); | ||||||
|  | 						redisCache.setCacheObject(redisKey, zbfMessageCountVO); | ||||||
|  | 						data = JSONUtil.toJsonStr(zbfMessageCountVO); | ||||||
|  | 					} | ||||||
|  | 					break; | ||||||
|  | 				default: | ||||||
|  | 					break; | ||||||
|  | 			} | ||||||
|  | 			if(StrUtil.isNotBlank(data)){ | ||||||
|  | 				SseUtil.pushMessage(messageKey, data); | ||||||
|  | 			} | ||||||
|  | 		} catch (Exception e) { | ||||||
|  | 			log.error("sse推送异常", e); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @ -0,0 +1,75 @@ | |||||||
|  | package com.ruoyi.common.util; | ||||||
|  |  | ||||||
|  | import cn.hutool.json.JSONUtil; | ||||||
|  | import com.ruoyi.common.core.redis.RedisCache; | ||||||
|  | import com.ruoyi.common.utils.spring.SpringUtils; | ||||||
|  | import org.slf4j.Logger; | ||||||
|  | import org.slf4j.LoggerFactory; | ||||||
|  | import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; | ||||||
|  |  | ||||||
|  | import java.io.IOException; | ||||||
|  | import java.util.Map; | ||||||
|  | import java.util.concurrent.ConcurrentHashMap; | ||||||
|  |  | ||||||
|  | public class SseUtil { | ||||||
|  | 	//日志 | ||||||
|  | 	private static final Logger log = LoggerFactory.getLogger(SseUtil.class); | ||||||
|  |  | ||||||
|  | 	private final static Map<String, SseEmitter> emitterMap = new ConcurrentHashMap<>(); | ||||||
|  |  | ||||||
|  | 	public static final String WGZ_PREFIX = "wgz-"; | ||||||
|  | 	public static final String BGT_PREFIX = "bgt-"; | ||||||
|  | 	public static final String FBS_PREFIX = "fbs-"; | ||||||
|  | 	public static final String ZBF_PREFIX = "zbf-"; | ||||||
|  | 	public static SseEmitter subscribe(String userId,String prefix) { | ||||||
|  | 		// Spring Boot 2.4.7中SseEmitter构造函数支持超时时间(单位:毫秒) | ||||||
|  | 		SseEmitter emitter = new SseEmitter(1 * 60 * 1000L);  // 30分钟超时 | ||||||
|  |  | ||||||
|  | 		// 存储emitter并设置回调(2.4.7中回调机制与主流版本一致) | ||||||
|  | 		String key = prefix + "-" +userId; | ||||||
|  | 		emitterMap.put(key, emitter); | ||||||
|  |  | ||||||
|  | 		// 利用闭包特性捕获userId和prefix | ||||||
|  | 		emitter.onCompletion(() -> emitterMap.remove(key)); | ||||||
|  | 		emitter.onTimeout(() -> { | ||||||
|  | 			emitter.complete(); | ||||||
|  | 			emitterMap.remove(key); | ||||||
|  | 			log.info("用户{}连接已超时", key); | ||||||
|  | 		}); | ||||||
|  | 		emitter.onError(e -> emitterMap.remove(key)); | ||||||
|  |  | ||||||
|  | 		String redisKey = "messageCount:"+prefix+":"+userId; | ||||||
|  |  | ||||||
|  | 		Object cacheObj = SpringUtils.getBean(RedisCache.class).getCacheObject(redisKey); | ||||||
|  | //		String name = cacheObj == null ? "connect" + userId : "messageCount"; | ||||||
|  | 		String data = cacheObj == null ? "连接已建立,用户ID:" + userId : JSONUtil.toJsonStr(cacheObj); | ||||||
|  | 		// 发送初始连接确认 | ||||||
|  | 		try { | ||||||
|  | 			emitter.send(SseEmitter.event() | ||||||
|  | //				.id("init") | ||||||
|  | //				.name(name) | ||||||
|  | 				.data(data) | ||||||
|  | 			); | ||||||
|  | 		} catch (IOException e) { | ||||||
|  | 			emitter.completeWithError(e); | ||||||
|  | 		} | ||||||
|  | 		return emitter; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public static void pushMessage(String key,String data){ | ||||||
|  | 		SseEmitter emitter = emitterMap.get(key); | ||||||
|  | 		if (emitter != null) { | ||||||
|  | 			try { | ||||||
|  | 				// 发送自定义事件(客户端通过事件名监听) | ||||||
|  | 				emitter.send(SseEmitter.event() | ||||||
|  | //					.id(String.valueOf(System.currentTimeMillis())) | ||||||
|  | //					.name("messageCount") | ||||||
|  | 					.data(data) | ||||||
|  | 				); | ||||||
|  | 			} catch (IOException e) { | ||||||
|  | 				emitter.completeWithError(e); | ||||||
|  | 				emitterMap.remove(key);  // 异常时清理无效连接 | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @ -46,4 +46,6 @@ public class FbsProjectDetailVO { | |||||||
| 	@ApiModelProperty("标段列表") | 	@ApiModelProperty("标段列表") | ||||||
| 	private List<FbsProjectSectionListVO> sectionList; | 	private List<FbsProjectSectionListVO> sectionList; | ||||||
|  |  | ||||||
|  | 	@ApiModelProperty("备注") | ||||||
|  | 	private String remark; | ||||||
| } | } | ||||||
|  | |||||||
| @ -22,6 +22,11 @@ public class FbsProjectSectionListVO { | |||||||
| 	@ApiModelProperty("项目地址") | 	@ApiModelProperty("项目地址") | ||||||
| 	private String projectAddress; | 	private String projectAddress; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	@ApiModelProperty("标段描述") | ||||||
|  | 	private String sectionDescribe; | ||||||
|  |  | ||||||
|  |  | ||||||
| 	@ApiModelProperty("分包列表") | 	@ApiModelProperty("分包列表") | ||||||
| 	private List<FbsProjectSubcontractingListVO> subList; | 	private List<FbsProjectSubcontractingListVO> subList; | ||||||
|  |  | ||||||
|  | |||||||
| @ -6,9 +6,12 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | |||||||
| import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; | import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; | ||||||
| import com.baomidou.mybatisplus.core.toolkit.Wrappers; | import com.baomidou.mybatisplus.core.toolkit.Wrappers; | ||||||
| import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | ||||||
|  | import com.ruoyi.common.constants.FbsMessageConstant; | ||||||
| import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl; | import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl; | ||||||
| import com.ruoyi.common.core.page.TableDataInfo; | import com.ruoyi.common.core.page.TableDataInfo; | ||||||
|  | import com.ruoyi.common.core.redis.RedisCache; | ||||||
| import com.ruoyi.common.enums.BgtMessageType; | import com.ruoyi.common.enums.BgtMessageType; | ||||||
|  | import com.ruoyi.common.util.MessageUtil; | ||||||
| import com.ruoyi.common.utils.PageUtils; | import com.ruoyi.common.utils.PageUtils; | ||||||
| import com.ruoyi.common.utils.SecurityUtils; | import com.ruoyi.common.utils.SecurityUtils; | ||||||
| import com.ruoyi.fbs.bo.FbsMessageQueryBo; | import com.ruoyi.fbs.bo.FbsMessageQueryBo; | ||||||
| @ -20,6 +23,7 @@ import com.ruoyi.fbs.domain.vo.FbsMessageDetailVO; | |||||||
| import com.ruoyi.fbs.domain.vo.FbsMessageVO; | import com.ruoyi.fbs.domain.vo.FbsMessageVO; | ||||||
| import com.ruoyi.fbs.mapper.FbsMessageMapper; | import com.ruoyi.fbs.mapper.FbsMessageMapper; | ||||||
| import com.ruoyi.fbs.service.IFbsMessageService; | import com.ruoyi.fbs.service.IFbsMessageService; | ||||||
|  | import org.springframework.beans.factory.annotation.Autowired; | ||||||
| import org.springframework.stereotype.Service; | import org.springframework.stereotype.Service; | ||||||
|  |  | ||||||
| import java.time.LocalTime; | import java.time.LocalTime; | ||||||
| @ -41,6 +45,9 @@ import static com.ruoyi.common.constants.WgzAndBgtMessageConstant.OPERATION_NEED | |||||||
| @Service | @Service | ||||||
| public class FbsMessageServiceImpl extends ServicePlusImpl<FbsMessageMapper, FbsMessage> implements IFbsMessageService { | public class FbsMessageServiceImpl extends ServicePlusImpl<FbsMessageMapper, FbsMessage> implements IFbsMessageService { | ||||||
|  |  | ||||||
|  | 	@Autowired | ||||||
|  | 	private RedisCache redisCache; | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public FbsMessage queryById(Long id){ |     public FbsMessage queryById(Long id){ | ||||||
|         return getById(id); |         return getById(id); | ||||||
| @ -122,6 +129,8 @@ public class FbsMessageServiceImpl extends ServicePlusImpl<FbsMessageMapper, Fbs | |||||||
| 			.eq(FbsMessage::getRecipientId, SecurityUtils.getAppUserId()) | 			.eq(FbsMessage::getRecipientId, SecurityUtils.getAppUserId()) | ||||||
| 			.eq(FbsMessage::getIsOperation, OPERATION_NEED)); | 			.eq(FbsMessage::getIsOperation, OPERATION_NEED)); | ||||||
| 		fbsMessageCountVO.setHandleMessageCount(handle); | 		fbsMessageCountVO.setHandleMessageCount(handle); | ||||||
|  |  | ||||||
|  | 		redisCache.setCacheObject(FbsMessageConstant.REDIS_KEY+SecurityUtils.getAppUserId(), fbsMessageCountVO); | ||||||
| 		return fbsMessageCountVO; | 		return fbsMessageCountVO; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @ -208,7 +217,9 @@ public class FbsMessageServiceImpl extends ServicePlusImpl<FbsMessageMapper, Fbs | |||||||
|  |  | ||||||
| 	@Override | 	@Override | ||||||
| 	public Boolean sendAMessage(FbsMessage bo) { | 	public Boolean sendAMessage(FbsMessage bo) { | ||||||
| 		return save(bo); | 		boolean save = save(bo); | ||||||
|  | 		MessageUtil.saveMessagePush(bo.getRecipientType(), bo.getRecipientId(), bo.getMessageLargeType(), bo.getIsOperation()); | ||||||
|  | 		return save; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	@Override | 	@Override | ||||||
| @ -222,6 +233,8 @@ public class FbsMessageServiceImpl extends ServicePlusImpl<FbsMessageMapper, Fbs | |||||||
| 		wrapper.eq(FbsMessage::getTableName, tableName); | 		wrapper.eq(FbsMessage::getTableName, tableName); | ||||||
| 		wrapper.set(FbsMessage::getIsOperation, OPERATION_ALREADY); | 		wrapper.set(FbsMessage::getIsOperation, OPERATION_ALREADY); | ||||||
| 		update(wrapper); | 		update(wrapper); | ||||||
|  | 		MessageUtil.operationMessagePush(recipientType, recipientId, 1); | ||||||
|  |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	@Override | 	@Override | ||||||
| @ -233,5 +246,6 @@ public class FbsMessageServiceImpl extends ServicePlusImpl<FbsMessageMapper, Fbs | |||||||
| 		wrapper.eq(FbsMessage::getTableName, tableName); | 		wrapper.eq(FbsMessage::getTableName, tableName); | ||||||
| 		wrapper.set(FbsMessage::getIsOperation, OPERATION_ALREADY); | 		wrapper.set(FbsMessage::getIsOperation, OPERATION_ALREADY); | ||||||
| 		update(wrapper); | 		update(wrapper); | ||||||
|  | 		MessageUtil.operationMessagePush(recipientType, recipientId, tableIds.size()); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | |||||||
| @ -29,6 +29,7 @@ import com.ruoyi.common.enums.RecruitApplyStatus; | |||||||
| import com.ruoyi.common.enums.TaskApplyStatus; | import com.ruoyi.common.enums.TaskApplyStatus; | ||||||
| import com.ruoyi.common.exception.BaseException; | import com.ruoyi.common.exception.BaseException; | ||||||
| import com.ruoyi.common.util.DataUtil; | import com.ruoyi.common.util.DataUtil; | ||||||
|  | import com.ruoyi.common.util.ValidUtil; | ||||||
| import com.ruoyi.common.utils.DateUtils; | import com.ruoyi.common.utils.DateUtils; | ||||||
| import com.ruoyi.common.utils.PageUtils; | import com.ruoyi.common.utils.PageUtils; | ||||||
| import com.ruoyi.common.utils.SecurityUtils; | import com.ruoyi.common.utils.SecurityUtils; | ||||||
| @ -168,6 +169,9 @@ public class FbsProjectTaskServiceImpl extends ServicePlusImpl<FbsProjectTaskMap | |||||||
| 		if( fbsUser.getCompanyId()==null){ | 		if( fbsUser.getCompanyId()==null){ | ||||||
| 			throw new BaseException("尚未企业认证"); | 			throw new BaseException("尚未企业认证"); | ||||||
| 		} | 		} | ||||||
|  | 		if (!ValidUtil.isValidChineseMobile(entity.getTaskContactPhone())) { | ||||||
|  | 			throw new BaseException("手机号格式不正确"); | ||||||
|  | 		} | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|  | |||||||
| @ -1,15 +1,14 @@ | |||||||
| package com.ruoyi.wgz.service; | package com.ruoyi.wgz.service; | ||||||
|  |  | ||||||
| import com.ruoyi.wgz.bo.req.WgzAppConfirmRegistrationReq; | import com.ruoyi.common.core.mybatisplus.core.IServicePlus; | ||||||
|  | import com.ruoyi.common.core.page.TableDataInfo; | ||||||
|  | import com.ruoyi.wgz.bo.WgzMessageQueryBo; | ||||||
| import com.ruoyi.wgz.bo.req.WgzAppGetMessageListReq; | import com.ruoyi.wgz.bo.req.WgzAppGetMessageListReq; | ||||||
| import com.ruoyi.wgz.bo.req.WgzAppReadUnreadReq; | import com.ruoyi.wgz.bo.req.WgzAppReadUnreadReq; | ||||||
| import com.ruoyi.wgz.bo.res.WgzAppGetMessageListRes; | import com.ruoyi.wgz.bo.res.WgzAppGetMessageListRes; | ||||||
| import com.ruoyi.wgz.bo.res.WgzAppMessageTypeStatisticsRes; | import com.ruoyi.wgz.bo.res.WgzAppMessageTypeStatisticsRes; | ||||||
| import com.ruoyi.wgz.bo.res.WgzAppRegistrationInformationRes; | import com.ruoyi.wgz.bo.res.WgzAppRegistrationInformationRes; | ||||||
| import com.ruoyi.wgz.domain.WgzMessage; | import com.ruoyi.wgz.domain.WgzMessage; | ||||||
| import com.ruoyi.wgz.bo.WgzMessageQueryBo; |  | ||||||
| import com.ruoyi.common.core.mybatisplus.core.IServicePlus; |  | ||||||
| import com.ruoyi.common.core.page.TableDataInfo; |  | ||||||
| import org.springframework.validation.annotation.Validated; | import org.springframework.validation.annotation.Validated; | ||||||
|  |  | ||||||
| import java.time.LocalDate; | import java.time.LocalDate; | ||||||
| @ -98,4 +97,9 @@ public interface IWgzMessageService extends IServicePlus<WgzMessage> { | |||||||
| 	 * 修改已读未读状态 | 	 * 修改已读未读状态 | ||||||
| 	 */ | 	 */ | ||||||
| 	Boolean userReadUnread(@Validated WgzAppReadUnreadReq req); | 	Boolean userReadUnread(@Validated WgzAppReadUnreadReq req); | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * 修改操作状态 | ||||||
|  | 	 */ | ||||||
|  | 	Boolean updateOperationStatus(Long  id); | ||||||
| } | } | ||||||
|  | |||||||
| @ -153,4 +153,9 @@ public interface IWgzPayCalculationService extends IServicePlus<WgzPayCalculatio | |||||||
| 	 * 获取任务下已审核通过的数据 | 	 * 获取任务下已审核通过的数据 | ||||||
| 	 */ | 	 */ | ||||||
| 	List<WgzPayCalculation> getPassListByTaskIds(List<Long> taskIds); | 	List<WgzPayCalculation> getPassListByTaskIds(List<Long> taskIds); | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * 总收入 | ||||||
|  | 	 */ | ||||||
|  | 	BigDecimal grossIncome(); | ||||||
| } | } | ||||||
|  | |||||||
| @ -8,10 +8,13 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | |||||||
| import com.ruoyi.bgt.domain.BgtProjectRecruit; | import com.ruoyi.bgt.domain.BgtProjectRecruit; | ||||||
| import com.ruoyi.bgt.service.IBgtProjectRecruitApplyService; | import com.ruoyi.bgt.service.IBgtProjectRecruitApplyService; | ||||||
| import com.ruoyi.bgt.service.IBgtProjectRecruitService; | import com.ruoyi.bgt.service.IBgtProjectRecruitService; | ||||||
|  | import com.ruoyi.common.constants.WgzAndBgtMessageConstant; | ||||||
| import com.ruoyi.common.core.domain.entity.SysDictData; | import com.ruoyi.common.core.domain.entity.SysDictData; | ||||||
| import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl; | import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl; | ||||||
| import com.ruoyi.common.core.page.TableDataInfo; | import com.ruoyi.common.core.page.TableDataInfo; | ||||||
|  | import com.ruoyi.common.core.redis.RedisCache; | ||||||
| import com.ruoyi.common.service.IAnnexService; | import com.ruoyi.common.service.IAnnexService; | ||||||
|  | import com.ruoyi.common.util.MessageUtil; | ||||||
| import com.ruoyi.common.utils.PageUtils; | import com.ruoyi.common.utils.PageUtils; | ||||||
| import com.ruoyi.common.utils.SecurityUtils; | import com.ruoyi.common.utils.SecurityUtils; | ||||||
| import com.ruoyi.system.service.ISysDictTypeService; | import com.ruoyi.system.service.ISysDictTypeService; | ||||||
| @ -69,6 +72,8 @@ public class WgzMessageServiceImpl extends ServicePlusImpl<WgzMessageMapper, Wgz | |||||||
|  |  | ||||||
| 	@Autowired | 	@Autowired | ||||||
| 	private IBgtProjectRecruitService iBgtProjectRecruitService; | 	private IBgtProjectRecruitService iBgtProjectRecruitService; | ||||||
|  | 	@Autowired | ||||||
|  | 	private RedisCache redisCache; | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public WgzMessage queryById(Long id){ |     public WgzMessage queryById(Long id){ | ||||||
| @ -143,7 +148,9 @@ public class WgzMessageServiceImpl extends ServicePlusImpl<WgzMessageMapper, Wgz | |||||||
|  |  | ||||||
| 	@Override | 	@Override | ||||||
| 	public Boolean sendAMessage(WgzMessage bo) { | 	public Boolean sendAMessage(WgzMessage bo) { | ||||||
| 		return save(bo); | 		boolean save = save(bo); | ||||||
|  | 		MessageUtil.saveMessagePush(bo.getRecipientType(), bo.getRecipientId(), bo.getMessageLargeType(), bo.getIsOperation()); | ||||||
|  | 		return save; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
| @ -192,7 +199,9 @@ public class WgzMessageServiceImpl extends ServicePlusImpl<WgzMessageMapper, Wgz | |||||||
| 			); | 			); | ||||||
| 			mp.put("3",daiBanCount); | 			mp.put("3",daiBanCount); | ||||||
| 		} | 		} | ||||||
| 		return res.setMp(mp); | 		res.setMp(mp); | ||||||
|  | 		redisCache.setCacheObject(WgzAndBgtMessageConstant.REDIS_KEY+SecurityUtils.getAppUserId(), res); | ||||||
|  | 		return res; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| 	@Override | 	@Override | ||||||
| @ -256,10 +265,25 @@ public class WgzMessageServiceImpl extends ServicePlusImpl<WgzMessageMapper, Wgz | |||||||
|  |  | ||||||
| 	@Override | 	@Override | ||||||
| 	public Boolean userReadUnread(WgzAppReadUnreadReq req) { | 	public Boolean userReadUnread(WgzAppReadUnreadReq req) { | ||||||
| 		WgzMessage wgzMessage = new WgzMessage().setId(req.getMessageId()).setReadStatus("1"); | 		WgzMessage wgzMessage = baseMapper.selectById(req.getMessageId()); | ||||||
| 		return baseMapper.updateById(wgzMessage) > 0; | 		boolean b = true; | ||||||
|  | 		if("0".equals(wgzMessage.getReadStatus())){ | ||||||
|  | 			MessageUtil.readMessagePush(wgzMessage.getRecipientType(), wgzMessage.getRecipientId(), wgzMessage.getMessageLargeType(), wgzMessage.getReadStatus()); | ||||||
|  | 			wgzMessage.setReadStatus("1"); | ||||||
|  | 			b = baseMapper.updateById(wgzMessage) > 0; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | 		return b; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	@Override | ||||||
|  | 	public Boolean updateOperationStatus(Long id) { | ||||||
|  | 		WgzMessage wgzMessage = baseMapper.selectById(id); | ||||||
|  | 		MessageUtil.operationMessagePush(wgzMessage.getRecipientType(), wgzMessage.getRecipientId(), 1); | ||||||
|  | 		wgzMessage.setIsOperation("2"); | ||||||
|  | 		return baseMapper.updateById(wgzMessage) > 0; | ||||||
|  |  | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * 判断招工是否已招满或已过期 | 	 * 判断招工是否已招满或已过期 | ||||||
|  | |||||||
| @ -701,4 +701,19 @@ public class WgzPayCalculationServiceImpl extends ServicePlusImpl<WgzPayCalculat | |||||||
| 			.eq(WgzPayCalculation::getAuditorType, AuditStatus.PASS.getCode()); | 			.eq(WgzPayCalculation::getAuditorType, AuditStatus.PASS.getCode()); | ||||||
| 		return list(wrapper); | 		return list(wrapper); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	@Override | ||||||
|  | 	public BigDecimal grossIncome() { | ||||||
|  | 		LambdaQueryWrapper<WgzPayCalculation> wrapper =  new LambdaQueryWrapper<>(); | ||||||
|  | 		wrapper.in(WgzPayCalculation::getUserId, SecurityUtils.getAppUserId()) | ||||||
|  | 			.eq(WgzPayCalculation::getAuditorType, AuditStatus.PASS.getCode()); | ||||||
|  | 		List<WgzPayCalculation> list = list(wrapper); | ||||||
|  | 		BigDecimal total = BigDecimal.ZERO; | ||||||
|  | 		for (WgzPayCalculation wgzPayCalculation : list) { | ||||||
|  | 			//金额*天数=实际工资 | ||||||
|  | 			total = total.add(wgzPayCalculation.getRecruitAmount().multiply(new BigDecimal(wgzPayCalculation.getNum()))); | ||||||
|  |  		} | ||||||
|  |  | ||||||
|  | 		return total; | ||||||
|  | 	} | ||||||
| } | } | ||||||
|  | |||||||
| @ -16,4 +16,7 @@ public class ZbfSubSwitchListDTO { | |||||||
|  |  | ||||||
| 	@ApiModelProperty("总包方用户") | 	@ApiModelProperty("总包方用户") | ||||||
| 	private Long zbfUserId; | 	private Long zbfUserId; | ||||||
|  |  | ||||||
|  | 	@ApiModelProperty("项目ID") | ||||||
|  | 	private Long projectId; | ||||||
| } | } | ||||||
|  | |||||||
| @ -19,6 +19,9 @@ public class ZbfProjectSectionListVO { | |||||||
| 	@ApiModelProperty("标段名称") | 	@ApiModelProperty("标段名称") | ||||||
| 	private String sectionName; | 	private String sectionName; | ||||||
|  |  | ||||||
|  | 	@ApiModelProperty("标段描述") | ||||||
|  | 	private String sectionDescribe; | ||||||
|  |  | ||||||
| 	@ApiModelProperty("项目地址") | 	@ApiModelProperty("项目地址") | ||||||
| 	private String projectAddress; | 	private String projectAddress; | ||||||
|  |  | ||||||
|  | |||||||
| @ -6,9 +6,12 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | |||||||
| import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; | import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; | ||||||
| import com.baomidou.mybatisplus.core.toolkit.Wrappers; | import com.baomidou.mybatisplus.core.toolkit.Wrappers; | ||||||
| import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; | ||||||
|  | import com.ruoyi.common.constants.ZbfMessageConstant; | ||||||
| import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl; | import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl; | ||||||
| import com.ruoyi.common.core.page.TableDataInfo; | import com.ruoyi.common.core.page.TableDataInfo; | ||||||
|  | import com.ruoyi.common.core.redis.RedisCache; | ||||||
| import com.ruoyi.common.enums.BgtMessageType; | import com.ruoyi.common.enums.BgtMessageType; | ||||||
|  | import com.ruoyi.common.util.MessageUtil; | ||||||
| import com.ruoyi.common.utils.PageUtils; | import com.ruoyi.common.utils.PageUtils; | ||||||
| import com.ruoyi.common.utils.SecurityUtils; | import com.ruoyi.common.utils.SecurityUtils; | ||||||
| import com.ruoyi.zbf.bo.ZbfMessageQueryBo; | import com.ruoyi.zbf.bo.ZbfMessageQueryBo; | ||||||
| @ -20,6 +23,7 @@ import com.ruoyi.zbf.domain.vo.ZbfMessageDetailVO; | |||||||
| import com.ruoyi.zbf.domain.vo.ZbfMessageVO; | import com.ruoyi.zbf.domain.vo.ZbfMessageVO; | ||||||
| import com.ruoyi.zbf.mapper.ZbfMessageMapper; | import com.ruoyi.zbf.mapper.ZbfMessageMapper; | ||||||
| import com.ruoyi.zbf.service.IZbfMessageService; | import com.ruoyi.zbf.service.IZbfMessageService; | ||||||
|  | import org.springframework.beans.factory.annotation.Autowired; | ||||||
| import org.springframework.stereotype.Service; | import org.springframework.stereotype.Service; | ||||||
|  |  | ||||||
| import java.time.LocalTime; | import java.time.LocalTime; | ||||||
| @ -40,6 +44,8 @@ import static com.ruoyi.common.constants.WgzAndBgtMessageConstant.OPERATION_NEED | |||||||
| @Service | @Service | ||||||
| public class ZbfMessageServiceImpl extends ServicePlusImpl<ZbfMessageMapper, ZbfMessage> implements IZbfMessageService { | public class ZbfMessageServiceImpl extends ServicePlusImpl<ZbfMessageMapper, ZbfMessage> implements IZbfMessageService { | ||||||
|  |  | ||||||
|  | 	@Autowired | ||||||
|  | 	private RedisCache redisCache; | ||||||
|     @Override |     @Override | ||||||
|     public ZbfMessage queryById(Long id){ |     public ZbfMessage queryById(Long id){ | ||||||
|         return getById(id); |         return getById(id); | ||||||
| @ -107,7 +113,9 @@ public class ZbfMessageServiceImpl extends ServicePlusImpl<ZbfMessageMapper, Zbf | |||||||
|  |  | ||||||
| 	@Override | 	@Override | ||||||
| 	public Boolean sendAMessage(ZbfMessage bo) { | 	public Boolean sendAMessage(ZbfMessage bo) { | ||||||
| 		return save(bo); | 		boolean save = save(bo); | ||||||
|  | 		MessageUtil.saveMessagePush(bo.getRecipientType(), bo.getRecipientId(), bo.getMessageLargeType(), bo.getIsOperation()); | ||||||
|  | 		return save; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	@Override | 	@Override | ||||||
| @ -121,6 +129,7 @@ public class ZbfMessageServiceImpl extends ServicePlusImpl<ZbfMessageMapper, Zbf | |||||||
| 		wrapper.eq(ZbfMessage::getTableName, tableName); | 		wrapper.eq(ZbfMessage::getTableName, tableName); | ||||||
| 		wrapper.set(ZbfMessage::getIsOperation, OPERATION_ALREADY); | 		wrapper.set(ZbfMessage::getIsOperation, OPERATION_ALREADY); | ||||||
| 		update(wrapper); | 		update(wrapper); | ||||||
|  | 		MessageUtil.operationMessagePush(recipientType, recipientId, 1); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	@Override | 	@Override | ||||||
| @ -132,6 +141,7 @@ public class ZbfMessageServiceImpl extends ServicePlusImpl<ZbfMessageMapper, Zbf | |||||||
| 		wrapper.eq(ZbfMessage::getTableName, tableName); | 		wrapper.eq(ZbfMessage::getTableName, tableName); | ||||||
| 		wrapper.set(ZbfMessage::getIsOperation, OPERATION_ALREADY); | 		wrapper.set(ZbfMessage::getIsOperation, OPERATION_ALREADY); | ||||||
| 		update(wrapper); | 		update(wrapper); | ||||||
|  | 		MessageUtil.operationMessagePush(recipientType, recipientId, tableIds.size()); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	@Override | 	@Override | ||||||
| @ -150,6 +160,7 @@ public class ZbfMessageServiceImpl extends ServicePlusImpl<ZbfMessageMapper, Zbf | |||||||
| 			.eq(ZbfMessage::getRecipientId, SecurityUtils.getAppUserId()) | 			.eq(ZbfMessage::getRecipientId, SecurityUtils.getAppUserId()) | ||||||
| 			.eq(ZbfMessage::getIsOperation, OPERATION_NEED)); | 			.eq(ZbfMessage::getIsOperation, OPERATION_NEED)); | ||||||
| 		zbfMessageCountVO.setHandleMessageCount(handle); | 		zbfMessageCountVO.setHandleMessageCount(handle); | ||||||
|  | 		redisCache.setCacheObject(ZbfMessageConstant.REDIS_KEY+SecurityUtils.getAppUserId(), zbfMessageCountVO); | ||||||
| 		return zbfMessageCountVO; | 		return zbfMessageCountVO; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | |||||||
| @ -204,9 +204,6 @@ public class ZbfProjectServiceImpl extends ServicePlusImpl<ZbfProjectMapper, Zbf | |||||||
| 					} | 					} | ||||||
| 					subListVO.add(fbsProjectSubcontractingListVO); | 					subListVO.add(fbsProjectSubcontractingListVO); | ||||||
| 				} | 				} | ||||||
| 				if (CollectionUtil.isEmpty(subListVO)) { |  | ||||||
| 					continue; |  | ||||||
| 				} |  | ||||||
| 				FbsProjectSectionListVO fbsProjectSectionListVO = new FbsProjectSectionListVO(); | 				FbsProjectSectionListVO fbsProjectSectionListVO = new FbsProjectSectionListVO(); | ||||||
| 				BeanUtil.copyProperties(zbfProjectSection, fbsProjectSectionListVO); | 				BeanUtil.copyProperties(zbfProjectSection, fbsProjectSectionListVO); | ||||||
| 				fbsProjectSectionListVO.setSubList(subListVO); | 				fbsProjectSectionListVO.setSubList(subListVO); | ||||||
| @ -363,9 +360,6 @@ public class ZbfProjectServiceImpl extends ServicePlusImpl<ZbfProjectMapper, Zbf | |||||||
| 				} | 				} | ||||||
| 				subListVO.add(fbsProjectSubcontractingListVO); | 				subListVO.add(fbsProjectSubcontractingListVO); | ||||||
| 			} | 			} | ||||||
| 			if (CollectionUtil.isEmpty(subListVO)) { |  | ||||||
| 				continue; |  | ||||||
| 			} |  | ||||||
| 			FbsProjectSectionListVO fbsProjectSectionListVO = new FbsProjectSectionListVO(); | 			FbsProjectSectionListVO fbsProjectSectionListVO = new FbsProjectSectionListVO(); | ||||||
| 			BeanUtil.copyProperties(zbfProjectSection, fbsProjectSectionListVO); | 			BeanUtil.copyProperties(zbfProjectSection, fbsProjectSectionListVO); | ||||||
| 			fbsProjectSectionListVO.setSubList(subListVO); | 			fbsProjectSectionListVO.setSubList(subListVO); | ||||||
| @ -543,15 +537,25 @@ public class ZbfProjectServiceImpl extends ServicePlusImpl<ZbfProjectMapper, Zbf | |||||||
| 	public TableDataInfo<FbsProgressListVO> fbsProgressList(FbsProgressListDTO dto) { | 	public TableDataInfo<FbsProgressListVO> fbsProgressList(FbsProgressListDTO dto) { | ||||||
| 		Page<FbsProgressListVO> fbsProgressListVOPage = new Page<>(); | 		Page<FbsProgressListVO> fbsProgressListVOPage = new Page<>(); | ||||||
| 		//查询所有创建的任务 | 		//查询所有创建的任务 | ||||||
| 		List<FbsProjectTask> taskList = fbsProjectTaskService.list(Wrappers.<FbsProjectTask>lambdaQuery() | 		LambdaQueryWrapper<FbsProjectTask> wrapper = Wrappers.<FbsProjectTask>lambdaQuery() | ||||||
| 			.eq(FbsProjectTask::getCreateId, SecurityUtils.getAppUserId()) | 			.eq(FbsProjectTask::getCreateId, SecurityUtils.getAppUserId()) | ||||||
| 			.eq(FbsProjectTask::getProjectId, dto.getProjectId()) | 			.eq(FbsProjectTask::getProjectId, dto.getProjectId()) | ||||||
| 		); | 			.orderByDesc(FbsProjectTask::getId); | ||||||
| 		List<Long> taskIds = taskList.stream().map(FbsProjectTask::getId).collect(Collectors.toList()); | 		Page<FbsProjectTask> fbsProjectTaskPage = fbsProjectTaskService.getBaseMapper().selectPage(PageUtils.buildPage(), wrapper); | ||||||
|  | 		List<Long> taskIds = fbsProjectTaskPage.getRecords().stream().map(FbsProjectTask::getId).collect(Collectors.toList()); | ||||||
| 		if (CollectionUtil.isNotEmpty(taskIds)) { | 		if (CollectionUtil.isNotEmpty(taskIds)) { | ||||||
| 			TableDataInfo<BgtProjectTaskProgress> progressByTaskIds = bgtProjectTaskProgressService.getProgressByTaskIds(dto.getPageSize(), dto.getPageNum(), taskIds); | 			List<BgtProjectTaskProgress> progressByTaskIds = bgtProjectTaskProgressService.getProgressByTaskIds(taskIds); | ||||||
| 			fbsProgressListVOPage.setTotal(progressByTaskIds.getTotal()); | 			Map<Long, Integer> map = progressByTaskIds.stream().collect(Collectors.toMap(BgtProjectTaskProgress::getTaskId, BgtProjectTaskProgress::getProgress)); | ||||||
| 			fbsProgressListVOPage.setRecords(BeanUtil.copyToList(progressByTaskIds.getRows(), FbsProgressListVO.class)); | 			ArrayList<FbsProgressListVO> fbsProgressListVOS = new ArrayList<>(); | ||||||
|  | 			for (FbsProjectTask fbsProjectTask : fbsProjectTaskPage.getRecords()) { | ||||||
|  | 				FbsProgressListVO fbsProgressListVO = new FbsProgressListVO(); | ||||||
|  | 				fbsProgressListVO.setId(fbsProjectTask.getId()); | ||||||
|  | 				fbsProgressListVO.setTaskName(fbsProjectTask.getTaskName()); | ||||||
|  | 				fbsProgressListVO.setProgress(map.get(fbsProjectTask.getId())==null?0:map.get(fbsProjectTask.getId())); | ||||||
|  | 				fbsProgressListVOS.add(fbsProgressListVO); | ||||||
|  | 			} | ||||||
|  | 			fbsProgressListVOPage.setTotal(fbsProjectTaskPage.getTotal()); | ||||||
|  | 			fbsProgressListVOPage.setRecords(fbsProgressListVOS); | ||||||
| 		} | 		} | ||||||
| 		return PageUtils.buildDataInfo(fbsProgressListVOPage); | 		return PageUtils.buildDataInfo(fbsProgressListVOPage); | ||||||
| 	} | 	} | ||||||
| @ -586,8 +590,9 @@ public class ZbfProjectServiceImpl extends ServicePlusImpl<ZbfProjectMapper, Zbf | |||||||
|  |  | ||||||
| 			//已支付金额 | 			//已支付金额 | ||||||
| 			vo.setPayAmount(BigDecimal.ZERO); | 			vo.setPayAmount(BigDecimal.ZERO); | ||||||
| 			if (CollectionUtil.isNotEmpty(subIds)) { | 			if (CollectionUtil.isNotEmpty(taskList)) { | ||||||
| 				List<BgtWageApplication> payList = bgtWageApplicationService.getPassListByTaskIds(subIds); | 				List<Long> taskIds = taskList.stream().map(FbsProjectTask::getId).collect(Collectors.toList()); | ||||||
|  | 				List<BgtWageApplication> payList = bgtWageApplicationService.getPassListByTaskIds(taskIds); | ||||||
| 				BigDecimal payAmount = payList.stream().map(BgtWageApplication::getApplicantAmount).reduce(BigDecimal.ZERO, BigDecimal::add); | 				BigDecimal payAmount = payList.stream().map(BgtWageApplication::getApplicantAmount).reduce(BigDecimal.ZERO, BigDecimal::add); | ||||||
| 				vo.setPayAmount(payAmount); | 				vo.setPayAmount(payAmount); | ||||||
| 			} | 			} | ||||||
| @ -867,7 +872,8 @@ public class ZbfProjectServiceImpl extends ServicePlusImpl<ZbfProjectMapper, Zbf | |||||||
| 			.eq(FbsProjectTask::getProjectId, id) | 			.eq(FbsProjectTask::getProjectId, id) | ||||||
| 			.isNotNull(FbsProjectTask::getUserId) | 			.isNotNull(FbsProjectTask::getUserId) | ||||||
| 		); | 		); | ||||||
| 		zbfPersonCountVO.setBgtCount(list.size()); | 		Set<Long> collect = list.stream().map(FbsProjectTask::getUserId).collect(Collectors.toSet()); | ||||||
|  | 		zbfPersonCountVO.setBgtCount(collect.size()); | ||||||
| 		List<Long> taskIds = list.stream().map(FbsProjectTask::getId).collect(Collectors.toList()); | 		List<Long> taskIds = list.stream().map(FbsProjectTask::getId).collect(Collectors.toList()); | ||||||
| 		zbfPersonCountVO.setWgzCount(0); | 		zbfPersonCountVO.setWgzCount(0); | ||||||
| 		if (CollectionUtil.isNotEmpty(taskIds)) { | 		if (CollectionUtil.isNotEmpty(taskIds)) { | ||||||
| @ -924,14 +930,24 @@ public class ZbfProjectServiceImpl extends ServicePlusImpl<ZbfProjectMapper, Zbf | |||||||
| 	public TableDataInfo<ZbfProgressListVO> zbfProgressList(ZbfProgressListDTO dto) { | 	public TableDataInfo<ZbfProgressListVO> zbfProgressList(ZbfProgressListDTO dto) { | ||||||
| 		Page<ZbfProgressListVO> voPage = new Page<>(); | 		Page<ZbfProgressListVO> voPage = new Page<>(); | ||||||
| 		//查询所有创建的任务 | 		//查询所有创建的任务 | ||||||
| 		List<FbsProjectTask> taskList = fbsProjectTaskService.list(Wrappers.<FbsProjectTask>lambdaQuery() | 		LambdaQueryWrapper<FbsProjectTask> wrapper = Wrappers.<FbsProjectTask>lambdaQuery() | ||||||
| 			.eq(FbsProjectTask::getProjectId, dto.getProjectId()) | 			.eq(FbsProjectTask::getProjectId, dto.getProjectId()) | ||||||
| 		); | 			.orderByDesc(FbsProjectTask::getId); | ||||||
| 		List<Long> taskIds = taskList.stream().map(FbsProjectTask::getId).collect(Collectors.toList()); | 		Page<FbsProjectTask> fbsProjectTaskPage = fbsProjectTaskService.getBaseMapper().selectPage(PageUtils.buildPage(), wrapper); | ||||||
|  | 		List<Long> taskIds = fbsProjectTaskPage.getRecords().stream().map(FbsProjectTask::getId).collect(Collectors.toList()); | ||||||
| 		if (CollectionUtil.isNotEmpty(taskIds)) { | 		if (CollectionUtil.isNotEmpty(taskIds)) { | ||||||
| 			TableDataInfo<BgtProjectTaskProgress> progressByTaskIds = bgtProjectTaskProgressService.getProgressByTaskIds(dto.getPageSize(), dto.getPageNum(), taskIds); | 			List<BgtProjectTaskProgress> progressByTaskIds = bgtProjectTaskProgressService.getProgressByTaskIds(taskIds); | ||||||
| 			voPage.setTotal(progressByTaskIds.getTotal()); | 			Map<Long, Integer> map = progressByTaskIds.stream().collect(Collectors.toMap(BgtProjectTaskProgress::getTaskId, BgtProjectTaskProgress::getProgress)); | ||||||
| 			voPage.setRecords(BeanUtil.copyToList(progressByTaskIds.getRows(), ZbfProgressListVO.class)); | 			ArrayList<ZbfProgressListVO> zbfProgressListVOS = new ArrayList<>(); | ||||||
|  | 			for (FbsProjectTask fbsProjectTask : fbsProjectTaskPage.getRecords()) { | ||||||
|  | 				ZbfProgressListVO zbfProgressListVO = new ZbfProgressListVO(); | ||||||
|  | 				zbfProgressListVO.setId(fbsProjectTask.getId()); | ||||||
|  | 				zbfProgressListVO.setTaskName(fbsProjectTask.getTaskName()); | ||||||
|  | 				zbfProgressListVO.setProgress(map.get(fbsProjectTask.getId())==null?0:map.get(fbsProjectTask.getId())); | ||||||
|  | 				zbfProgressListVOS.add(zbfProgressListVO); | ||||||
|  | 			} | ||||||
|  | 			voPage.setTotal(fbsProjectTaskPage.getTotal()); | ||||||
|  | 			voPage.setRecords(zbfProgressListVOS); | ||||||
| 		} | 		} | ||||||
| 		return PageUtils.buildDataInfo(voPage); | 		return PageUtils.buildDataInfo(voPage); | ||||||
| 	} | 	} | ||||||
| @ -980,6 +996,7 @@ public class ZbfProjectServiceImpl extends ServicePlusImpl<ZbfProjectMapper, Zbf | |||||||
| 		LambdaQueryWrapper<ZbfProject> wrapper = new LambdaQueryWrapper<>(); | 		LambdaQueryWrapper<ZbfProject> wrapper = new LambdaQueryWrapper<>(); | ||||||
| 		wrapper.eq(ZbfProject::getUserId, SecurityUtils.getAppUserId()); | 		wrapper.eq(ZbfProject::getUserId, SecurityUtils.getAppUserId()); | ||||||
| 		wrapper.like(StrUtil.isNotBlank(dto.getProjectName()), ZbfProject::getProjectName, dto.getProjectName()); | 		wrapper.like(StrUtil.isNotBlank(dto.getProjectName()), ZbfProject::getProjectName, dto.getProjectName()); | ||||||
|  | 		wrapper.orderByDesc(ZbfProject::getId); | ||||||
| 		Page<ZbfProject> result = page(PageUtils.buildPage(), wrapper); | 		Page<ZbfProject> result = page(PageUtils.buildPage(), wrapper); | ||||||
| 		return PageUtils.buildDataInfo(result); | 		return PageUtils.buildDataInfo(result); | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -56,17 +56,19 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" | |||||||
|     </select> |     </select> | ||||||
|  |  | ||||||
|     <select id="getProgressByTaskIds" resultType="com.ruoyi.bgt.domain.BgtProjectTaskProgress"> |     <select id="getProgressByTaskIds" resultType="com.ruoyi.bgt.domain.BgtProjectTaskProgress"> | ||||||
|         SELECT t.* |         SELECT * | ||||||
|         FROM bgt_project_task_progress t |         FROM ( | ||||||
|         JOIN ( |         SELECT | ||||||
|         SELECT task_id, MAX(progress) AS maxProgress |         *, | ||||||
|  |         ROW_NUMBER() OVER (PARTITION BY task_id ORDER BY progress DESC) as rn | ||||||
|         FROM bgt_project_task_progress |         FROM bgt_project_task_progress | ||||||
|         WHERE audit_status = '2' and task_id IN |         WHERE audit_status = '2' | ||||||
|  |         AND task_id IN | ||||||
|         <foreach item="taskId" collection="taskIds" open="(" separator="," close=")"> |         <foreach item="taskId" collection="taskIds" open="(" separator="," close=")"> | ||||||
|             #{taskId} |             #{taskId} | ||||||
|         </foreach> |         </foreach> | ||||||
|         GROUP BY task_id |         ) AS sub | ||||||
|         ) sub ON t.task_id = sub.task_id AND t.progress = sub.maxProgress |         WHERE sub.rn = 1 order by create_time desc | ||||||
|     </select> |     </select> | ||||||
|  |  | ||||||
| </mapper> | </mapper> | ||||||
|  | |||||||
| @ -35,7 +35,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" | |||||||
|         SELECT zps.id,zps.project_id,zps.section_name |         SELECT zps.id,zps.project_id,zps.section_name | ||||||
|         FROM zbf_project_section zps |         FROM zbf_project_section zps | ||||||
|             left JOIN zbf_project zp ON zps.project_id = zp.id |             left JOIN zbf_project zp ON zps.project_id = zp.id | ||||||
|         WHERE zp.user_id = #{dto.zbfUserId} |         WHERE  zp.id = #{dto.projectId} and zp.user_id = #{dto.zbfUserId} | ||||||
|     </select> |     </select> | ||||||
|  |  | ||||||
| </mapper> | </mapper> | ||||||
|  | |||||||
| @ -197,6 +197,23 @@ | |||||||
|           > |           > | ||||||
|             确认上传 |             确认上传 | ||||||
|           </el-button> |           </el-button> | ||||||
|  |           <div style="background-color: #f5f7fa; border-radius: 4px"> | ||||||
|  |             <h4 style="margin: 0 0 10px 0; color: #409eff">操作流程:</h4> | ||||||
|  |             <ol style="margin: 0; padding-left: 20px"> | ||||||
|  |               <li>选择主题</li> | ||||||
|  |               <li>勾选需要上传文件的人员</li> | ||||||
|  |               <li>点击"下载模板"按钮</li> | ||||||
|  |               <li>解压下载的模板文件</li> | ||||||
|  |               <li>将图片或PDF文件放入相应人员的文件夹中</li> | ||||||
|  |               <li>压缩文件夹并上传</li> | ||||||
|  |             </ol> | ||||||
|  |             <h4 style="margin: 15px 0 10px 0; color: #f56c6c">注意事项:</h4> | ||||||
|  |             <ul style="margin: 0; padding-left: 20px"> | ||||||
|  |               <li>请确保压缩文件为.zip格式</li> | ||||||
|  |               <li>压缩层级不要过深,建议直接压缩人员文件夹</li> | ||||||
|  |               <li>每个人员的文件请放入对应的文件夹中</li> | ||||||
|  |             </ul> | ||||||
|  |           </div> | ||||||
|         </div> |         </div> | ||||||
|       </div> |       </div> | ||||||
|       <!-- 查看详情弹窗 --> |       <!-- 查看详情弹窗 --> | ||||||
| @ -260,7 +277,7 @@ | |||||||
|       mounted() { |       mounted() { | ||||||
|         const protocol = window.location.protocol; |         const protocol = window.location.protocol; | ||||||
|         const host = window.location.host; |         const host = window.location.host; | ||||||
|         this.baseUrl = `${protocol}//${host}`; // 动态获取基础 URL |         // this.baseUrl = `${protocol}//${host}/lhyg`; // 动态获取基础 URL | ||||||
|           // 获取 URL 中的 userId 参数 |           // 获取 URL 中的 userId 参数 | ||||||
|         const urlParams = new URLSearchParams(window.location.search); |         const urlParams = new URLSearchParams(window.location.search); | ||||||
|         this.userId = urlParams.get("userId"); |         this.userId = urlParams.get("userId"); | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 zt
					zt