package com.designhub.service; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.designhub.entity.DelayPenaltyRecord; import com.designhub.entity.DelayPenaltyRule; import com.designhub.mapper.DelayPenaltyRecordMapper; import com.designhub.mapper.DelayPenaltyRuleMapper; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.time.LocalDateTime; import java.time.temporal.ChronoUnit; import java.util.List; /** * 延误扣分Service */ @Slf4j @Service @RequiredArgsConstructor public class DelayPenaltyService { private final DelayPenaltyRecordMapper delayPenaltyRecordMapper; private final DelayPenaltyRuleMapper delayPenaltyRuleMapper; /** * 计算延误扣分 * 根据需求文档的规则: * - 轻微延误(< 2小时):每小时扣2分 * - 一般延误(2-8小时):每小时扣3分 * - 严重延误(8-24小时):每小时扣5分 * - 重大延误(> 24小时):基础50分+每天10分 */ public DelayPenaltyRecord calculateDelayPenalty(Long taskId, Long designerId, LocalDateTime deadline, LocalDateTime actualTime) { if (deadline == null || actualTime == null) { return null; } // 如果实际时间早于截止时间,未延误 if (actualTime.isBefore(deadline) || actualTime.isEqual(deadline)) { return null; } // 计算延误小时数 long delayHours = ChronoUnit.HOURS.between(deadline, actualTime); long delayDays = ChronoUnit.DAYS.between(deadline, actualTime); // 确定延误等级和扣分 String delayLevel; Integer penaltyScore; if (delayHours < 2) { // 轻微延误:每小时扣2分 delayLevel = "light"; penaltyScore = (int) Math.ceil(delayHours * 2.0); } else if (delayHours < 8) { // 一般延误:每小时扣3分 delayLevel = "general"; penaltyScore = (int) Math.ceil(delayHours * 3.0); } else if (delayHours < 24) { // 严重延误:每小时扣5分 delayLevel = "severe"; penaltyScore = (int) Math.ceil(delayHours * 5.0); } else { // 重大延误:基础50分+每天10分 delayLevel = "major"; penaltyScore = 50 + (int) delayDays * 10; } // 创建延误扣分记录 DelayPenaltyRecord record = new DelayPenaltyRecord(); record.setTaskId(taskId); record.setDesignerId(designerId); record.setDelayDays((int) delayDays); record.setDelayHours(delayHours); record.setDelayLevel(delayLevel); record.setPenaltyScore(penaltyScore); record.setOriginalDeadline(deadline); record.setActualTime(actualTime); record.setStatus("confirmed"); log.info("计算延误扣分: taskId={}, designerId={}, delayHours={}, delayLevel={}, penaltyScore={}", taskId, designerId, delayHours, delayLevel, penaltyScore); return record; } /** * 保存延误扣分记录 */ @Transactional(rollbackFor = Exception.class) public DelayPenaltyRecord saveDelayPenaltyRecord(DelayPenaltyRecord record) { if (record == null) { return null; } delayPenaltyRecordMapper.insert(record); log.info("保存延误扣分记录: recordId={}, taskId={}, penaltyScore={}", record.getId(), record.getTaskId(), record.getPenaltyScore()); return record; } /** * 根据任务ID查询延误记录 */ public List getDelayRecordsByTaskId(Long taskId) { return delayPenaltyRecordMapper.findByTaskId(taskId); } /** * 根据设计师ID查询延误记录 */ public List getDelayRecordsByDesignerId(Long designerId) { return delayPenaltyRecordMapper.findByDesignerId(designerId); } /** * 统计设计师的延误扣分总数 */ public Integer getTotalPenaltyScoreByDesignerId(Long designerId) { Integer total = delayPenaltyRecordMapper.sumPenaltyScoreByDesignerId(designerId); return total != null ? total : 0; } /** * 申诉延误扣分 */ @Transactional(rollbackFor = Exception.class) public void appealDelayPenalty(Long recordId, Long designerId, String appealReason) { DelayPenaltyRecord record = delayPenaltyRecordMapper.selectById(recordId); if (record == null) { throw new RuntimeException("延误扣分记录不存在"); } if (!record.getDesignerId().equals(designerId)) { throw new RuntimeException("无权申诉此记录"); } if (!"confirmed".equals(record.getStatus())) { throw new RuntimeException("该记录已申诉或已处理"); } record.setStatus("appealed"); record.setAppealReason(appealReason); record.setAppealTime(LocalDateTime.now()); delayPenaltyRecordMapper.updateById(record); log.info("设计师申诉延误扣分: recordId={}, designerId={}, reason={}", recordId, designerId, appealReason); } /** * 管理员审批申诉 */ @Transactional(rollbackFor = Exception.class) public void approveAppeal(Long recordId, Long approverId, Boolean approved, String appealResult) { DelayPenaltyRecord record = delayPenaltyRecordMapper.selectById(recordId); if (record == null) { throw new RuntimeException("延误扣分记录不存在"); } if (!"appealed".equals(record.getStatus())) { throw new RuntimeException("该记录不是申诉状态"); } if (approved) { record.setStatus("approved"); } else { record.setStatus("rejected"); } record.setAppealResult(appealResult); record.setApproverId(approverId); record.setApproveTime(LocalDateTime.now()); delayPenaltyRecordMapper.updateById(record); log.info("管理员审批申诉: recordId={}, approverId={}, approved={}", recordId, approverId, approved); } }