From 0b40608761f23e82b43dd5c46f780781579907f0 Mon Sep 17 00:00:00 2001 From: gaoxq <376340421@qq.com> Date: Sun, 14 Dec 2025 14:21:32 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E9=A2=84=E8=AD=A6=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jeesite/modules/app/dao/MailReceived.java | 24 + .../modules/app/utils/LoggerUtils.java | 1 + .../modules/app/utils/MailReceiveUtils.java | 666 ++++++++++++++++++ .../modules/biz/dao/BizMailAccountDao.java | 15 + .../biz/dao/BizMailAttachmentsDao.java | 15 + .../modules/biz/dao/BizMailReceivedDao.java | 15 + .../modules/biz/dao/BizMailSentDao.java | 15 + .../modules/biz/entity/BizMailAccount.java | 114 +++ .../biz/entity/BizMailAttachments.java | 115 +++ .../modules/biz/entity/BizMailReceived.java | 113 +++ .../modules/biz/entity/BizMailSent.java | 114 +++ .../biz/service/BizMailAccountService.java | 134 ++++ .../service/BizMailAttachmentsService.java | 134 ++++ .../biz/service/BizMailReceivedService.java | 134 ++++ .../biz/service/BizMailSentService.java | 137 ++++ .../biz/web/BizMailAccountController.java | 191 +++++ .../biz/web/BizMailAttachmentsController.java | 146 ++++ .../biz/web/BizMailReceivedController.java | 146 ++++ .../biz/web/BizMailSentController.java | 146 ++++ .../modules/biz/BizMailAccountDao.xml | 15 + .../modules/biz/BizMailAttachmentsDao.xml | 15 + .../modules/biz/BizMailReceivedDao.xml | 15 + .../mappings/modules/biz/BizMailSentDao.xml | 15 + web-vue/packages/biz/api/biz/mailAccount.ts | 63 ++ .../packages/biz/api/biz/mailAttachments.ts | 55 ++ web-vue/packages/biz/api/biz/mailReceived.ts | 58 ++ web-vue/packages/biz/api/biz/mailSent.ts | 60 ++ .../packages/biz/views/biz/dbConfig/form.vue | 2 +- .../biz/views/biz/mailInfo/account/form.vue | 186 +++++ .../views/biz/mailInfo/account/formImport.vue | 103 +++ .../biz/views/biz/mailInfo/account/list.vue | 311 ++++++++ .../biz/views/biz/mailInfo/account/select.ts | 180 +++++ .../biz/mailInfo/attachments/formImport.vue | 103 +++ .../views/biz/mailInfo/attachments/list.vue | 258 +++++++ .../packages/biz/views/biz/mailInfo/index.vue | 39 + .../biz/mailInfo/received/formImport.vue | 103 +++ .../biz/views/biz/mailInfo/received/list.vue | 227 ++++++ .../biz/views/biz/mailInfo/sent/form.vue | 137 ++++ .../views/biz/mailInfo/sent/formImport.vue | 103 +++ .../biz/views/biz/mailInfo/sent/list.vue | 252 +++++++ .../biz/views/biz/mailInfo/sent/select.ts | 196 ++++++ web-vue/packages/core/views/sys/menu/form.vue | 2 +- 42 files changed, 4871 insertions(+), 2 deletions(-) create mode 100644 web-api/src/main/java/com/jeesite/modules/app/dao/MailReceived.java create mode 100644 web-api/src/main/java/com/jeesite/modules/app/utils/MailReceiveUtils.java create mode 100644 web-api/src/main/java/com/jeesite/modules/biz/dao/BizMailAccountDao.java create mode 100644 web-api/src/main/java/com/jeesite/modules/biz/dao/BizMailAttachmentsDao.java create mode 100644 web-api/src/main/java/com/jeesite/modules/biz/dao/BizMailReceivedDao.java create mode 100644 web-api/src/main/java/com/jeesite/modules/biz/dao/BizMailSentDao.java create mode 100644 web-api/src/main/java/com/jeesite/modules/biz/entity/BizMailAccount.java create mode 100644 web-api/src/main/java/com/jeesite/modules/biz/entity/BizMailAttachments.java create mode 100644 web-api/src/main/java/com/jeesite/modules/biz/entity/BizMailReceived.java create mode 100644 web-api/src/main/java/com/jeesite/modules/biz/entity/BizMailSent.java create mode 100644 web-api/src/main/java/com/jeesite/modules/biz/service/BizMailAccountService.java create mode 100644 web-api/src/main/java/com/jeesite/modules/biz/service/BizMailAttachmentsService.java create mode 100644 web-api/src/main/java/com/jeesite/modules/biz/service/BizMailReceivedService.java create mode 100644 web-api/src/main/java/com/jeesite/modules/biz/service/BizMailSentService.java create mode 100644 web-api/src/main/java/com/jeesite/modules/biz/web/BizMailAccountController.java create mode 100644 web-api/src/main/java/com/jeesite/modules/biz/web/BizMailAttachmentsController.java create mode 100644 web-api/src/main/java/com/jeesite/modules/biz/web/BizMailReceivedController.java create mode 100644 web-api/src/main/java/com/jeesite/modules/biz/web/BizMailSentController.java create mode 100644 web-api/src/main/resources/mappings/modules/biz/BizMailAccountDao.xml create mode 100644 web-api/src/main/resources/mappings/modules/biz/BizMailAttachmentsDao.xml create mode 100644 web-api/src/main/resources/mappings/modules/biz/BizMailReceivedDao.xml create mode 100644 web-api/src/main/resources/mappings/modules/biz/BizMailSentDao.xml create mode 100644 web-vue/packages/biz/api/biz/mailAccount.ts create mode 100644 web-vue/packages/biz/api/biz/mailAttachments.ts create mode 100644 web-vue/packages/biz/api/biz/mailReceived.ts create mode 100644 web-vue/packages/biz/api/biz/mailSent.ts create mode 100644 web-vue/packages/biz/views/biz/mailInfo/account/form.vue create mode 100644 web-vue/packages/biz/views/biz/mailInfo/account/formImport.vue create mode 100644 web-vue/packages/biz/views/biz/mailInfo/account/list.vue create mode 100644 web-vue/packages/biz/views/biz/mailInfo/account/select.ts create mode 100644 web-vue/packages/biz/views/biz/mailInfo/attachments/formImport.vue create mode 100644 web-vue/packages/biz/views/biz/mailInfo/attachments/list.vue create mode 100644 web-vue/packages/biz/views/biz/mailInfo/index.vue create mode 100644 web-vue/packages/biz/views/biz/mailInfo/received/formImport.vue create mode 100644 web-vue/packages/biz/views/biz/mailInfo/received/list.vue create mode 100644 web-vue/packages/biz/views/biz/mailInfo/sent/form.vue create mode 100644 web-vue/packages/biz/views/biz/mailInfo/sent/formImport.vue create mode 100644 web-vue/packages/biz/views/biz/mailInfo/sent/list.vue create mode 100644 web-vue/packages/biz/views/biz/mailInfo/sent/select.ts diff --git a/web-api/src/main/java/com/jeesite/modules/app/dao/MailReceived.java b/web-api/src/main/java/com/jeesite/modules/app/dao/MailReceived.java new file mode 100644 index 00000000..8b3cd771 --- /dev/null +++ b/web-api/src/main/java/com/jeesite/modules/app/dao/MailReceived.java @@ -0,0 +1,24 @@ +package com.jeesite.modules.app.dao; + +import com.jeesite.modules.biz.entity.BizMailAttachments; +import com.jeesite.modules.biz.entity.BizMailReceived; +import lombok.Data; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +@Data +public class MailReceived implements Serializable { + + private BizMailReceived received; + + private List attachments = new ArrayList<>(); + + + public MailReceived(BizMailReceived received, List attachments) { + this.received = received; + this.attachments = attachments; + } + +} diff --git a/web-api/src/main/java/com/jeesite/modules/app/utils/LoggerUtils.java b/web-api/src/main/java/com/jeesite/modules/app/utils/LoggerUtils.java index 45836918..887b438d 100644 --- a/web-api/src/main/java/com/jeesite/modules/app/utils/LoggerUtils.java +++ b/web-api/src/main/java/com/jeesite/modules/app/utils/LoggerUtils.java @@ -144,6 +144,7 @@ public class LoggerUtils { StandardCharsets.UTF_8 // 避免中文乱码 ) )) { + System.out.print(logContent); writer.write(logContent.toString()); writer.flush(); } catch (IOException e) { diff --git a/web-api/src/main/java/com/jeesite/modules/app/utils/MailReceiveUtils.java b/web-api/src/main/java/com/jeesite/modules/app/utils/MailReceiveUtils.java new file mode 100644 index 00000000..867e9684 --- /dev/null +++ b/web-api/src/main/java/com/jeesite/modules/app/utils/MailReceiveUtils.java @@ -0,0 +1,666 @@ +package com.jeesite.modules.app.utils; + +import com.jeesite.modules.app.dao.MailReceived; +import com.jeesite.modules.biz.entity.BizMailAccount; +import com.jeesite.modules.biz.entity.BizMailAttachments; +import com.jeesite.modules.biz.entity.BizMailReceived; + +import javax.activation.MimetypesFileTypeMap; +import javax.mail.*; +import javax.mail.internet.*; +import javax.mail.search.FlagTerm; +import java.io.*; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.StandardOpenOption; +import java.security.MessageDigest; +import java.util.*; + +public class MailReceiveUtils { + + // 连接重试配置 + private static final int CONNECT_RETRY_TIMES = 3; + private static final long CONNECT_RETRY_INTERVAL = 1000L; + private static final LoggerUtils logger = LoggerUtils.getInstance(); + + // 缓存ByteBuffer + private static final ThreadLocal BUFFER_LOCAL = ThreadLocal.withInitial(() -> ByteBuffer.allocate(8192)); + + // MIME类型映射(修复附件FileType识别) + private static final MimetypesFileTypeMap MIME_TYPE_MAP = new MimetypesFileTypeMap(); + + static { + // 扩展MIME类型映射,解决常见文件类型识别错误 + MIME_TYPE_MAP.addMimeTypes("application/pdf pdf"); + MIME_TYPE_MAP.addMimeTypes("application/msword doc"); + MIME_TYPE_MAP.addMimeTypes("application/vnd.openxmlformats-officedocument.wordprocessingml.document docx"); + MIME_TYPE_MAP.addMimeTypes("application/vnd.ms-excel xls"); + MIME_TYPE_MAP.addMimeTypes("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx"); + MIME_TYPE_MAP.addMimeTypes("application/vnd.ms-powerpoint ppt"); + MIME_TYPE_MAP.addMimeTypes("application/vnd.openxmlformats-officedocument.presentationml.presentation pptx"); + MIME_TYPE_MAP.addMimeTypes("image/jpeg jpg jpeg"); + MIME_TYPE_MAP.addMimeTypes("image/png png"); + MIME_TYPE_MAP.addMimeTypes("image/gif gif"); + MIME_TYPE_MAP.addMimeTypes("application/zip zip"); + MIME_TYPE_MAP.addMimeTypes("application/x-rar-compressed rar"); + MIME_TYPE_MAP.addMimeTypes("application/x-7z-compressed 7z"); + } + + /** + * 接收未读邮件(优化:优先解析HTML格式正文) + */ + public static List receiveUnreadMails(BizMailAccount mailAccount, String saveBasePath) throws Exception { + List receivedMailList = new ArrayList<>(); + Session session = createMailSession(mailAccount); + Store store = null; + Folder folder = null; + + try { + // 1. 建立IMAP连接(带重试) + store = session.getStore("imap"); + boolean isConnected = false; + int retryCount = 0; + while (!isConnected) { + try { + store.connect(mailAccount.getHost(), mailAccount.getImapPort(), + mailAccount.getUsername(), mailAccount.getPassword()); + isConnected = store.isConnected(); + if (isConnected) { + logger.info("第" + (retryCount + 1) + "次连接IMAP成功:" + mailAccount.getHost()); + } + } catch (AuthenticationFailedException e) { + logger.error("账号/密码错误,直接返回", e); + return receivedMailList; + } catch (MessagingException e) { + retryCount++; + logger.error("第" + retryCount + "次连接失败:" + e.getMessage()); + if (retryCount >= CONNECT_RETRY_TIMES) { + throw new IllegalStateException("IMAP连接失败(重试3次)", e); + } + Thread.sleep(CONNECT_RETRY_INTERVAL); + } + } + + // 2. 打开收件箱 + folder = store.getFolder("INBOX"); + if (folder == null || !folder.exists()) { + logger.error("收件箱不存在"); + return receivedMailList; + } + folder.open(Folder.READ_WRITE); + logger.info("未读邮件数:" + folder.getUnreadMessageCount()); + + // 3. 筛选未读邮件 + Message[] unreadMessages = folder.search(new FlagTerm(new Flags(Flags.Flag.SEEN), false)); + if (unreadMessages == null || unreadMessages.length == 0) { + logger.warn("无未读邮件"); + return receivedMailList; + } + + // 4. 处理每封邮件 + for (Message message : unreadMessages) { + try { + BizMailReceived bizMail = buildBizMailReceived(message, mailAccount); + // 记录整封邮件附件下载开始时间 + long mailAttachDownloadStart = System.currentTimeMillis(); + logger.info("开始下载邮件[" + getMessageId(message) + "]的附件,开始时间:" + new Date(mailAttachDownloadStart)); + + List attachments = downloadExplicitAttachments(message, bizMail.getMessageId(), saveBasePath); + + // 记录整封邮件附件下载结束时间 + long mailAttachDownloadEnd = System.currentTimeMillis(); + logger.info("完成下载邮件[" + getMessageId(message) + "]的附件,结束时间:" + new Date(mailAttachDownloadEnd) + + ",耗时:" + (mailAttachDownloadEnd - mailAttachDownloadStart) + "ms"); + + receivedMailList.add(new MailReceived(bizMail, attachments)); + message.setFlag(Flags.Flag.SEEN, true); // 标记已读 + } catch (Exception e) { + logger.error("处理邮件失败(Message-ID:" + getMessageId(message) + "):" + e.getMessage(), e); + continue; + } + } + + } finally { + // 关闭资源 + if (folder != null && folder.isOpen()) { + try { + folder.close(true); + } catch (MessagingException e) { + logger.error("关闭文件夹失败", e); + } + } + if (store != null && store.isConnected()) { + try { + store.close(); + } catch (MessagingException e) { + logger.error("关闭连接失败", e); + } + } + BUFFER_LOCAL.remove(); + } + + return receivedMailList; + } + + /** + * 创建邮件会话(优化编码+IMAP配置) + */ + private static Session createMailSession(BizMailAccount mailAccount) { + Properties props = new Properties(); + boolean sslEnable = "true".equals(mailAccount.getSslEnable()); + props.put("mail.imap.host", mailAccount.getHost()); + props.put("mail.imap.port", mailAccount.getImapPort()); + props.put("mail.imap.ssl.enable", sslEnable); + props.put("mail.imap.ssl.protocols", "TLSv1.2"); // 强制TLS1.2,避免SSL漏洞 + props.put("mail.imap.auth", "true"); + props.put("mail.imap.connectiontimeout", "10000"); + props.put("mail.imap.timeout", "30000"); + props.put("mail.imap.partialfetch", "false"); // 禁用部分获取,避免内容截断 + props.put("mail.mime.charset", "UTF-8"); + props.put("mail.mime.base64.ignoreerrors", "true"); + props.put("mail.mime.decodefilenamehandler", "com.sun.mail.imap.protocol.IMAPUTF8DecodeHandler"); + // 关键:启用UTF-8文件名解码 + System.setProperty("mail.mime.encodeparameters", "false"); + + return Session.getInstance(props, new Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(mailAccount.getUsername(), mailAccount.getPassword()); + } + }); + } + + /** + * 构建邮件实体(核心优化:优先解析HTML正文) + */ + private static BizMailReceived buildBizMailReceived(Message message, BizMailAccount mailAccount) throws Exception { + BizMailReceived received = new BizMailReceived(); + received.setCreateTime(new Date()); + received.setMessageId(getMessageId(message)); + received.setAccountId(mailAccount.getId()); + received.setUstatus("1"); + received.setMailbox("INBOX"); + + // 发件人(修复编码) + Address[] from = message.getFrom(); + if (from != null && from.length > 0) { + InternetAddress fromAddr = (InternetAddress) from[0]; + received.setFromAddress(fromAddr.getAddress()); + // 优先解码发件人名称 + String personal = fromAddr.getPersonal(); + if (personal != null) { + received.setFromName(decodeMimeText(personal)); + } else { + received.setFromName(fromAddr.getAddress()); + } + } + + // 收件人/抄送/密送(修复编码) + received.setToAddresses(convertAddresses(message.getRecipients(Message.RecipientType.TO))); + received.setCcAddresses(convertAddresses(message.getRecipients(Message.RecipientType.CC))); + received.setBccAddresses(convertAddresses(message.getRecipients(Message.RecipientType.BCC))); + + // 主题(修复乱码) + String subject = message.getSubject(); + received.setSubject(subject == null ? "" : decodeMimeText(subject)); + + // 核心优化:优先解析HTML格式正文 + String htmlContent = parseHtmlMailContent(message); + // 最终空内容兜底 + received.setMailContent(htmlContent.isEmpty() ? "

(无正文内容)

" : htmlContent); + + // 时间 + received.setReceivedTime(new Date()); + received.setSendTime(message.getSentDate() != null ? message.getSentDate() : new Date()); + + // 是否有显式附件 + received.setHasAttachment(hasExplicitAttachment(message) ? "1" : "0"); + + return received; + } + + /** + * 核心优化:专门解析HTML格式正文(优先提取HTML,无则将纯文本转为HTML) + */ + private static String parseHtmlMailContent(Message message) throws Exception { + Object content = message.getContent(); + StringBuilder htmlSb = new StringBuilder(); + + // 递归提取HTML内容 + extractHtmlContentRecursive(content, htmlSb); + + // 清理HTML内容,去除无效标签和空白 + String rawHtml = htmlSb.toString().replaceAll("\\n+", "").replaceAll("\\s+", " ").trim(); + // 如果没有提取到HTML内容,尝试提取纯文本并转为HTML格式 + if (rawHtml.isEmpty()) { + String plainText = extractPlainTextContent(message); + if (!plainText.isEmpty()) { + // 将纯文本转为基本HTML格式(换行转
,空格转 ) + rawHtml = "

