Forráskód Böngészése

1.新增发送薪资邮件相关功能(待优化)

GouGengquan 5 napja
szülő
commit
b131f4b0c0

+ 96 - 0
biz-base/src/main/java/com/dayou/controller/HrPayslipEmailController.java

@@ -0,0 +1,96 @@
+package com.dayou.controller;
+
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestMapping;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import org.springframework.web.bind.annotation.RestController;
+import com.dayou.controller.BaseController;
+import com.dayou.service.IHrPayslipEmailService;
+import com.dayou.entity.HrPayslipEmail;
+import com.dayou.common.RestResponse;
+import org.springframework.web.bind.annotation.*;
+import com.dayou.utils.ConvertUtil;
+import com.dayou.utils.HttpKit;
+import com.dayou.exception.ErrorCode;
+
+import java.util.Date;
+import java.util.List;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import org.springframework.http.MediaType;
+import org.springframework.web.multipart.MultipartFile;
+
+/**
+ * 人力资源_薪资(工资条)通知邮件
+ *
+ * @author GouGengquan
+ * @since 2025-07-25
+ */
+@RestController
+@RequestMapping("hrPayslipEmail")
+@Slf4j
+public class HrPayslipEmailController extends BaseController {
+    @Autowired
+    private IHrPayslipEmailService hrPayslipEmailService;
+
+    /**
+     * 人力资源_薪资(工资条)通知邮件列表
+     */
+    @GetMapping("/page")
+    public RestResponse<Page<HrPayslipEmail>> page(HrPayslipEmail hrPayslipEmail, Page page) {
+        Page<HrPayslipEmail> pages = hrPayslipEmailService.selectPage(page, hrPayslipEmail);
+        return RestResponse.data(pages);
+    }
+
+    /**
+     * 人力资源_薪资(工资条)通知邮件详情
+     */
+    @GetMapping("/{id}")
+    public RestResponse<HrPayslipEmail> detail(@PathVariable Long id) {
+        HrPayslipEmail xHrPayslipEmail = hrPayslipEmailService.detail(id);
+        return RestResponse.data(xHrPayslipEmail);
+    }
+
+    /**
+     * 批量发送工资条邮件
+     * @param file 工资条excel表
+     * @return Boolean
+     */
+    @PostMapping("/sendEmailBatch")
+    public RestResponse<Boolean> sendEmailBatch(@RequestPart("file") MultipartFile file, @RequestPart("subject") String subject, @RequestPart("year") String year, @RequestPart("month") String month) throws Exception {
+        return RestResponse.data(hrPayslipEmailService.sendEmailBatch(file, subject, year, month));
+    }
+
+    /**
+     * 人力资源_薪资(工资条)通知邮件新增
+     */
+    // @PostMapping("")
+    public RestResponse<Boolean> save(@RequestBody HrPayslipEmail hrPayslipEmail) {
+        Boolean ret = hrPayslipEmailService.add(hrPayslipEmail);
+        return RestResponse.data(ret);
+    }
+
+    /**
+     * 人力资源_薪资(工资条)通知邮件更新
+     */
+    // @PutMapping("")
+    public RestResponse<Boolean> update(@RequestBody HrPayslipEmail hrPayslipEmail) {
+        Boolean ret = hrPayslipEmailService.update(hrPayslipEmail);
+        return RestResponse.data(ret);
+    }
+
+    /**
+     * 人力资源_薪资(工资条)通知邮件删除
+     */
+    // @DeleteMapping("/{id}")
+    public RestResponse<Boolean> delete(@PathVariable Long id) {
+        Boolean ret = hrPayslipEmailService.delete(id);
+        return RestResponse.data(ret);
+    }
+
+
+}
+

+ 3 - 2
biz-base/src/main/resources/application-local.yml

@@ -86,7 +86,8 @@ posyspath:  /Users/wuwei/pageoffice
 mail:
   configs:
     # 邮箱信息
-    - host: smtp.qq.com #host
+    - business-name: hr_payslip
+      host: smtp.qq.com #host
       port: 465 #端口
       protocol: smtp #协议
       username: xxxxxx@qq.com #邮箱
@@ -95,4 +96,4 @@ mail:
       auth: true #smtp auth
       SSL-enable: true #ssl加密是否开启
       SSL-required: true #ssl加密是否必须
-    # 多个邮箱则以相同格式添加一个信息在configs下
+    # 多个邮箱则以相同格式添加一个信息在configs下

+ 244 - 0
biz-base/src/main/resources/ftl/hr/payslip_email.ftl

