qiangdanxitong/backend/src/main/java/com/designhub/service/ProgressCheckService.java
2026-01-08 14:49:03 +08:00

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();
}
}