Explorar o código

12.30,推送邮件相关的

Crazy hai 5 meses
pai
achega
3fffb39f63

+ 138 - 14
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/MailTemplateController.java

@@ -3,11 +3,13 @@ package cn.iocoder.yudao.module.system.controller.admin.mail;
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
 import cn.iocoder.yudao.module.system.controller.admin.mail.vo.template.*;
 import cn.iocoder.yudao.module.system.controller.admin.studentAttendance.vo.StudentAttendanceEmailVO;
 import cn.iocoder.yudao.module.system.controller.admin.studentAttendance.vo.StudentAttendancePageReqVO;
 import cn.iocoder.yudao.module.system.controller.admin.studentAttendance.vo.StudentAttendanceRespVO;
 import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserPageReqVO;
+import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.graduateStudentExportExcelVO;
 import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
 import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO;
 import cn.iocoder.yudao.module.system.dal.dataobject.studentAttendance.StudentAttendanceDO;
@@ -18,6 +20,9 @@ import cn.iocoder.yudao.module.system.service.mail.MailTemplateService;
 import cn.iocoder.yudao.module.system.service.permission.PermissionService;
 import cn.iocoder.yudao.module.system.service.studentAttendance.StudentAttendanceService;
 import cn.iocoder.yudao.module.system.service.user.AdminUserService;
+import com.alibaba.excel.EasyExcel;
+import com.alibaba.excel.ExcelWriter;
+import com.alibaba.excel.write.metadata.WriteSheet;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.Parameter;
 import io.swagger.v3.oas.annotations.tags.Tag;
@@ -27,6 +32,7 @@ import org.springframework.web.bind.annotation.*;
 
 import javax.annotation.Resource;
 import javax.validation.Valid;
+import java.io.*;
 import java.time.DayOfWeek;
 import java.time.LocalDate;
 import java.time.temporal.TemporalAdjusters;
