From 34981c30a78e8bbd7791131059a9210f9928b62c Mon Sep 17 00:00:00 2001
From: 刘光辉 <347230014@qq.com>
Date: 星期四, 17 九月 2026 09:24:09 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/master' into master
---
jnpf-lims/jnpf-lims-biz/src/main/java/jnpf/util/LimsSxtJihuaUtil.java | 273 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 273 insertions(+), 0 deletions(-)
diff --git a/jnpf-lims/jnpf-lims-biz/src/main/java/jnpf/util/LimsSxtJihuaUtil.java b/jnpf-lims/jnpf-lims-biz/src/main/java/jnpf/util/LimsSxtJihuaUtil.java
new file mode 100644
index 0000000..4e55d52
--- /dev/null
+++ b/jnpf-lims/jnpf-lims-biz/src/main/java/jnpf/util/LimsSxtJihuaUtil.java
@@ -0,0 +1,273 @@
+package jnpf.util;
+
+import jnpf.limsEntity.LimsSxtQuyangJihuaEntity;
+import lombok.extern.slf4j.Slf4j;
+
+import java.time.LocalDate;
+import java.time.temporal.ChronoUnit;
+
+/**
+ * 鍙栨牱璁″垝鍛ㄦ湡鍒ゆ柇宸ュ叿绫�
+ *
+ */
+@Slf4j
+public class LimsSxtJihuaUtil {
+ /**
+ * 鍒ゆ柇璁″垝鍦ㄦ寚瀹氭棩鏈熸槸鍚﹀簲璇ユ墽琛�
+ *
+ * @param plan 璁″垝瀹炰綋
+ * @param date 鐩爣鏃ユ湡
+ * @return true-闇�瑕佹墽琛岋紝false-涓嶉渶瑕佹墽琛�
+ */
+ public static boolean shouldExecuteOnDate(LimsSxtQuyangJihuaEntity plan, LocalDate date) {
+ if (plan == null || date == null) {
+ log.debug("璁″垝鎴栨棩鏈熶负绌�");
+ return false;
+ }
+
+ // 1. 妫�鏌ュ垹闄ゆ爣蹇�
+ if (isDeleted(plan)) {
+ log.debug("璁″垝宸插垹闄わ紝fId={}", plan.getId());
+ return false;
+ }
+
+ // 2. 妫�鏌ユ祦绋嬬姸鎬侊紙2=宸查�氳繃鐢熸晥锛屾牴鎹笟鍔¤皟鏁达級
+ if (!isApproved(plan)) {
+ log.debug("璁″垝娴佺▼鐘舵�佹湭鐢熸晥锛宖Id={}, state={}", plan.getId(), plan.getFFlowState());
+ return false;
+ }
+
+ // 3. 妫�鏌ユ槸鍚﹀湪璁″垝鏃堕棿鑼冨洿鍐�
+ if (!isInDateRange(plan, date)) {
+ log.debug("璁″垝涓嶅湪鏃堕棿鑼冨洿鍐咃紝fId={}, date={}", plan.getId(), date);
+ return false;
+ }
+
+ // 4. 鏍规嵁鍛ㄦ湡绫诲瀷鍒ゆ柇
+ String cycleType = plan.getJihuaZhouqiLeixing();
+ if (cycleType == null || cycleType.isEmpty()) {
+ log.debug("璁″垝鍛ㄦ湡绫诲瀷涓虹┖锛宖Id={}", plan.getId());
+ return false;
+ }
+
+ int interval = parseInterval(plan.getJihuaZhouqiJiange());
+ if (interval < 0) {
+ log.debug("璁″垝鍛ㄦ湡闂撮殧鏃犳晥锛宖Id={}, interval={}", plan.getId(), interval);
+ return false;
+ }
+
+ LocalDate startDate = plan.getKaishiShijian().toInstant()
+ .atZone(java.time.ZoneId.systemDefault()).toLocalDate();
+
+ return matchCycle(cycleType, startDate, date, interval);
+ }
+
+ // ==================== 鍓嶇疆妫�鏌ユ柟娉� ====================
+
+ /**
+ * 妫�鏌ユ槸鍚﹀凡鍒犻櫎锛歠_delete_mark = 1 琛ㄧず宸插垹闄�
+ */
+ private static boolean isDeleted(LimsSxtQuyangJihuaEntity plan) {
+ Integer deleteMark = plan.getFDeleteMark();
+ return deleteMark != null && deleteMark == 1;
+ }
+
+ /**
+ * 妫�鏌ユ祦绋嬬姸鎬佹槸鍚﹀凡閫氳繃锛�2=宸查�氳繃锛�
+ */
+ private static boolean isApproved(LimsSxtQuyangJihuaEntity plan) {
+ Integer flowState = plan.getFFlowState();
+ return flowState != null && flowState == 2;
+ }
+
+ /**
+ * 妫�鏌ユ槸鍚﹀湪璁″垝鏃堕棿鑼冨洿鍐咃紙鍖呭惈璧锋鏃ユ湡锛�
+ */
+ private static boolean isInDateRange(LimsSxtQuyangJihuaEntity plan, LocalDate date) {
+ LocalDate startDate = plan.getKaishiShijian().toInstant()
+ .atZone(java.time.ZoneId.systemDefault()).toLocalDate();
+ LocalDate endDate = plan.getJieshuShijian().toInstant()
+ .atZone(java.time.ZoneId.systemDefault()).toLocalDate();
+ return !date.isBefore(startDate) && !date.isAfter(endDate);
+ }
+
+ /**
+ * 瑙f瀽鍛ㄦ湡闂撮殧
+ */
+ private static int parseInterval(String intervalStr) {
+ if (intervalStr == null || intervalStr.trim().isEmpty()) {
+ return -1;
+ }
+ try {
+ return Integer.parseInt(intervalStr.trim());
+ } catch (NumberFormatException e) {
+ log.error("瑙f瀽鍛ㄦ湡闂撮殧澶辫触: {}", intervalStr, e);
+ return -1;
+ }
+ }
+
+ // ==================== 鍛ㄦ湡鍖归厤鏂规硶 ====================
+
+ /**
+ * 鏍规嵁鍛ㄦ湡绫诲瀷鍖归厤
+ */
+ private static boolean matchCycle(String cycleType, LocalDate startDate, LocalDate targetDate, int interval) {
+ long daysDiff = ChronoUnit.DAYS.between(startDate, targetDate);
+
+ switch (cycleType.toLowerCase()) {
+ case "daily":
+ return matchDaily(daysDiff, interval);
+
+ case "weekly":
+ return matchWeekly(startDate, targetDate, daysDiff, interval);
+
+ case "monthly":
+ return matchMonthly(startDate, targetDate, interval);
+
+ case "quarterly":
+ return matchQuarterly(startDate, targetDate, interval);
+
+ case "yearly":
+ return matchYearly(startDate, targetDate, interval);
+
+ default:
+ log.warn("鏈煡鐨勫懆鏈熺被鍨�: {}", cycleType);
+ return false;
+ }
+ }
+
+ // ==================== 鍚勫懆鏈熷叿浣撳尮閰嶉�昏緫 ====================
+
+ /**
+ * 姣忔棩鍛ㄦ湡鍖归厤
+ * 閫昏緫锛氳窛寮�濮嬫棩鏈熺殑澶╂暟宸� % (闂撮殧 + 1) = 0
+ * 绀轰緥锛氬紑濮�7/14锛岄棿闅�1 鈫� 7/14, 7/16, 7/18...
+ */
+ private static boolean matchDaily(long daysDiff, int interval) {
+ return daysDiff % executionStep(interval) == 0;
+ }
+
+ /**
+ * 姣忓懆鍛ㄦ湡鍖归厤
+ * 閫昏緫锛氭槦鏈熷嚑鐩稿悓 + 鍛ㄦ暟宸� % (闂撮殧 + 1) = 0
+ * 绀轰緥锛氬紑濮�7/14(鍛ㄤ簩)锛岄棿闅�1 鈫� 闅斿懆鍛ㄤ簩鎵ц
+ */
+ private static boolean matchWeekly(LocalDate startDate, LocalDate targetDate, long daysDiff, int interval) {
+ // 鏄熸湡鍑犵浉鍚岋紙LocalDate.DayOfWeek: 鍛ㄤ竴=1, 鍛ㄦ棩=7锛�
+ if (targetDate.getDayOfWeek() != startDate.getDayOfWeek()) {
+ return false;
+ }
+ long weekDiff = daysDiff / 7;
+ return weekDiff % executionStep(interval) == 0;
+ }
+
+ /**
+ * 姣忔湀鍛ㄦ湡鍖归厤锛堝惈鏈堟湯杈圭晫澶勭悊锛�
+ * 閫昏緫锛氭棩鏈熷尮閰� + 鏈堜唤宸� % (闂撮殧 + 1) = 0
+ * 绀轰緥锛氬紑濮�1/31锛岄棿闅�1 鈫� 1/31, 3/31, 5/31...
+ */
+ private static boolean matchMonthly(LocalDate startDate, LocalDate targetDate, int interval) {
+ // 鏃ユ湡鍖归厤锛堝惈鏈堟湯杈圭晫锛�
+ if (!isSameDayOfMonthWithBoundary(startDate, targetDate)) {
+ return false;
+ }
+ long monthDiff = ChronoUnit.MONTHS.between(
+ startDate.withDayOfMonth(1),
+ targetDate.withDayOfMonth(1)
+ );
+ return monthDiff % executionStep(interval) == 0;
+ }
+
+ /**
+ * 姣忓鍛ㄦ湡鍖归厤锛堝惈鏈堟湯杈圭晫澶勭悊锛�
+ * 閫昏緫锛氬悓鏈堝悓鏃� + 瀛e害宸� % (闂撮殧 + 1) = 0
+ * 绀轰緥锛氬紑濮�1/31锛岄棿闅�1 鈫� 1/31, 7/31...
+ */
+ private static boolean matchQuarterly(LocalDate startDate, LocalDate targetDate, int interval) {
+ // 鏃ユ湡鍖归厤锛堝惈鏈堟湯杈圭晫锛�
+ if (!isSameDayOfMonthWithBoundary(startDate, targetDate)) {
+ return false;
+ }
+ long monthDiff = ChronoUnit.MONTHS.between(
+ startDate.withDayOfMonth(1),
+ targetDate.withDayOfMonth(1)
+ );
+ if (monthDiff % 3 != 0) {
+ return false;
+ }
+ long quarterDiff = monthDiff / 3;
+ return quarterDiff % executionStep(interval) == 0;
+ }
+
+ /**
+ * 姣忓勾鍛ㄦ湡鍖归厤锛堝惈2鏈�29鏃ュ鐞嗭級
+ * 閫昏緫锛氭湀鏃ョ浉鍚� + 骞翠唤宸� % (闂撮殧 + 1) = 0
+ * 绀轰緥锛氬紑濮�2024-02-29锛岄棿闅�1 鈫� 2024-02-29, 2026-02-28...
+ */
+ private static boolean matchYearly(LocalDate startDate, LocalDate targetDate, int interval) {
+ // 鏈堟棩鍖归厤锛堝惈2鏈�29鏃ュ鐞嗭級
+ if (!isSameMonthAndDayWithLeapYear(startDate, targetDate)) {
+ return false;
+ }
+ long yearDiff = targetDate.getYear() - startDate.getYear();
+ return yearDiff % executionStep(interval) == 0;
+ }
+
+ private static long executionStep(int interval) {
+ return (long) interval + 1;
+ }
+
+ // ==================== 杈圭晫澶勭悊鏂规硶 ====================
+
+ /**
+ * 鍒ゆ柇鏃ユ湡鏄惁鍖归厤锛堝惈鏈堟湯杈圭晫澶勭悊锛�
+ * <p>
+ * 瑙勫垯锛�
+ * - 濡傛灉寮�濮嬫棩鏈熸槸褰撴湀鏈�鍚庝竴澶� 鈫� 鐩爣鏃ユ湡涔熷繀椤绘槸褰撴湀鏈�鍚庝竴澶╋紙鑷姩閫傞厤涓嶅悓鏈堜唤鐨勫ぉ鏁板樊寮傦級
+ * - 鍚﹀垯 鈫� 鏃ユ湡蹇呴』鐩稿悓
+ * <p>
+ * 绀轰緥锛�
+ * - 寮�濮� 1/31 鈫� 鍖归厤 1/31, 2/28, 3/31, 4/30, 5/31...
+ * - 寮�濮� 2/28 鈫� 鍖归厤 1/28, 2/28, 3/28, 4/28...
+ * - 寮�濮� 2/29 鈫� 鍖归厤 2/29锛堥棸骞达級鎴� 2/28锛堥潪闂板勾锛�
+ */
+ private static boolean isSameDayOfMonthWithBoundary(LocalDate startDate, LocalDate targetDate) {
+ // 濡傛灉寮�濮嬫棩鏈熸槸褰撴湀鏈�鍚庝竴澶�
+ if (startDate.getDayOfMonth() == startDate.lengthOfMonth()) {
+ // 鐩爣鏃ユ湡涔熷繀椤绘槸褰撴湀鏈�鍚庝竴澶�
+ return targetDate.getDayOfMonth() == targetDate.lengthOfMonth();
+ }
+ // 鍚﹀垯鏃ユ湡蹇呴』鐩稿悓
+ return startDate.getDayOfMonth() == targetDate.getDayOfMonth();
+ }
+
+ /**
+ * 鍒ゆ柇鏈堟棩鏄惁鍖归厤锛堝惈2鏈�29鏃ュ鐞嗭級
+ * <p>
+ * 瑙勫垯锛�
+ * - 寮�濮嬫棩鏈熸槸 2/29 鈫� 鐩爣鏃ユ湡蹇呴』鏄� 2/29锛堥棸骞达級鎴� 2/28锛堥潪闂板勾锛�
+ * - 鍚﹀垯 鈫� 鏈堟棩瀹屽叏鐩稿悓
+ * <p>
+ * 绀轰緥锛�
+ * - 寮�濮� 2024-02-29 鈫� 鍖归厤 2024-02-29, 2025-02-28, 2026-02-28, 2028-02-29
+ * - 寮�濮� 2024-03-15 鈫� 鍖归厤 2025-03-15, 2026-03-15...
+ */
+ private static boolean isSameMonthAndDayWithLeapYear(LocalDate startDate, LocalDate targetDate) {
+ // 濡傛灉寮�濮嬫棩鏈熸槸2鏈�29鏃�
+ if (startDate.getMonthValue() == 2 && startDate.getDayOfMonth() == 29) {
+ // 鐩爣鏃ユ湡蹇呴』鏄�2鏈�
+ if (targetDate.getMonthValue() != 2) {
+ return false;
+ }
+ // 闂板勾蹇呴』鏄�29鏃ワ紝闈為棸骞村彲浠ユ槸28鏃�
+ if (targetDate.isLeapYear()) {
+ return targetDate.getDayOfMonth() == 29;
+ } else {
+ return targetDate.getDayOfMonth() == 28;
+ }
+ }
+ // 鏅�氭棩鏈燂細鏈堟棩瀹屽叏鐩稿悓
+ return startDate.getMonthValue() == targetDate.getMonthValue()
+ && startDate.getDayOfMonth() == targetDate.getDayOfMonth();
+ }
+}
--
Gitblit v1.8.0