@@ -0,0 +1,244 @@
+<div lang="ZH-CN" style="word-wrap:break-word;text-justify-trim:punctuation">
+    <div class="WordSection1" style="layout-grid:15.6pt">
+        <p class="MsoNormal" style="text-indent:21.0pt">您好!以下是您<span lang="EN-US">${year}</span>年<span lang="EN-US">${month}</span>月的工资明细,请注意查收,如有疑问请及时与人力行政部联系!
+        </p>
+        <p class="MsoNormal"><span lang="EN-US">
+                <o:p>&nbsp;</o:p>
+            </span></p>
+        <table class="MsoTableGrid" border="1" cellspacing="0" cellpadding="0"
+               style="border-collapse:collapse;border:none">
+            <tbody>
+            <tr>
+                <td width="553" colspan="4" valign="top"
+                    style="width:414.8pt;border:solid windowtext 1.0pt;padding:0cm 5.4pt 0cm 5.4pt">
+                    <p class="MsoNormal" align="center" style="text-align:center">员工信息</p>
+                </td>
+            </tr>
+            <tr>
+                <td width="138" valign="top"
+                    style="width:103.7pt;border:solid windowtext 1.0pt;border-top:none;padding:0cm 5.4pt 0cm 5.4pt">
+                    <p class="MsoNormal">姓名</p>
+                </td>
+                <td width="138" valign="top"
+                    style="width:103.7pt;border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 5.4pt 0cm 5.4pt">
+                    <p class="MsoNormal">${name}</p>
+                </td>
+                <td width="138" valign="top"
+                    style="width:103.7pt;border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 5.4pt 0cm 5.4pt">
+                    <p class="MsoNormal">部门</p>
+                </td>
+                <td width="138" valign="top"
+                    style="width:103.7pt;border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 5.4pt 0cm 5.4pt">
+                    <p class="MsoNormal">${department}</p>
+                </td>
+            </tr>
+            <tr>
+                <td width="553" colspan="4" valign="top"
+                    style="width:414.8pt;border:solid windowtext 1.0pt;border-top:none;padding:0cm 5.4pt 0cm 5.4pt">
+                    <p class="MsoNormal" align="center" style="text-align:center">工资信息</p>
+                </td>
+            </tr>
+            <tr>
+                <td width="138" valign="top"
+                    style="width:103.7pt;border:solid windowtext 1.0pt;border-top:none;padding:0cm 5.4pt 0cm 5.4pt">
+                    <p class="MsoNormal">基本工资</p>
+                </td>
+                <td width="138" valign="top"
+                    style="width:103.7pt;border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 5.4pt 0cm 5.4pt">
+                    <p class="MsoNormal"><span lang="EN-US">${baseSalary}</span></p>
+                </td>
+                <td width="138" valign="top"
+                    style="width:103.7pt;border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 5.4pt 0cm 5.4pt">
+                    <p class="MsoNormal">绩效工资</p>
+                </td>
+                <td width="138" valign="top"
+                    style="width:103.7pt;border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 5.4pt 0cm 5.4pt">
+                    <p class="MsoNormal"><span lang="EN-US">${performanceSalary}</span></p>
+                </td>
+            </tr>
+            <tr>
+                <td width="138" valign="top"
+                    style="width:103.7pt;border:solid windowtext 1.0pt;border-top:none;padding:0cm 5.4pt 0cm 5.4pt">
+                    <p class="MsoNormal">提成工资</p>
+                </td>
+                <td width="138" valign="top"
+                    style="width:103.7pt;border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 5.4pt 0cm 5.4pt">
+                    <p class="MsoNormal"><span lang="EN-US">${commissionSalary}</span></p>
+                </td>
+                <td width="138" valign="top"
+                    style="width:103.7pt;border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 5.4pt 0cm 5.4pt">
+                    <p class="MsoNormal">加班工资</p>
+                </td>
+                <td width="138" valign="top"
+                    style="width:103.7pt;border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 5.4pt 0cm 5.4pt">
+                    <p class="MsoNormal"><span lang="EN-US">${overtimeSalary}</span></p>
+                </td>
+            </tr>
+            <tr>
+                <td width="138" valign="top"
+                    style="width:103.7pt;border:solid windowtext 1.0pt;border-top:none;padding:0cm 5.4pt 0cm 5.4pt">
+                    <p class="MsoNormal">餐补</p>
+                </td>
+                <td width="138" valign="top"
+                    style="width:103.7pt;border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 5.4pt 0cm 5.4pt">
+                    <p class="MsoNormal"><span lang="EN-US">${mealAllowance}</span></p>
+                </td>
+                <td width="138" valign="top"
+                    style="width:103.7pt;border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 5.4pt 0cm 5.4pt">
+                    <p class="MsoNormal">交通通讯补贴</p>
+                </td>
+                <td width="138" valign="top"
+                    style="width:103.7pt;border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 5.4pt 0cm 5.4pt">
+                    <p class="MsoNormal"><span lang="EN-US">${transportationCommunicationAllowance}</span></p>
+                </td>
+            </tr>
+            <tr>
+                <td width="138" valign="top"
+                    style="width:103.7pt;border:solid windowtext 1.0pt;border-top:none;padding:0cm 5.4pt 0cm 5.4pt">
+                    <p class="MsoNormal">兼职津贴</p>
+                </td>
+                <td width="138" valign="top"
+                    style="width:103.7pt;border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 5.4pt 0cm 5.4pt">
+                    <p class="MsoNormal"><span lang="EN-US">${partTimeAllowance}</span></p>
+                </td>
+                <td width="138" valign="top"
+                    style="width:103.7pt;border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 5.4pt 0cm 5.4pt">
+                    <p class="MsoNormal">保密津贴</p>
+                </td>
+                <td width="138" valign="top"
+                    style="width:103.7pt;border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 5.4pt 0cm 5.4pt">
+                    <p class="MsoNormal"><span lang="EN-US">${confidentialityAllowance}</span></p>
+                </td>
+            </tr>
+            <tr>
+                <td width="138" valign="top"
+                    style="width:103.7pt;border:solid windowtext 1.0pt;border-top:none;padding:0cm 5.4pt 0cm 5.4pt">
+                    <p class="MsoNormal">工龄工资</p>
+                </td>
+                <td width="138" valign="top"
+                    style="width:103.7pt;border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 5.4pt 0cm 5.4pt">
+                    <p class="MsoNormal"><span lang="EN-US">${senioritySalary}</span></p>
+                </td>
+                <td width="138" valign="top"
+                    style="width:103.7pt;border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 5.4pt 0cm 5.4pt">
+                    <p class="MsoNormal">双师津贴</p>
+                </td>
+                <td width="138" valign="top"
+                    style="width:103.7pt;border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 5.4pt 0cm 5.4pt">
+                    <p class="MsoNormal"><span lang="EN-US">${dualRegistrationAllowance}</span></p>
+                </td>
+            </tr>
+            <tr>
+                <td width="138" valign="top"
+                    style="width:103.7pt;border:solid windowtext 1.0pt;border-top:none;padding:0cm 5.4pt 0cm 5.4pt">
+                    <p class="MsoNormal">其它补贴</p>
+                </td>
+                <td width="138" valign="top"
+                    style="width:103.7pt;border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 5.4pt 0cm 5.4pt">
+                    <p class="MsoNormal"><span lang="EN-US">${otherAllowance}</span></p>
+                </td>
+                <td width="138" valign="top"
+                    style="width:103.7pt;border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 5.4pt 0cm 5.4pt">
+                    <p class="MsoNormal">考勤等其他扣款</p>
+                </td>
+                <td width="138" valign="top"
+                    style="width:103.7pt;border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 5.4pt 0cm 5.4pt">
+                    <p class="MsoNormal"><span lang="EN-US">${otherDeductions}</span></p>
+                </td>
+            </tr>
+            <tr>
+                <td width="138" valign="top"
+                    style="width:103.7pt;border:solid windowtext 1.0pt;border-top:none;padding:0cm 5.4pt 0cm 5.4pt">
+                    <p class="MsoNormal">应发合计</p>
+                </td>
+                <td width="138" valign="top"
+                    style="width:103.7pt;border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 5.4pt 0cm 5.4pt">
+                    <p class="MsoNormal"><span lang="EN-US">${grossPay}</span></p>
+                </td>
+                <td width="138" valign="top"
+                    style="width:103.7pt;border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 5.4pt 0cm 5.4pt">
+                    <p class="MsoNormal"><span lang="EN-US">
+                                <o:p>&nbsp;</o:p>
+                            </span></p>
+                </td>
+                <td width="138" valign="top"
+                    style="width:103.7pt;border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 5.4pt 0cm 5.4pt">
+                    <p class="MsoNormal"><span lang="EN-US">
+                                <o:p>&nbsp;</o:p>
+                            </span></p>
+                </td>
+            </tr>
+            <tr>
+                <td width="138" valign="top"
+                    style="width:103.7pt;border:solid windowtext 1.0pt;border-top:none;padding:0cm 5.4pt 0cm 5.4pt">
+                    <p class="MsoNormal">社保个人</p>
+                </td>
+                <td width="138" valign="top"
+                    style="width:103.7pt;border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 5.4pt 0cm 5.4pt">
+                    <p class="MsoNormal"><span lang="EN-US">${personalSocialSecurity}</span></p>
+                </td>
+                <td width="138" valign="top"
+                    style="width:103.7pt;border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 5.4pt 0cm 5.4pt">
+                    <p class="MsoNormal">公积金个人</p>
+                </td>
+                <td width="138" valign="top"
+                    style="width:103.7pt;border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 5.4pt 0cm 5.4pt">
+                    <p class="MsoNormal"><span lang="EN-US">${personalHousingFund}</span></p>
+                </td>
+            </tr>
+            <tr>
+                <td width="138" valign="top"
+                    style="width:103.7pt;border:solid windowtext 1.0pt;border-top:none;padding:0cm 5.4pt 0cm 5.4pt">
+                    <p class="MsoNormal">所得税</p>
+                </td>
+                <td width="138" valign="top"
+                    style="width:103.7pt;border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 5.4pt 0cm 5.4pt">
+                    <p class="MsoNormal"><span lang="EN-US">${tax}</span></p>
+                </td>
+                <td width="138" valign="top"
+                    style="width:103.7pt;border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 5.4pt 0cm 5.4pt">
+                    <p class="MsoNormal"><span lang="EN-US">
+                                <o:p>&nbsp;</o:p>
+                            </span></p>
+                </td>
+                <td width="138" valign="top"
+                    style="width:103.7pt;border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 5.4pt 0cm 5.4pt">
+                    <p class="MsoNormal"><span lang="EN-US">
+                                <o:p>&nbsp;</o:p>
+                            </span></p>
+                </td>
+            </tr>
+            <tr>
+                <td width="138" valign="top"
+                    style="width:103.7pt;border:solid windowtext 1.0pt;border-top:none;padding:0cm 5.4pt 0cm 5.4pt">
+                    <p class="MsoNormal">实发金额</p>
+                </td>
+                <td width="138" valign="top"
+                    style="width:103.7pt;border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 5.4pt 0cm 5.4pt">
+                    <p class="MsoNormal"><span lang="EN-US">${netPay}</span></p>
+                </td>
+                <td width="138" valign="top"
+                    style="width:103.7pt;border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 5.4pt 0cm 5.4pt">
+                    <p class="MsoNormal"><span lang="EN-US">
+                                <o:p>&nbsp;</o:p>
+                            </span></p>
+                </td>
+                <td width="138" valign="top"
+                    style="width:103.7pt;border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 5.4pt 0cm 5.4pt">
+                    <p class="MsoNormal"><span lang="EN-US">
+                                <o:p>&nbsp;</o:p>
+                            </span></p>
+                </td>
+            </tr>
+            </tbody>
+        </table>
+        <p class="MsoNormal"><span lang="EN-US">
+                <o:p>&nbsp;</o:p>
+            </span></p>
+        <p class="MsoNormal">大友评估公司感谢您的努力工作!</p>
+        <p class="MsoNormal"><span lang="EN-US">
+                <o:p>&nbsp;</o:p>
+            </span></p>
+        <p class="MsoNormal" align="right" style="text-align:right">人力行政部</p>
+    </div>
+</div>