@@ -53,7 +59,7 @@ public class MailTemplateController {
     @Resource
     private PermissionService permissionService;
 
-    @Scheduled(cron = "0 30 22 * * ?") // 每天晚上 22:30
+    @Scheduled(cron = "0 30 8 * * ?") // 每天晚上 22:30
     @Operation(summary = "定时发送邮件给导师")
     public void sendMailToTeacherScheduled() {
         // 创建结果对象并设置属性
@@ -62,11 +68,16 @@ public class MailTemplateController {
         List<AdminUserDO> TeacherList = adminUserService.getUserList(reqVO);
         StudentAttendancePageReqVO pageReqVO =new StudentAttendancePageReqVO();
         Map<String, Object> templateParams =new HashMap<>();//模板参数设置
-        // 获取当前这天
-        LocalDate today = LocalDate.now();
+        // 获取前一天
+        LocalDate yesterday = LocalDate.now().minusDays(1);
+        // 检查昨天是否是周日
+        if (yesterday.getDayOfWeek() == DayOfWeek.MONDAY) {
+            return; // 直接返回,不推送周日的
+        }
+
         if ( TeacherList!=null&& !TeacherList.isEmpty()) {
             for (AdminUserDO teacher : TeacherList) {
-                pageReqVO.setDate(today);
+                pageReqVO.setDate(yesterday);
                 List<StudentAttendanceEmailVO> normalList = BeanUtils.toBean(
                         studentAttendanceService.getStudentAttendanceListForTeacher(pageReqVO.setDeptId(String.valueOf(teacher.getDeptId()))),
                         StudentAttendanceEmailVO.class
@@ -118,16 +129,14 @@ public class MailTemplateController {
                 }
             }
         }
-
     }
 
-    @Scheduled(cron = "0 30 22 * * ?") // 每天晚上 22:30
+    @Scheduled(cron = "0 30 8 * * ?") // 每天晚上 22:30
     @Operation(summary = "定时发送邮件给学院")
     public void sendMailToCollegeScheduled() {
         testCollege();
     }
 
-
     @PostMapping("/create")
     @Operation(summary = "创建邮件模版")
     @PreAuthorize("@ss.hasPermission('system:mail-template:create')")
@@ -195,11 +204,17 @@ public class MailTemplateController {
         List<AdminUserDO> TeacherList = adminUserService.getUserList(reqVO);
         StudentAttendancePageReqVO pageReqVO =new StudentAttendancePageReqVO();
         Map<String, Object> templateParams =new HashMap<>();//模板参数设置
-        // 获取当前这天
-        LocalDate today = LocalDate.now();
+
+        // 获取前一天
+        LocalDate yesterday = LocalDate.now().minusDays(1);
+        // 检查昨天是否是周日
+//        if (yesterday.getDayOfWeek() == DayOfWeek.SUNDAY) {
+//            return; // 直接返回,不推送周日的
+//        }
+
         if ( TeacherList!=null&& !TeacherList.isEmpty()) {
             for (AdminUserDO teacher : TeacherList) {
-                pageReqVO.setDate(today);
+                pageReqVO.setDate(yesterday);
                 List<StudentAttendanceEmailVO> normalList = BeanUtils.toBean(
                         studentAttendanceService.getStudentAttendanceListForTeacher(pageReqVO.setDeptId(String.valueOf(teacher.getDeptId()))),
                         StudentAttendanceEmailVO.class
@@ -274,11 +289,16 @@ public class MailTemplateController {
 
         Map<String, Object> templateParams =new HashMap<>();//模板参数设置
 
-        // 获取当前这天
-        LocalDate today = LocalDate.now();
-        if ( collegeList!=null && !collegeList.isEmpty()) {
+        // 获取前一天
+        LocalDate yesterday = LocalDate.now().minusDays(1);
+//        // 检查昨天是否是周日
+//        if (yesterday.getDayOfWeek() == DayOfWeek.SUNDAY) {
+//            return; // 直接返回,不推送周日的
+//        }
+
+        if ( !collegeList.isEmpty()) {
             for (AdminUserDO college : collegeList) {
-                attendanceReqVO.setDate(today);
+                attendanceReqVO.setDate(yesterday);
                 List<StudentAttendanceEmailVO> normalList = BeanUtils.toBean(
                         studentAttendanceService.getStudentAttendanceListForTeacher(attendanceReqVO),
                         StudentAttendanceEmailVO.class
@@ -336,7 +356,111 @@ public class MailTemplateController {
                 }
             }
         }
+    }
+
+    @PostMapping("/SendExcelToTeacher")
+    @Operation(summary = "发送Excel给导师")
+    public void sendExcelMailToTeacherScheduled() throws IOException {
+        // 创建结果对象并设置属性
+        UserPageReqVO reqVO = new UserPageReqVO();
+        reqVO.setUserType("3"); // 找导师
+        List<AdminUserDO> TeacherList = adminUserService.getUserList(reqVO);
+        StudentAttendancePageReqVO pageReqVO = new StudentAttendancePageReqVO();
+        Map<String, Object> templateParams = new HashMap<>(); // 模板参数设置
+
+        LocalDate today = LocalDate.now();
+        if (TeacherList != null && !TeacherList.isEmpty()) {
+            for (AdminUserDO teacher : TeacherList) {
+                pageReqVO.setDate(today);
+                List<StudentAttendanceTemplateVO> normalList = BeanUtils.toBean(
+                        studentAttendanceService.getStudentAttendanceListForTeacher(pageReqVO.setDeptId(String.valueOf(0))),
+                        StudentAttendanceTemplateVO.class
+                );
+                List<StudentAttendanceTemplateVO> errorList = BeanUtils.toBean(
+                        studentAttendanceService.getStudentAttendanceErrorListForTeacher(pageReqVO.setDeptId(String.valueOf(0))),
+                        StudentAttendanceTemplateVO.class
+                );
+                List<StudentAttendanceTemplateVO> excusedList = BeanUtils.toBean(
+                        studentAttendanceService.getStudentAttendanceExcusedListForTeacher(pageReqVO.setDeptId(String.valueOf(0))),
+                        StudentAttendanceTemplateVO.class
+                );
+                // 输出 Excel
+                ByteArrayOutputStream normalOutputStream = new ByteArrayOutputStream();
+                ByteArrayOutputStream errorOutputStream = new ByteArrayOutputStream();
+                ByteArrayOutputStream excusedOutputStream = new ByteArrayOutputStream();
+
+                EasyExcel.write(normalOutputStream, StudentAttendanceTemplateVO.class).sheet("正常打卡信息").doWrite(normalList);
+                normalOutputStream.close();
+                EasyExcel.write(errorOutputStream, StudentAttendanceTemplateVO.class).sheet("未打卡信息").doWrite(errorList);
+                errorOutputStream.close();
+                EasyExcel.write(excusedOutputStream, StudentAttendanceTemplateVO.class).sheet("请假信息").doWrite(excusedList);
+                errorOutputStream.close();
+
+                // 构造附件Map
+                Map<String, InputStream> attachments = new HashMap<>();
+                attachments.put("正常考勤信息.xlsx", new ByteArrayInputStream(normalOutputStream.toByteArray()));
+                attachments.put("未打卡信息.xlsx", new ByteArrayInputStream(normalOutputStream.toByteArray()));
+                attachments.put("请假.xlsx", new ByteArrayInputStream(normalOutputStream.toByteArray()));
+
+                // 发送邮件,包含附件
+                if (teacher.getEmail() != null) {
+                    mailSendService.sendSingleMailToMemberWithAttachments(teacher.getEmail(), null, "attendance-list-excel", templateParams, attachments);
+                }
+            }
+        }
+    }
+
+    @PostMapping("/CeshiSendExcel")
+    @Operation(summary = "测试发送Excel")
+    public void CeshiSendExcelMail() throws IOException {
+        // 创建结果对象并设置属性
+        UserPageReqVO reqVO = new UserPageReqVO();
+        reqVO.setUserType("3"); // 找导师
+        List<AdminUserDO> TeacherList = adminUserService.getUserList(reqVO);
+        StudentAttendancePageReqVO pageReqVO = new StudentAttendancePageReqVO();
+        Map<String, Object> templateParams = new HashMap<>(); // 模板参数设置
+
+        LocalDate today = LocalDate.now();
+        if (TeacherList != null && !TeacherList.isEmpty()) {
+            for (AdminUserDO teacher : TeacherList) {
+                pageReqVO.setDate(today);
+                List<StudentAttendanceTemplateVO> normalList = BeanUtils.toBean(
+                        studentAttendanceService.getStudentAttendanceListForTeacher(pageReqVO.setDeptId(String.valueOf(teacher.getDeptId()))),
+                        StudentAttendanceTemplateVO.class
+                );
+                List<StudentAttendanceTemplateVO> errorList = BeanUtils.toBean(
+                        studentAttendanceService.getStudentAttendanceErrorListForTeacher(pageReqVO.setDeptId(String.valueOf(teacher.getDeptId()))),
+                        StudentAttendanceTemplateVO.class
+                );
+                List<StudentAttendanceTemplateVO> excusedList = BeanUtils.toBean(
+                        studentAttendanceService.getStudentAttendanceExcusedListForTeacher(pageReqVO.setDeptId(String.valueOf(teacher.getDeptId()))),
+                        StudentAttendanceTemplateVO.class
+                );
+                // 输出单个Excel文件,包含多个Sheet
+                try (ExcelWriter excelWriter = EasyExcel.write("attendance.xlsx", StudentAttendanceTemplateVO.class).build()) {
+                    WriteSheet writeSheetNormal = EasyExcel.writerSheet("正常打卡信息").build();
+                    WriteSheet writeSheetError = EasyExcel.writerSheet("未打卡信息").build();
+                    WriteSheet writeSheetExcused = EasyExcel.writerSheet("请假信息").build();
+
+                    excelWriter.write(normalList, writeSheetNormal);
+                    excelWriter.write(errorList, writeSheetError);
+                    excelWriter.write(excusedList, writeSheetExcused);
+                }
+
+                // 构造附件Map
+                Map<String, InputStream> attachments = new HashMap<>();
+                try (FileInputStream fileInputStream = new FileInputStream("attendance.xlsx")) {
+                    attachments.put("考勤信息.xlsx", fileInputStream);
+                }
 
+                // 发送邮件,包含附件
+                if (teacher.getEmail() != null) {
+                    mailSendService.sendSingleMailToMemberWithAttachments(teacher.getEmail(), null, "attendance-list-excel", templateParams, attachments);
+                }
+            }
+        }
     }
 
+
+
 }

+ 27 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/mail/vo/template/StudentAttendanceTemplateVO.java

@@ -0,0 +1,27 @@
+package cn.iocoder.yudao.module.system.controller.admin.mail.vo.template;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Schema(description = "管理后台 - 邮件学生考勤信息模版的Response VO")
+@Data
+public class StudentAttendanceTemplateVO {
+
+
+    @Schema(description = "学生名字")
+    @ExcelProperty(value = "学生名字")
+    private String studentName;
+
+    @Schema(description = "学生学号")
+    @ExcelProperty(value = "学生学号")
+    private String userNumber;
+
+    @Schema(description = "日期")
+    @ExcelProperty(value = "日期")
+    private String date;
+
+    @Schema(description = "打卡时间")
+    @ExcelProperty(value = "打卡时间")
+    private String clockInTime;
+}

+ 8 - 1
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/consumer/mail/MailSendConsumer.java

@@ -21,11 +21,18 @@ public class MailSendConsumer {
     @Resource
     private MailSendService mailSendService;
 
+//    @EventListener
+//    @Async // Spring Event 默认在 Producer 发送的线程,通过 @Async 实现异步
+//    public void onMessage(MailSendMessage message) {
+//        log.info("[onMessage][消息内容({})]", message);
+//        mailSendService.doSendMail(message);
+//    }
+
     @EventListener
     @Async // Spring Event 默认在 Producer 发送的线程,通过 @Async 实现异步
     public void onMessage(MailSendMessage message) {
         log.info("[onMessage][消息内容({})]", message);
-        mailSendService.doSendMail(message);
+        mailSendService.doSendMailWithAttachments(message);
     }
 
 }

+ 7 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/message/mail/MailSendMessage.java

@@ -4,6 +4,8 @@ import lombok.Data;
 
 import javax.validation.constraints.NotEmpty;
 import javax.validation.constraints.NotNull;
+import java.io.InputStream;
+import java.util.Map;
 
 /**
  * 邮箱发送消息
@@ -44,4 +46,9 @@ public class MailSendMessage {
     @NotEmpty(message = "邮件内容不能为空")
     private String content;
 
+    /**
+     * 邮件附件
+     */
+    private  Map<String, InputStream> attachments;
+
 }

+ 32 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/mq/producer/mail/MailProducer.java

@@ -1,11 +1,24 @@
 package cn.iocoder.yudao.module.system.mq.producer.mail;
 
+import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO;
+import cn.iocoder.yudao.module.system.enums.mail.MailSendStatusEnum;
 import cn.iocoder.yudao.module.system.mq.message.mail.MailSendMessage;
+import cn.iocoder.yudao.module.system.service.mail.MailAccountService;
+import cn.iocoder.yudao.module.system.service.mail.MailLogService;
+import cn.iocoder.yudao.module.system.service.mail.MailTemplateService;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.context.ApplicationContext;
+import org.springframework.core.io.ByteArrayResource;
+import org.springframework.mail.MailSender;
+import org.springframework.mail.javamail.MimeMessageHelper;
 import org.springframework.stereotype.Component;
 
 import javax.annotation.Resource;
+import javax.mail.MessagingException;
+import javax.mail.internet.MimeMessage;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.Map;
 
 /**
  * Mail 邮件相关消息的 Producer
@@ -38,4 +51,23 @@ public class MailProducer {
         applicationContext.publishEvent(message);
     }
 
+    //带附件
+    public void sendMailSendMessageWithAttachments(Long sendLogId, String mail, Long accountId,
+                                    String nickname, String title, String content,  Map<String, InputStream> attachments) {
+        // 创建邮件发送消息对象,并包含附件信息
+        MailSendMessage message = new MailSendMessage()
+                .setLogId(sendLogId)
+                .setMail(mail)
+                .setAccountId(accountId)
+                .setNickname(nickname)
+                .setTitle(title)
+                .setContent(content)
+                .setAttachments(attachments); // 添加附件信息
+
+        // 发布事件,事件监听器将处理邮件发送逻辑,包括附件
+        applicationContext.publishEvent(message);
+    }
+
+
+
 }

+ 9 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailSendService.java

@@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.system.service.mail;
 
 import cn.iocoder.yudao.module.system.mq.message.mail.MailSendMessage;
 
+import java.io.InputStream;
 import java.util.Map;
 
 /**
@@ -36,6 +37,9 @@ public interface MailSendService {
     Long sendSingleMailToMember(String mail, Long userId,
                                 String templateCode, Map<String, Object> templateParams);
 
+    Long sendSingleMailToMemberWithAttachments(String mail, Long userId,
+                                String templateCode, Map<String, Object> templateParams, Map<String, InputStream> attachments);
+
     /**
      * 发送单条邮件给用户
      *
@@ -49,6 +53,9 @@ public interface MailSendService {
     Long sendSingleMail(String mail, Long userId, Integer userType,
                         String templateCode, Map<String, Object> templateParams);
 
+    Long sendSingleMailWithAttachments(String mail, Long userId, Integer userType,
+                                       String templateCode, Map<String, Object> templateParams,  Map<String, InputStream> attachments);
+
     /**
      * 执行真正的邮件发送
      * 注意,该方法仅仅提供给 MQ Consumer 使用
@@ -57,4 +64,6 @@ public interface MailSendService {
      */
     void doSendMail(MailSendMessage message);
 
+    void doSendMailWithAttachments(MailSendMessage message);
+
 }

+ 59 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImpl.java

@@ -18,6 +18,7 @@ import org.springframework.stereotype.Service;
 import org.springframework.validation.annotation.Validated;
 
 import javax.annotation.Resource;
+import java.io.InputStream;
 import java.util.Map;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
@@ -74,6 +75,17 @@ public class MailSendServiceImpl implements MailSendService {
         return sendSingleMail(mail, userId, UserTypeEnum.MEMBER.getValue(), templateCode, templateParams);
     }
 
+    @Override
+    public Long sendSingleMailToMemberWithAttachments(String mail, Long userId,
+                                       String templateCode, Map<String, Object> templateParams,Map<String, InputStream> attachments) {
+        // 如果 mail 为空,则加载用户编号对应的邮箱
+        if (StrUtil.isEmpty(mail)) {
+            mail = memberService.getMemberUserEmail(userId);
+        }
+        // 执行发送
+        return sendSingleMailWithAttachments(mail, userId, UserTypeEnum.MEMBER.getValue(), templateCode, templateParams,attachments);
+    }
+
     @Override
     public Long sendSingleMail(String mail, Long userId, Integer userType,
                                String templateCode, Map<String, Object> templateParams) {
@@ -100,6 +112,34 @@ public class MailSendServiceImpl implements MailSendService {
         return sendLogId;
     }
 
+    @Override
+    public Long sendSingleMailWithAttachments(String mail, Long userId, Integer userType,
+                                             String templateCode, Map<String, Object> templateParams, Map<String, InputStream> attachments) {
+        // 校验邮箱模版是否合法
+        MailTemplateDO template = validateMailTemplate(templateCode);
+        // 校验邮箱账号是否合法
+        MailAccountDO account = validateMailAccount(template.getAccountId());
+
+        // 校验邮箱是否存在
+        mail = validateMail(mail);
+        validateTemplateParams(template, templateParams);
+
+        // 创建发送日志。如果模板被禁用,则不发送短信,只记录日志
+        Boolean isSend = CommonStatusEnum.ENABLE.getStatus().equals(template.getStatus());
+        String title = mailTemplateService.formatMailTemplateContent(template.getTitle(), templateParams);
+        String content = mailTemplateService.formatMailTemplateContent(template.getContent(), templateParams);
+        Long sendLogId = mailLogService.createMailLog(userId, userType, mail,
+                account, template, content, templateParams, isSend);
+        // 发送 MQ 消息,异步执行发送短信
+        if (isSend) {
+            mailProducer.sendMailSendMessageWithAttachments(sendLogId, mail, account.getId(),
+                    template.getNickname(), title, content, attachments);
+        }
+        return sendLogId;
+    }
+
+
+
     @Override
     public void doSendMail(MailSendMessage message) {
         // 1. 创建发送账号
@@ -117,6 +157,25 @@ public class MailSendServiceImpl implements MailSendService {
         }
     }
 
+    @Override
+    public void doSendMailWithAttachments(MailSendMessage message) {
+        // 1. 创建发送账号
+        MailAccountDO account = validateMailAccount(message.getAccountId());
+        MailAccount mailAccount = buildMailAccount(account, message.getNickname());
+        // 2. 发送邮件
+        try {
+            // 检查是否有附件
+            Map<String, InputStream> attachments = message.getAttachments();
+            String messageId = MailUtil.send(mailAccount, message.getMail(),
+                    message.getTitle(), message.getContent(), attachments, true);
+            // 3. 更新结果(成功)
+            mailLogService.updateMailSendResult(message.getLogId(), messageId, null);
+        } catch (Exception e) {
+            // 3. 更新结果(异常)
+            mailLogService.updateMailSendResult(message.getLogId(), null, e);
+        }
+    }
+
     private MailAccount buildMailAccount(MailAccountDO account, String nickname) {
         String from = StrUtil.isNotEmpty(nickname) ? nickname + " <" + account.getMail() + ">" : account.getMail();
         return new MailAccount().setFrom(from).setAuth(true)