From 47768d890fbfc1a5f3e93ca26137847361415e9e Mon Sep 17 00:00:00 2001
From: buhuazhen <hua100783@gmail.com>
Date: 星期二, 28 十月 2025 10:54:16 +0800
Subject: [PATCH] Merge branch 'master' into pim_meet
---
src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskServiceImpl.java | 450 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 450 insertions(+), 0 deletions(-)
diff --git a/src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskServiceImpl.java b/src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskServiceImpl.java
new file mode 100644
index 0000000..33c815e
--- /dev/null
+++ b/src/main/java/com/ruoyi/inspectiontask/service/impl/TimingTaskServiceImpl.java
@@ -0,0 +1,450 @@
+package com.ruoyi.inspectiontask.service.impl;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.common.utils.bean.BeanUtils;
+import com.ruoyi.inspectiontask.dto.TimingTaskDto;
+import com.ruoyi.inspectiontask.mapper.InspectionTaskMapper;
+import com.ruoyi.inspectiontask.mapper.TimingTaskMapper;
+import com.ruoyi.inspectiontask.pojo.TimingTask;
+import com.ruoyi.inspectiontask.service.TimingTaskService;
+import com.ruoyi.project.system.domain.SysUser;
+import com.ruoyi.project.system.mapper.SysUserMapper;
+import lombok.extern.slf4j.Slf4j;
+import org.quartz.SchedulerException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.time.*;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * @author :yys
+ * @date : 2025/9/19 10:55
+ */
+@Service
+@Slf4j
+public class TimingTaskServiceImpl extends ServiceImpl<TimingTaskMapper, TimingTask> implements TimingTaskService {
+
+ @Autowired
+ private TimingTaskMapper timingTaskMapper;
+
+ @Autowired
+ private InspectionTaskMapper inspectionTaskMapper;
+
+ @Autowired
+ private TimingTaskScheduler timingTaskScheduler;
+
+ @Autowired
+ private SysUserMapper sysUserMapper;
+
+
+ @Override
+ public IPage<TimingTaskDto> selectTimingTaskList(Page<TimingTask> page, TimingTask timingTask) {
+ // 1. 鍏堝垎椤垫煡璇㈠畾鏃朵换鍔℃暟鎹�
+ IPage<TimingTask> taskPage = timingTaskMapper.selectPage(page, null);
+
+ // 2. 濡傛灉娌℃湁鏁版嵁锛岀洿鎺ヨ繑鍥炵┖鍒嗛〉
+ if (taskPage.getRecords().isEmpty()) {
+ return new Page<>(taskPage.getCurrent(), taskPage.getSize(), taskPage.getTotal());
+ }
+
+ // 3. 鏀堕泦鎵�鏈夐渶瑕佹煡璇㈢殑鐢ㄦ埛ID
+ Set<Long> userIds = new HashSet<>();
+
+ // 鏀堕泦鐧昏浜篒D
+ taskPage.getRecords().forEach(task -> {
+ if (task.getRegistrantId() != null) {
+ userIds.add(task.getRegistrantId());
+ }
+ });
+
+ // 鏀堕泦宸℃浜篒D锛堝涓狪D浠ラ�楀彿鍒嗛殧锛�
+ taskPage.getRecords().forEach(task -> {
+ if (StringUtils.isNotBlank(task.getInspectorIds())) {
+ Arrays.stream(task.getInspectorIds().split(","))
+ .filter(StringUtils::isNotBlank)
+ .map(Long::valueOf)
+ .forEach(userIds::add);
+ }
+ });
+
+ // 4. 鎵归噺鏌ヨ鐢ㄦ埛淇℃伅
+ Map<Long, String> userNickNameMap = new HashMap<>();
+ if (!userIds.isEmpty()) {
+ List<SysUser> users = sysUserMapper.selectUserByIds((new ArrayList<>(userIds)));
+ users.forEach(user -> userNickNameMap.put(user.getUserId(), user.getNickName()));
+ }
+
+ // 5. 杞崲涓篋TO
+ List<TimingTaskDto> dtoList = taskPage.getRecords().stream().map(task -> {
+ TimingTaskDto dto = new TimingTaskDto();
+ // 澶嶅埗鍩烘湰灞炴��
+ BeanUtils.copyProperties(task, dto);
+
+ // 璁剧疆鐧昏浜烘樀绉�
+ if (task.getRegistrantId() != null) {
+ dto.setRegistrant(userNickNameMap.getOrDefault(task.getRegistrantId(), "鏈煡鐢ㄦ埛"));
+ }
+
+ // 璁剧疆宸℃浜烘樀绉板垪琛�
+ if (StringUtils.isNotBlank(task.getInspectorIds())) {
+ List<String> inspectorNickNames = new ArrayList<>();
+ for (String idStr : task.getInspectorIds().split(",")) {
+ if (StringUtils.isNotBlank(idStr)) {
+ Long id = Long.valueOf(idStr);
+ inspectorNickNames.add(userNickNameMap.getOrDefault(id, "鏈煡鐢ㄦ埛"));
+ }
+ }
+ dto.setInspector(inspectorNickNames);
+ }
+
+ return dto;
+ }).collect(Collectors.toList());
+
+ // 6. 鏋勫缓杩斿洖鐨勫垎椤靛璞�
+ Page<TimingTaskDto> resultPage = new Page<>(taskPage.getCurrent(), taskPage.getSize(), taskPage.getTotal());
+ resultPage.setRecords(dtoList);
+ return resultPage;
+ }
+
+ @Override
+ @Transactional
+ public int addOrEditTimingTask(TimingTaskDto timingTaskDto) throws SchedulerException {
+ TimingTask timingTask = new TimingTask();
+ BeanUtils.copyProperties(timingTaskDto, timingTask);
+
+ // 璁剧疆鍒涘缓浜轰俊鎭拰榛樿鍊�
+ if (Objects.isNull(timingTaskDto.getId())) {
+ timingTask.setRegistrationDate(LocalDate.now());
+ timingTask.setActive(true);
+
+ // 璁$畻棣栨鎵ц鏃堕棿
+ LocalDateTime firstExecutionTime = calculateFirstExecutionTime(timingTask);
+ timingTask.setNextExecutionTime(firstExecutionTime);
+
+ int result = timingTaskMapper.insert(timingTask);
+ if (result > 0) {
+ // 鏂板鎴愬姛鍚庢坊鍔犲埌璋冨害鍣�
+ timingTaskScheduler.scheduleTimingTask(timingTask);
+ }
+ return result;
+ } else {
+ int result = timingTaskMapper.updateById(timingTask);
+ if (result > 0) {
+ // 鏇存柊鎴愬姛鍚庨噸鏂拌皟搴︿换鍔�
+ timingTaskScheduler.rescheduleTimingTask(timingTask);
+ }
+ return result;
+ }
+ }
+
+ private LocalDateTime calculateFirstExecutionTime(TimingTask task) {
+ // 鏍规嵁棰戠巼绫诲瀷鍜岃鎯呰绠楅娆℃墽琛屾椂闂�
+ String frequencyType = task.getFrequencyType();
+ if ("DAILY".equals(frequencyType)) {
+ // 濡傛灉鏄瘡澶╂墽琛岋紝璁$畻浠婂ぉ鎴栨槑澶╃殑鍏蜂綋鏃堕棿
+ return calculateDailyFirstExecution(task.getFrequencyDetail());
+ } else if ("WEEKLY".equals(frequencyType)) {
+ // 濡傛灉鏄瘡鍛ㄦ墽琛岋紝璁$畻涓嬪懆鐨勫叿浣撴槦鏈熷嚑
+ return calculateWeeklyFirstExecution(task.getFrequencyDetail());
+ } else if ("MONTHLY".equals(frequencyType)) {
+ // 濡傛灉鏄瘡鏈堟墽琛岋紝璁$畻涓嬩釜鏈堢殑鍏蜂綋鏃ユ湡
+ return calculateMonthlyFirstExecution(task.getFrequencyDetail());
+ } else if ("QUARTERLY".equals(frequencyType)) {
+ // 鑷畾涔夐鐜囷紝濡傛瘡灏忔椂銆佹瘡30鍒嗛挓绛�
+ return calculateCustomFirstExecution(task.getFrequencyDetail());
+ } else {
+ throw new IllegalArgumentException("涓嶆敮鎸佺殑棰戠巼绫诲瀷: " + task.getFrequencyType());
+ }
+ }
+
+ private LocalDateTime calculateDailyFirstExecution(String frequencyDetail) {
+ // frequencyDetail鍙兘鏄叿浣撴椂闂达紝濡� "14:30"
+ LocalTime executionTime = LocalTime.parse(frequencyDetail);
+ LocalDateTime now = LocalDateTime.now();
+ LocalDateTime todayExecution = LocalDateTime.of(now.toLocalDate(), executionTime);
+
+ // 濡傛灉浠婂ぉ鐨勬椂闂村凡杩囷紝鍒欏畨鎺掓槑澶╂墽琛�
+ return now.isBefore(todayExecution) ? todayExecution : todayExecution.plusDays(1);
+ }
+
+ // 鏄犲皠鏄熸湡绠�鍐欎笌DayOfWeek
+ private static final Map<String, DayOfWeek> WEEK_DAY_MAP = new HashMap<>();
+ static {
+ WEEK_DAY_MAP.put("MON", DayOfWeek.MONDAY);
+ WEEK_DAY_MAP.put("TUE", DayOfWeek.TUESDAY);
+ WEEK_DAY_MAP.put("WED", DayOfWeek.WEDNESDAY);
+ WEEK_DAY_MAP.put("THU", DayOfWeek.THURSDAY);
+ WEEK_DAY_MAP.put("FRI", DayOfWeek.FRIDAY);
+ WEEK_DAY_MAP.put("SAT", DayOfWeek.SATURDAY);
+ WEEK_DAY_MAP.put("SUN", DayOfWeek.SUNDAY);
+ }
+
+ private LocalDateTime calculateWeeklyFirstExecution(String frequencyDetail) {
+ // 瑙f瀽杈撳叆鍙傛暟
+ String[] parts = frequencyDetail.split(",");
+ if (parts.length != 2) {
+ throw new IllegalArgumentException("鍙傛暟鏍煎紡閿欒锛屽簲涓�'MON,13:43'鏍煎紡");
+ }
+
+ String weekDayStr = parts[0].trim();
+ String timeStr = parts[1].trim();
+
+ // 鑾峰彇瀵瑰簲鐨勬槦鏈熷嚑
+ DayOfWeek targetDay = WEEK_DAY_MAP.get(weekDayStr);
+ if (targetDay == null) {
+ throw new IllegalArgumentException("鏃犳晥鐨勬槦鏈熺畝鍐�: " + weekDayStr);
+ }
+
+ // 瑙f瀽鏃堕棿
+ LocalTime targetTime = LocalTime.parse(timeStr, DateTimeFormatter.ofPattern("HH:mm"));
+
+ // 鑾峰彇褰撳墠鏃堕棿
+ LocalDateTime now = LocalDateTime.now();
+ LocalDateTime targetDateTime = now.with(targetDay).with(targetTime);
+
+ // 濡傛灉璁$畻鍑虹殑鏃堕棿鍦ㄥ綋鍓嶆椂闂翠箣鍓嶏紝鍒欏姞涓�鍛�
+ if (targetDateTime.isBefore(now)) {
+ targetDateTime = targetDateTime.plusWeeks(1);
+ }
+
+ return targetDateTime;
+ }
+
+ private LocalDateTime calculateMonthlyFirstExecution(String frequencyDetail) {
+ // 瑙f瀽杈撳叆鍙傛暟
+ String[] parts = frequencyDetail.split(",");
+ if (parts.length != 2) {
+ throw new IllegalArgumentException("鍙傛暟鏍煎紡閿欒锛屽簲涓�'03,17:00'鏍煎紡");
+ }
+
+ String dayStr = parts[0].trim();
+ String timeStr = parts[1].trim();
+
+ // 瑙f瀽鏃ユ湡
+ int dayOfMonth;
+ try {
+ dayOfMonth = Integer.parseInt(dayStr);
+ } catch (NumberFormatException e) {
+ throw new IllegalArgumentException("鏃犳晥鐨勬棩鏈熸牸寮�: " + dayStr, e);
+ }
+
+ // 楠岃瘉鏃ユ湡鏈夋晥鎬э紙1-31涔嬮棿锛�
+ if (dayOfMonth < 1 || dayOfMonth > 31) {
+ throw new IllegalArgumentException("鏃ユ湡蹇呴』鍦�1-31涔嬮棿: " + dayOfMonth);
+ }
+
+ // 瑙f瀽鏃堕棿
+ LocalTime targetTime;
+ try {
+ targetTime = LocalTime.parse(timeStr, DateTimeFormatter.ofPattern("HH:mm"));
+ } catch (DateTimeException e) {
+ throw new IllegalArgumentException("鏃犳晥鐨勬椂闂存牸寮�: " + timeStr, e);
+ }
+
+ // 鑾峰彇褰撳墠鏃堕棿
+ LocalDateTime now = LocalDateTime.now();
+ LocalDateTime targetDateTime = now.withDayOfMonth(dayOfMonth).with(targetTime);
+
+ // 妫�鏌ユ棩鏈熸槸鍚﹁鑷姩璋冩暣锛堝31鏃ュ湪灏忔湀浼氳璋冩暣锛�
+ boolean isDateAdjusted = targetDateTime.getDayOfMonth() != dayOfMonth;
+
+ // 濡傛灉鐩爣鏃堕棿鍦ㄥ綋鍓嶆椂闂翠箣鍓嶏紝鎴栬�呮棩鏈熻绯荤粺鑷姩璋冩暣浜�
+ if (targetDateTime.isBefore(now) || isDateAdjusted) {
+ // 璁$畻涓嬩釜鏈堢殑鏃ユ湡
+ LocalDateTime nextMonth = now.plusMonths(1);
+ // 灏濊瘯璁剧疆涓嬩釜鏈堢殑鐩爣鏃ユ湡
+ LocalDateTime nextMonthTarget = nextMonth.withDayOfMonth(dayOfMonth).with(targetTime);
+
+ // 濡傛灉涓嬩釜鏈堢殑鏃ユ湡涔熻璋冩暣浜嗭紝灏辩敤涓嬩釜鏈堢殑鏈�鍚庝竴澶�
+ if (nextMonthTarget.getDayOfMonth() != dayOfMonth) {
+ // 姝g‘鑾峰彇涓嬩釜鏈堢殑鏈�鍚庝竴澶╋紙淇isLeapYear璋冪敤闂锛�
+ int lastDayOfMonth = nextMonth.getMonth().length(
+ Year.of(nextMonth.getYear()).isLeap()
+ );
+ nextMonthTarget = nextMonth.withDayOfMonth(lastDayOfMonth).with(targetTime);
+ }
+
+ targetDateTime = nextMonthTarget;
+ }
+
+ return targetDateTime;
+ }
+
+ private LocalDateTime calculateCustomFirstExecution(String frequencyDetail) {
+ return null;
+ }
+
+ @Override
+ @Transactional
+ public void updateTaskExecutionTime(Long taskId) {
+ TimingTask task = timingTaskMapper.selectById(taskId);
+ if (task == null) {
+ throw new RuntimeException("瀹氭椂浠诲姟涓嶅瓨鍦紝ID: " + taskId);
+ }
+
+ // 鏇存柊鏈�鍚庢墽琛屾椂闂翠负褰撳墠鏃堕棿
+ task.setLastExecutionTime(LocalDateTime.now());
+
+ // 璁$畻涓嬫鎵ц鏃堕棿
+ LocalDateTime nextExecutionTime = calculateNextExecutionTime(
+ task.getFrequencyType(),
+ task.getFrequencyDetail(),
+ LocalDateTime.now()
+ );
+ task.setNextExecutionTime(nextExecutionTime);
+
+ // 鏇存柊鏁版嵁搴�
+ timingTaskMapper.updateById(task);
+ }
+
+ /**
+ * 璁$畻涓嬫鎵ц鏃堕棿
+ */
+ private LocalDateTime calculateNextExecutionTime(String frequencyType,
+ String frequencyDetail,
+ LocalDateTime currentTime) {
+ try {
+ switch (frequencyType) {
+ case "DAILY":
+ return calculateDailyNextTime(frequencyDetail, currentTime);
+ case "WEEKLY":
+ return calculateWeeklyNextTime(frequencyDetail, currentTime);
+ case "MONTHLY":
+ return calculateMonthlyNextTime(frequencyDetail, currentTime);
+ case "QUARTERLY":
+ return calculateQuarterlyNextTime(frequencyDetail, currentTime);
+ default:
+ throw new IllegalArgumentException("涓嶆敮鎸佺殑棰戠巼绫诲瀷: " + frequencyType);
+ }
+ } catch (Exception e) {
+ throw new RuntimeException("璁$畻涓嬫鎵ц鏃堕棿澶辫触: " + e.getMessage(), e);
+ }
+ }
+
+ /**
+ * 璁$畻姣忔棩浠诲姟鐨勪笅娆℃墽琛屾椂闂�
+ */
+ private LocalDateTime calculateDailyNextTime(String timeStr, LocalDateTime current) {
+ LocalTime executionTime = LocalTime.parse(timeStr); // 瑙f瀽鏍煎紡 "HH:mm"
+ LocalDateTime nextTime = LocalDateTime.of(current.toLocalDate(), executionTime);
+
+ // 濡傛灉浠婂ぉ鐨勬椂闂村凡杩囷紝鍒欏畨鎺掓槑澶�
+ return current.isBefore(nextTime) ? nextTime : nextTime.plusDays(1);
+ }
+
+ /**
+ * 璁$畻姣忓懆浠诲姟鐨勪笅娆℃墽琛屾椂闂�
+ */
+ private LocalDateTime calculateWeeklyNextTime(String detail, LocalDateTime current) {
+ String[] parts = detail.split(",");
+ String dayOfWeekStr = parts[0]; // 濡� "MON" 鎴� "MON|WED|FRI"
+ LocalTime time = LocalTime.parse(parts[1]); // 鏃堕棿閮ㄥ垎
+
+ // 瑙f瀽鏄熸湡鍑�(鏀寔澶氫釜鏄熸湡)
+ Set<DayOfWeek> targetDays = parseDayOfWeeks(dayOfWeekStr);
+
+ // 浠庡綋鍓嶆椂闂村紑濮嬫壘涓嬩竴涓鍚堟潯浠剁殑鏄熸湡鍑�
+ LocalDateTime nextTime = current;
+ while (true) {
+ nextTime = nextTime.plusDays(1);
+ if (targetDays.contains(nextTime.getDayOfWeek())) {
+ return LocalDateTime.of(nextTime.toLocalDate(), time);
+ }
+
+ // 闃叉鏃犻檺寰幆(鐞嗚涓婁笉浼氬彂鐢�)
+ if (nextTime.isAfter(current.plusYears(1))) {
+ throw new RuntimeException("鏃犳硶鎵惧埌涓嬫鎵ц鏃堕棿");
+ }
+ }
+ }
+
+ /**
+ * 璁$畻姣忔湀浠诲姟鐨勪笅娆℃墽琛屾椂闂�
+ */
+ private LocalDateTime calculateMonthlyNextTime(String detail, LocalDateTime current) {
+ String[] parts = detail.split(",");
+ int dayOfMonth = Integer.parseInt(parts[0]);
+ LocalTime time = LocalTime.parse(parts[1]);
+
+ // 浠庝笅涓湀寮�濮嬭绠�
+ LocalDateTime nextTime = current.plusMonths(1)
+ .withDayOfMonth(Math.min(dayOfMonth, current.plusMonths(1).toLocalDate().lengthOfMonth()))
+ .with(time);
+
+ return nextTime;
+ }
+
+ /**
+ * 璁$畻姣忓搴︿换鍔$殑涓嬫鎵ц鏃堕棿
+ */
+ private LocalDateTime calculateQuarterlyNextTime(String detail, LocalDateTime current) {
+ String[] parts = detail.split(",");
+ int quarterMonth = Integer.parseInt(parts[0]); // 1=绗�1涓湀锛�2=绗�2涓湀锛�3=绗�3涓湀
+ int dayOfMonth = Integer.parseInt(parts[1]);
+ LocalTime time = LocalTime.parse(parts[2]);
+
+ // 璁$畻褰撳墠瀛e害
+ int currentQuarter = (current.getMonthValue() - 1) / 3 + 1;
+ int currentMonthInQuarter = (current.getMonthValue() - 1) % 3 + 1;
+
+ YearMonth targetYearMonth;
+ if (currentMonthInQuarter < quarterMonth) {
+ // 鏈搴﹀唴杩樻湁鎵ц鏈轰細
+ targetYearMonth = YearMonth.from(current)
+ .plusMonths(quarterMonth - currentMonthInQuarter);
+ } else {
+ // 闇�瑕佸埌涓嬩釜瀛e害
+ targetYearMonth = YearMonth.from(current)
+ .plusMonths(3 - currentMonthInQuarter + quarterMonth);
+ }
+
+ // 澶勭悊鏈堟湯鏃ユ湡
+ int adjustedDay = Math.min(dayOfMonth, targetYearMonth.lengthOfMonth());
+
+ return LocalDateTime.of(
+ targetYearMonth.getYear(),
+ targetYearMonth.getMonthValue(),
+ adjustedDay,
+ time.getHour(),
+ time.getMinute()
+ );
+ }
+
+ /**
+ * 瑙f瀽鏄熸湡鍑犲瓧绗︿覆
+ */
+ private Set<DayOfWeek> parseDayOfWeeks(String dayOfWeekStr) {
+ Set<DayOfWeek> days = new HashSet<>();
+ String[] dayStrs = dayOfWeekStr.split("\\|");
+
+ for (String dayStr : dayStrs) {
+ switch (dayStr) {
+ case "MON": days.add(DayOfWeek.MONDAY); break;
+ case "TUE": days.add(DayOfWeek.TUESDAY); break;
+ case "WED": days.add(DayOfWeek.WEDNESDAY); break;
+ case "THU": days.add(DayOfWeek.THURSDAY); break;
+ case "FRI": days.add(DayOfWeek.FRIDAY); break;
+ case "SAT": days.add(DayOfWeek.SATURDAY); break;
+ case "SUN": days.add(DayOfWeek.SUNDAY); break;
+ default: throw new IllegalArgumentException("鏃犳晥鐨勬槦鏈熷嚑: " + dayStr);
+ }
+ }
+
+ return days;
+ }
+
+
+
+ @Override
+ public int delByIds(Long[] ids) {
+ return timingTaskMapper.deleteBatchIds(Arrays.asList(ids));
+ }
+
+}
--
Gitblit v1.9.3