package com.ruoyi.safe.service.impl;
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
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.project.system.domain.SysUser;
|
import com.ruoyi.project.system.mapper.SysUserMapper;
|
import com.ruoyi.safe.mapper.SafeLineInspectionTaskMapper;
|
import com.ruoyi.safe.pojo.SafeLineInspectionTask;
|
import com.ruoyi.safe.service.SafeLineInspectionTaskService;
|
import lombok.RequiredArgsConstructor;
|
import org.quartz.SchedulerException;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
|
import java.time.DayOfWeek;
|
import java.time.LocalDateTime;
|
import java.time.LocalTime;
|
import java.time.YearMonth;
|
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeParseException;
|
import java.util.ArrayList;
|
import java.util.Arrays;
|
import java.util.HashMap;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.Objects;
|
import java.util.Set;
|
import java.util.stream.Collectors;
|
|
/**
|
* <p>
|
* 安全生产--线路定时巡检任务 服务实现类
|
* </p>
|
*/
|
@Service
|
@RequiredArgsConstructor
|
public class SafeLineInspectionTaskServiceImpl extends ServiceImpl<SafeLineInspectionTaskMapper, SafeLineInspectionTask> implements SafeLineInspectionTaskService {
|
|
private static final int ENABLED = 1;
|
private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm");
|
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 final SafeLineInspectionTaskMapper safeLineInspectionTaskMapper;
|
private final SafeLineInspectionTaskScheduler safeLineInspectionTaskScheduler;
|
private final SysUserMapper sysUserMapper;
|
|
@Override
|
public IPage<SafeLineInspectionTask> pageSafeLineInspectionTask(Page<SafeLineInspectionTask> page, SafeLineInspectionTask task) {
|
LambdaQueryWrapper<SafeLineInspectionTask> queryWrapper = new LambdaQueryWrapper<>();
|
queryWrapper.like(StringUtils.isNotBlank(task.getInspectionName()), SafeLineInspectionTask::getInspectionName, task.getInspectionName())
|
.like(StringUtils.isNotBlank(task.getLineName()), SafeLineInspectionTask::getLineName, task.getLineName())
|
.like(StringUtils.isNotBlank(task.getInspectionProject()), SafeLineInspectionTask::getInspectionProject, task.getInspectionProject())
|
.eq(task.getIsEnabled() != null, SafeLineInspectionTask::getIsEnabled, task.getIsEnabled())
|
.orderByDesc(SafeLineInspectionTask::getId);
|
|
IPage<SafeLineInspectionTask> result = safeLineInspectionTaskMapper.selectPage(page, queryWrapper);
|
fillInspectorName(result.getRecords());
|
return result;
|
}
|
|
@Override
|
@Transactional
|
public boolean saveOrUpdateTask(SafeLineInspectionTask task) throws SchedulerException {
|
SafeLineInspectionTask oldTask = null;
|
if (task.getId() != null) {
|
oldTask = safeLineInspectionTaskMapper.selectById(task.getId());
|
if (oldTask == null) {
|
throw new IllegalArgumentException("定时巡检任务不存在");
|
}
|
}
|
|
normalizeTask(task, oldTask);
|
task.setNextExecutionTime(calculateFirstExecutionTime(task.getFrequencyType(), task.getFrequencyDetail()));
|
|
boolean result;
|
if (task.getId() == null) {
|
result = safeLineInspectionTaskMapper.insert(task) > 0;
|
if (result && isEnabled(task.getIsEnabled())) {
|
safeLineInspectionTaskScheduler.scheduleTask(task);
|
}
|
return result;
|
}
|
|
result = safeLineInspectionTaskMapper.updateById(task) > 0;
|
if (result) {
|
boolean oldEnabled = oldTask != null && isEnabled(oldTask.getIsEnabled());
|
boolean newEnabled = isEnabled(task.getIsEnabled());
|
if (!newEnabled) {
|
safeLineInspectionTaskScheduler.unscheduleTask(task.getId());
|
} else if (oldEnabled) {
|
safeLineInspectionTaskScheduler.rescheduleTask(task);
|
} else {
|
safeLineInspectionTaskScheduler.scheduleTask(task);
|
}
|
}
|
return result;
|
}
|
|
@Override
|
@Transactional
|
public boolean removeTaskByIds(List<Long> ids) {
|
boolean removed = removeBatchByIds(ids);
|
if (removed) {
|
for (Long id : ids) {
|
safeLineInspectionTaskScheduler.unscheduleTask(id);
|
}
|
}
|
return removed;
|
}
|
|
@Override
|
public LocalDateTime calculateFirstExecutionTime(String frequencyType, String frequencyDetail) {
|
LocalDateTime now = LocalDateTime.now();
|
return calculateNextExecutionTime(frequencyType, frequencyDetail, now);
|
}
|
|
@Override
|
public LocalDateTime calculateNextExecutionTime(String frequencyType, String frequencyDetail, LocalDateTime currentTime) {
|
validateFrequency(frequencyType, frequencyDetail);
|
return switch (frequencyType) {
|
case "DAILY" -> calculateDailyNextTime(frequencyDetail, currentTime);
|
case "WEEKLY" -> calculateWeeklyNextTime(frequencyDetail, currentTime);
|
case "MONTHLY" -> calculateMonthlyNextTime(frequencyDetail, currentTime);
|
default -> throw new IllegalArgumentException("不支持的频率类型: " + frequencyType);
|
};
|
}
|
|
private void normalizeTask(SafeLineInspectionTask task, SafeLineInspectionTask oldTask) {
|
if (StringUtils.isBlank(task.getInspectionName())) {
|
throw new IllegalArgumentException("巡检任务名称不能为空");
|
}
|
if (StringUtils.isBlank(task.getLineName())) {
|
throw new IllegalArgumentException("线路名称不能为空");
|
}
|
if (StringUtils.isBlank(task.getInspectionProject())) {
|
throw new IllegalArgumentException("巡检项目不能为空");
|
}
|
if (StringUtils.isBlank(task.getInspectorId())) {
|
throw new IllegalArgumentException("巡检人不能为空");
|
}
|
task.setIsEnabled(resolveEnabledValue(task.getIsEnabled(), oldTask));
|
task.setFrequencyType(task.getFrequencyType() == null ? null : task.getFrequencyType().trim().toUpperCase());
|
task.setFrequencyDetail(task.getFrequencyDetail() == null ? null : task.getFrequencyDetail().trim());
|
validateFrequency(task.getFrequencyType(), task.getFrequencyDetail());
|
}
|
|
private void validateFrequency(String frequencyType, String frequencyDetail) {
|
if (StringUtils.isBlank(frequencyType) || StringUtils.isBlank(frequencyDetail)) {
|
throw new IllegalArgumentException("任务频率不能为空");
|
}
|
switch (frequencyType) {
|
case "DAILY" -> parseTime(frequencyDetail);
|
case "WEEKLY" -> {
|
String[] parts = splitFrequencyDetail(frequencyDetail);
|
if (!WEEK_DAY_MAP.containsKey(parts[0])) {
|
throw new IllegalArgumentException("无效的星期: " + parts[0]);
|
}
|
parseTime(parts[1]);
|
}
|
case "MONTHLY" -> {
|
String[] parts = splitFrequencyDetail(frequencyDetail);
|
validateDayOfMonth(parts[0]);
|
parseTime(parts[1]);
|
}
|
default -> throw new IllegalArgumentException("不支持的频率类型: " + frequencyType);
|
}
|
}
|
|
private LocalDateTime calculateDailyNextTime(String timeStr, LocalDateTime currentTime) {
|
LocalTime executionTime = parseTime(timeStr);
|
LocalDateTime candidate = LocalDateTime.of(currentTime.toLocalDate(), executionTime);
|
return currentTime.isBefore(candidate) ? candidate : candidate.plusDays(1);
|
}
|
|
private LocalDateTime calculateWeeklyNextTime(String detail, LocalDateTime currentTime) {
|
String[] parts = splitFrequencyDetail(detail);
|
DayOfWeek targetDay = WEEK_DAY_MAP.get(parts[0]);
|
LocalTime targetTime = parseTime(parts[1]);
|
int daysUntil = targetDay.getValue() - currentTime.getDayOfWeek().getValue();
|
|
if (daysUntil < 0 || (daysUntil == 0 && !currentTime.toLocalTime().isBefore(targetTime))) {
|
daysUntil += 7;
|
}
|
return LocalDateTime.of(currentTime.toLocalDate().plusDays(daysUntil), targetTime);
|
}
|
|
private LocalDateTime calculateMonthlyNextTime(String detail, LocalDateTime currentTime) {
|
String[] parts = splitFrequencyDetail(detail);
|
int dayOfMonth = validateDayOfMonth(parts[0]);
|
LocalTime targetTime = parseTime(parts[1]);
|
YearMonth currentMonth = YearMonth.from(currentTime);
|
for (int i = 0; i < 24; i++) {
|
YearMonth targetMonth = currentMonth.plusMonths(i);
|
if (dayOfMonth > targetMonth.lengthOfMonth()) {
|
continue;
|
}
|
LocalDateTime candidate = LocalDateTime.of(
|
targetMonth.getYear(),
|
targetMonth.getMonthValue(),
|
dayOfMonth,
|
targetTime.getHour(),
|
targetTime.getMinute()
|
);
|
if (currentTime.isBefore(candidate)) {
|
return candidate;
|
}
|
}
|
throw new IllegalArgumentException("无法计算下次执行时间");
|
}
|
|
private String[] splitFrequencyDetail(String detail) {
|
String[] parts = detail.split(",");
|
if (parts.length != 2) {
|
throw new IllegalArgumentException("频率详情格式错误");
|
}
|
return Arrays.stream(parts).map(String::trim).toArray(String[]::new);
|
}
|
|
private LocalTime parseTime(String timeStr) {
|
try {
|
return LocalTime.parse(timeStr, TIME_FORMATTER);
|
} catch (DateTimeParseException e) {
|
throw new IllegalArgumentException("时间格式必须为HH:mm", e);
|
}
|
}
|
|
private int validateDayOfMonth(String dayStr) {
|
try {
|
int day = Integer.parseInt(dayStr);
|
if (day < 1 || day > 31) {
|
throw new IllegalArgumentException("日期必须在1-31之间");
|
}
|
return day;
|
} catch (NumberFormatException e) {
|
throw new IllegalArgumentException("日期必须在1-31之间", e);
|
}
|
}
|
|
private Integer resolveEnabledValue(Integer requestEnabled, SafeLineInspectionTask oldTask) {
|
if (requestEnabled != null) {
|
return requestEnabled;
|
}
|
if (oldTask != null && oldTask.getIsEnabled() != null) {
|
return oldTask.getIsEnabled();
|
}
|
return ENABLED;
|
}
|
|
private boolean isEnabled(Integer enabledValue) {
|
return Objects.equals(enabledValue, ENABLED);
|
}
|
|
private void fillInspectorName(List<SafeLineInspectionTask> records) {
|
if (records == null || records.isEmpty()) {
|
return;
|
}
|
|
Set<Long> userIds = records.stream()
|
.map(SafeLineInspectionTask::getInspectorId)
|
.filter(StringUtils::isNotBlank)
|
.flatMap(ids -> Arrays.stream(ids.split(",")))
|
.map(String::trim)
|
.filter(StringUtils::isNotBlank)
|
.map(this::parseUserId)
|
.filter(Objects::nonNull)
|
.collect(Collectors.toSet());
|
|
if (userIds.isEmpty()) {
|
return;
|
}
|
|
Map<Long, String> userNameMap = new HashMap<>();
|
List<SysUser> users = sysUserMapper.selectUserByIds(new ArrayList<>(userIds));
|
users.forEach(user -> userNameMap.put(user.getUserId(), user.getNickName()));
|
|
for (SafeLineInspectionTask record : records) {
|
if (StringUtils.isBlank(record.getInspectorId())) {
|
continue;
|
}
|
List<String> names = Arrays.stream(record.getInspectorId().split(","))
|
.map(String::trim)
|
.filter(StringUtils::isNotBlank)
|
.map(this::parseUserId)
|
.filter(Objects::nonNull)
|
.map(id -> userNameMap.getOrDefault(id, "未知用户"))
|
.collect(Collectors.toList());
|
record.setInspector(names);
|
record.setInspectorName(String.join(",", names));
|
}
|
}
|
|
private Long parseUserId(String idStr) {
|
try {
|
return Long.parseLong(idStr);
|
} catch (NumberFormatException e) {
|
return null;
|
}
|
}
|
}
|