" + plainText.replaceAll("\\n", "
").replaceAll(" ", " ") + "

"; + } + } + + // 标准化HTML结构 + return standardizeHtml(rawHtml); + } + + /** + * 递归提取HTML内容(优先获取text/html类型) + */ + private static void extractHtmlContentRecursive(Object content, StringBuilder sb) throws Exception { + if (content == null) { + return; + } + + // 1. 直接是HTML文本(极少情况) + if (content instanceof String text) { + if (text.contains("") || text.contains("") || text.contains("

") || text.contains("
")) { + sb.append(text); + } + return; + } + + // 2. MimeMultipart:优先提取text/html部分 + if (content instanceof MimeMultipart multipart) { + String multipartType = multipart.getContentType().split(";")[0].trim().toLowerCase(); + + // 处理multipart/alternative(多格式正文,优先取text/html) + if ("multipart/alternative".equals(multipartType)) { + for (int i = 0; i < multipart.getCount(); i++) { + BodyPart part = multipart.getBodyPart(i); + String partType = part.getContentType().split(";")[0].trim().toLowerCase(); + if ("text/html".equals(partType)) { + // 读取HTML内容并追加 + sb.append(readBodyPartContent(part)); + return; // 找到HTML后直接返回,不再处理其他部分 + } + } + } + + // 处理其他multipart类型(递归提取所有HTML部分) + for (int i = 0; i < multipart.getCount(); i++) { + BodyPart bodyPart = multipart.getBodyPart(i); + String disposition = bodyPart.getDisposition(); + + // 跳过显式附件 + if (Part.ATTACHMENT.equalsIgnoreCase(disposition)) { + continue; + } + + // 提取HTML内容 + String partType = bodyPart.getContentType().split(";")[0].trim().toLowerCase(); + if ("text/html".equals(partType)) { + sb.append(readBodyPartContent(bodyPart)); + } else { + // 递归解析子内容 + extractHtmlContentRecursive(bodyPart.getContent(), sb); + } + } + return; + } + + // 3. 单个MimeBodyPart:如果是HTML类型则读取 + if (content instanceof MimeBodyPart bodyPart) { + String disposition = bodyPart.getDisposition(); + // 跳过显式附件 + if (Part.ATTACHMENT.equalsIgnoreCase(disposition)) { + return; + } + + String partType = bodyPart.getContentType().split(";")[0].trim().toLowerCase(); + if ("text/html".equals(partType)) { + sb.append(readBodyPartContent(bodyPart)); + } + } + } + + /** + * 提取纯文本内容(作为HTML的降级方案) + */ + private static String extractPlainTextContent(Message message) throws Exception { + Object content = message.getContent(); + StringBuilder plainSb = new StringBuilder(); + + extractPlainTextRecursive(content, plainSb); + + return plainSb.toString().replaceAll("^\\s+|\\s+$", "").replaceAll("\\n+", "\n"); + } + + /** + * 递归提取纯文本内容 + */ + private static void extractPlainTextRecursive(Object content, StringBuilder sb) throws Exception { + if (content == null) { + return; + } + + // 纯文本直接追加 + if (content instanceof String) { + String text = ((String) content).trim(); + if (!text.isEmpty()) { + sb.append(text).append("\n"); + } + return; + } + + // 处理MimeMultipart + if (content instanceof MimeMultipart multipart) { + for (int i = 0; i < multipart.getCount(); i++) { + BodyPart bodyPart = multipart.getBodyPart(i); + // 跳过附件 + if (Part.ATTACHMENT.equalsIgnoreCase(bodyPart.getDisposition())) { + continue; + } + // 提取纯文本 + extractPlainTextRecursive(bodyPart.getContent(), sb); + } + return; + } + + // 处理单个BodyPart + if (content instanceof MimeBodyPart bodyPart) { + if (Part.ATTACHMENT.equalsIgnoreCase(bodyPart.getDisposition())) { + return; + } + // 读取纯文本内容 + String partContent = readBodyPartContent(bodyPart); + if (!partContent.isEmpty()) { + sb.append(partContent).append("\n"); + } + } + } + + /** + * 标准化HTML结构(补全基本标签,确保格式合法) + */ + private static String standardizeHtml(String html) { + if (html.isEmpty()) { + return ""; + } + + // 补全HTML基本结构 + if (!html.startsWith("")) { + html = "" + html + ""; + } + + // 修复常见的HTML格式问题 + html = html.replaceAll("
", "
") + .replaceAll("


", "
") + .replaceAll("&", "&") + .replaceAll("

\\s*

", "") // 移除空p标签 + .replaceAll(">\\s+<", "><"); // 移除标签间多余空格 + + return html; + } + + /** + * 读取BodyPart内容(优先原始流,自动识别编码) + */ + private static String readBodyPartContent(BodyPart part) throws Exception { + // 1. 获取ContentType和编码 + String contentType = part.getContentType() == null ? "" : part.getContentType().toLowerCase(); + Charset charset = getCharsetFromContentType(contentType); + + // 2. 优先读取原始输入流(避免getContent()的自动转换错误) + try (InputStream is = part.getInputStream(); + BufferedInputStream bis = new BufferedInputStream(is); + BufferedReader reader = new BufferedReader(new InputStreamReader(bis, charset))) { + + StringBuilder sb = new StringBuilder(); + char[] buffer = new char[4096]; + int bytesRead; + while ((bytesRead = reader.read(buffer)) != -1) { + sb.append(buffer, 0, bytesRead); + } + // 清理无效字符 + return sb.toString(); + } catch (Exception e) { + logger.warn("读取BodyPart流失败:" + e.getMessage()); + Object fallbackContent = part.getContent(); + return fallbackContent instanceof String ? ((String) fallbackContent).trim() : ""; + } + } + + /** + * 获取邮件内容 + */ + private static Charset getCharsetFromContentType(String contentType) { + if (contentType == null || contentType.isEmpty()) { + return StandardCharsets.UTF_8; + } + + // 提取charset参数(支持多种格式) + String charsetStr = null; + String[] parts = contentType.split(";"); + for (String part : parts) { + part = part.trim().toLowerCase(); + if (part.startsWith("charset=")) { + charsetStr = part.substring("charset=".length()).trim() + .replace("\"", "").replace("'", ""); + break; + } + } + + // 验证编码有效性 + if (charsetStr != null && !charsetStr.isEmpty()) { + try { + return Charset.forName(charsetStr); + } catch (Exception e) { + logger.warn("不支持的编码:" + charsetStr + ",使用默认UTF-8"); + } + } + + // 兜底编码(优先GBK,兼容中文邮件) + try { + return Charset.forName("GBK"); + } catch (Exception e) { + return StandardCharsets.UTF_8; + } + } + + /** + * 解码MIME编码的文本(主题/发件人名称等) + */ + private static String decodeMimeText(String text) { + if (text == null || text.isEmpty()) { + return ""; + } + try { + return MimeUtility.decodeText(text); + } catch (UnsupportedEncodingException e) { + // 多级降级处理 + try { + return new String(text.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8); + } catch (Exception e1) { + try { + return new String(text.getBytes(StandardCharsets.ISO_8859_1), "GBK"); + } catch (Exception e2) { + try { + return new String(text.getBytes(StandardCharsets.ISO_8859_1), "GB2312"); + } catch (Exception e3) { + return text; + } + } + } + } + } + + /** + * 下载显式附件(保持原有逻辑) + */ + private static List downloadExplicitAttachments(Message message, String messageId, String saveBasePath) throws Exception { + List attachments = new ArrayList<>(); + if (!message.isMimeType("multipart/*")) { + return attachments; + } + + MimeMultipart multipart = (MimeMultipart) message.getContent(); + File saveDir = new File(saveBasePath); + if (!saveDir.exists()) { + Files.createDirectories(saveDir.toPath()); + } + + // 遍历所有显式附件 + for (int i = 0; i < multipart.getCount(); i++) { + BodyPart part = multipart.getBodyPart(i); + if (Part.ATTACHMENT.equalsIgnoreCase(part.getDisposition())) { + try { + BizMailAttachments attach = downloadSingleAttachment(part, messageId, saveDir); + attachments.add(attach); + } catch (Exception e) { + logger.error("单附件下载失败(文件名:" + part.getFileName() + "):" + e.getMessage(), e); + } + } + } + + return attachments; + } + + /** + * 下载单个附件(保持原有逻辑) + */ + private static BizMailAttachments downloadSingleAttachment(BodyPart part, String messageId, File saveDir) throws Exception { + BizMailAttachments attachment = new BizMailAttachments(); + + // 1. 记录单个附件下载开始时间 + long attachDownloadStartTime = System.currentTimeMillis(); + String originalFileName = part.getFileName(); + String fileNameForLog = originalFileName == null ? "未知文件名" : decodeMimeText(originalFileName); + logger.info("开始下载附件[" + fileNameForLog + "],开始时间:" + new Date(attachDownloadStartTime)); + + // 2. 修复:文件名解码(解决乱码) + if (originalFileName != null) { + originalFileName = decodeMimeText(originalFileName); + } else { + originalFileName = "unknown_" + System.currentTimeMillis(); + } + + // 3. 修复:附件FileType(优先从文件扩展名识别,解决ContentType错误) + String fileExt = getFileExtension(originalFileName); + String fileType = MIME_TYPE_MAP.getContentType(originalFileName); + // 降级处理:如果MIME类型为空,使用BodyPart的ContentType + if (fileType == null || fileType.isEmpty() || fileType.equals("application/octet-stream")) { + fileType = part.getContentType().split(";")[0].trim(); // 去除charset等参数 + } + + // 4. 计算MD5+保存文件 + MessageDigest md = MessageDigest.getInstance("MD5"); + ByteBuffer buffer = BUFFER_LOCAL.get(); + buffer.clear(); + + // 临时文件 + File tempFile = new File(saveDir, UUID.randomUUID().toString()); + try (InputStream is = part.getInputStream(); + FileChannel channel = FileChannel.open(tempFile.toPath(), StandardOpenOption.CREATE, StandardOpenOption.WRITE)) { + + int bytesRead; + while ((bytesRead = is.read(buffer.array())) != -1) { + md.update(buffer.array(), 0, bytesRead); + buffer.limit(bytesRead); + channel.write(buffer); + buffer.clear(); + } + } + + // MD5命名(避免重名) + String md5 = bytesToHex(md.digest()); + File finalFile = new File(saveDir, md5 + (fileExt.isEmpty() ? "" : "." + fileExt)); + + // 处理文件已存在 + if (finalFile.exists()) { + logger.warn("附件已存在(MD5:" + md5 + "),跳过重复保存"); + } else { + if (!tempFile.renameTo(finalFile)) { + logger.warn("附件重命名失败,使用临时文件名:" + tempFile.getName()); + finalFile = tempFile; + } + } + + // 5. 记录单个附件下载结束时间 + long attachDownloadEndTime = System.currentTimeMillis(); + long costTime = attachDownloadEndTime - attachDownloadStartTime; + logger.info("完成下载附件[" + originalFileName + "],结束时间:" + new Date(attachDownloadEndTime) + + ",耗时:" + costTime + "ms,文件路径:" + finalFile.getAbsolutePath()); + + // 6. 封装附件信息(修复FileType,增加下载时间字段) + attachment.setStoragePath(finalFile.getAbsolutePath()); + attachment.setFileSize(finalFile.length()); + attachment.setCreateTime(new Date()); + attachment.setTid(System.currentTimeMillis()); + attachment.setMailId(System.currentTimeMillis()); + attachment.setMessageId(messageId); + attachment.setFileName(originalFileName); + attachment.setFileType(fileType); // 修复后的MIME类型 + attachment.setFileExt(fileExt); + attachment.setFileMd5(md5); + attachment.setDownloadCount(0); + attachment.setIsCompressed(isCompressedFile(originalFileName) ? "1" : "0"); + attachment.setIsEncrypted("N"); + attachment.setDownloadStartTime(new Date(attachDownloadStartTime)); // 附件下载开始时间 + attachment.setDownloadEndTime(new Date(attachDownloadEndTime)); // 附件下载结束时间 + attachment.setDownloadCostTime(costTime); // 附件下载耗时(毫秒) + + return attachment; + } + + /** + * 判断是否有显式附件 + */ + private static boolean hasExplicitAttachment(Message message) throws Exception { + if (!message.isMimeType("multipart/*")) { + return false; + } + MimeMultipart multipart = (MimeMultipart) message.getContent(); + for (int i = 0; i < multipart.getCount(); i++) { + if (Part.ATTACHMENT.equalsIgnoreCase(multipart.getBodyPart(i).getDisposition())) { + return true; + } + } + return false; + } + + // ------------------------ 工具方法 ------------------------ + private static String getMessageId(Message message) throws MessagingException { + String[] ids = message.getHeader("Message-ID"); + if (ids != null && ids.length > 0) { + return ids[0].replace("<", "").replace(">", "").trim(); + } + return UUID.randomUUID().toString() + "@" + message.getSession().getProperty("mail.imap.host"); + } + + private static String convertAddresses(Address[] addresses) throws Exception { + if (addresses == null || addresses.length == 0) { + return ""; + } + StringBuilder sb = new StringBuilder(); + for (Address addr : addresses) { + sb.append(decodeMimeText(addr.toString())).append(","); + } + return !sb.isEmpty() ? sb.substring(0, sb.length() - 1) : ""; + } + + private static String getFileExtension(String fileName) { + if (fileName == null || !fileName.contains(".")) { + return ""; + } + return fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase(); + } + + private static boolean isCompressedFile(String fileName) { + Set exts = new HashSet<>(Arrays.asList("zip", "rar", "7z", "tar", "gz", "bz2")); + return exts.contains(getFileExtension(fileName)); + } + + private static String bytesToHex(byte[] bytes) { + char[] hex = new char[bytes.length * 2]; + for (int i = 0; i < bytes.length; i++) { + int v = bytes[i] & 0xFF; + hex[i * 2] = Character.forDigit(v >>> 4, 16); + hex[i * 2 + 1] = Character.forDigit(v & 0x0F, 16); + } + return new String(hex).toLowerCase(); + } +} \ No newline at end of file diff --git a/web-api/src/main/java/com/jeesite/modules/biz/dao/BizMailAccountDao.java b/web-api/src/main/java/com/jeesite/modules/biz/dao/BizMailAccountDao.java new file mode 100644 index 00000000..c1c55775 --- /dev/null +++ b/web-api/src/main/java/com/jeesite/modules/biz/dao/BizMailAccountDao.java @@ -0,0 +1,15 @@ +package com.jeesite.modules.biz.dao; + +import com.jeesite.common.dao.CrudDao; +import com.jeesite.common.mybatis.annotation.MyBatisDao; +import com.jeesite.modules.biz.entity.BizMailAccount; + +/** + * 邮件信息DAO接口 + * @author gaoxq + * @version 2025-12-14 + */ +@MyBatisDao(dataSourceName="work") +public interface BizMailAccountDao extends CrudDao { + +} \ No newline at end of file diff --git a/web-api/src/main/java/com/jeesite/modules/biz/dao/BizMailAttachmentsDao.java b/web-api/src/main/java/com/jeesite/modules/biz/dao/BizMailAttachmentsDao.java new file mode 100644 index 00000000..6dfa1c7f --- /dev/null +++ b/web-api/src/main/java/com/jeesite/modules/biz/dao/BizMailAttachmentsDao.java @@ -0,0 +1,15 @@ +package com.jeesite.modules.biz.dao; + +import com.jeesite.common.dao.CrudDao; +import com.jeesite.common.mybatis.annotation.MyBatisDao; +import com.jeesite.modules.biz.entity.BizMailAttachments; + +/** + * 邮件附件表DAO接口 + * @author gaoxq + * @version 2025-12-14 + */ +@MyBatisDao(dataSourceName="work") +public interface BizMailAttachmentsDao extends CrudDao { + +} \ No newline at end of file diff --git a/web-api/src/main/java/com/jeesite/modules/biz/dao/BizMailReceivedDao.java b/web-api/src/main/java/com/jeesite/modules/biz/dao/BizMailReceivedDao.java new file mode 100644 index 00000000..39081223 --- /dev/null +++ b/web-api/src/main/java/com/jeesite/modules/biz/dao/BizMailReceivedDao.java @@ -0,0 +1,15 @@ +package com.jeesite.modules.biz.dao; + +import com.jeesite.common.dao.CrudDao; +import com.jeesite.common.mybatis.annotation.MyBatisDao; +import com.jeesite.modules.biz.entity.BizMailReceived; + +/** + * 收件DAO接口 + * @author gaoxq + * @version 2025-12-14 + */ +@MyBatisDao(dataSourceName="work") +public interface BizMailReceivedDao extends CrudDao { + +} \ No newline at end of file diff --git a/web-api/src/main/java/com/jeesite/modules/biz/dao/BizMailSentDao.java b/web-api/src/main/java/com/jeesite/modules/biz/dao/BizMailSentDao.java new file mode 100644 index 00000000..e0adea4e --- /dev/null +++ b/web-api/src/main/java/com/jeesite/modules/biz/dao/BizMailSentDao.java @@ -0,0 +1,15 @@ +package com.jeesite.modules.biz.dao; + +import com.jeesite.common.dao.CrudDao; +import com.jeesite.common.mybatis.annotation.MyBatisDao; +import com.jeesite.modules.biz.entity.BizMailSent; + +/** + * 发件DAO接口 + * @author gaoxq + * @version 2025-12-14 + */ +@MyBatisDao(dataSourceName="work") +public interface BizMailSentDao extends CrudDao { + +} \ No newline at end of file diff --git a/web-api/src/main/java/com/jeesite/modules/biz/entity/BizMailAccount.java b/web-api/src/main/java/com/jeesite/modules/biz/entity/BizMailAccount.java new file mode 100644 index 00000000..498067fe --- /dev/null +++ b/web-api/src/main/java/com/jeesite/modules/biz/entity/BizMailAccount.java @@ -0,0 +1,114 @@ +package com.jeesite.modules.biz.entity; + +import java.io.Serializable; +import java.util.Date; + +import com.jeesite.common.mybatis.annotation.JoinTable; +import com.jeesite.common.mybatis.annotation.JoinTable.Type; +import com.fasterxml.jackson.annotation.JsonFormat; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; + +import com.jeesite.common.entity.DataEntity; +import com.jeesite.common.mybatis.annotation.Column; +import com.jeesite.common.mybatis.annotation.Table; +import com.jeesite.common.mybatis.mapper.query.QueryType; +import com.jeesite.common.utils.excel.annotation.ExcelField; +import com.jeesite.common.utils.excel.annotation.ExcelField.Align; +import com.jeesite.common.utils.excel.annotation.ExcelFields; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serial; + +/** + * 邮件信息Entity + * + * @author gaoxq + * @version 2025-12-14 + */ +@EqualsAndHashCode(callSuper = true) +@Table(name = "biz_mail_account", alias = "a", label = "邮件信息信息", columns = { + @Column(name = "create_time", attrName = "createTime", label = "记录时间", isUpdate = false), + @Column(name = "id", attrName = "id", label = "主键ID", isPK = true), + @Column(name = "account_name", attrName = "accountName", label = "配置名称"), + @Column(name = "host", attrName = "host", label = "发送地址"), + @Column(name = "smtp_port", attrName = "smtpPort", label = "SMTP端口", isQuery = false), + @Column(name = "imap_host", attrName = "imapHost", label = "接收地址"), + @Column(name = "imap_port", attrName = "imapPort", label = "IMAP端口", isQuery = false), + @Column(name = "username", attrName = "username", label = "用户名称"), + @Column(name = "password", attrName = "password", label = "用户密码", isQuery = false), + @Column(name = "from_address", attrName = "fromAddress", label = "发件人地址"), + @Column(name = "ssl_enable", attrName = "sslEnable", label = "是否启用SSL"), + @Column(name = "ustatus", attrName = "ustatus", label = "状态"), + @Column(name = "remark", attrName = "remark", label = "备注", isQuery = false), + @Column(name = "update_time", attrName = "updateTime", label = "更新时间", isQuery = false), + @Column(name = "f_tenant_id", attrName = "ftenantId", label = "租户id", isUpdate = false, isQuery = false), + @Column(name = "f_flow_id", attrName = "fflowId", label = "流程id", isUpdate = false, isQuery = false), + @Column(name = "f_flow_task_id", attrName = "fflowTaskId", label = "流程任务主键", isUpdate = false, isQuery = false), + @Column(name = "f_flow_state", attrName = "fflowState", label = "流程任务状态", isUpdate = false, isQuery = false, isUpdateForce = true), +}, orderBy = "a.create_time DESC" +) +@Data +public class BizMailAccount extends DataEntity implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + private Date createTime; // 记录时间 + private String accountName; + private String host; // 服务地址 + private Integer smtpPort; // SMTP端口 + private String imapHost; + private Integer imapPort; // IMAP端口 + private String username; // 用户名称 + private String password; // 用户密码 + private String fromAddress; // 发件人地址 + private String sslEnable; // 是否启用SSL + private String ustatus; + private String remark; // 备注 + private Date updateTime; // 更新时间 + private String ftenantId; // 租户id + private String fflowId; // 流程id + private String fflowTaskId; // 流程任务主键 + private Integer fflowState; // 流程任务状态 + + @ExcelFields({ + @ExcelField(title = "记录时间", attrName = "createTime", align = Align.CENTER, sort = 10, dataFormat = "yyyy-MM-dd hh:mm"), + @ExcelField(title = "主键标识", attrName = "id", align = Align.CENTER, sort = 20), + @ExcelField(title = "SMTP服务", attrName = "host", align = Align.CENTER, sort = 30), + @ExcelField(title = "SMTP端口", attrName = "smtpPort", align = Align.CENTER, sort = 40), + @ExcelField(title = "IMAP服务", attrName = "imapHost", align = Align.CENTER, sort = 50), + @ExcelField(title = "IMAP端口", attrName = "imapPort", align = Align.CENTER, sort = 50), + @ExcelField(title = "用户名称", attrName = "username", align = Align.CENTER, sort = 60), + @ExcelField(title = "发件地址", attrName = "fromAddress", align = Align.CENTER, sort = 80), + @ExcelField(title = "是否启用SSL", attrName = "sslEnable", dictType = "is_open", align = Align.CENTER, sort = 90), + @ExcelField(title = "状态", attrName = "ustatus", dictType = "ustatus", align = Align.CENTER, sort = 100), + @ExcelField(title = "备注", attrName = "remark", align = Align.CENTER, sort = 110), + @ExcelField(title = "更新时间", attrName = "updateTime", align = Align.CENTER, sort = 120, dataFormat = "yyyy-MM-dd hh:mm"), + }) + public BizMailAccount() { + this(null); + } + + public BizMailAccount(String id) { + super(id); + } + + public Date getCreateTime_gte() { + return sqlMap.getWhere().getValue("create_time", QueryType.GTE); + } + + public void setCreateTime_gte(Date createTime) { + sqlMap.getWhere().and("create_time", QueryType.GTE, createTime); + } + + public Date getCreateTime_lte() { + return sqlMap.getWhere().getValue("create_time", QueryType.LTE); + } + + public void setCreateTime_lte(Date createTime) { + sqlMap.getWhere().and("create_time", QueryType.LTE, createTime); + } + +} \ No newline at end of file diff --git a/web-api/src/main/java/com/jeesite/modules/biz/entity/BizMailAttachments.java b/web-api/src/main/java/com/jeesite/modules/biz/entity/BizMailAttachments.java new file mode 100644 index 00000000..2cb7c771 --- /dev/null +++ b/web-api/src/main/java/com/jeesite/modules/biz/entity/BizMailAttachments.java @@ -0,0 +1,115 @@ +package com.jeesite.modules.biz.entity; + +import java.io.Serializable; +import java.util.Date; + +import com.jeesite.common.mybatis.annotation.JoinTable; +import com.jeesite.common.mybatis.annotation.JoinTable.Type; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; + +import com.jeesite.common.entity.DataEntity; +import com.jeesite.common.mybatis.annotation.Column; +import com.jeesite.common.mybatis.annotation.Table; +import com.jeesite.common.mybatis.mapper.query.QueryType; +import com.jeesite.common.utils.excel.annotation.ExcelField; +import com.jeesite.common.utils.excel.annotation.ExcelField.Align; +import com.jeesite.common.utils.excel.annotation.ExcelFields; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serial; + +/** + * 邮件附件表Entity + * + * @author gaoxq + * @version 2025-12-14 + */ +@EqualsAndHashCode(callSuper = true) +@Table(name = "biz_mail_attachments", alias = "a", label = "邮件附件表信息", columns = { + @Column(name = "create_time", attrName = "createTime", label = "记录时间", isUpdate = false, isUpdateForce = true), + @Column(name = "id", attrName = "tid", label = "附件标识", isPK = true), + @Column(name = "mail_id", attrName = "mailId", label = "收件标识"), + @Column(name = "message_id", attrName = "messageId", label = "消息标识", isQuery = false), + @Column(name = "file_name", attrName = "fileName", label = "附件名称", queryType = QueryType.LIKE), + @Column(name = "file_size", attrName = "fileSize", label = "文件大小", isQuery = false), + @Column(name = "file_type", attrName = "fileType", label = "文件类型", isQuery = false), + @Column(name = "file_ext", attrName = "fileExt", label = "文件扩展名"), + @Column(name = "storage_path", attrName = "storagePath", label = "存储路径", isQuery = false), + @Column(name = "file_md5", attrName = "fileMd5", label = "文件MD5", isQuery = false), + @Column(name = "download_count", attrName = "downloadCount", label = "下载次数", isQuery = false, isUpdateForce = true), + @Column(name = "is_compressed", attrName = "isCompressed", label = "是否压缩"), + @Column(name = "is_encrypted", attrName = "isEncrypted", label = "是否加密"), + @Column(name = "download_start_time", attrName = "downloadStartTime", label = "下载开始时间"), + @Column(name = "download_end_time", attrName = "downloadEndTime", label = "下载结束时间"), + @Column(name = "download_cost_time", attrName = "downloadCostTime", label = "下载耗时"), +}, orderBy = "a.create_time DESC" +) +@Data +public class BizMailAttachments extends DataEntity implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + private Date createTime; // 记录时间 + private Long tid; // 附件标识 + private Long mailId; // 收件标识 + private String messageId; // 消息标识 + private String fileName; // 附件名称 + private Long fileSize; // 文件大小 + private String fileType; // 文件类型 + private String fileExt; // 文件扩展名 + private String storagePath; // 存储路径 + private String fileMd5; // 文件MD5 + private Integer downloadCount; // 下载次数 + private String isCompressed; // 是否压缩 + private String isEncrypted; // 是否加密 + + private Date downloadStartTime; // 附件下载开始时间 + private Date downloadEndTime; // 附件下载结束时间 + private Long downloadCostTime; // 附件下载耗时(毫秒) + + @ExcelFields({ + @ExcelField(title = "记录时间", attrName = "createTime", align = Align.CENTER, sort = 10, dataFormat = "yyyy-MM-dd hh:mm"), + @ExcelField(title = "附件标识", attrName = "tid", align = Align.CENTER, sort = 20), + @ExcelField(title = "收件标识", attrName = "mailId", align = Align.CENTER, sort = 30), + @ExcelField(title = "消息标识", attrName = "messageId", align = Align.CENTER, sort = 40), + @ExcelField(title = "附件名称", attrName = "fileName", align = Align.CENTER, sort = 50), + @ExcelField(title = "文件大小", attrName = "fileSize", align = Align.CENTER, sort = 60), + @ExcelField(title = "文件类型", attrName = "fileType", align = Align.CENTER, sort = 70), + @ExcelField(title = "文件扩展名", attrName = "fileExt", align = Align.CENTER, sort = 80), + @ExcelField(title = "存储路径", attrName = "storagePath", align = Align.CENTER, sort = 90), + @ExcelField(title = "文件MD5", attrName = "fileMd5", align = Align.CENTER, sort = 100), + @ExcelField(title = "下载次数", attrName = "downloadCount", align = Align.CENTER, sort = 110), + @ExcelField(title = "是否压缩", attrName = "isCompressed", align = Align.CENTER, sort = 120), + @ExcelField(title = "是否加密", attrName = "isEncrypted", align = Align.CENTER, sort = 130), + }) + public BizMailAttachments() { + this(null); + } + + public BizMailAttachments(String id) { + super(id); + } + + public Date getCreateTime_gte() { + return sqlMap.getWhere().getValue("create_time", QueryType.GTE); + } + + public void setCreateTime_gte(Date createTime) { + sqlMap.getWhere().and("create_time", QueryType.GTE, createTime); + } + + public Date getCreateTime_lte() { + return sqlMap.getWhere().getValue("create_time", QueryType.LTE); + } + + public void setCreateTime_lte(Date createTime) { + sqlMap.getWhere().and("create_time", QueryType.LTE, createTime); + } + +} \ No newline at end of file diff --git a/web-api/src/main/java/com/jeesite/modules/biz/entity/BizMailReceived.java b/web-api/src/main/java/com/jeesite/modules/biz/entity/BizMailReceived.java new file mode 100644 index 00000000..78b0da46 --- /dev/null +++ b/web-api/src/main/java/com/jeesite/modules/biz/entity/BizMailReceived.java @@ -0,0 +1,113 @@ +package com.jeesite.modules.biz.entity; + +import java.io.Serializable; +import java.util.Date; + +import com.jeesite.common.mybatis.annotation.JoinTable; +import com.jeesite.common.mybatis.annotation.JoinTable.Type; +import com.fasterxml.jackson.annotation.JsonFormat; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; + +import com.jeesite.common.entity.DataEntity; +import com.jeesite.common.mybatis.annotation.Column; +import com.jeesite.common.mybatis.annotation.Table; +import com.jeesite.common.mybatis.mapper.query.QueryType; +import com.jeesite.common.utils.excel.annotation.ExcelField; +import com.jeesite.common.utils.excel.annotation.ExcelField.Align; +import com.jeesite.common.utils.excel.annotation.ExcelFields; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serial; + +/** + * 收件Entity + * + * @author gaoxq + * @version 2025-12-14 + */ +@EqualsAndHashCode(callSuper = true) +@Table(name = "biz_mail_received", alias = "a", label = "收件信息", columns = { + @Column(name = "create_time", attrName = "createTime", label = "记录时间", isUpdate = false), + @Column(name = "id", attrName = "id", label = "主键ID", isPK = true), + @Column(name = "message_id", attrName = "messageId", label = "邮件服务器消息ID", isQuery = false), + @Column(name = "account_id", attrName = "accountId", label = "邮件账户标识"), + @Column(name = "from_address", attrName = "fromAddress", label = "发件人地址", isQuery = false), + @Column(name = "from_name", attrName = "fromName", label = "发件人名称", queryType = QueryType.LIKE), + @Column(name = "to_addresses", attrName = "toAddresses", label = "收件人地址", isQuery = false), + @Column(name = "cc_addresses", attrName = "ccAddresses", label = "抄送地址", isQuery = false), + @Column(name = "bcc_addresses", attrName = "bccAddresses", label = "密送地址", isQuery = false), + @Column(name = "subject", attrName = "subject", label = "邮件主题", queryType = QueryType.LIKE), + @Column(name = "mail_content", attrName = "mailContent", label = "邮件内容", isQuery = false), + @Column(name = "received_time", attrName = "receivedTime", label = "接收时间", isQuery = false), + @Column(name = "send_time", attrName = "sendTime", label = "发送时间", isQuery = false, isUpdateForce = true), + @Column(name = "has_attachment", attrName = "hasAttachment", label = "是否有附件"), + @Column(name = "mailbox", attrName = "mailbox", label = "mailbox", isQuery = false), + @Column(name = "ustatus", attrName = "ustatus", label = "状态"), +}, orderBy = "a.id DESC" +) +@Data +public class BizMailReceived extends DataEntity implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + private Date createTime; // 记录时间 + private String messageId; // 邮件服务器消息ID + private String accountId; // 邮件账户标识 + private String fromAddress; // 发件人地址 + private String fromName; // 发件人名称 + private String toAddresses; // 收件人地址 + private String ccAddresses; // 抄送地址 + private String bccAddresses; // 密送地址 + private String subject; // 邮件主题 + private String mailContent; // 邮件内容 + private Date receivedTime; // 接收时间 + private Date sendTime; // 发送时间 + private String hasAttachment; // 是否有附件 + private String mailbox; // mailbox + private String ustatus; // 状态 + + @ExcelFields({ + @ExcelField(title = "记录时间", attrName = "createTime", align = Align.CENTER, sort = 10, dataFormat = "yyyy-MM-dd hh:mm"), + @ExcelField(title = "主键ID", attrName = "id", align = Align.CENTER, sort = 20), + @ExcelField(title = "邮件服务器消息ID", attrName = "messageId", align = Align.CENTER, sort = 30), + @ExcelField(title = "邮件账户标识", attrName = "accountId", align = Align.CENTER, sort = 40), + @ExcelField(title = "发件人地址", attrName = "fromAddress", align = Align.CENTER, sort = 50), + @ExcelField(title = "发件人名称", attrName = "fromName", align = Align.CENTER, sort = 60), + @ExcelField(title = "收件人地址", attrName = "toAddresses", align = Align.CENTER, sort = 70), + @ExcelField(title = "抄送地址", attrName = "ccAddresses", align = Align.CENTER, sort = 80), + @ExcelField(title = "密送地址", attrName = "bccAddresses", align = Align.CENTER, sort = 90), + @ExcelField(title = "邮件主题", attrName = "subject", align = Align.CENTER, sort = 100), + @ExcelField(title = "邮件内容", attrName = "mailContent", align = Align.CENTER, sort = 110), + @ExcelField(title = "接收时间", attrName = "receivedTime", align = Align.CENTER, sort = 120, dataFormat = "yyyy-MM-dd hh:mm"), + @ExcelField(title = "发送时间", attrName = "sendTime", align = Align.CENTER, sort = 130, dataFormat = "yyyy-MM-dd hh:mm"), + @ExcelField(title = "是否有附件", attrName = "hasAttachment", align = Align.CENTER, sort = 140), + @ExcelField(title = "状态", attrName = "ustatus", align = Align.CENTER, sort = 160), + }) + public BizMailReceived() { + this(null); + } + + public BizMailReceived(String id) { + super(id); + } + + public Date getCreateTime_gte() { + return sqlMap.getWhere().getValue("create_time", QueryType.GTE); + } + + public void setCreateTime_gte(Date createTime) { + sqlMap.getWhere().and("create_time", QueryType.GTE, createTime); + } + + public Date getCreateTime_lte() { + return sqlMap.getWhere().getValue("create_time", QueryType.LTE); + } + + public void setCreateTime_lte(Date createTime) { + sqlMap.getWhere().and("create_time", QueryType.LTE, createTime); + } + +} \ No newline at end of file diff --git a/web-api/src/main/java/com/jeesite/modules/biz/entity/BizMailSent.java b/web-api/src/main/java/com/jeesite/modules/biz/entity/BizMailSent.java new file mode 100644 index 00000000..cdd835b8 --- /dev/null +++ b/web-api/src/main/java/com/jeesite/modules/biz/entity/BizMailSent.java @@ -0,0 +1,114 @@ +package com.jeesite.modules.biz.entity; + +import java.io.Serializable; +import java.util.Date; + +import com.jeesite.common.mybatis.annotation.JoinTable; +import com.jeesite.common.mybatis.annotation.JoinTable.Type; +import com.fasterxml.jackson.annotation.JsonFormat; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; + +import com.jeesite.common.entity.DataEntity; +import com.jeesite.common.mybatis.annotation.Column; +import com.jeesite.common.mybatis.annotation.Table; +import com.jeesite.common.mybatis.mapper.query.QueryType; +import com.jeesite.common.utils.excel.annotation.ExcelField; +import com.jeesite.common.utils.excel.annotation.ExcelField.Align; +import com.jeesite.common.utils.excel.annotation.ExcelFields; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serial; + +/** + * 发件Entity + * + * @author gaoxq + * @version 2025-12-14 + */ +@EqualsAndHashCode(callSuper = true) +@Table(name = "biz_mail_sent", alias = "a", label = "发件信息", columns = { + @Column(name = "create_time", attrName = "createTime", label = "记录时间", isUpdate = false, isUpdateForce = true), + @Column(name = "id", attrName = "id", label = "主键标识", isPK = true), + @Column(name = "message_id", attrName = "messageId", label = "件服务器消息标识", isQuery = false), + @Column(name = "account_id", attrName = "accountId", label = "邮件账户标识"), + @Column(name = "from_address", attrName = "fromAddress", label = "发件人地址", queryType = QueryType.LIKE), + @Column(name = "to_addresses", attrName = "toAddresses", label = "收件人地址", isQuery = false), + @Column(name = "cc_addresses", attrName = "ccAddresses", label = "抄送人地址", isQuery = false), + @Column(name = "subject", attrName = "subject", label = "邮件主题", queryType = QueryType.LIKE), + @Column(name = "content", attrName = "content", label = "邮件内容", isQuery = false), + @Column(name = "send_time", attrName = "sendTime", label = "发送时间", isQuery = false, isUpdateForce = true), + @Column(name = "send_status", attrName = "sendStatus", label = "发送状态"), + @Column(name = "error_msg", attrName = "errorMsg", label = "错误信息", isQuery = false), + @Column(name = "has_attachment", attrName = "hasAttachment", label = "是否有附件"), + @Column(name = "update_time", attrName = "updateTime", label = "更新时间", isQuery = false, isUpdateForce = true), + @Column(name = "f_tenant_id", attrName = "ftenantId", label = "租户id", isUpdate = false, isQuery = false), + @Column(name = "f_flow_id", attrName = "fflowId", label = "流程id", isUpdate = false, isQuery = false), + @Column(name = "f_flow_task_id", attrName = "fflowTaskId", label = "流程任务主键", isUpdate = false, isQuery = false), + @Column(name = "f_flow_state", attrName = "fflowState", label = "流程任务状态", isUpdate = false, isQuery = false, isUpdateForce = true), +}, orderBy = "a.create_time DESC" +) +@Data +public class BizMailSent extends DataEntity implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + private Date createTime; // 记录时间 + private String messageId; // 件服务器消息标识 + private String accountId; // 邮件账户标识 + private String fromAddress; // 发件人地址 + private String toAddresses; // 收件人地址 + private String ccAddresses; // 抄送人地址 + private String subject; // 邮件主题 + private String content; // 邮件内容 + private Date sendTime; // 发送时间 + private String sendStatus; // 发送状态 + private String errorMsg; // 错误信息 + private String hasAttachment; // 是否有附件 + private Date updateTime; // 更新时间 + private String ftenantId; // 租户id + private String fflowId; // 流程id + private String fflowTaskId; // 流程任务主键 + private Integer fflowState; // 流程任务状态 + + @ExcelFields({ + @ExcelField(title = "记录时间", attrName = "createTime", align = Align.CENTER, sort = 10, dataFormat = "yyyy-MM-dd hh:mm"), + @ExcelField(title = "主键标识", attrName = "id", align = Align.CENTER, sort = 20), + @ExcelField(title = "件服务器消息标识", attrName = "messageId", align = Align.CENTER, sort = 30), + @ExcelField(title = "邮件账户标识", attrName = "accountId", align = Align.CENTER, sort = 40), + @ExcelField(title = "发件人地址", attrName = "fromAddress", align = Align.CENTER, sort = 50), + @ExcelField(title = "收件人地址", attrName = "toAddresses", align = Align.CENTER, sort = 60), + @ExcelField(title = "抄送人地址", attrName = "ccAddresses", align = Align.CENTER, sort = 70), + @ExcelField(title = "邮件主题", attrName = "subject", align = Align.CENTER, sort = 80), + @ExcelField(title = "邮件内容", attrName = "content", align = Align.CENTER, sort = 90), + @ExcelField(title = "发送时间", attrName = "sendTime", align = Align.CENTER, sort = 100, dataFormat = "yyyy-MM-dd hh:mm"), + @ExcelField(title = "发送状态", attrName = "sendStatus", align = Align.CENTER, sort = 110), + @ExcelField(title = "错误信息", attrName = "errorMsg", align = Align.CENTER, sort = 120), + @ExcelField(title = "是否有附件", attrName = "hasAttachment", align = Align.CENTER, sort = 130), + @ExcelField(title = "更新时间", attrName = "updateTime", align = Align.CENTER, sort = 140, dataFormat = "yyyy-MM-dd hh:mm"), + }) + public BizMailSent() { + this(null); + } + + public BizMailSent(String id) { + super(id); + } + public Date getCreateTime_gte() { + return sqlMap.getWhere().getValue("create_time", QueryType.GTE); + } + + public void setCreateTime_gte(Date createTime) { + sqlMap.getWhere().and("create_time", QueryType.GTE, createTime); + } + + public Date getCreateTime_lte() { + return sqlMap.getWhere().getValue("create_time", QueryType.LTE); + } + + public void setCreateTime_lte(Date createTime) { + sqlMap.getWhere().and("create_time", QueryType.LTE, createTime); + } + +} \ No newline at end of file diff --git a/web-api/src/main/java/com/jeesite/modules/biz/service/BizMailAccountService.java b/web-api/src/main/java/com/jeesite/modules/biz/service/BizMailAccountService.java new file mode 100644 index 00000000..b136385a --- /dev/null +++ b/web-api/src/main/java/com/jeesite/modules/biz/service/BizMailAccountService.java @@ -0,0 +1,134 @@ +package com.jeesite.modules.biz.service; + +import java.util.List; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.jeesite.common.entity.Page; +import com.jeesite.common.service.CrudService; +import com.jeesite.modules.biz.entity.BizMailAccount; +import com.jeesite.modules.biz.dao.BizMailAccountDao; +import com.jeesite.common.service.ServiceException; +import com.jeesite.common.config.Global; +import com.jeesite.common.validator.ValidatorUtils; +import com.jeesite.common.utils.excel.ExcelImport; +import org.springframework.web.multipart.MultipartFile; +import jakarta.validation.ConstraintViolation; +import jakarta.validation.ConstraintViolationException; + +/** + * 邮件信息Service + * @author gaoxq + * @version 2025-12-14 + */ +@Service +public class BizMailAccountService extends CrudService { + + /** + * 获取单条数据 + * @param bizMailAccount 主键 + */ + @Override + public BizMailAccount get(BizMailAccount bizMailAccount) { + return super.get(bizMailAccount); + } + + /** + * 查询分页数据 + * @param bizMailAccount 查询条件 + * @param bizMailAccount page 分页对象 + */ + @Override + public Page findPage(BizMailAccount bizMailAccount) { + return super.findPage(bizMailAccount); + } + + /** + * 查询列表数据 + * @param bizMailAccount 查询条件 + */ + @Override + public List findList(BizMailAccount bizMailAccount) { + return super.findList(bizMailAccount); + } + + /** + * 保存数据(插入或更新) + * @param bizMailAccount 数据对象 + */ + @Override + @Transactional + public void save(BizMailAccount bizMailAccount) { + super.save(bizMailAccount); + } + + /** + * 导入数据 + * @param file 导入的数据文件 + */ + @Transactional + public String importData(MultipartFile file) { + if (file == null){ + throw new ServiceException(text("请选择导入的数据文件!")); + } + int successNum = 0; int failureNum = 0; + StringBuilder successMsg = new StringBuilder(); + StringBuilder failureMsg = new StringBuilder(); + try(ExcelImport ei = new ExcelImport(file, 2, 0)){ + List list = ei.getDataList(BizMailAccount.class); + for (BizMailAccount bizMailAccount : list) { + try{ + ValidatorUtils.validateWithException(bizMailAccount); + this.save(bizMailAccount); + successNum++; + successMsg.append("
" + successNum + "、编号 " + bizMailAccount.getId() + " 导入成功"); + } catch (Exception e) { + failureNum++; + String msg = "
" + failureNum + "、编号 " + bizMailAccount.getId() + " 导入失败:"; + if (e instanceof ConstraintViolationException){ + ConstraintViolationException cve = (ConstraintViolationException)e; + for (ConstraintViolation violation : cve.getConstraintViolations()) { + msg += Global.getText(violation.getMessage()) + " ("+violation.getPropertyPath()+")"; + } + }else{ + msg += e.getMessage(); + } + failureMsg.append(msg); + logger.error(msg, e); + } + } + } catch (Exception e) { + logger.error(e.getMessage(), e); + failureMsg.append(e.getMessage()); + return failureMsg.toString(); + } + if (failureNum > 0) { + failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:"); + throw new ServiceException(failureMsg.toString()); + }else{ + successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条,数据如下:"); + } + return successMsg.toString(); + } + + /** + * 更新状态 + * @param bizMailAccount 数据对象 + */ + @Override + @Transactional + public void updateStatus(BizMailAccount bizMailAccount) { + super.updateStatus(bizMailAccount); + } + + /** + * 删除数据 + * @param bizMailAccount 数据对象 + */ + @Override + @Transactional + public void delete(BizMailAccount bizMailAccount) { + super.delete(bizMailAccount); + } + +} \ No newline at end of file diff --git a/web-api/src/main/java/com/jeesite/modules/biz/service/BizMailAttachmentsService.java b/web-api/src/main/java/com/jeesite/modules/biz/service/BizMailAttachmentsService.java new file mode 100644 index 00000000..c9e593b5 --- /dev/null +++ b/web-api/src/main/java/com/jeesite/modules/biz/service/BizMailAttachmentsService.java @@ -0,0 +1,134 @@ +package com.jeesite.modules.biz.service; + +import java.util.List; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.jeesite.common.entity.Page; +import com.jeesite.common.service.CrudService; +import com.jeesite.modules.biz.entity.BizMailAttachments; +import com.jeesite.modules.biz.dao.BizMailAttachmentsDao; +import com.jeesite.common.service.ServiceException; +import com.jeesite.common.config.Global; +import com.jeesite.common.validator.ValidatorUtils; +import com.jeesite.common.utils.excel.ExcelImport; +import org.springframework.web.multipart.MultipartFile; +import jakarta.validation.ConstraintViolation; +import jakarta.validation.ConstraintViolationException; + +/** + * 邮件附件表Service + * @author gaoxq + * @version 2025-12-14 + */ +@Service +public class BizMailAttachmentsService extends CrudService { + + /** + * 获取单条数据 + * @param bizMailAttachments 主键 + */ + @Override + public BizMailAttachments get(BizMailAttachments bizMailAttachments) { + return super.get(bizMailAttachments); + } + + /** + * 查询分页数据 + * @param bizMailAttachments 查询条件 + * @param bizMailAttachments page 分页对象 + */ + @Override + public Page findPage(BizMailAttachments bizMailAttachments) { + return super.findPage(bizMailAttachments); + } + + /** + * 查询列表数据 + * @param bizMailAttachments 查询条件 + */ + @Override + public List findList(BizMailAttachments bizMailAttachments) { + return super.findList(bizMailAttachments); + } + + /** + * 保存数据(插入或更新) + * @param bizMailAttachments 数据对象 + */ + @Override + @Transactional + public void save(BizMailAttachments bizMailAttachments) { + super.save(bizMailAttachments); + } + + /** + * 导入数据 + * @param file 导入的数据文件 + */ + @Transactional + public String importData(MultipartFile file) { + if (file == null){ + throw new ServiceException(text("请选择导入的数据文件!")); + } + int successNum = 0; int failureNum = 0; + StringBuilder successMsg = new StringBuilder(); + StringBuilder failureMsg = new StringBuilder(); + try(ExcelImport ei = new ExcelImport(file, 2, 0)){ + List list = ei.getDataList(BizMailAttachments.class); + for (BizMailAttachments bizMailAttachments : list) { + try{ + ValidatorUtils.validateWithException(bizMailAttachments); + this.save(bizMailAttachments); + successNum++; + successMsg.append("
" + successNum + "、编号 " + bizMailAttachments.getId() + " 导入成功"); + } catch (Exception e) { + failureNum++; + String msg = "
" + failureNum + "、编号 " + bizMailAttachments.getId() + " 导入失败:"; + if (e instanceof ConstraintViolationException){ + ConstraintViolationException cve = (ConstraintViolationException)e; + for (ConstraintViolation violation : cve.getConstraintViolations()) { + msg += Global.getText(violation.getMessage()) + " ("+violation.getPropertyPath()+")"; + } + }else{ + msg += e.getMessage(); + } + failureMsg.append(msg); + logger.error(msg, e); + } + } + } catch (Exception e) { + logger.error(e.getMessage(), e); + failureMsg.append(e.getMessage()); + return failureMsg.toString(); + } + if (failureNum > 0) { + failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:"); + throw new ServiceException(failureMsg.toString()); + }else{ + successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条,数据如下:"); + } + return successMsg.toString(); + } + + /** + * 更新状态 + * @param bizMailAttachments 数据对象 + */ + @Override + @Transactional + public void updateStatus(BizMailAttachments bizMailAttachments) { + super.updateStatus(bizMailAttachments); + } + + /** + * 删除数据 + * @param bizMailAttachments 数据对象 + */ + @Override + @Transactional + public void delete(BizMailAttachments bizMailAttachments) { + super.delete(bizMailAttachments); + } + +} \ No newline at end of file diff --git a/web-api/src/main/java/com/jeesite/modules/biz/service/BizMailReceivedService.java b/web-api/src/main/java/com/jeesite/modules/biz/service/BizMailReceivedService.java new file mode 100644 index 00000000..de7f6eb9 --- /dev/null +++ b/web-api/src/main/java/com/jeesite/modules/biz/service/BizMailReceivedService.java @@ -0,0 +1,134 @@ +package com.jeesite.modules.biz.service; + +import java.util.List; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.jeesite.common.entity.Page; +import com.jeesite.common.service.CrudService; +import com.jeesite.modules.biz.entity.BizMailReceived; +import com.jeesite.modules.biz.dao.BizMailReceivedDao; +import com.jeesite.common.service.ServiceException; +import com.jeesite.common.config.Global; +import com.jeesite.common.validator.ValidatorUtils; +import com.jeesite.common.utils.excel.ExcelImport; +import org.springframework.web.multipart.MultipartFile; +import jakarta.validation.ConstraintViolation; +import jakarta.validation.ConstraintViolationException; + +/** + * 收件Service + * @author gaoxq + * @version 2025-12-14 + */ +@Service +public class BizMailReceivedService extends CrudService { + + /** + * 获取单条数据 + * @param bizMailReceived 主键 + */ + @Override + public BizMailReceived get(BizMailReceived bizMailReceived) { + return super.get(bizMailReceived); + } + + /** + * 查询分页数据 + * @param bizMailReceived 查询条件 + * @param bizMailReceived page 分页对象 + */ + @Override + public Page findPage(BizMailReceived bizMailReceived) { + return super.findPage(bizMailReceived); + } + + /** + * 查询列表数据 + * @param bizMailReceived 查询条件 + */ + @Override + public List findList(BizMailReceived bizMailReceived) { + return super.findList(bizMailReceived); + } + + /** + * 保存数据(插入或更新) + * @param bizMailReceived 数据对象 + */ + @Override + @Transactional + public void save(BizMailReceived bizMailReceived) { + super.save(bizMailReceived); + } + + /** + * 导入数据 + * @param file 导入的数据文件 + */ + @Transactional + public String importData(MultipartFile file) { + if (file == null){ + throw new ServiceException(text("请选择导入的数据文件!")); + } + int successNum = 0; int failureNum = 0; + StringBuilder successMsg = new StringBuilder(); + StringBuilder failureMsg = new StringBuilder(); + try(ExcelImport ei = new ExcelImport(file, 2, 0)){ + List list = ei.getDataList(BizMailReceived.class); + for (BizMailReceived bizMailReceived : list) { + try{ + ValidatorUtils.validateWithException(bizMailReceived); + this.save(bizMailReceived); + successNum++; + successMsg.append("
" + successNum + "、编号 " + bizMailReceived.getId() + " 导入成功"); + } catch (Exception e) { + failureNum++; + String msg = "
" + failureNum + "、编号 " + bizMailReceived.getId() + " 导入失败:"; + if (e instanceof ConstraintViolationException){ + ConstraintViolationException cve = (ConstraintViolationException)e; + for (ConstraintViolation violation : cve.getConstraintViolations()) { + msg += Global.getText(violation.getMessage()) + " ("+violation.getPropertyPath()+")"; + } + }else{ + msg += e.getMessage(); + } + failureMsg.append(msg); + logger.error(msg, e); + } + } + } catch (Exception e) { + logger.error(e.getMessage(), e); + failureMsg.append(e.getMessage()); + return failureMsg.toString(); + } + if (failureNum > 0) { + failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:"); + throw new ServiceException(failureMsg.toString()); + }else{ + successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条,数据如下:"); + } + return successMsg.toString(); + } + + /** + * 更新状态 + * @param bizMailReceived 数据对象 + */ + @Override + @Transactional + public void updateStatus(BizMailReceived bizMailReceived) { + super.updateStatus(bizMailReceived); + } + + /** + * 删除数据 + * @param bizMailReceived 数据对象 + */ + @Override + @Transactional + public void delete(BizMailReceived bizMailReceived) { + super.delete(bizMailReceived); + } + +} \ No newline at end of file diff --git a/web-api/src/main/java/com/jeesite/modules/biz/service/BizMailSentService.java b/web-api/src/main/java/com/jeesite/modules/biz/service/BizMailSentService.java new file mode 100644 index 00000000..c2bfa59a --- /dev/null +++ b/web-api/src/main/java/com/jeesite/modules/biz/service/BizMailSentService.java @@ -0,0 +1,137 @@ +package com.jeesite.modules.biz.service; + +import java.util.List; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.jeesite.common.entity.Page; +import com.jeesite.common.service.CrudService; +import com.jeesite.modules.biz.entity.BizMailSent; +import com.jeesite.modules.biz.dao.BizMailSentDao; +import com.jeesite.common.service.ServiceException; +import com.jeesite.modules.file.utils.FileUploadUtils; +import com.jeesite.common.config.Global; +import com.jeesite.common.validator.ValidatorUtils; +import com.jeesite.common.utils.excel.ExcelImport; +import org.springframework.web.multipart.MultipartFile; +import jakarta.validation.ConstraintViolation; +import jakarta.validation.ConstraintViolationException; + +/** + * 发件Service + * @author gaoxq + * @version 2025-12-14 + */ +@Service +public class BizMailSentService extends CrudService { + + /** + * 获取单条数据 + * @param bizMailSent 主键 + */ + @Override + public BizMailSent get(BizMailSent bizMailSent) { + return super.get(bizMailSent); + } + + /** + * 查询分页数据 + * @param bizMailSent 查询条件 + * @param bizMailSent page 分页对象 + */ + @Override + public Page findPage(BizMailSent bizMailSent) { + return super.findPage(bizMailSent); + } + + /** + * 查询列表数据 + * @param bizMailSent 查询条件 + */ + @Override + public List findList(BizMailSent bizMailSent) { + return super.findList(bizMailSent); + } + + /** + * 保存数据(插入或更新) + * @param bizMailSent 数据对象 + */ + @Override + @Transactional + public void save(BizMailSent bizMailSent) { + super.save(bizMailSent); + // 保存上传附件 + FileUploadUtils.saveFileUpload(bizMailSent, bizMailSent.getId(), "bizMailSent_file"); + } + + /** + * 导入数据 + * @param file 导入的数据文件 + */ + @Transactional + public String importData(MultipartFile file) { + if (file == null){ + throw new ServiceException(text("请选择导入的数据文件!")); + } + int successNum = 0; int failureNum = 0; + StringBuilder successMsg = new StringBuilder(); + StringBuilder failureMsg = new StringBuilder(); + try(ExcelImport ei = new ExcelImport(file, 2, 0)){ + List list = ei.getDataList(BizMailSent.class); + for (BizMailSent bizMailSent : list) { + try{ + ValidatorUtils.validateWithException(bizMailSent); + this.save(bizMailSent); + successNum++; + successMsg.append("
" + successNum + "、编号 " + bizMailSent.getId() + " 导入成功"); + } catch (Exception e) { + failureNum++; + String msg = "
" + failureNum + "、编号 " + bizMailSent.getId() + " 导入失败:"; + if (e instanceof ConstraintViolationException){ + ConstraintViolationException cve = (ConstraintViolationException)e; + for (ConstraintViolation violation : cve.getConstraintViolations()) { + msg += Global.getText(violation.getMessage()) + " ("+violation.getPropertyPath()+")"; + } + }else{ + msg += e.getMessage(); + } + failureMsg.append(msg); + logger.error(msg, e); + } + } + } catch (Exception e) { + logger.error(e.getMessage(), e); + failureMsg.append(e.getMessage()); + return failureMsg.toString(); + } + if (failureNum > 0) { + failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:"); + throw new ServiceException(failureMsg.toString()); + }else{ + successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条,数据如下:"); + } + return successMsg.toString(); + } + + /** + * 更新状态 + * @param bizMailSent 数据对象 + */ + @Override + @Transactional + public void updateStatus(BizMailSent bizMailSent) { + super.updateStatus(bizMailSent); + } + + /** + * 删除数据 + * @param bizMailSent 数据对象 + */ + @Override + @Transactional + public void delete(BizMailSent bizMailSent) { + super.delete(bizMailSent); + } + +} \ No newline at end of file diff --git a/web-api/src/main/java/com/jeesite/modules/biz/web/BizMailAccountController.java b/web-api/src/main/java/com/jeesite/modules/biz/web/BizMailAccountController.java new file mode 100644 index 00000000..552645f6 --- /dev/null +++ b/web-api/src/main/java/com/jeesite/modules/biz/web/BizMailAccountController.java @@ -0,0 +1,191 @@ +package com.jeesite.modules.biz.web; + +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import com.jeesite.modules.app.dao.MailReceived; +import com.jeesite.modules.app.utils.MailReceiveUtils; +import com.jeesite.modules.biz.entity.BizMailAttachments; +import com.jeesite.modules.biz.entity.BizMailReceived; +import com.jeesite.modules.biz.service.BizMailAttachmentsService; +import com.jeesite.modules.biz.service.BizMailReceivedService; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import org.apache.shiro.authz.annotation.RequiresPermissions; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +import com.jeesite.common.config.Global; +import com.jeesite.common.collect.ListUtils; +import com.jeesite.common.entity.Page; +import com.jeesite.common.lang.DateUtils; +import com.jeesite.common.utils.excel.ExcelExport; +import com.jeesite.common.utils.excel.annotation.ExcelField.Type; +import org.springframework.web.multipart.MultipartFile; +import com.jeesite.common.web.BaseController; +import com.jeesite.modules.biz.entity.BizMailAccount; +import com.jeesite.modules.biz.service.BizMailAccountService; + +/** + * 邮件信息Controller + * + * @author gaoxq + * @version 2025-12-14 + */ +@Controller +@RequestMapping(value = "${adminPath}/biz/mailAccount") +public class BizMailAccountController extends BaseController { + + private final BizMailAccountService bizMailAccountService; + + private static final ExecutorService MAIL_EXECUTOR = Executors.newFixedThreadPool(5); + + @Resource + private BizMailReceivedService receivedService; + + @Resource + private BizMailAttachmentsService attachmentsService; + + + private String MAIL_PATH = "/ogsapp/mail"; + + public BizMailAccountController(BizMailAccountService bizMailAccountService) { + this.bizMailAccountService = bizMailAccountService; + } + + /** + * 获取数据 + */ + @ModelAttribute + public BizMailAccount get(String id, boolean isNewRecord) { + return bizMailAccountService.get(id, isNewRecord); + } + + /** + * 查询列表 + */ + @RequiresPermissions("biz:mailAccount:view") + @RequestMapping(value = {"list", ""}) + public String list(BizMailAccount bizMailAccount, Model model) { + model.addAttribute("bizMailAccount", bizMailAccount); + return "modules/biz/bizMailAccountList"; + } + + /** + * 查询列表数据 + */ + @RequiresPermissions("biz:mailAccount:view") + @RequestMapping(value = "listData") + @ResponseBody + public Page listData(BizMailAccount bizMailAccount, HttpServletRequest request, HttpServletResponse response) { + bizMailAccount.setPage(new Page<>(request, response)); + Page page = bizMailAccountService.findPage(bizMailAccount); + return page; + } + + /** + * 查看编辑表单 + */ + @RequiresPermissions("biz:mailAccount:view") + @RequestMapping(value = "form") + public String form(BizMailAccount bizMailAccount, Model model) { + model.addAttribute("bizMailAccount", bizMailAccount); + return "modules/biz/bizMailAccountForm"; + } + + /** + * 保存数据 + */ + @RequiresPermissions("biz:mailAccount:edit") + @PostMapping(value = "save") + @ResponseBody + public String save(@Validated BizMailAccount bizMailAccount) { + bizMailAccountService.save(bizMailAccount); + return renderResult(Global.TRUE, text("保存邮件信息成功!")); + } + + /** + * 导出数据 + */ + @RequiresPermissions("biz:mailAccount:view") + @RequestMapping(value = "exportData") + public void exportData(BizMailAccount bizMailAccount, HttpServletResponse response) { + List list = bizMailAccountService.findList(bizMailAccount); + String fileName = "邮件信息" + DateUtils.getDate("yyyyMMddHHmmss") + ".xlsx"; + try (ExcelExport ee = new ExcelExport("邮件信息", BizMailAccount.class)) { + ee.setDataList(list).write(response, fileName); + } + } + + /** + * 下载模板 + */ + @RequiresPermissions("biz:mailAccount:view") + @RequestMapping(value = "importTemplate") + public void importTemplate(HttpServletResponse response) { + BizMailAccount bizMailAccount = new BizMailAccount(); + List list = ListUtils.newArrayList(bizMailAccount); + String fileName = "邮件信息模板.xlsx"; + try (ExcelExport ee = new ExcelExport("邮件信息", BizMailAccount.class, Type.IMPORT)) { + ee.setDataList(list).write(response, fileName); + } + } + + /** + * 导入数据 + */ + @ResponseBody + @RequiresPermissions("biz:mailAccount:edit") + @PostMapping(value = "importData") + public String importData(MultipartFile file) { + try { + String message = bizMailAccountService.importData(file); + return renderResult(Global.TRUE, "posfull:" + message); + } catch (Exception ex) { + return renderResult(Global.FALSE, "posfull:" + ex.getMessage()); + } + } + + /** + * 删除数据 + */ + @RequiresPermissions("biz:mailAccount:edit") + @RequestMapping(value = "delete") + @ResponseBody + public String delete(BizMailAccount bizMailAccount) { + bizMailAccountService.delete(bizMailAccount); + return renderResult(Global.TRUE, text("删除邮件信息成功!")); + } + + /** + * 邮件接收 + */ + @RequestMapping(value = "received") + @ResponseBody + public String received(BizMailAccount bizMailAccount) { + MAIL_EXECUTOR.submit(() -> { + try { + List receivedList = MailReceiveUtils.receiveUnreadMails(bizMailAccount, MAIL_PATH); + for (MailReceived mailReceived : receivedList) { + BizMailReceived received = mailReceived.getReceived(); + List attachments = mailReceived.getAttachments(); + for (BizMailAttachments mailAttachments : attachments) { + attachmentsService.insert(mailAttachments); + } + receivedService.save(received); + } + } catch (Exception e) { + logger.error("后台处理邮件失败", e.getMessage()); + } + }); + return renderResult(Global.TRUE, text("操作接收邮件成功!")); + } +} \ No newline at end of file diff --git a/web-api/src/main/java/com/jeesite/modules/biz/web/BizMailAttachmentsController.java b/web-api/src/main/java/com/jeesite/modules/biz/web/BizMailAttachmentsController.java new file mode 100644 index 00000000..270b9480 --- /dev/null +++ b/web-api/src/main/java/com/jeesite/modules/biz/web/BizMailAttachmentsController.java @@ -0,0 +1,146 @@ +package com.jeesite.modules.biz.web; + +import java.util.List; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import org.apache.shiro.authz.annotation.RequiresPermissions; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +import com.jeesite.common.config.Global; +import com.jeesite.common.collect.ListUtils; +import com.jeesite.common.entity.Page; +import com.jeesite.common.lang.DateUtils; +import com.jeesite.common.utils.excel.ExcelExport; +import com.jeesite.common.utils.excel.annotation.ExcelField.Type; +import org.springframework.web.multipart.MultipartFile; +import com.jeesite.common.web.BaseController; +import com.jeesite.modules.biz.entity.BizMailAttachments; +import com.jeesite.modules.biz.service.BizMailAttachmentsService; + +/** + * 邮件附件表Controller + * @author gaoxq + * @version 2025-12-14 + */ +@Controller +@RequestMapping(value = "${adminPath}/biz/mailAttachments") +public class BizMailAttachmentsController extends BaseController { + + private final BizMailAttachmentsService bizMailAttachmentsService; + + public BizMailAttachmentsController(BizMailAttachmentsService bizMailAttachmentsService) { + this.bizMailAttachmentsService = bizMailAttachmentsService; + } + + /** + * 获取数据 + */ + @ModelAttribute + public BizMailAttachments get(Long tid, boolean isNewRecord) { + return bizMailAttachmentsService.get(tid, isNewRecord); + } + + /** + * 查询列表 + */ + @RequiresPermissions("biz:mailAttachments:view") + @RequestMapping(value = {"list", ""}) + public String list(BizMailAttachments bizMailAttachments, Model model) { + model.addAttribute("bizMailAttachments", bizMailAttachments); + return "modules/biz/bizMailAttachmentsList"; + } + + /** + * 查询列表数据 + */ + @RequiresPermissions("biz:mailAttachments:view") + @RequestMapping(value = "listData") + @ResponseBody + public Page listData(BizMailAttachments bizMailAttachments, HttpServletRequest request, HttpServletResponse response) { + bizMailAttachments.setPage(new Page<>(request, response)); + Page page = bizMailAttachmentsService.findPage(bizMailAttachments); + return page; + } + + /** + * 查看编辑表单 + */ + @RequiresPermissions("biz:mailAttachments:view") + @RequestMapping(value = "form") + public String form(BizMailAttachments bizMailAttachments, Model model) { + model.addAttribute("bizMailAttachments", bizMailAttachments); + return "modules/biz/bizMailAttachmentsForm"; + } + + /** + * 保存数据 + */ + @RequiresPermissions("biz:mailAttachments:edit") + @PostMapping(value = "save") + @ResponseBody + public String save(@Validated BizMailAttachments bizMailAttachments) { + bizMailAttachmentsService.save(bizMailAttachments); + return renderResult(Global.TRUE, text("保存邮件附件表成功!")); + } + + /** + * 导出数据 + */ + @RequiresPermissions("biz:mailAttachments:view") + @RequestMapping(value = "exportData") + public void exportData(BizMailAttachments bizMailAttachments, HttpServletResponse response) { + List list = bizMailAttachmentsService.findList(bizMailAttachments); + String fileName = "邮件附件表" + DateUtils.getDate("yyyyMMddHHmmss") + ".xlsx"; + try(ExcelExport ee = new ExcelExport("邮件附件表", BizMailAttachments.class)){ + ee.setDataList(list).write(response, fileName); + } + } + + /** + * 下载模板 + */ + @RequiresPermissions("biz:mailAttachments:view") + @RequestMapping(value = "importTemplate") + public void importTemplate(HttpServletResponse response) { + BizMailAttachments bizMailAttachments = new BizMailAttachments(); + List list = ListUtils.newArrayList(bizMailAttachments); + String fileName = "邮件附件表模板.xlsx"; + try(ExcelExport ee = new ExcelExport("邮件附件表", BizMailAttachments.class, Type.IMPORT)){ + ee.setDataList(list).write(response, fileName); + } + } + + /** + * 导入数据 + */ + @ResponseBody + @RequiresPermissions("biz:mailAttachments:edit") + @PostMapping(value = "importData") + public String importData(MultipartFile file) { + try { + String message = bizMailAttachmentsService.importData(file); + return renderResult(Global.TRUE, "posfull:"+message); + } catch (Exception ex) { + return renderResult(Global.FALSE, "posfull:"+ex.getMessage()); + } + } + + /** + * 删除数据 + */ + @RequiresPermissions("biz:mailAttachments:edit") + @RequestMapping(value = "delete") + @ResponseBody + public String delete(BizMailAttachments bizMailAttachments) { + bizMailAttachmentsService.delete(bizMailAttachments); + return renderResult(Global.TRUE, text("删除邮件附件表成功!")); + } + +} \ No newline at end of file diff --git a/web-api/src/main/java/com/jeesite/modules/biz/web/BizMailReceivedController.java b/web-api/src/main/java/com/jeesite/modules/biz/web/BizMailReceivedController.java new file mode 100644 index 00000000..03d2a375 --- /dev/null +++ b/web-api/src/main/java/com/jeesite/modules/biz/web/BizMailReceivedController.java @@ -0,0 +1,146 @@ +package com.jeesite.modules.biz.web; + +import java.util.List; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import org.apache.shiro.authz.annotation.RequiresPermissions; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +import com.jeesite.common.config.Global; +import com.jeesite.common.collect.ListUtils; +import com.jeesite.common.entity.Page; +import com.jeesite.common.lang.DateUtils; +import com.jeesite.common.utils.excel.ExcelExport; +import com.jeesite.common.utils.excel.annotation.ExcelField.Type; +import org.springframework.web.multipart.MultipartFile; +import com.jeesite.common.web.BaseController; +import com.jeesite.modules.biz.entity.BizMailReceived; +import com.jeesite.modules.biz.service.BizMailReceivedService; + +/** + * 收件Controller + * @author gaoxq + * @version 2025-12-14 + */ +@Controller +@RequestMapping(value = "${adminPath}/biz/mailReceived") +public class BizMailReceivedController extends BaseController { + + private final BizMailReceivedService bizMailReceivedService; + + public BizMailReceivedController(BizMailReceivedService bizMailReceivedService) { + this.bizMailReceivedService = bizMailReceivedService; + } + + /** + * 获取数据 + */ + @ModelAttribute + public BizMailReceived get(String id, boolean isNewRecord) { + return bizMailReceivedService.get(id, isNewRecord); + } + + /** + * 查询列表 + */ + @RequiresPermissions("biz:mailReceived:view") + @RequestMapping(value = {"list", ""}) + public String list(BizMailReceived bizMailReceived, Model model) { + model.addAttribute("bizMailReceived", bizMailReceived); + return "modules/biz/bizMailReceivedList"; + } + + /** + * 查询列表数据 + */ + @RequiresPermissions("biz:mailReceived:view") + @RequestMapping(value = "listData") + @ResponseBody + public Page listData(BizMailReceived bizMailReceived, HttpServletRequest request, HttpServletResponse response) { + bizMailReceived.setPage(new Page<>(request, response)); + Page page = bizMailReceivedService.findPage(bizMailReceived); + return page; + } + + /** + * 查看编辑表单 + */ + @RequiresPermissions("biz:mailReceived:view") + @RequestMapping(value = "form") + public String form(BizMailReceived bizMailReceived, Model model) { + model.addAttribute("bizMailReceived", bizMailReceived); + return "modules/biz/bizMailReceivedForm"; + } + + /** + * 保存数据 + */ + @RequiresPermissions("biz:mailReceived:edit") + @PostMapping(value = "save") + @ResponseBody + public String save(@Validated BizMailReceived bizMailReceived) { + bizMailReceivedService.save(bizMailReceived); + return renderResult(Global.TRUE, text("保存收件成功!")); + } + + /** + * 导出数据 + */ + @RequiresPermissions("biz:mailReceived:view") + @RequestMapping(value = "exportData") + public void exportData(BizMailReceived bizMailReceived, HttpServletResponse response) { + List list = bizMailReceivedService.findList(bizMailReceived); + String fileName = "收件" + DateUtils.getDate("yyyyMMddHHmmss") + ".xlsx"; + try(ExcelExport ee = new ExcelExport("收件", BizMailReceived.class)){ + ee.setDataList(list).write(response, fileName); + } + } + + /** + * 下载模板 + */ + @RequiresPermissions("biz:mailReceived:view") + @RequestMapping(value = "importTemplate") + public void importTemplate(HttpServletResponse response) { + BizMailReceived bizMailReceived = new BizMailReceived(); + List list = ListUtils.newArrayList(bizMailReceived); + String fileName = "收件模板.xlsx"; + try(ExcelExport ee = new ExcelExport("收件", BizMailReceived.class, Type.IMPORT)){ + ee.setDataList(list).write(response, fileName); + } + } + + /** + * 导入数据 + */ + @ResponseBody + @RequiresPermissions("biz:mailReceived:edit") + @PostMapping(value = "importData") + public String importData(MultipartFile file) { + try { + String message = bizMailReceivedService.importData(file); + return renderResult(Global.TRUE, "posfull:"+message); + } catch (Exception ex) { + return renderResult(Global.FALSE, "posfull:"+ex.getMessage()); + } + } + + /** + * 删除数据 + */ + @RequiresPermissions("biz:mailReceived:edit") + @RequestMapping(value = "delete") + @ResponseBody + public String delete(BizMailReceived bizMailReceived) { + bizMailReceivedService.delete(bizMailReceived); + return renderResult(Global.TRUE, text("删除收件成功!")); + } + +} \ No newline at end of file diff --git a/web-api/src/main/java/com/jeesite/modules/biz/web/BizMailSentController.java b/web-api/src/main/java/com/jeesite/modules/biz/web/BizMailSentController.java new file mode 100644 index 00000000..fef42831 --- /dev/null +++ b/web-api/src/main/java/com/jeesite/modules/biz/web/BizMailSentController.java @@ -0,0 +1,146 @@ +package com.jeesite.modules.biz.web; + +import java.util.List; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import org.apache.shiro.authz.annotation.RequiresPermissions; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +import com.jeesite.common.config.Global; +import com.jeesite.common.collect.ListUtils; +import com.jeesite.common.entity.Page; +import com.jeesite.common.lang.DateUtils; +import com.jeesite.common.utils.excel.ExcelExport; +import com.jeesite.common.utils.excel.annotation.ExcelField.Type; +import org.springframework.web.multipart.MultipartFile; +import com.jeesite.common.web.BaseController; +import com.jeesite.modules.biz.entity.BizMailSent; +import com.jeesite.modules.biz.service.BizMailSentService; + +/** + * 发件Controller + * @author gaoxq + * @version 2025-12-14 + */ +@Controller +@RequestMapping(value = "${adminPath}/biz/mailSent") +public class BizMailSentController extends BaseController { + + private final BizMailSentService bizMailSentService; + + public BizMailSentController(BizMailSentService bizMailSentService) { + this.bizMailSentService = bizMailSentService; + } + + /** + * 获取数据 + */ + @ModelAttribute + public BizMailSent get(String id, boolean isNewRecord) { + return bizMailSentService.get(id, isNewRecord); + } + + /** + * 查询列表 + */ + @RequiresPermissions("biz:mailSent:view") + @RequestMapping(value = {"list", ""}) + public String list(BizMailSent bizMailSent, Model model) { + model.addAttribute("bizMailSent", bizMailSent); + return "modules/biz/bizMailSentList"; + } + + /** + * 查询列表数据 + */ + @RequiresPermissions("biz:mailSent:view") + @RequestMapping(value = "listData") + @ResponseBody + public Page listData(BizMailSent bizMailSent, HttpServletRequest request, HttpServletResponse response) { + bizMailSent.setPage(new Page<>(request, response)); + Page page = bizMailSentService.findPage(bizMailSent); + return page; + } + + /** + * 查看编辑表单 + */ + @RequiresPermissions("biz:mailSent:view") + @RequestMapping(value = "form") + public String form(BizMailSent bizMailSent, Model model) { + model.addAttribute("bizMailSent", bizMailSent); + return "modules/biz/bizMailSentForm"; + } + + /** + * 保存数据 + */ + @RequiresPermissions("biz:mailSent:edit") + @PostMapping(value = "save") + @ResponseBody + public String save(@Validated BizMailSent bizMailSent) { + bizMailSentService.save(bizMailSent); + return renderResult(Global.TRUE, text("保存发件成功!")); + } + + /** + * 导出数据 + */ + @RequiresPermissions("biz:mailSent:view") + @RequestMapping(value = "exportData") + public void exportData(BizMailSent bizMailSent, HttpServletResponse response) { + List list = bizMailSentService.findList(bizMailSent); + String fileName = "发件" + DateUtils.getDate("yyyyMMddHHmmss") + ".xlsx"; + try(ExcelExport ee = new ExcelExport("发件", BizMailSent.class)){ + ee.setDataList(list).write(response, fileName); + } + } + + /** + * 下载模板 + */ + @RequiresPermissions("biz:mailSent:view") + @RequestMapping(value = "importTemplate") + public void importTemplate(HttpServletResponse response) { + BizMailSent bizMailSent = new BizMailSent(); + List list = ListUtils.newArrayList(bizMailSent); + String fileName = "发件模板.xlsx"; + try(ExcelExport ee = new ExcelExport("发件", BizMailSent.class, Type.IMPORT)){ + ee.setDataList(list).write(response, fileName); + } + } + + /** + * 导入数据 + */ + @ResponseBody + @RequiresPermissions("biz:mailSent:edit") + @PostMapping(value = "importData") + public String importData(MultipartFile file) { + try { + String message = bizMailSentService.importData(file); + return renderResult(Global.TRUE, "posfull:"+message); + } catch (Exception ex) { + return renderResult(Global.FALSE, "posfull:"+ex.getMessage()); + } + } + + /** + * 删除数据 + */ + @RequiresPermissions("biz:mailSent:edit") + @RequestMapping(value = "delete") + @ResponseBody + public String delete(BizMailSent bizMailSent) { + bizMailSentService.delete(bizMailSent); + return renderResult(Global.TRUE, text("删除发件成功!")); + } + +} \ No newline at end of file diff --git a/web-api/src/main/resources/mappings/modules/biz/BizMailAccountDao.xml b/web-api/src/main/resources/mappings/modules/biz/BizMailAccountDao.xml new file mode 100644 index 00000000..52e16c09 --- /dev/null +++ b/web-api/src/main/resources/mappings/modules/biz/BizMailAccountDao.xml @@ -0,0 +1,15 @@ + + + + + + + \ No newline at end of file diff --git a/web-api/src/main/resources/mappings/modules/biz/BizMailAttachmentsDao.xml b/web-api/src/main/resources/mappings/modules/biz/BizMailAttachmentsDao.xml new file mode 100644 index 00000000..50794edd --- /dev/null +++ b/web-api/src/main/resources/mappings/modules/biz/BizMailAttachmentsDao.xml @@ -0,0 +1,15 @@ + + + + + + + \ No newline at end of file diff --git a/web-api/src/main/resources/mappings/modules/biz/BizMailReceivedDao.xml b/web-api/src/main/resources/mappings/modules/biz/BizMailReceivedDao.xml new file mode 100644 index 00000000..e131f1fb --- /dev/null +++ b/web-api/src/main/resources/mappings/modules/biz/BizMailReceivedDao.xml @@ -0,0 +1,15 @@ + + + + + + + \ No newline at end of file diff --git a/web-api/src/main/resources/mappings/modules/biz/BizMailSentDao.xml b/web-api/src/main/resources/mappings/modules/biz/BizMailSentDao.xml new file mode 100644 index 00000000..7f7a311f --- /dev/null +++ b/web-api/src/main/resources/mappings/modules/biz/BizMailSentDao.xml @@ -0,0 +1,15 @@ + + + + + + + \ No newline at end of file diff --git a/web-vue/packages/biz/api/biz/mailAccount.ts b/web-vue/packages/biz/api/biz/mailAccount.ts new file mode 100644 index 00000000..69e254ad --- /dev/null +++ b/web-vue/packages/biz/api/biz/mailAccount.ts @@ -0,0 +1,63 @@ +/** + * Copyright (c) 2013-Now http://jeesite.com All rights reserved. + * No deletion without permission, or be held responsible to law. + * @author gaoxq + */ +import { defHttp } from '@jeesite/core/utils/http/axios'; +import { useGlobSetting } from '@jeesite/core/hooks/setting'; +import { BasicModel, Page } from '@jeesite/core/api/model/baseModel'; +import { UploadApiResult } from '@jeesite/core/api/sys/upload'; +import { UploadFileParams } from '@jeesite/types/axios'; +import { AxiosProgressEvent } from 'axios'; + +const { ctxPath, adminPath } = useGlobSetting(); + +export interface BizMailAccount extends BasicModel { + createTime: string; // 记录时间 + accountName: string; + host: string; // SMTP服务 + smtpPort: number; // SMTP端口 + imapHost: string; // IMAP服务 + imapPort: number; // IMAP端口 + username: string; // 用户名称 + password: string; // 用户密码 + fromAddress: string; // 发件人地址 + sslEnable?: string; // 是否启用SSL + ustatus: string; //状态 + remark?: string; // 备注 + updateTime: string; // 更新时间 + ftenantId?: string; // 租户id + fflowId?: string; // 流程id + fflowTaskId?: string; // 流程任务主键 + fflowState?: number; // 流程任务状态 +} + +export const bizMailAccountList = (params?: BizMailAccount | any) => + defHttp.get({ url: adminPath + '/biz/mailAccount/list', params }); + +export const bizMailAccountListData = (params?: BizMailAccount | any) => + defHttp.post>({ url: adminPath + '/biz/mailAccount/listData', params }); + +export const bizMailAccountForm = (params?: BizMailAccount | any) => + defHttp.get({ url: adminPath + '/biz/mailAccount/form', params }); + +export const bizMailAccountSave = (params?: any, data?: BizMailAccount | any) => + defHttp.postJson({ url: adminPath + '/biz/mailAccount/save', params, data }); + +export const bizMailAccountImportData = ( + params: UploadFileParams, + onUploadProgress: (progressEvent: AxiosProgressEvent) => void, +) => + defHttp.uploadFile( + { + url: ctxPath + adminPath + '/biz/mailAccount/importData', + onUploadProgress, + }, + params, + ); + +export const bizMailAccountDelete = (params?: BizMailAccount | any) => + defHttp.get({ url: adminPath + '/biz/mailAccount/delete', params }); + +export const bizMailReceived = (params?: BizMailAccount | any) => + defHttp.get({ url: adminPath + '/biz/mailAccount/received', params }); diff --git a/web-vue/packages/biz/api/biz/mailAttachments.ts b/web-vue/packages/biz/api/biz/mailAttachments.ts new file mode 100644 index 00000000..33d86b7d --- /dev/null +++ b/web-vue/packages/biz/api/biz/mailAttachments.ts @@ -0,0 +1,55 @@ +/** + * Copyright (c) 2013-Now http://jeesite.com All rights reserved. + * No deletion without permission, or be held responsible to law. + * @author gaoxq + */ +import { defHttp } from '@jeesite/core/utils/http/axios'; +import { useGlobSetting } from '@jeesite/core/hooks/setting'; +import { BasicModel, Page } from '@jeesite/core/api/model/baseModel'; +import { UploadApiResult } from '@jeesite/core/api/sys/upload'; +import { UploadFileParams } from '@jeesite/types/axios'; +import { AxiosProgressEvent } from 'axios'; + +const { ctxPath, adminPath } = useGlobSetting(); + +export interface BizMailAttachments extends BasicModel { + createTime?: string; // 记录时间 + mailId: number; // 收件标识 + messageId: string; // 消息标识 + fileName: string; // 附件名称 + fileSize: number; // 文件大小 + fileType?: string; // 文件类型 + fileExt?: string; // 文件扩展名 + storagePath: string; // 存储路径 + fileMd5?: string; // 文件MD5 + downloadCount?: number; // 下载次数 + isCompressed?: string; // 是否压缩 + isEncrypted?: string; // 是否加密 +} + +export const bizMailAttachmentsList = (params?: BizMailAttachments | any) => + defHttp.get({ url: adminPath + '/biz/mailAttachments/list', params }); + +export const bizMailAttachmentsListData = (params?: BizMailAttachments | any) => + defHttp.post>({ url: adminPath + '/biz/mailAttachments/listData', params }); + +export const bizMailAttachmentsForm = (params?: BizMailAttachments | any) => + defHttp.get({ url: adminPath + '/biz/mailAttachments/form', params }); + +export const bizMailAttachmentsSave = (params?: any, data?: BizMailAttachments | any) => + defHttp.postJson({ url: adminPath + '/biz/mailAttachments/save', params, data }); + +export const bizMailAttachmentsImportData = ( + params: UploadFileParams, + onUploadProgress: (progressEvent: AxiosProgressEvent) => void, +) => + defHttp.uploadFile( + { + url: ctxPath + adminPath + '/biz/mailAttachments/importData', + onUploadProgress, + }, + params, + ); + +export const bizMailAttachmentsDelete = (params?: BizMailAttachments | any) => + defHttp.get({ url: adminPath + '/biz/mailAttachments/delete', params }); diff --git a/web-vue/packages/biz/api/biz/mailReceived.ts b/web-vue/packages/biz/api/biz/mailReceived.ts new file mode 100644 index 00000000..5dd506c1 --- /dev/null +++ b/web-vue/packages/biz/api/biz/mailReceived.ts @@ -0,0 +1,58 @@ +/** + * Copyright (c) 2013-Now http://jeesite.com All rights reserved. + * No deletion without permission, or be held responsible to law. + * @author gaoxq + */ +import { defHttp } from '@jeesite/core/utils/http/axios'; +import { useGlobSetting } from '@jeesite/core/hooks/setting'; +import { BasicModel, Page } from '@jeesite/core/api/model/baseModel'; +import { UploadApiResult } from '@jeesite/core/api/sys/upload'; +import { UploadFileParams } from '@jeesite/types/axios'; +import { AxiosProgressEvent } from 'axios'; + +const { ctxPath, adminPath } = useGlobSetting(); + +export interface BizMailReceived extends BasicModel { + createTime: string; // 记录时间 + messageId: string; // 邮件服务器消息ID + accountId: string; // 邮件账户标识 + fromAddress: string; // 发件人地址 + fromName?: string; // 发件人名称 + toAddresses: string; // 收件人地址 + ccAddresses?: string; // 抄送地址 + bccAddresses?: string; // 密送地址 + subject: string; // 邮件主题 + mailContent?: string; // 邮件内容 + receivedTime: string; // 接收时间 + sendTime?: string; // 发送时间 + hasAttachment?: string; // 是否有附件 + mailbox: string; // mailbox + ustatus: string; // 状态 +} + +export const bizMailReceivedList = (params?: BizMailReceived | any) => + defHttp.get({ url: adminPath + '/biz/mailReceived/list', params }); + +export const bizMailReceivedListData = (params?: BizMailReceived | any) => + defHttp.post>({ url: adminPath + '/biz/mailReceived/listData', params }); + +export const bizMailReceivedForm = (params?: BizMailReceived | any) => + defHttp.get({ url: adminPath + '/biz/mailReceived/form', params }); + +export const bizMailReceivedSave = (params?: any, data?: BizMailReceived | any) => + defHttp.postJson({ url: adminPath + '/biz/mailReceived/save', params, data }); + +export const bizMailReceivedImportData = ( + params: UploadFileParams, + onUploadProgress: (progressEvent: AxiosProgressEvent) => void, +) => + defHttp.uploadFile( + { + url: ctxPath + adminPath + '/biz/mailReceived/importData', + onUploadProgress, + }, + params, + ); + +export const bizMailReceivedDelete = (params?: BizMailReceived | any) => + defHttp.get({ url: adminPath + '/biz/mailReceived/delete', params }); diff --git a/web-vue/packages/biz/api/biz/mailSent.ts b/web-vue/packages/biz/api/biz/mailSent.ts new file mode 100644 index 00000000..1ae7ba23 --- /dev/null +++ b/web-vue/packages/biz/api/biz/mailSent.ts @@ -0,0 +1,60 @@ +/** + * Copyright (c) 2013-Now http://jeesite.com All rights reserved. + * No deletion without permission, or be held responsible to law. + * @author gaoxq + */ +import { defHttp } from '@jeesite/core/utils/http/axios'; +import { useGlobSetting } from '@jeesite/core/hooks/setting'; +import { BasicModel, Page } from '@jeesite/core/api/model/baseModel'; +import { UploadApiResult } from '@jeesite/core/api/sys/upload'; +import { UploadFileParams } from '@jeesite/types/axios'; +import { AxiosProgressEvent } from 'axios'; + +const { ctxPath, adminPath } = useGlobSetting(); + +export interface BizMailSent extends BasicModel { + createTime?: string; // 记录时间 + messageId: string; // 件服务器消息标识 + accountId: string; // 邮件账户标识 + fromAddress: string; // 发件人地址 + toAddresses: string; // 收件人地址 + ccAddresses?: string; // 抄送人地址 + subject: string; // 邮件主题 + content: string; // 邮件内容 + sendTime?: string; // 发送时间 + sendStatus: string; // 发送状态 + errorMsg?: string; // 错误信息 + hasAttachment?: string; // 是否有附件 + updateTime?: string; // 更新时间 + ftenantId?: string; // 租户id + fflowId?: string; // 流程id + fflowTaskId?: string; // 流程任务主键 + fflowState?: number; // 流程任务状态 +} + +export const bizMailSentList = (params?: BizMailSent | any) => + defHttp.get({ url: adminPath + '/biz/mailSent/list', params }); + +export const bizMailSentListData = (params?: BizMailSent | any) => + defHttp.post>({ url: adminPath + '/biz/mailSent/listData', params }); + +export const bizMailSentForm = (params?: BizMailSent | any) => + defHttp.get({ url: adminPath + '/biz/mailSent/form', params }); + +export const bizMailSentSave = (params?: any, data?: BizMailSent | any) => + defHttp.postJson({ url: adminPath + '/biz/mailSent/save', params, data }); + +export const bizMailSentImportData = ( + params: UploadFileParams, + onUploadProgress: (progressEvent: AxiosProgressEvent) => void, +) => + defHttp.uploadFile( + { + url: ctxPath + adminPath + '/biz/mailSent/importData', + onUploadProgress, + }, + params, + ); + +export const bizMailSentDelete = (params?: BizMailSent | any) => + defHttp.get({ url: adminPath + '/biz/mailSent/delete', params }); diff --git a/web-vue/packages/biz/views/biz/dbConfig/form.vue b/web-vue/packages/biz/views/biz/dbConfig/form.vue index 835a19d4..51558917 100644 --- a/web-vue/packages/biz/views/biz/dbConfig/form.vue +++ b/web-vue/packages/biz/views/biz/dbConfig/form.vue @@ -91,7 +91,7 @@ { label: t('数据库密码'), field: 'dbPassword', - component: 'Input', + component: 'InputPassword', componentProps: { maxlength: 256, }, diff --git a/web-vue/packages/biz/views/biz/mailInfo/account/form.vue b/web-vue/packages/biz/views/biz/mailInfo/account/form.vue new file mode 100644 index 00000000..587aa64e --- /dev/null +++ b/web-vue/packages/biz/views/biz/mailInfo/account/form.vue @@ -0,0 +1,186 @@ + + + diff --git a/web-vue/packages/biz/views/biz/mailInfo/account/formImport.vue b/web-vue/packages/biz/views/biz/mailInfo/account/formImport.vue new file mode 100644 index 00000000..2558d17f --- /dev/null +++ b/web-vue/packages/biz/views/biz/mailInfo/account/formImport.vue @@ -0,0 +1,103 @@ + + + diff --git a/web-vue/packages/biz/views/biz/mailInfo/account/list.vue b/web-vue/packages/biz/views/biz/mailInfo/account/list.vue new file mode 100644 index 00000000..ca7deeef --- /dev/null +++ b/web-vue/packages/biz/views/biz/mailInfo/account/list.vue @@ -0,0 +1,311 @@ + + + diff --git a/web-vue/packages/biz/views/biz/mailInfo/account/select.ts b/web-vue/packages/biz/views/biz/mailInfo/account/select.ts new file mode 100644 index 00000000..8dc6db2e --- /dev/null +++ b/web-vue/packages/biz/views/biz/mailInfo/account/select.ts @@ -0,0 +1,180 @@ +import { useI18n } from '@jeesite/core/hooks/web/useI18n'; +import { BasicColumn, BasicTableProps, FormProps } from '@jeesite/core/components/Table'; +import { bizMailAccountListData } from '@jeesite/biz/api/biz/mailAccount'; + +const { t } = useI18n('biz.mailAccount'); + +const modalProps = { + title: t('邮件信息选择'), +}; + +const searchForm: FormProps = { + baseColProps: { md: 8, lg: 6 }, + labelWidth: 90, + schemas: [ + { + label: t('记录时间起'), + field: 'createTime_gte', + component: 'DatePicker', + componentProps: { + format: 'YYYY-MM-DD HH:mm', + showTime: { format: 'HH:mm' }, + }, + }, + { + label: t('记录时间止'), + field: 'createTime_lte', + component: 'DatePicker', + componentProps: { + format: 'YYYY-MM-DD HH:mm', + showTime: { format: 'HH:mm' }, + }, + }, + { + label: t('服务地址'), + field: 'host', + component: 'Input', + }, + { + label: t('用户名称'), + field: 'username', + component: 'Input', + }, + { + label: t('发件人地址'), + field: 'fromAddress', + component: 'Input', + }, + { + label: t('是否启用SSL'), + field: 'sslEnable', + component: 'Select', + componentProps: { + dictType: 'is_open', + allowClear: true, + }, + }, + { + label: t('状态'), + field: 'status', + component: 'Select', + componentProps: { + dictType: 'ustatus', + allowClear: true, + }, + }, + ], +}; + +const tableColumns: BasicColumn[] = [ + { + title: t('记录时间'), + dataIndex: 'createTime', + key: 'a.create_time', + sorter: true, + width: 230, + align: 'left', + slot: 'firstColumn', + }, + { + title: t('服务地址'), + dataIndex: 'host', + key: 'a.host', + sorter: true, + width: 130, + align: 'left', + }, + { + title: t('SMTP端口'), + dataIndex: 'smtpPort', + key: 'a.smtp_port', + sorter: true, + width: 130, + align: 'center', + }, + { + title: t('IMAP端口'), + dataIndex: 'imapPort', + key: 'a.imap_port', + sorter: true, + width: 130, + align: 'center', + }, + { + title: t('用户名称'), + dataIndex: 'username', + key: 'a.username', + sorter: true, + width: 130, + align: 'left', + }, + { + title: t('用户密码'), + dataIndex: 'password', + key: 'a.password', + sorter: true, + width: 130, + align: 'left', + }, + { + title: t('发件人地址'), + dataIndex: 'fromAddress', + key: 'a.from_address', + sorter: true, + width: 130, + align: 'left', + }, + { + title: t('是否启用SSL'), + dataIndex: 'sslEnable', + key: 'a.ssl_enable', + sorter: true, + width: 130, + align: 'center', + dictType: 'is_open', + }, + { + title: t('状态'), + dataIndex: 'status', + key: 'a.status', + sorter: true, + width: 130, + align: 'center', + dictType: 'ustatus', + }, + { + title: t('备注'), + dataIndex: 'remark', + key: 'a.remark', + sorter: true, + width: 130, + align: 'left', + }, + { + title: t('更新时间'), + dataIndex: 'updateTime', + key: 'a.update_time', + sorter: true, + width: 130, + align: 'center', + }, +]; + +const tableProps: BasicTableProps = { + api: bizMailAccountListData, + beforeFetch: (params) => { + params['isAll'] = true; + return params; + }, + columns: tableColumns, + formConfig: searchForm, + rowKey: 'id', +}; + +export default { + modalProps, + tableProps, + itemCode: 'id', + itemName: 'id', + isShowCode: false, +}; diff --git a/web-vue/packages/biz/views/biz/mailInfo/attachments/formImport.vue b/web-vue/packages/biz/views/biz/mailInfo/attachments/formImport.vue new file mode 100644 index 00000000..a6234290 --- /dev/null +++ b/web-vue/packages/biz/views/biz/mailInfo/attachments/formImport.vue @@ -0,0 +1,103 @@ + + + diff --git a/web-vue/packages/biz/views/biz/mailInfo/attachments/list.vue b/web-vue/packages/biz/views/biz/mailInfo/attachments/list.vue new file mode 100644 index 00000000..5d53fe5d --- /dev/null +++ b/web-vue/packages/biz/views/biz/mailInfo/attachments/list.vue @@ -0,0 +1,258 @@ + + + diff --git a/web-vue/packages/biz/views/biz/mailInfo/index.vue b/web-vue/packages/biz/views/biz/mailInfo/index.vue new file mode 100644 index 00000000..8aec0bad --- /dev/null +++ b/web-vue/packages/biz/views/biz/mailInfo/index.vue @@ -0,0 +1,39 @@ + + + + \ No newline at end of file diff --git a/web-vue/packages/biz/views/biz/mailInfo/received/formImport.vue b/web-vue/packages/biz/views/biz/mailInfo/received/formImport.vue new file mode 100644 index 00000000..c98dc5fd --- /dev/null +++ b/web-vue/packages/biz/views/biz/mailInfo/received/formImport.vue @@ -0,0 +1,103 @@ + + + diff --git a/web-vue/packages/biz/views/biz/mailInfo/received/list.vue b/web-vue/packages/biz/views/biz/mailInfo/received/list.vue new file mode 100644 index 00000000..a0dd1c9b --- /dev/null +++ b/web-vue/packages/biz/views/biz/mailInfo/received/list.vue @@ -0,0 +1,227 @@ + + + diff --git a/web-vue/packages/biz/views/biz/mailInfo/sent/form.vue b/web-vue/packages/biz/views/biz/mailInfo/sent/form.vue new file mode 100644 index 00000000..0445c14f --- /dev/null +++ b/web-vue/packages/biz/views/biz/mailInfo/sent/form.vue @@ -0,0 +1,137 @@ + + + diff --git a/web-vue/packages/biz/views/biz/mailInfo/sent/formImport.vue b/web-vue/packages/biz/views/biz/mailInfo/sent/formImport.vue new file mode 100644 index 00000000..554a4f91 --- /dev/null +++ b/web-vue/packages/biz/views/biz/mailInfo/sent/formImport.vue @@ -0,0 +1,103 @@ + + + diff --git a/web-vue/packages/biz/views/biz/mailInfo/sent/list.vue b/web-vue/packages/biz/views/biz/mailInfo/sent/list.vue new file mode 100644 index 00000000..95d447a4 --- /dev/null +++ b/web-vue/packages/biz/views/biz/mailInfo/sent/list.vue @@ -0,0 +1,252 @@ + + + diff --git a/web-vue/packages/biz/views/biz/mailInfo/sent/select.ts b/web-vue/packages/biz/views/biz/mailInfo/sent/select.ts new file mode 100644 index 00000000..44e99b55 --- /dev/null +++ b/web-vue/packages/biz/views/biz/mailInfo/sent/select.ts @@ -0,0 +1,196 @@ +import { useI18n } from '@jeesite/core/hooks/web/useI18n'; +import { BasicColumn, BasicTableProps, FormProps } from '@jeesite/core/components/Table'; +import { bizMailSentListData } from '@jeesite/biz/api/biz/mailSent'; + +const { t } = useI18n('biz.mailSent'); + +const modalProps = { + title: t('发件选择'), +}; + +const searchForm: FormProps = { + baseColProps: { md: 8, lg: 6 }, + labelWidth: 90, + schemas: [ + { + label: t('记录时间起'), + field: 'createTime_gte', + component: 'DatePicker', + componentProps: { + format: 'YYYY-MM-DD HH:mm', + showTime: { format: 'HH:mm' }, + }, + }, + { + label: t('记录时间止'), + field: 'createTime_lte', + component: 'DatePicker', + componentProps: { + format: 'YYYY-MM-DD HH:mm', + showTime: { format: 'HH:mm' }, + }, + }, + { + label: t('邮件账户标识'), + field: 'accountId', + component: 'Input', + }, + { + label: t('发件人地址'), + field: 'fromAddress', + component: 'Input', + }, + { + label: t('邮件主题'), + field: 'subject', + component: 'Input', + }, + { + label: t('发送状态'), + field: 'sendStatus', + component: 'Select', + componentProps: { + dictType: '', + allowClear: true, + }, + }, + { + label: t('是否有附件'), + field: 'hasAttachment', + component: 'Select', + componentProps: { + dictType: '', + allowClear: true, + }, + }, + ], +}; + +const tableColumns: BasicColumn[] = [ + { + title: t('记录时间'), + dataIndex: 'createTime', + key: 'a.create_time', + sorter: true, + width: 230, + align: 'left', + slot: 'firstColumn', + }, + { + title: t('件服务器消息标识'), + dataIndex: 'messageId', + key: 'a.message_id', + sorter: true, + width: 130, + align: 'left', + }, + { + title: t('邮件账户标识'), + dataIndex: 'accountId', + key: 'a.account_id', + sorter: true, + width: 130, + align: 'left', + }, + { + title: t('发件人地址'), + dataIndex: 'fromAddress', + key: 'a.from_address', + sorter: true, + width: 130, + align: 'left', + }, + { + title: t('收件人地址'), + dataIndex: 'toAddresses', + key: 'a.to_addresses', + sorter: true, + width: 130, + align: 'left', + }, + { + title: t('抄送人地址'), + dataIndex: 'ccAddresses', + key: 'a.cc_addresses', + sorter: true, + width: 130, + align: 'left', + }, + { + title: t('邮件主题'), + dataIndex: 'subject', + key: 'a.subject', + sorter: true, + width: 130, + align: 'left', + }, + { + title: t('邮件内容'), + dataIndex: 'content', + key: 'a.content', + sorter: true, + width: 130, + align: 'left', + }, + { + title: t('发送时间'), + dataIndex: 'sendTime', + key: 'a.send_time', + sorter: true, + width: 130, + align: 'center', + }, + { + title: t('发送状态'), + dataIndex: 'sendStatus', + key: 'a.send_status', + sorter: true, + width: 130, + align: 'left', + dictType: '', + }, + { + title: t('错误信息'), + dataIndex: 'errorMsg', + key: 'a.error_msg', + sorter: true, + width: 130, + align: 'left', + }, + { + title: t('是否有附件'), + dataIndex: 'hasAttachment', + key: 'a.has_attachment', + sorter: true, + width: 130, + align: 'left', + dictType: '', + }, + { + title: t('更新时间'), + dataIndex: 'updateTime', + key: 'a.update_time', + sorter: true, + width: 130, + align: 'center', + }, +]; + +const tableProps: BasicTableProps = { + api: bizMailSentListData, + beforeFetch: (params) => { + params['isAll'] = true; + return params; + }, + columns: tableColumns, + formConfig: searchForm, + rowKey: 'id', +}; + +export default { + modalProps, + tableProps, + itemCode: 'id', + itemName: 'id', + isShowCode: false, +}; diff --git a/web-vue/packages/core/views/sys/menu/form.vue b/web-vue/packages/core/views/sys/menu/form.vue index a2ef9556..6b93b634 100644 --- a/web-vue/packages/core/views/sys/menu/form.vue +++ b/web-vue/packages/core/views/sys/menu/form.vue @@ -184,7 +184,7 @@ helpMessage: '控制器中定义的权限标识,如:@RequiresPermissions("权限标识")', component: 'Input', componentProps: { - maxlength: 100, + maxlength: 1000, }, },