+ 5 - 0
common/src/main/java/com/dayou/configuration/MailConfig.java

@@ -21,6 +21,11 @@ public class MailConfig {
     public static class MailProperties {
 
         /**
+         * 业务名称
+         */
+        private String businessName;
+
+        /**
          * host
          */
         private String host;

+ 7 - 9
common/src/main/java/com/dayou/configuration/MailSenderConfig.java

@@ -7,6 +7,7 @@ import org.springframework.stereotype.Component;
 
 import javax.annotation.PostConstruct;
 import java.util.List;
+import java.util.Map;
 import java.util.Properties;
 
 @Slf4j
@@ -16,7 +17,7 @@ public class MailSenderConfig {
 
     private final MailConfig mailConfig;
 
-    private final List<JavaMailSenderImpl> senderList;
+    private final Map<String, JavaMailSenderImpl> senderMap;
 
     /**
      * 初始化 sender
@@ -41,7 +42,7 @@ public class MailSenderConfig {
             properties.setProperty("mail.smtp.ssl.required", mailProperties.getSSLRequired());
             javaMailSender.setJavaMailProperties(properties);
             // 添加数据
-            senderList.add(javaMailSender);
+            senderMap.put(mailProperties.getBusinessName(),javaMailSender);
         });
         log.info("初始化MailSender成功");
     }
@@ -51,16 +52,13 @@ public class MailSenderConfig {
      *
      * @return CustomMailSender
      */
-    public JavaMailSenderImpl getSenderByName(String username) {
+    public JavaMailSenderImpl getSenderByBusiness(String businessName) {
         // 判断MailSender是否为空
-        if (senderList.isEmpty()) {
+        if (senderMap.isEmpty()) {
             buildMailSender();
         }
         // 返回指定邮箱地址的MailSender
-        return senderList.stream()
-                .filter(sender -> username.equals(sender.getUsername()))
-                .findFirst()
-                .orElse(null);
+        return senderMap.get(businessName);
     }
 
     /**
@@ -68,7 +66,7 @@ public class MailSenderConfig {
      * TODO: 后面如果改成数据库动态加载邮箱配置的话可以用clear重新加载配置
      */
     public void clear() {
-        senderList.clear();
+        senderMap.clear();
     }
 
 }

+ 25 - 1
common/src/main/java/com/dayou/utils/Freemarker.java

@@ -5,6 +5,7 @@ import freemarker.template.Template;
 import freemarker.template.TemplateException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
 
 import java.io.*;
 import java.util.Map;
@@ -47,7 +48,7 @@ public class Freemarker {
      * @param templateName 模板文件名称
      * @return
      */
-    private Template getTemplate(String templateName) {
+    public Template getTemplate(String templateName) {
         logger.debug("Freemarker getTemplate");
         try {
             Template template = configuration.getTemplate(templateName);
@@ -86,4 +87,27 @@ public class Freemarker {
             throw new RuntimeException(e);
         }
     }
+
+    /**
+     * 转换为字符串并返回
+     *
+     * @param templatePath 模板所在路径 xxx/xxx/template
+     * @param templateName 模板名字 xxx.ftl
+     * @param root      数据集合
+     */
+    public String toString(String templatePath, String templateName, Map<String, String> root) {
+        try {
+            getInstance(templatePath);
+            Template template = getTemplate(templateName);
+            return FreeMarkerTemplateUtils.processTemplateIntoString(template,root);
+        } catch (FileNotFoundException e) {
+            e.printStackTrace();
+            throw new RuntimeException(e);
+        } catch (IOException e) {
+            e.printStackTrace();
+            throw new RuntimeException(e);
+        } catch (TemplateException e) {
+            throw new RuntimeException(e);
+        }
+    }
 }

+ 16 - 0
dao/src/main/java/com/dayou/mapper/HrPayslipEmailMapper.java

@@ -0,0 +1,16 @@
+package com.dayou.mapper;
+
+import com.dayou.entity.HrPayslipEmail;
+import com.dayou.dao.CustomBaseMapper;
+
+/**
+ * <p>
+ * 人力资源_薪资(工资条)通知邮件 Mapper 接口
+ * </p>
+ *
+ * @author GouGengquan
+ * @since 2025-07-25
+ */
+public interface HrPayslipEmailMapper extends CustomBaseMapper<HrPayslipEmail> {
+
+}

+ 31 - 0
dao/src/main/resources/mapper/HrPayslipEmailMapper.xml

@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.dayou.mapper.HrPayslipEmailMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.dayou.entity.HrPayslipEmail">
+        <result column="id" property="id" />
+        <result column="deleted" property="deleted" />
+        <result column="created" property="created" />
+        <result column="modified" property="modified" />
+        <result column="operator_id" property="operatorId" />
+        <result column="sender_email" property="senderEmail" />
+        <result column="recipient_email" property="recipientEmail" />
+        <result column="recipient_name" property="recipientName" />
+        <result column="id_no" property="idNo" />
+        <result column="department" property="department" />
+        <result column="send_time" property="sendTime" />
+        <result column="sending_status" property="sendingStatus" />
+        <result column="failure_reason" property="failureReason" />
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="Base_Column_List">
+        id,
+        deleted,
+        created,
+        modified,
+        operator_id, sender_email, recipient_email, recipient_name, id_no, department, send_time, sending_status, failure_reason
+    </sql>
+
+</mapper>

+ 0 - 10
domain/src/main/java/com/dayou/dto/MailMessageDTO.java

@@ -1,10 +0,0 @@
-package com.dayou.dto;
-
-import lombok.Data;
-
-@Data
-public class MailMessageDTO {
-
-
-
-}

+ 157 - 0
domain/src/main/java/com/dayou/dto/PayslipMailMessageDTO.java

@@ -0,0 +1,157 @@
+package com.dayou.dto;
+
+import com.dayou.annotation.Excel;
+import lombok.Data;
+
+@Data
+public class PayslipMailMessageDTO {
+
+    /**
+     * 年份
+     */
+    private String year;
+
+    /**
+     * 月份
+     */
+    private String month;
+
+    /**
+     * 姓名
+     */
+    @Excel(name = "姓名")
+    private String name;
+
+    /**
+     * 身份证号
+     */
+    @Excel(name = "身份证号")
+    private String idNo;
+
+    /**
+     * 部门
+     */
+    @Excel(name = "部门")
+    private String department;
+
+    /**
+     * 邮箱
+     */
+    @Excel(name = "邮箱")
+    private String email;
+
+    /**
+     * 工资总额
+     */
+    @Excel(name = "工资总额")
+    private String grossSalary;
+
+    /**
+     * 基本工资
+     */
+    @Excel(name = "基本工资")
+    private String baseSalary;
+
+    /**
+     * 绩效工资
+     */
+    @Excel(name = "绩效工资")
+    private String performanceSalary;
+
+    /**
+     * 提成工资
+     */
+    @Excel(name = "提成工资")
+    private String commissionSalary;
+
+    /**
+     * 加班工资
+     */
+    @Excel(name = "加班工资")
+    private String overtimeSalary;
+
+    /**
+     * 餐补
+     */
+    @Excel(name = "餐补")
+    private String mealAllowance;
+
+    /**
+     * 交通通讯补贴
+     */
+    @Excel(name = "交通通讯补贴")
+    private String transportationCommunicationAllowance;
+
+    /**
+     * 工龄工资
+     */
+    @Excel(name = "工龄工资")
+    private String senioritySalary;
+
+    /**
+     * 双师津贴
+     */
+    @Excel(name = "双师津贴")
+    private String dualRegistrationAllowance;
+
+    /**
+     * 其它扣款
+     */
+    @Excel(name = "其它扣款")
+    private String otherDeductions;
+
+    /**
+     * 应发合计
+     */
+    @Excel(name = "应发合计")
+    private String grossPay;
+
+    /**
+     * 社保个人
+     */
+    @Excel(name = "社保个人")
+    private String personalSocialSecurity;
+
+    /**
+     * 公积金个人
+     */
+    @Excel(name = "公积金个人")
+    private String personalHousingFund;
+
+    /**
+     * 税金
+     */
+    @Excel(name = "税金")
+    private String tax;
+
+    /**
+     * 应扣合计
+     */
+    @Excel(name = "应扣合计")
+    private String totalDeductions;
+
+    /**
+     * 实发金额
+     */
+    @Excel(name = "实发金额")
+    private String netPay;
+
+    /**
+     * 兼职津贴
+     */
+    @Excel(name = "兼职津贴")
+    private String partTimeAllowance;
+
+    /**
+     * 保密津贴
+     */
+    @Excel(name = "保密津贴")
+    private String confidentialityAllowance;
+
+    /**
+     * 其它补贴
+     */
+    @Excel(name = "其它补贴")
+    private String otherAllowance;
+
+}

+ 86 - 0
domain/src/main/java/com/dayou/entity/HrPayslipEmail.java

@@ -0,0 +1,86 @@
+package com.dayou.entity;
+import com.dayou.common.BaseEntity;
+import java.time.LocalDateTime;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import com.dayou.annotation.ExcelSheet;
+import com.dayou.annotation.ExportCell;
+import com.dayou.annotation.ImportCell;
+/**
+ * <p>
+ * 人力资源_薪资(工资条)通知邮件
+ * </p>
+ *
+ * @author GouGengquan
+ * @since 2025-07-25
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ExcelSheet(sheetName = "人力资源_薪资(工资条)通知邮件")
+public class HrPayslipEmail extends BaseEntity {
+
+    private static final long serialVersionUID=1L;
+
+    /**
+     * 操作人用户id
+     */
+    private Long operatorId;
+
+    /**
+     * 发件人邮箱
+     */
+    @ImportCell
+    @ExportCell(columnName = "发件人邮箱")
+    private String senderEmail;
+
+    /**
+     * 收件人邮箱
+     */
+    @ImportCell
+    @ExportCell(columnName = "收件人邮箱")
+    private String recipientEmail;
+
+    /**
+     * 收件人姓名
+     */
+    @ImportCell
+    @ExportCell(columnName = "收件人姓名")
+    private String recipientName;
+
+    /**
+     * 身份证号
+     */
+    @ImportCell
+    @ExportCell(columnName = "身份证号")
+    private String idNo;
+
+    /**
+     * 部门
+     */
+    @ImportCell
+    @ExportCell(columnName = "部门")
+    private String department;
+
+    /**
+     * 发送时间
+     */
+    @ImportCell
+    @ExportCell(columnName = "发送时间")
+    private LocalDateTime sendTime;
+
+    /**
+     * 发送状态
+     */
+    @ImportCell
+    @ExportCell(columnName = "发送状态")
+    private Boolean sendingStatus;
+
+    /**
+     * 失败原因(发送失败才有)
+     */
+    @ImportCell
+    @ExportCell(columnName = "失败原因(发送失败才有)")
+    private String failureReason;
+
+
+}

+ 38 - 0
service/src/main/java/com/dayou/service/IHrPayslipEmailService.java

@@ -0,0 +1,38 @@
+package com.dayou.service;
+import com.dayou.entity.HrPayslipEmail;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.IOException;
+
+/**
+ * <p>
+ * 人力资源_薪资(工资条)通知邮件 服务类
+ * </p>
+ *
+ * @author GouGengquan
+ * @since 2025-07-25
+ */
+public interface IHrPayslipEmailService extends IService<HrPayslipEmail> {
+
+        Page<HrPayslipEmail> selectPage(Page page,HrPayslipEmail hrPayslipEmail);
+
+        HrPayslipEmail detail(Long id);
+
+        /**
+         * 批量发送工资条邮件
+         * @param file 工资条excel表
+         * @return Boolean
+         */
+        Boolean sendEmailBatch(MultipartFile file, String subject, String year, String month) throws Exception;
+
+        Boolean add(HrPayslipEmail hrPayslipEmail);
+
+        Boolean update(HrPayslipEmail hrPayslipEmail);
+
+        Boolean delete(Long id);
+
+}

+ 161 - 0
service/src/main/java/com/dayou/service/impl/HrPayslipEmailServiceImpl.java

@@ -0,0 +1,161 @@
+package com.dayou.service.impl;
+
+import com.dayou.configuration.MailSenderConfig;
+import com.dayou.dto.PayslipMailMessageDTO;
+import com.dayou.entity.HrPayslipEmail;
+import com.dayou.exception.ErrorCode;
+import com.dayou.mapper.HrPayslipEmailMapper;
+import com.dayou.service.IHrPayslipEmailService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.dayou.utils.ExcelPlusUtil;
+import com.dayou.utils.Freemarker;
+import com.dayou.utils.LoginContext;
+import org.springframework.mail.MailException;
+import org.springframework.mail.javamail.JavaMailSenderImpl;
+import org.springframework.mail.javamail.MimeMessageHelper;
+import org.springframework.stereotype.Service;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.IOException;
+import java.time.LocalDateTime;
+import java.util.*;
+
+import javax.mail.MessagingException;
+import javax.mail.internet.MimeMessage;
+
+/**
+ * <p>
+ * 人力资源_薪资(工资条)通知邮件 服务实现类
+ * </p>
+ *
+ * @author GouGengquan
+ * @since 2025-07-25
+ */
+@Service
+public class HrPayslipEmailServiceImpl extends ServiceImpl<HrPayslipEmailMapper, HrPayslipEmail> implements IHrPayslipEmailService {
+
+    private final MailSenderConfig senderConfig;
+
+    public HrPayslipEmailServiceImpl(MailSenderConfig senderConfig) {
+        this.senderConfig = senderConfig;
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public Page<HrPayslipEmail> selectPage(Page page, HrPayslipEmail hrPayslipEmail) {
+        return this.page(page, new QueryWrapper<HrPayslipEmail>(hrPayslipEmail));
+    }
+
+    @Override
+    public HrPayslipEmail detail(Long id) {
+        return this.getById(id);
+    }
+
+    /**
+     * 批量发送工资条邮件
+     *
+     * @param file 工资条excel表
+     * @return Boolean
+     */
+    @Override
+    public Boolean sendEmailBatch(MultipartFile file, String subject, String year, String month) throws Exception {
+        ExcelPlusUtil<PayslipMailMessageDTO> util = new ExcelPlusUtil<>(PayslipMailMessageDTO.class);
+        List<PayslipMailMessageDTO> dtoList = util.importExcel(file.getInputStream());
+        // 构建邮件发送
+        JavaMailSenderImpl mailSender = senderConfig.getSenderByBusiness("hr_payslip");
+        //创建MimeMessage对象
+        MimeMessage mimeMessage = mailSender.createMimeMessage();
+        MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage, true, "UTF-8");
+        //邮件发送人
+        messageHelper.setFrom(Objects.requireNonNull(mailSender.getUsername()));
+
+        // 循环发送邮件
+        for (PayslipMailMessageDTO dto : dtoList) {
+            HrPayslipEmail hrPayslipEmail = new HrPayslipEmail();
+            try {
+                // 保存发送信息
+                hrPayslipEmail.setOperatorId(LoginContext.getCurrentUserId());
+                hrPayslipEmail.setSenderEmail(mailSender.getUsername());
+                hrPayslipEmail.setRecipientEmail(dto.getEmail());
+                hrPayslipEmail.setRecipientName(dto.getName());
+                hrPayslipEmail.setIdNo(dto.getIdNo());
+                hrPayslipEmail.setDepartment(dto.getDepartment());
+                hrPayslipEmail.setSendTime(LocalDateTime.now());
+
+                // 发送邮件
+                dto.setYear(year);
+                dto.setMonth(month);
+                messageHelper.setTo(dto.getEmail());
+                messageHelper.setSubject(subject);
+                // 根据ftl模板构建html内容
+                String html = buildHtml(dto);
+                // 发送html需要设置为true
+                messageHelper.setText(html, true);
+                mailSender.send(messageHelper.getMimeMessage());
+                // 发送成功状态true
+                hrPayslipEmail.setSendingStatus(true);
+            } catch (Exception sendException) { // 单个邮件发送失败手动捕获处理
+                log.error("邮箱:" + dto.getEmail() + "的薪资邮件发送失败" + sendException.getMessage());
+                // 发送失败状态false
+                hrPayslipEmail.setSendingStatus(false);
+                hrPayslipEmail.setFailureReason(sendException.getMessage());
+            }
+            // 保存邮件发送记录
+            this.save(hrPayslipEmail);
+
+        }
+        return Boolean.TRUE;
+    }
+
+    /**
+     * 构建邮件html内容
+     *
+     * @param dto 工资条信息
+     * @return String
+     */
+    private static String buildHtml(PayslipMailMessageDTO dto) {
+        Map<String, String> dataMap = new HashMap<>();
+        dataMap.put("year", dto.getYear());
+        dataMap.put("month", dto.getMonth());
+        dataMap.put("name", dto.getName());
+        dataMap.put("department", dto.getDepartment());
+        dataMap.put("baseSalary", dto.getBaseSalary());
+        dataMap.put("performanceSalary", dto.getPerformanceSalary());
+        dataMap.put("commissionSalary", dto.getCommissionSalary());
+        dataMap.put("overtimeSalary", dto.getOvertimeSalary());
+        dataMap.put("mealAllowance", dto.getMealAllowance());
+        dataMap.put("transportationCommunicationAllowance", dto.getTransportationCommunicationAllowance());
+        dataMap.put("senioritySalary", dto.getSenioritySalary());
+        dataMap.put("dualRegistrationAllowance", dto.getDualRegistrationAllowance());
+        dataMap.put("otherDeductions", dto.getOtherDeductions());
+        dataMap.put("grossPay", dto.getGrossPay());
+        dataMap.put("personalSocialSecurity", dto.getPersonalSocialSecurity());
+        dataMap.put("personalHousingFund", dto.getPersonalHousingFund());
+        dataMap.put("tax", dto.getTax());
+        dataMap.put("netPay", dto.getNetPay());
+        dataMap.put("partTimeAllowance", dto.getPartTimeAllowance());
+        dataMap.put("confidentialityAllowance", dto.getConfidentialityAllowance());
+        dataMap.put("otherAllowance", dto.getOtherAllowance());
+        Freemarker freemarker = new Freemarker();
+        return freemarker.toString("/ftl/hr", "payslip_email.ftl", dataMap);
+    }
+
+    @Override
+    public Boolean add(HrPayslipEmail hrPayslipEmail) {
+        return this.save(hrPayslipEmail);
+    }
+
+    @Override
+    public Boolean update(HrPayslipEmail hrPayslipEmail) {
+        return this.updateById(hrPayslipEmail);
+    }
+
+    @Override
+    public Boolean delete(Long id) {
+        //逻辑删除
+        return this.removeById(id);
+    }
+}

+ 28 - 1
sql/update_sql.sql

@@ -1000,4 +1000,31 @@ CREATE TABLE `assets_complaint`
     `modified`         timestamp(6)                                           NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6) COMMENT '修改时间',
     PRIMARY KEY (`id`) USING BTREE
 ) ENGINE = InnoDB
-  DEFAULT CHARSET = utf8mb4 COMMENT ='资产业务项目投诉表';
+  DEFAULT CHARSET = utf8mb4 COMMENT ='资产业务项目投诉表';
+
+/**
+  日期:2025-07-25
+  修改人:苟耕铨
+  已更新到test-env
+ */
+#  新增人力资源_薪资(工资条)通知邮件表
+CREATE TABLE `hr_payslip_email`
+(
+    `id`              bigint(20)   NOT NULL AUTO_INCREMENT COMMENT '自增主键',
+    `operator_id`     bigint(20)   NOT NULL COMMENT '操作人用户id',
+    `sender_email`    varchar(255) NOT NULL COMMENT '发件人邮箱',
+    `recipient_email` varchar(255) NOT NULL COMMENT '收件人邮箱',
+    `recipient_name`  varchar(255) NOT NULL COMMENT '收件人姓名',
+    `id_no`           varchar(31)  NOT NULL COMMENT '身份证号',
+    `department`      varchar(255) NOT NULL COMMENT '部门',
+    `send_time`       datetime     NOT NULL COMMENT '发送时间',
+    `sending_status`  bit(1)       NOT NULL DEFAULT b'0' COMMENT '发送状态',
+    `failure_reason`  text COMMENT '失败原因(发送失败才有)',
+    `deleted`         bit(1)       NOT NULL DEFAULT b'0' COMMENT '逻辑删除标识:1:删除 0:未删除',
+    `created`         datetime     NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    `modified`        timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6) COMMENT '修改时间',
+    PRIMARY KEY (`id`),
+    KEY `sender_id` (`operator_id`) USING BTREE
+) ENGINE = InnoDB
+  AUTO_INCREMENT = 5
+  DEFAULT CHARSET = utf8mb4 COMMENT ='人力资源_薪资(工资条)通知邮件';