223 lines
9.6 KiB
Java
223 lines
9.6 KiB
Java
package com.designhub.service;
|
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
import com.designhub.entity.*;
|
|
import com.designhub.mapper.*;
|
|
import lombok.RequiredArgsConstructor;
|
|
import lombok.extern.slf4j.Slf4j;
|
|
import org.springframework.scheduling.annotation.Scheduled;
|
|
import org.springframework.stereotype.Service;
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
|
import java.math.BigDecimal;
|
|
import java.time.LocalDate;
|
|
import java.time.LocalDateTime;
|
|
import java.time.LocalTime;
|
|
import java.util.*;
|
|
|
|
/**
|
|
* 进度检查服务 - 每日检查设计师是否更新了进度
|
|
*/
|
|
@Slf4j
|
|
@Service
|
|
@RequiredArgsConstructor
|
|
public class ProgressCheckService {
|
|
|
|
private final TaskMapper taskMapper;
|
|
private final TaskItemMapper taskItemMapper;
|
|
private final UserMapper userMapper;
|
|
private final ProgressDeductionLogMapper progressDeductionLogMapper;
|
|
private final SystemConfigService systemConfigService;
|
|
private final DingTalkService dingTalkService;
|
|
private final DepartmentMapper departmentMapper;
|
|
|
|
/**
|
|
* 每天18点执行进度检查
|
|
* cron: 秒 分 时 日 月 周
|
|
*/
|
|
@Scheduled(cron = "0 0 18 * * ?")
|
|
public void checkDailyProgressUpdate() {
|
|
log.info("========== 开始每日进度更新检查 ==========");
|
|
|
|
try {
|
|
// 检查是否启用
|
|
String enabledStr = systemConfigService.getConfigValue("progress.daily_check_enabled");
|
|
if (!"true".equalsIgnoreCase(enabledStr)) {
|
|
log.info("每日进度检查功能已禁用,跳过检查");
|
|
return;
|
|
}
|
|
|
|
// 获取扣分配置
|
|
String deductionStr = systemConfigService.getConfigValue("progress.no_update_deduction");
|
|
BigDecimal deductionScore = new BigDecimal(deductionStr != null ? deductionStr : "1");
|
|
|
|
String notifyStr = systemConfigService.getConfigValue("progress.notify_on_deduction");
|
|
boolean notifyEnabled = "true".equalsIgnoreCase(notifyStr);
|
|
|
|
LocalDate today = LocalDate.now();
|
|
LocalDateTime startOfDay = today.atStartOfDay();
|
|
LocalDateTime endOfDay = today.atTime(LocalTime.MAX);
|
|
|
|
// 1. 检查主任务
|
|
List<Task> inProgressTasks = taskMapper.selectList(
|
|
new LambdaQueryWrapper<Task>()
|
|
.eq(Task::getStatus, "in_progress")
|
|
.eq(Task::getDeleted, 0)
|
|
.isNotNull(Task::getReceiverId)
|
|
);
|
|
|
|
Map<Long, List<String>> userMissedTasks = new HashMap<>();
|
|
|
|
for (Task task : inProgressTasks) {
|
|
// 检查今天是否更新过进度
|
|
boolean updatedToday = task.getUpdateTime() != null &&
|
|
task.getUpdateTime().isAfter(startOfDay) &&
|
|
task.getUpdateTime().isBefore(endOfDay);
|
|
|
|
if (!updatedToday) {
|
|
Long userId = task.getReceiverId();
|
|
|
|
// 检查今天是否已经对该任务扣过分
|
|
Long existingCount = progressDeductionLogMapper.selectCount(
|
|
new LambdaQueryWrapper<ProgressDeductionLog>()
|
|
.eq(ProgressDeductionLog::getUserId, userId)
|
|
.eq(ProgressDeductionLog::getTaskId, task.getId())
|
|
.isNull(ProgressDeductionLog::getTaskItemId)
|
|
.eq(ProgressDeductionLog::getDeductionDate, today)
|
|
);
|
|
|
|
if (existingCount == 0) {
|
|
// 记录扣分
|
|
ProgressDeductionLog deductionLog = new ProgressDeductionLog();
|
|
deductionLog.setUserId(userId);
|
|
deductionLog.setTaskId(task.getId());
|
|
deductionLog.setDeductionDate(today);
|
|
deductionLog.setDeductionScore(deductionScore);
|
|
deductionLog.setReason("当日未更新任务进度");
|
|
deductionLog.setNotified(notifyEnabled ? 1 : 0);
|
|
deductionLog.setCreateTime(LocalDateTime.now());
|
|
progressDeductionLogMapper.insert(deductionLog);
|
|
|
|
// 记录待通知
|
|
userMissedTasks.computeIfAbsent(userId, k -> new ArrayList<>())
|
|
.add(task.getTitle());
|
|
|
|
log.info("用户 {} 任务【{}】今日未更新进度,扣除 {} 分",
|
|
userId, task.getTitle(), deductionScore);
|
|
}
|
|
}
|
|
}
|
|
|
|
// 2. 检查子任务
|
|
List<TaskItem> inProgressItems = taskItemMapper.selectList(
|
|
new LambdaQueryWrapper<TaskItem>()
|
|
.eq(TaskItem::getStatus, "in_progress")
|
|
.isNotNull(TaskItem::getReceiverId)
|
|
);
|
|
|
|
for (TaskItem item : inProgressItems) {
|
|
boolean updatedToday = item.getUpdateTime() != null &&
|
|
item.getUpdateTime().isAfter(startOfDay) &&
|
|
item.getUpdateTime().isBefore(endOfDay);
|
|
|
|
if (!updatedToday) {
|
|
Long userId = item.getReceiverId();
|
|
|
|
// 检查今天是否已经对该子任务扣过分
|
|
Long existingCount = progressDeductionLogMapper.selectCount(
|
|
new LambdaQueryWrapper<ProgressDeductionLog>()
|
|
.eq(ProgressDeductionLog::getUserId, userId)
|
|
.eq(ProgressDeductionLog::getTaskItemId, item.getId())
|
|
.eq(ProgressDeductionLog::getDeductionDate, today)
|
|
);
|
|
|
|
if (existingCount == 0) {
|
|
// 记录扣分
|
|
ProgressDeductionLog deductionLog = new ProgressDeductionLog();
|
|
deductionLog.setUserId(userId);
|
|
deductionLog.setTaskId(item.getTaskId());
|
|
deductionLog.setTaskItemId(item.getId());
|
|
deductionLog.setDeductionDate(today);
|
|
deductionLog.setDeductionScore(deductionScore);
|
|
deductionLog.setReason("当日未更新子任务进度");
|
|
deductionLog.setNotified(notifyEnabled ? 1 : 0);
|
|
deductionLog.setCreateTime(LocalDateTime.now());
|
|
progressDeductionLogMapper.insert(deductionLog);
|
|
|
|
// 记录待通知
|
|
userMissedTasks.computeIfAbsent(userId, k -> new ArrayList<>())
|
|
.add("子任务#" + item.getGroupNo());
|
|
|
|
log.info("用户 {} 子任务【#{}】今日未更新进度,扣除 {} 分",
|
|
userId, item.getGroupNo(), deductionScore);
|
|
}
|
|
}
|
|
}
|
|
|
|
// 3. 发送钉钉通知
|
|
if (notifyEnabled && !userMissedTasks.isEmpty()) {
|
|
sendDingTalkNotifications(userMissedTasks, deductionScore);
|
|
}
|
|
|
|
log.info("========== 每日进度检查完成,共处理 {} 位设计师 ==========", userMissedTasks.size());
|
|
|
|
} catch (Exception e) {
|
|
log.error("每日进度检查执行失败", e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 发送钉钉通知
|
|
*/
|
|
private void sendDingTalkNotifications(Map<Long, List<String>> userMissedTasks, BigDecimal deductionScore) {
|
|
for (Map.Entry<Long, List<String>> entry : userMissedTasks.entrySet()) {
|
|
Long userId = entry.getKey();
|
|
List<String> tasks = entry.getValue();
|
|
|
|
try {
|
|
User user = userMapper.selectById(userId);
|
|
if (user == null || user.getPhone() == null) {
|
|
// 如果没有手机号,无法发送钉钉通知
|
|
log.warn("用户 {} 没有绑定手机号,跳过钉钉通知", userId);
|
|
continue;
|
|
}
|
|
|
|
StringBuilder content = new StringBuilder();
|
|
content.append("⚠️ **进度更新提醒**\n\n");
|
|
content.append("您有 **").append(tasks.size()).append("** 个进行中的任务今日未更新进度:\n\n");
|
|
|
|
for (int i = 0; i < Math.min(tasks.size(), 5); i++) {
|
|
content.append("• ").append(tasks.get(i)).append("\n");
|
|
}
|
|
if (tasks.size() > 5) {
|
|
content.append("• ...等共 ").append(tasks.size()).append(" 个任务\n");
|
|
}
|
|
|
|
content.append("\n**已扣除积分:").append(deductionScore.multiply(BigDecimal.valueOf(tasks.size()))).append(" 分**");
|
|
content.append("\n\n💡 温馨提示:请每日下班前更新任务进度,以便跟进项目状态。");
|
|
|
|
// 使用手机号作为钉钉用户标识发送通知
|
|
dingTalkService.sendWorkNotification(
|
|
java.util.Collections.singletonList(user.getPhone()),
|
|
"进度更新提醒",
|
|
content.toString()
|
|
);
|
|
log.info("已向用户 {} 发送进度提醒通知", user.getRealName());
|
|
|
|
} catch (Exception e) {
|
|
log.error("向用户 {} 发送钉钉通知失败", userId, e);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 手动触发进度检查(用于测试)
|
|
*/
|
|
@Transactional(rollbackFor = Exception.class)
|
|
public void manualCheckProgress() {
|
|
log.info("手动触发进度检查");
|
|
checkDailyProgressUpdate();
|
|
}
|
|
}
|
|
|