diff --git a/ruoyi-oa/src/main/java/com/ruoyi/oa/controller/OaEmailAccountController.java b/ruoyi-oa/src/main/java/com/ruoyi/oa/controller/OaEmailAccountController.java new file mode 100644 index 0000000..223bc23 --- /dev/null +++ b/ruoyi-oa/src/main/java/com/ruoyi/oa/controller/OaEmailAccountController.java @@ -0,0 +1,112 @@ +package com.ruoyi.oa.controller; + +import java.util.List; +import java.util.Arrays; +import java.util.concurrent.TimeUnit; + +import lombok.RequiredArgsConstructor; +import javax.servlet.http.HttpServletResponse; +import javax.validation.constraints.*; +import org.springframework.web.bind.annotation.*; +import org.springframework.validation.annotation.Validated; +import com.ruoyi.common.annotation.RepeatSubmit; +import com.ruoyi.common.annotation.Log; +import com.ruoyi.common.core.controller.BaseController; +import com.ruoyi.common.core.domain.PageQuery; +import com.ruoyi.common.core.domain.R; +import com.ruoyi.common.core.validate.AddGroup; +import com.ruoyi.common.core.validate.EditGroup; +import com.ruoyi.common.core.validate.QueryGroup; +import com.ruoyi.common.enums.BusinessType; +import com.ruoyi.common.utils.poi.ExcelUtil; +import com.ruoyi.oa.domain.vo.OaEmailAccountVo; +import com.ruoyi.oa.domain.bo.OaEmailAccountBo; +import com.ruoyi.oa.service.IOaEmailAccountService; +import com.ruoyi.common.core.page.TableDataInfo; +import com.ruoyi.oa.domain.request.EmailSendRequest; + +/** + * 发件人邮箱账号管理 + * + * @author Joshi + * @date 2025-07-10 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/oa/emailAccount") +public class OaEmailAccountController extends BaseController { + + private final IOaEmailAccountService iOaEmailAccountService; + + /** + * 查询发件人邮箱账号管理列表 + */ + @GetMapping("/list") + public TableDataInfo list(OaEmailAccountBo bo, PageQuery pageQuery) { + return iOaEmailAccountService.queryPageList(bo, pageQuery); + } + + /** + * 导出发件人邮箱账号管理列表 + */ + @Log(title = "发件人邮箱账号管理", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(OaEmailAccountBo bo, HttpServletResponse response) { + List list = iOaEmailAccountService.queryList(bo); + ExcelUtil.exportExcel(list, "发件人邮箱账号管理", OaEmailAccountVo.class, response); + } + + /** + * 获取发件人邮箱账号管理详细信息 + * + * @param emailId 主键 + */ + @GetMapping("/{emailId}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long emailId) { + return R.ok(iOaEmailAccountService.queryById(emailId)); + } + + /** + * 新增发件人邮箱账号管理 + */ + @Log(title = "发件人邮箱账号管理", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody OaEmailAccountBo bo) { + return toAjax(iOaEmailAccountService.insertByBo(bo)); + } + + /** + * 修改发件人邮箱账号管理 + */ + @Log(title = "发件人邮箱账号管理", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody OaEmailAccountBo bo) { + return toAjax(iOaEmailAccountService.updateByBo(bo)); + } + + /** + * 删除发件人邮箱账号管理 + * + * @param emailIds 主键串 + */ + @Log(title = "发件人邮箱账号管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{emailIds}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] emailIds) { + return toAjax(iOaEmailAccountService.deleteWithValidByIds(Arrays.asList(emailIds), true)); + } + + /** + * 批量发送邮件(支持网易企业邮箱、飞书SMTP) + */ + @PostMapping("/sendBatchEmail") + public R sendBatchEmail(@RequestBody EmailSendRequest request) { + // 调用Service批量发送邮件 + String result = iOaEmailAccountService.sendBatchEmail(request); + return R.ok(result); + } +} diff --git a/ruoyi-oa/src/main/java/com/ruoyi/oa/domain/OaEmailAccount.java b/ruoyi-oa/src/main/java/com/ruoyi/oa/domain/OaEmailAccount.java new file mode 100644 index 0000000..da93f1e --- /dev/null +++ b/ruoyi-oa/src/main/java/com/ruoyi/oa/domain/OaEmailAccount.java @@ -0,0 +1,68 @@ +package com.ruoyi.oa.domain; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; +import java.io.Serializable; +import java.util.Date; +import java.math.BigDecimal; + +import com.ruoyi.common.core.domain.BaseEntity; + +/** + * 发件人邮箱账号管理对象 oa_email_account + * + * @author Joshi + * @date 2025-07-10 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("oa_email_account") +public class OaEmailAccount extends BaseEntity { + + private static final long serialVersionUID=1L; + + /** + * + */ + @TableId(value = "email_id") + private Long emailId; + /** + * 邮箱账号 + */ + private String email; + /** + * 邮箱授权码/密码(SMTP方式用) + */ + private String password; + /** + * SMTP服务器地址(SMTP方式用) + */ + private String smtpHost; + /** + * SMTP端口(SMTP方式用) + */ + private Long smtpPort; + /** + * API方式用accessKey + */ + private String accessKey; + /** + * API方式用secretKey + */ + private String secretKey; + /** + * 邮箱类型(0网易 1QQ 2阿里云API 3SendGridAPI等) + */ + private Long type; + /** + * 备注 + */ + private String remark; + /** + * 删除标志:0正常;1已删除 + */ + @TableLogic + private Integer delFlag; + +} diff --git a/ruoyi-oa/src/main/java/com/ruoyi/oa/domain/bo/OaEmailAccountBo.java b/ruoyi-oa/src/main/java/com/ruoyi/oa/domain/bo/OaEmailAccountBo.java new file mode 100644 index 0000000..d713440 --- /dev/null +++ b/ruoyi-oa/src/main/java/com/ruoyi/oa/domain/bo/OaEmailAccountBo.java @@ -0,0 +1,70 @@ +package com.ruoyi.oa.domain.bo; + +import com.ruoyi.common.core.validate.AddGroup; +import com.ruoyi.common.core.validate.EditGroup; +import lombok.Data; +import lombok.EqualsAndHashCode; +import javax.validation.constraints.*; + +import java.util.Date; + +import com.ruoyi.common.core.domain.BaseEntity; + +/** + * 发件人邮箱账号管理业务对象 oa_email_account + * + * @author Joshi + * @date 2025-07-10 + */ + +@Data +@EqualsAndHashCode(callSuper = true) +public class OaEmailAccountBo extends BaseEntity { + + /** + * + */ + private Long emailId; + + /** + * 邮箱账号 + */ + private String email; + + /** + * 邮箱授权码/密码(SMTP方式用) + */ + private String password; + + /** + * SMTP服务器地址(SMTP方式用) + */ + private String smtpHost; + + /** + * SMTP端口(SMTP方式用) + */ + private Long smtpPort; + + /** + * API方式用accessKey + */ + private String accessKey; + + /** + * API方式用secretKey + */ + private String secretKey; + + /** + * 邮箱类型(0网易 1QQ 2阿里云API 3SendGridAPI等) + */ + private Long type; + + /** + * 备注 + */ + private String remark; + + +} diff --git a/ruoyi-oa/src/main/java/com/ruoyi/oa/domain/request/EmailSendRequest.java b/ruoyi-oa/src/main/java/com/ruoyi/oa/domain/request/EmailSendRequest.java new file mode 100644 index 0000000..26bb27e --- /dev/null +++ b/ruoyi-oa/src/main/java/com/ruoyi/oa/domain/request/EmailSendRequest.java @@ -0,0 +1,19 @@ +package com.ruoyi.oa.domain.request; + +import lombok.Data; +import java.util.List; + +/** + * 邮件批量发送请求参数 + */ +@Data +public class EmailSendRequest { + /** 发件人邮箱账号ID */ + private Long emailAccountId; + /** 收件人邮箱列表 */ + private List toList; + /** 邮件主题 */ + private String subject; + /** 邮件正文 */ + private String content; +} \ No newline at end of file diff --git a/ruoyi-oa/src/main/java/com/ruoyi/oa/domain/vo/OaEmailAccountVo.java b/ruoyi-oa/src/main/java/com/ruoyi/oa/domain/vo/OaEmailAccountVo.java new file mode 100644 index 0000000..ada6c25 --- /dev/null +++ b/ruoyi-oa/src/main/java/com/ruoyi/oa/domain/vo/OaEmailAccountVo.java @@ -0,0 +1,83 @@ +package com.ruoyi.oa.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.ruoyi.common.annotation.ExcelDictFormat; +import com.ruoyi.common.convert.ExcelDictConvert; +import lombok.Data; +import java.util.Date; + + + +/** + * 发件人邮箱账号管理视图对象 oa_email_account + * + * @author Joshi + * @date 2025-07-10 + */ +@Data +@ExcelIgnoreUnannotated +public class OaEmailAccountVo { + + private static final long serialVersionUID = 1L; + + /** + * + */ + @ExcelProperty(value = "") + private Long emailId; + + /** + * 邮箱账号 + */ + @ExcelProperty(value = "邮箱账号") + private String email; + + /** + * 邮箱授权码/密码(SMTP方式用) + */ + @ExcelProperty(value = "邮箱授权码/密码", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "S=MTP方式用") + private String password; + + /** + * SMTP服务器地址(SMTP方式用) + */ + @ExcelProperty(value = "SMTP服务器地址", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "S=MTP方式用") + private String smtpHost; + + /** + * SMTP端口(SMTP方式用) + */ + @ExcelProperty(value = "SMTP端口", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "S=MTP方式用") + private Long smtpPort; + + /** + * API方式用accessKey + */ + @ExcelProperty(value = "API方式用accessKey") + private String accessKey; + + /** + * API方式用secretKey + */ + @ExcelProperty(value = "API方式用secretKey") + private String secretKey; + + /** + * 邮箱类型(0网易 1QQ 2阿里云API 3SendGridAPI等) + */ + @ExcelProperty(value = "邮箱类型", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=网易,1=QQ,2=阿里云API,3=SendGridAPI等") + private Long type; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + +} diff --git a/ruoyi-oa/src/main/java/com/ruoyi/oa/mapper/OaEmailAccountMapper.java b/ruoyi-oa/src/main/java/com/ruoyi/oa/mapper/OaEmailAccountMapper.java new file mode 100644 index 0000000..5b6ecd6 --- /dev/null +++ b/ruoyi-oa/src/main/java/com/ruoyi/oa/mapper/OaEmailAccountMapper.java @@ -0,0 +1,15 @@ +package com.ruoyi.oa.mapper; + +import com.ruoyi.oa.domain.OaEmailAccount; +import com.ruoyi.oa.domain.vo.OaEmailAccountVo; +import com.ruoyi.common.core.mapper.BaseMapperPlus; + +/** + * 发件人邮箱账号管理Mapper接口 + * + * @author Joshi + * @date 2025-07-10 + */ +public interface OaEmailAccountMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-oa/src/main/java/com/ruoyi/oa/service/IOaEmailAccountService.java b/ruoyi-oa/src/main/java/com/ruoyi/oa/service/IOaEmailAccountService.java new file mode 100644 index 0000000..6a465ec --- /dev/null +++ b/ruoyi-oa/src/main/java/com/ruoyi/oa/service/IOaEmailAccountService.java @@ -0,0 +1,55 @@ +package com.ruoyi.oa.service; + +import com.ruoyi.oa.domain.OaEmailAccount; +import com.ruoyi.oa.domain.request.EmailSendRequest; +import com.ruoyi.oa.domain.vo.OaEmailAccountVo; +import com.ruoyi.oa.domain.bo.OaEmailAccountBo; +import com.ruoyi.common.core.page.TableDataInfo; +import com.ruoyi.common.core.domain.PageQuery; + +import java.util.Collection; +import java.util.List; + +/** + * 发件人邮箱账号管理Service接口 + * + * @author Joshi + * @date 2025-07-10 + */ +public interface IOaEmailAccountService { + + /** + * 查询发件人邮箱账号管理 + */ + OaEmailAccountVo queryById(Long emailId); + + /** + * 查询发件人邮箱账号管理列表 + */ + TableDataInfo queryPageList(OaEmailAccountBo bo, PageQuery pageQuery); + + /** + * 查询发件人邮箱账号管理列表 + */ + List queryList(OaEmailAccountBo bo); + + /** + * 新增发件人邮箱账号管理 + */ + Boolean insertByBo(OaEmailAccountBo bo); + + /** + * 修改发件人邮箱账号管理 + */ + Boolean updateByBo(OaEmailAccountBo bo); + + /** + * 校验并批量删除发件人邮箱账号管理信息 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 批量发送邮件(支持网易企业邮箱、飞书SMTP) + */ + String sendBatchEmail(EmailSendRequest request); +} diff --git a/ruoyi-oa/src/main/java/com/ruoyi/oa/service/impl/OaEmailAccountServiceImpl.java b/ruoyi-oa/src/main/java/com/ruoyi/oa/service/impl/OaEmailAccountServiceImpl.java new file mode 100644 index 0000000..046c97b --- /dev/null +++ b/ruoyi-oa/src/main/java/com/ruoyi/oa/service/impl/OaEmailAccountServiceImpl.java @@ -0,0 +1,226 @@ +package com.ruoyi.oa.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.common.core.page.TableDataInfo; +import com.ruoyi.common.core.domain.PageQuery; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import com.ruoyi.oa.domain.bo.OaEmailAccountBo; +import com.ruoyi.oa.domain.vo.OaEmailAccountVo; +import com.ruoyi.oa.domain.OaEmailAccount; +import com.ruoyi.oa.mapper.OaEmailAccountMapper; +import com.ruoyi.oa.service.IOaEmailAccountService; +import com.ruoyi.oa.domain.request.EmailSendRequest; +import cn.hutool.extra.mail.MailAccount; +import cn.hutool.extra.mail.MailUtil; + +import java.util.List; +import java.util.Map; +import java.util.Collection; + +/** + * 发件人邮箱账号管理Service业务层处理 + * + * @author Joshi + * @date 2025-07-10 + */ +@RequiredArgsConstructor +@Service +public class OaEmailAccountServiceImpl implements IOaEmailAccountService { + + private final OaEmailAccountMapper baseMapper; + + /** + * 查询发件人邮箱账号管理 + */ + @Override + public OaEmailAccountVo queryById(Long emailId){ + return baseMapper.selectVoById(emailId); + } + + /** + * 查询发件人邮箱账号管理列表 + */ + @Override + public TableDataInfo queryPageList(OaEmailAccountBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } + + /** + * 查询发件人邮箱账号管理列表 + */ + @Override + public List queryList(OaEmailAccountBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(OaEmailAccountBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(StringUtils.isNotBlank(bo.getEmail()), OaEmailAccount::getEmail, bo.getEmail()); + lqw.eq(StringUtils.isNotBlank(bo.getPassword()), OaEmailAccount::getPassword, bo.getPassword()); + lqw.eq(StringUtils.isNotBlank(bo.getSmtpHost()), OaEmailAccount::getSmtpHost, bo.getSmtpHost()); + lqw.eq(bo.getSmtpPort() != null, OaEmailAccount::getSmtpPort, bo.getSmtpPort()); + lqw.eq(StringUtils.isNotBlank(bo.getAccessKey()), OaEmailAccount::getAccessKey, bo.getAccessKey()); + lqw.eq(StringUtils.isNotBlank(bo.getSecretKey()), OaEmailAccount::getSecretKey, bo.getSecretKey()); + lqw.eq(bo.getType() != null, OaEmailAccount::getType, bo.getType()); + return lqw; + } + + /** + * 新增发件人邮箱账号管理 + */ + @Override + public Boolean insertByBo(OaEmailAccountBo bo) { + OaEmailAccount add = BeanUtil.toBean(bo, OaEmailAccount.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setEmailId(add.getEmailId()); + } + return flag; + } + + /** + * 修改发件人邮箱账号管理 + */ + @Override + public Boolean updateByBo(OaEmailAccountBo bo) { + OaEmailAccount update = BeanUtil.toBean(bo, OaEmailAccount.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(OaEmailAccount entity){ + //TODO 做一些数据校验,如唯一约束 + } + + /** + * 批量删除发件人邮箱账号管理 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if(isValid){ + //TODO 做一些业务上的校验,判断是否需要校验 + } + return baseMapper.deleteBatchIds(ids) > 0; + } + + @Override + public String sendBatchEmail(EmailSendRequest request) { + OaEmailAccount account = baseMapper.selectById(request.getEmailAccountId()); + if (account == null) { + return "发件人邮箱账号不存在"; + } + int type = account.getType() == null ? -1 : account.getType().intValue(); + int success = 0, fail = 0; + StringBuilder failList = new StringBuilder(); + + if (type == 0 || type == 1) { + // 网易/QQ邮箱 SMTP方式(已实现) + MailAccount mailAccount = new MailAccount(); + mailAccount.setHost(account.getSmtpHost()); + mailAccount.setPort(account.getSmtpPort() == null ? 465 : account.getSmtpPort().intValue()); + mailAccount.setAuth(true); + mailAccount.setFrom(account.getEmail()); + mailAccount.setUser(account.getEmail()); + mailAccount.setPass(account.getPassword()); + mailAccount.setSslEnable(true); + for (String to : request.getToList()) { + try { + MailUtil.send(mailAccount, to, request.getSubject(), request.getContent(), false); + success++; + } catch (Exception e) { + fail++; + failList.append(to).append(", "); + } + } + } +// else if (type == 2) { +// // 阿里云邮件推送API +// for (String to : request.getToList()) { +// try { +// boolean result = sendAliyunMail(account, to, request.getSubject(), request.getContent()); +// if (result) { +// success++; +// } else { +// fail++; +// failList.append(to).append(", "); +// } +// } catch (Exception e) { +// fail++; +// failList.append(to).append(", "); +// } +// } +// } else if (type == 3) { +// // 飞书邮件API +// for (String to : request.getToList()) { +// try { +// boolean result = sendFeishuMail(account, to, request.getSubject(), request.getContent()); +// if (result) { +// success++; +// } else { +// fail++; +// failList.append(to).append(", "); +// } +// } catch (Exception e) { +// fail++; +// failList.append(to).append(", "); +// } +// } +// } + else { + return "不支持的邮箱类型"; + } + return "发送成功" + success + "封,失败" + fail + "封" + (fail > 0 ? (",失败邮箱:" + failList) : ""); + } +// private boolean sendAliyunMail(OaEmailAccount account, String to, String subject, String content) { +// try { +// DefaultProfile profile = DefaultProfile.getProfile( +// "cn-hangzhou", +// account.getAccessKey(), +// account.getSecretKey() +// ); +// IAcsClient client = new DefaultAcsClient(profile); +// +// SingleSendMailRequest request = new SingleSendMailRequest(); +// request.setAccountName(account.getEmail()); +// request.setFromAlias("发件人昵称"); +// request.setAddressType(1); +// request.setReplyToAddress(true); +// request.setToAddress(to); +// request.setSubject(subject); +// request.setHtmlBody(content); +// +// SingleSendMailResponse response = client.getAcsResponse(request); +// return true; +// } catch (ClientException e) { +// // 打印日志 e.getErrCode() + e.getErrMsg() +// return false; +// } +// } +// private boolean sendFeishuMail(OaEmailAccount account, String to, String subject, String content) { +// // 1. 获取access_token(用account.getAccessKey()/getSecretKey()) +// // 2. 调用飞书邮件API发送邮件 +// // 这里只做伪代码,实际需查飞书开放平台文档 +// try { +// // String accessToken = getFeishuAccessToken(account.getAccessKey(), account.getSecretKey()); +// // 用accessToken和邮件参数发POST请求 +// // RestTemplate restTemplate = new RestTemplate(); +// // String response = restTemplate.postForObject(apiUrl, params, String.class); +// return true; +// } catch (Exception e) { +// return false; +// } +// } +} diff --git a/ruoyi-oa/src/main/resources/mapper/oa/OaEmailAccountMapper.xml b/ruoyi-oa/src/main/resources/mapper/oa/OaEmailAccountMapper.xml new file mode 100644 index 0000000..ee049d9 --- /dev/null +++ b/ruoyi-oa/src/main/resources/mapper/oa/OaEmailAccountMapper.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + +