新增预警页面

This commit is contained in:
2025-12-14 21:54:26 +08:00
parent 0b40608761
commit f3da7da439
33 changed files with 1666 additions and 780 deletions

View File

@@ -0,0 +1,79 @@
package com.jeesite.modules.app.Job;
import com.jeesite.common.config.Global;
import com.jeesite.modules.app.dao.MailReceived;
import com.jeesite.modules.app.utils.LoggerUtils;
import com.jeesite.modules.app.utils.MailReceiveUtils;
import com.jeesite.modules.biz.entity.BizMailAccount;
import com.jeesite.modules.biz.entity.BizMailAttachments;
import com.jeesite.modules.biz.entity.BizMailReceived;
import com.jeesite.modules.biz.service.BizMailAccountService;
import com.jeesite.modules.biz.service.BizMailAttachmentsService;
import com.jeesite.modules.biz.service.BizMailReceivedService;
import jakarta.annotation.Resource;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Controller;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
@Controller
public class mailJob {
@Resource
private BizMailAccountService bizMailAccountService;
@Resource
private BizMailReceivedService receivedService;
@Resource
private BizMailAttachmentsService attachmentsService;
@Resource(name = "hostMonitorExecutor")
private ThreadPoolTaskExecutor hostMonitorExecutor;
private String MAIL_PATH = "/ogsapp/mail";
private static final LoggerUtils logger = LoggerUtils.getInstance();
private static final boolean CRON_JOB = Boolean.parseBoolean(Global.getConfig("biz.cron.MailJob", "false"));
@Scheduled(cron = "10 0/15 * * * ?")
public void getMailReceived() {
if (CRON_JOB) {
List<BizMailAccount> accounts = bizMailAccountService.findList(new BizMailAccount());
List<CompletableFuture<Void>> futures = new ArrayList<>(accounts.size());
for (BizMailAccount account : accounts) {
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
try {
List<MailReceived> receivedList = MailReceiveUtils.receiveUnreadMails(account, MAIL_PATH);
for (MailReceived mailReceived : receivedList) {
BizMailReceived received = mailReceived.getReceived();
List<BizMailAttachments> attachments = mailReceived.getAttachments();
for (BizMailAttachments mailAttachments : attachments) {
attachmentsService.insert(mailAttachments);
}
receivedService.save(received);
}
} catch (Exception e) {
logger.error(e.getMessage());
}
}, hostMonitorExecutor); // 指定使用配置的线程池
futures.add(future);
}
try {
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
.get(60, TimeUnit.SECONDS); // 超时时间可根据业务调整
} catch (Exception e) {
logger.error(e.getMessage());
}
}
}
}

View File

@@ -0,0 +1,162 @@
package com.jeesite.modules.app.utils;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.FileCopyUtils;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
/**
* 文件下载工具类
* 支持两种方式:
* 1. 基于HttpServletResponse直接输出适用于传统Servlet/SSM
* 2. 返回ResponseEntity<byte[]>适用于SpringBoot
* 修复点:解决文件名前后加下划线、中文乱码、浏览器兼容性问题
*/
public class FileDownloadUtils {
/**
* 私有构造方法,禁止实例化
*/
private FileDownloadUtils() {
throw new UnsupportedOperationException("工具类禁止实例化");
}
/**
* 方式1通过HttpServletResponse下载文件推荐SSM/Servlet使用
*
* @param orgFileName 文件完整路径例如D:/files/test.pdf
* @param fileName 下载时显示的文件名(例如:测试文件.pdf
* @param response HttpServletResponse对象
* @throws Exception 文件操作异常
*/
public static void downloadFile(String orgFileName, String fileName, HttpServletResponse response) throws Exception {
// 1. 构建完整文件路径
Path fullFilePath = Paths.get(orgFileName);
File file = fullFilePath.toFile();
// 2. 校验文件合法性
validateFile(file);
// 3. 清理并编码文件名(避免特殊字符导致的解析异常)
String encodedFileName = encodeFileName(fileName);
// 4. 设置响应头(核心修复:解决下划线/乱码问题)
setDownloadResponseHeader(response, encodedFileName, file.length());
// 5. 读取文件并写入响应输出流try-with-resources自动关闭流
try (InputStream inputStream = new BufferedInputStream(Files.newInputStream(fullFilePath));
OutputStream outputStream = new BufferedOutputStream(response.getOutputStream())) {
FileCopyUtils.copy(inputStream, outputStream);
outputStream.flush();
} catch (IOException e) {
throw new IOException("文件下载失败:" + e.getMessage(), e);
}
}
/**
* 方式2返回ResponseEntity<byte[]>推荐SpringBoot使用
*
* @param orgFileName 文件完整路径例如D:/files/test.pdf
* @param fileName 下载时显示的文件名(例如:测试文件.pdf
* @return ResponseEntity<byte [ ]> 下载响应实体
* @throws IOException 文件操作异常
*/
public static ResponseEntity<byte[]> downloadFile(String orgFileName, String fileName) throws IOException {
// 1. 构建完整文件路径
Path fullFilePath = Paths.get(orgFileName);
File file = fullFilePath.toFile();
// 2. 校验文件合法性
validateFile(file);
// 3. 读取文件字节数组
byte[] fileBytes = Files.readAllBytes(fullFilePath);
// 4. 清理并编码文件名
String encodedFileName = encodeFileName(fileName);
HttpHeaders headers = new HttpHeaders();
// 核心修复使用RFC 5987标准移除多余双引号避免下划线问题
headers.set(HttpHeaders.CONTENT_DISPOSITION,
String.format("attachment; filename=%s; filename*=UTF-8''%s",
encodedFileName, encodedFileName));
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
headers.setContentLength(fileBytes.length);
// 禁止缓存
headers.setCacheControl("no-cache, no-store, must-revalidate");
headers.setPragma("no-cache");
headers.setExpires(0);
// 6. 返回响应实体
return new ResponseEntity<>(fileBytes, headers, HttpStatus.OK);
}
/**
* 校验文件合法性(存在性、是否为文件、读取权限)
*
* @param file 待校验文件
* @throws FileNotFoundException 文件不合法异常
*/
private static void validateFile(File file) throws FileNotFoundException {
if (!file.exists()) {
throw new FileNotFoundException("文件不存在:" + file.getAbsolutePath());
}
if (file.isDirectory()) {
throw new FileNotFoundException("路径指向目录,不是文件:" + file.getAbsolutePath());
}
if (!file.canRead()) {
throw new FileNotFoundException("文件无读取权限:" + file.getAbsolutePath());
}
}
/**
* 设置下载响应头(核心修复:解决下划线/乱码/浏览器兼容问题)
*
* @param response HttpServletResponse
* @param encodedFileName 编码后的文件名
* @param fileSize 文件大小
*/
private static void setDownloadResponseHeader(HttpServletResponse response, String encodedFileName, long fileSize) {
// 设置响应内容类型为二进制流
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
// 设置字符编码
response.setCharacterEncoding(StandardCharsets.UTF_8.name());
// 设置内容长度
response.setContentLengthLong(fileSize);
// 核心修复使用RFC 5987标准移除多余双引号避免浏览器解析出下划线
response.setHeader(HttpHeaders.CONTENT_DISPOSITION,
String.format("attachment; filename=%s; filename*=UTF-8''%s",
encodedFileName, encodedFileName));
// 禁止缓存
response.setHeader(HttpHeaders.CACHE_CONTROL, "no-cache, no-store, must-revalidate");
response.setHeader(HttpHeaders.PRAGMA, "no-cache");
response.setDateHeader(HttpHeaders.EXPIRES, 0);
}
/**
* 编码文件名(解决中文乱码+空格转+号导致的下划线问题)
*
* @param fileName 清理后的文件名
* @return 编码后的文件名
*/
private static String encodeFileName(String fileName) {
try {
// 修复:将空格编码为%20而非+,避免浏览器解析为下划线
return URLEncoder.encode(fileName, StandardCharsets.UTF_8.name())
.replace("+", "%20");
} catch (UnsupportedEncodingException e) {
// 理论上UTF-8不会抛出此异常兜底返回原文件名
return fileName;
}
}
}

View File

@@ -598,11 +598,10 @@ public class MailReceiveUtils {
attachment.setFileMd5(md5);
attachment.setDownloadCount(0);
attachment.setIsCompressed(isCompressedFile(originalFileName) ? "1" : "0");
attachment.setIsEncrypted("N");
attachment.setIsEncrypted("0");
attachment.setDownloadStartTime(new Date(attachDownloadStartTime)); // 附件下载开始时间
attachment.setDownloadEndTime(new Date(attachDownloadEndTime)); // 附件下载结束时间
attachment.setDownloadCostTime(costTime); // 附件下载耗时(毫秒)
return attachment;
}

View File

@@ -0,0 +1,164 @@
package com.jeesite.modules.app.utils;
import com.jeesite.modules.biz.entity.BizMailAccount;
import com.jeesite.modules.biz.entity.BizMailSent;
import com.jeesite.modules.file.entity.FileUpload;
import javax.mail.*;
import javax.mail.internet.*;
import java.io.File;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MailSendUtils {
private static final ExecutorService MAIL_EXECUTOR = Executors.newFixedThreadPool(5);
private static String FILE_PATH = "/ogsapp/files";
/**
* 同步发送HTML格式邮件
*
* @param mailAccount 邮件账户配置
* @param mailSent 邮件发送内容信息
* @return BizMailSent 填充发送结果后的对象
*/
public static BizMailSent sendHtmlMail(BizMailAccount mailAccount, BizMailSent mailSent, List<FileUpload> fileUploads) {
// 初始化发送结果对象
mailSent.setId(mailSent.getId());
mailSent.setCreateTime(new Date());
mailSent.setSendStatus("0"); // 默认失败状态
// 1. 参数校验
if (!validateParams(mailAccount, mailSent)) {
mailSent.setErrorMsg("参数校验失败:邮件账户或发送内容不完整");
return mailSent;
}
Properties props = new Properties();
props.put("mail.smtp.host", mailAccount.getHost());
props.put("mail.smtp.port", mailAccount.getSmtpPort().toString());
props.put("mail.smtp.auth", "true"); // 开启认证
props.put("mail.smtp.socketFactory.port", mailAccount.getSmtpPort().toString());
// SSL配置
if (mailAccount.getSslEnable().equals("true")) {
props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
props.put("mail.smtp.starttls.enable", "true");
}
// 3. 创建认证器
Authenticator authenticator = new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(mailAccount.getUsername(), mailAccount.getPassword());
}
};
// 4. 创建邮件会话
Session session = Session.getInstance(props, authenticator);
session.setDebug(false); // 生产环境关闭调试
try {
// 5. 构建MIME邮件消息
MimeMessage message = new MimeMessage(session);
// 设置发件人
message.setFrom(new InternetAddress(mailAccount.getFromAddress()));
// 设置收件人
if (mailSent.getToAddresses() != null && !mailSent.getToAddresses().isEmpty()) {
String[] toArray = mailSent.getToAddresses().split(",");
InternetAddress[] toAddresses = new InternetAddress[toArray.length];
for (int i = 0; i < toArray.length; i++) {
toAddresses[i] = new InternetAddress(toArray[i].trim());
}
message.setRecipients(Message.RecipientType.TO, toAddresses);
}
// 设置抄送人
if (mailSent.getCcAddresses() != null && !mailSent.getCcAddresses().isEmpty()) {
String[] ccArray = mailSent.getCcAddresses().split(",");
InternetAddress[] ccAddresses = new InternetAddress[ccArray.length];
for (int i = 0; i < ccArray.length; i++) {
ccAddresses[i] = new InternetAddress(ccArray[i].trim());
}
message.setRecipients(Message.RecipientType.CC, ccAddresses);
}
// 设置邮件主题
message.setSubject(mailSent.getSubject(), "UTF-8");
// 构建邮件内容支持HTML和附件
MimeMultipart multipart = new MimeMultipart("mixed");
// HTML内容部分
MimeBodyPart contentPart = new MimeBodyPart();
contentPart.setContent(mailSent.getContent(), "text/html;charset=UTF-8");
multipart.addBodyPart(contentPart);
if (fileUploads.size() > 0) {
mailSent.setHasAttachment("1");
for (FileUpload upload : fileUploads) {
MimeBodyPart attachmentPart = new MimeBodyPart();
File file = new File(FILE_PATH + upload.getFileUrl());
attachmentPart.attachFile(file);
attachmentPart.setFileName(MimeUtility.encodeText(file.getName(), "UTF-8", "B"));
multipart.addBodyPart(attachmentPart);
}
}
// 设置邮件内容
message.setContent(multipart);
// 设置发送时间
message.setSentDate(new Date());
// 6. 发送邮件
Transport.send(message);
// 7. 更新发送结果
mailSent.setSendTime(new Date());
mailSent.setSendStatus("1");
mailSent.setErrorMsg("");
mailSent.setMessageId(message.getMessageID()); // 邮件服务器消息ID
} catch (Exception e) {
// 捕获所有异常,记录错误信息
mailSent.setErrorMsg("邮件发送失败:" + e.getMessage());
mailSent.setSendTime(new Date());
// 打印异常栈(生产环境建议日志记录)
e.printStackTrace();
}
return mailSent;
}
/**
* 异步发送HTML格式邮件
*
* @param mailAccount 邮件账户配置
* @param mailSent 邮件发送内容信息
*/
public static void sendHtmlMailAsync(BizMailAccount mailAccount, BizMailSent mailSent, List<FileUpload> fileUploads) {
MAIL_EXECUTOR.submit(() -> sendHtmlMail(mailAccount, mailSent, fileUploads));
}
/**
* 参数校验
*
* @param mailAccount 邮件账户
* @param mailSent 邮件内容
* @return 校验结果
*/
private static boolean validateParams(BizMailAccount mailAccount, BizMailSent mailSent) {
// 校验账户必填项
if (mailAccount == null || mailAccount.getHost() == null || mailAccount.getSmtpPort() == null
|| mailAccount.getUsername() == null || mailAccount.getPassword() == null
|| mailAccount.getFromAddress() == null) {
return false;
}
// 校验邮件内容必填项
return mailSent != null && mailSent.getToAddresses() != null && !mailSent.getToAddresses().isEmpty()
&& mailSent.getSubject() != null && mailSent.getContent() != null;
}
/**
* 关闭线程池(应用关闭时调用)
*/
public static void shutdownExecutor() {
MAIL_EXECUTOR.shutdown();
}
}

View File

@@ -3,15 +3,6 @@ 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;
@@ -35,7 +26,7 @@ import java.io.Serial;
@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 = "message_id", attrName = "messageId", label = "消息标识"),
@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),

View File

@@ -46,6 +46,12 @@ import java.io.Serial;
@Column(name = "has_attachment", attrName = "hasAttachment", label = "是否有附件"),
@Column(name = "mailbox", attrName = "mailbox", label = "mailbox", isQuery = false),
@Column(name = "ustatus", attrName = "ustatus", label = "状态"),
}, joinTable = {
@JoinTable(type = Type.LEFT_JOIN, entity = BizMailAccount.class, attrName = "this", alias = "b",
on = "a.account_id = b.id",
columns = {
@Column(name = "account_name", attrName = "accountName", label = "配置名称"),
}),
}, orderBy = "a.id DESC"
)
@Data
@@ -69,11 +75,12 @@ public class BizMailReceived extends DataEntity<BizMailReceived> implements Seri
private String mailbox; // mailbox
private String ustatus; // 状态
private String accountName;
@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 = "id", align = Align.CENTER, sort = 20),
@ExcelField(title = "配置名称", attrName = "accountName", 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),

View File

@@ -47,6 +47,12 @@ import java.io.Serial;
@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),
}, joinTable = {
@JoinTable(type = Type.LEFT_JOIN, entity = BizMailAccount.class, attrName = "this", alias = "b",
on = "a.account_id = b.id",
columns = {
@Column(name = "account_name", attrName = "accountName", label = "配置名称"),
}),
}, orderBy = "a.create_time DESC"
)
@Data
@@ -72,11 +78,12 @@ public class BizMailSent extends DataEntity<BizMailSent> implements Serializable
private String fflowTaskId; // 流程任务主键
private Integer fflowState; // 流程任务状态
private String accountName;
@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 = "accountName", 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),
@@ -95,6 +102,7 @@ public class BizMailSent extends DataEntity<BizMailSent> implements Serializable
public BizMailSent(String id) {
super(id);
}
public Date getCreateTime_gte() {
return sqlMap.getWhere().getValue("create_time", QueryType.GTE);
}

View File

@@ -1,17 +1,18 @@
package com.jeesite.modules.biz.web;
import java.io.File;
import java.util.List;
import com.jeesite.modules.app.utils.FileDownloadUtils;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.http.ResponseEntity;
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 org.springframework.web.bind.annotation.*;
import com.jeesite.common.config.Global;
import com.jeesite.common.collect.ListUtils;
@@ -26,6 +27,7 @@ import com.jeesite.modules.biz.service.BizMailAttachmentsService;
/**
* 邮件附件表Controller
*
* @author gaoxq
* @version 2025-12-14
*/
@@ -33,114 +35,130 @@ import com.jeesite.modules.biz.service.BizMailAttachmentsService;
@RequestMapping(value = "${adminPath}/biz/mailAttachments")
public class BizMailAttachmentsController extends BaseController {
private final BizMailAttachmentsService bizMailAttachmentsService;
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<BizMailAttachments> listData(BizMailAttachments bizMailAttachments, HttpServletRequest request, HttpServletResponse response) {
bizMailAttachments.setPage(new Page<>(request, response));
Page<BizMailAttachments> page = bizMailAttachmentsService.findPage(bizMailAttachments);
return page;
}
public BizMailAttachmentsController(BizMailAttachmentsService bizMailAttachmentsService) {
this.bizMailAttachmentsService = bizMailAttachmentsService;
}
/**
* 查看编辑表单
*/
@RequiresPermissions("biz:mailAttachments:view")
@RequestMapping(value = "form")
public String form(BizMailAttachments bizMailAttachments, Model model) {
model.addAttribute("bizMailAttachments", bizMailAttachments);
return "modules/biz/bizMailAttachmentsForm";
}
/**
* 获取数据
*/
@ModelAttribute
public BizMailAttachments get(Long tid, boolean isNewRecord) {
return bizMailAttachmentsService.get(tid, isNewRecord);
}
/**
* 保存数据
*/
@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 = {"list", ""})
public String list(BizMailAttachments bizMailAttachments, Model model) {
model.addAttribute("bizMailAttachments", bizMailAttachments);
return "modules/biz/bizMailAttachmentsList";
}
/**
* 导出数据
*/
@RequiresPermissions("biz:mailAttachments:view")
@RequestMapping(value = "exportData")
public void exportData(BizMailAttachments bizMailAttachments, HttpServletResponse response) {
List<BizMailAttachments> 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 = "listData")
@ResponseBody
public Page<BizMailAttachments> listData(BizMailAttachments bizMailAttachments, HttpServletRequest request, HttpServletResponse response) {
bizMailAttachments.setPage(new Page<>(request, response));
Page<BizMailAttachments> page = bizMailAttachmentsService.findPage(bizMailAttachments);
return page;
}
/**
* 下载模板
*/
@RequiresPermissions("biz:mailAttachments:view")
@RequestMapping(value = "importTemplate")
public void importTemplate(HttpServletResponse response) {
BizMailAttachments bizMailAttachments = new BizMailAttachments();
List<BizMailAttachments> list = ListUtils.newArrayList(bizMailAttachments);
String fileName = "邮件附件表模板.xlsx";
try(ExcelExport ee = new ExcelExport("邮件附件表", BizMailAttachments.class, Type.IMPORT)){
ee.setDataList(list).write(response, fileName);
}
}
/**
* 查看编辑表单
*/
@RequiresPermissions("biz:mailAttachments:view")
@RequestMapping(value = "form")
public String form(BizMailAttachments bizMailAttachments, Model model) {
model.addAttribute("bizMailAttachments", bizMailAttachments);
return "modules/biz/bizMailAttachmentsForm";
}
/**
* 导入数据
*/
@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("删除邮件附件表成功!"));
}
/**
* 保存数据
*/
@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<BizMailAttachments> 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<BizMailAttachments> 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("删除邮件附件表成功!"));
}
@RequestMapping(value = "listAll")
@ResponseBody
public List<BizMailAttachments> listAll(BizMailAttachments bizMailAttachments) {
return bizMailAttachmentsService.findList(bizMailAttachments);
}
@PostMapping(value = "downloadFile")
public void downloadFile(BizMailAttachments bizMailAttachments, HttpServletResponse response) {
try {
BizMailAttachments attachments = bizMailAttachmentsService.get(bizMailAttachments);
FileDownloadUtils.downloadFile(attachments.getStoragePath(), attachments.getFileName(), response);
} catch (Exception e) {
System.out.print(e.getMessage());
}
}
}

View File

@@ -1,6 +1,7 @@
package com.jeesite.modules.biz.web;
import java.util.List;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
@@ -26,6 +27,7 @@ import com.jeesite.modules.biz.service.BizMailReceivedService;
/**
* 收件Controller
*
* @author gaoxq
* @version 2025-12-14
*/
@@ -33,114 +35,114 @@ import com.jeesite.modules.biz.service.BizMailReceivedService;
@RequestMapping(value = "${adminPath}/biz/mailReceived")
public class BizMailReceivedController extends BaseController {
private final BizMailReceivedService bizMailReceivedService;
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<BizMailReceived> listData(BizMailReceived bizMailReceived, HttpServletRequest request, HttpServletResponse response) {
bizMailReceived.setPage(new Page<>(request, response));
Page<BizMailReceived> page = bizMailReceivedService.findPage(bizMailReceived);
return page;
}
public BizMailReceivedController(BizMailReceivedService bizMailReceivedService) {
this.bizMailReceivedService = bizMailReceivedService;
}
/**
* 查看编辑表单
*/
@RequiresPermissions("biz:mailReceived:view")
@RequestMapping(value = "form")
public String form(BizMailReceived bizMailReceived, Model model) {
model.addAttribute("bizMailReceived", bizMailReceived);
return "modules/biz/bizMailReceivedForm";
}
/**
* 获取数据
*/
@ModelAttribute
public BizMailReceived get(String id, boolean isNewRecord) {
return bizMailReceivedService.get(id, isNewRecord);
}
/**
* 保存数据
*/
@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 = {"list", ""})
public String list(BizMailReceived bizMailReceived, Model model) {
model.addAttribute("bizMailReceived", bizMailReceived);
return "modules/biz/bizMailReceivedList";
}
/**
* 导出数据
*/
@RequiresPermissions("biz:mailReceived:view")
@RequestMapping(value = "exportData")
public void exportData(BizMailReceived bizMailReceived, HttpServletResponse response) {
List<BizMailReceived> 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 = "listData")
@ResponseBody
public Page<BizMailReceived> listData(BizMailReceived bizMailReceived, HttpServletRequest request, HttpServletResponse response) {
bizMailReceived.setPage(new Page<>(request, response));
Page<BizMailReceived> page = bizMailReceivedService.findPage(bizMailReceived);
return page;
}
/**
* 下载模板
*/
@RequiresPermissions("biz:mailReceived:view")
@RequestMapping(value = "importTemplate")
public void importTemplate(HttpServletResponse response) {
BizMailReceived bizMailReceived = new BizMailReceived();
List<BizMailReceived> list = ListUtils.newArrayList(bizMailReceived);
String fileName = "收件模板.xlsx";
try(ExcelExport ee = new ExcelExport("收件", BizMailReceived.class, Type.IMPORT)){
ee.setDataList(list).write(response, fileName);
}
}
/**
* 查看编辑表单
*/
@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<BizMailReceived> 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<BizMailReceived> 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("删除收件成功!"));
}
/**
* 导入数据
*/
@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("删除收件成功!"));
}
}

View File

@@ -1,6 +1,14 @@
package com.jeesite.modules.biz.web;
import java.util.List;
import com.jeesite.modules.app.utils.MailSendUtils;
import com.jeesite.modules.app.utils.vDate;
import com.jeesite.modules.biz.entity.BizMailAccount;
import com.jeesite.modules.biz.service.BizMailAccountService;
import com.jeesite.modules.file.entity.FileUpload;
import com.jeesite.modules.file.utils.FileUploadUtils;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
@@ -26,6 +34,7 @@ import com.jeesite.modules.biz.service.BizMailSentService;
/**
* 发件Controller
*
* @author gaoxq
* @version 2025-12-14
*/
@@ -33,114 +42,132 @@ import com.jeesite.modules.biz.service.BizMailSentService;
@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<BizMailSent> listData(BizMailSent bizMailSent, HttpServletRequest request, HttpServletResponse response) {
bizMailSent.setPage(new Page<>(request, response));
Page<BizMailSent> page = bizMailSentService.findPage(bizMailSent);
return page;
}
@Resource
private BizMailAccountService accountService;
/**
* 查看编辑表单
*/
@RequiresPermissions("biz:mailSent:view")
@RequestMapping(value = "form")
public String form(BizMailSent bizMailSent, Model model) {
model.addAttribute("bizMailSent", bizMailSent);
return "modules/biz/bizMailSentForm";
}
private final BizMailSentService bizMailSentService;
/**
* 保存数据
*/
@RequiresPermissions("biz:mailSent:edit")
@PostMapping(value = "save")
@ResponseBody
public String save(@Validated BizMailSent bizMailSent) {
bizMailSentService.save(bizMailSent);
return renderResult(Global.TRUE, text("保存发件成功!"));
}
public BizMailSentController(BizMailSentService bizMailSentService) {
this.bizMailSentService = bizMailSentService;
}
/**
* 导出数据
*/
@RequiresPermissions("biz:mailSent:view")
@RequestMapping(value = "exportData")
public void exportData(BizMailSent bizMailSent, HttpServletResponse response) {
List<BizMailSent> list = bizMailSentService.findList(bizMailSent);
String fileName = "发件" + DateUtils.getDate("yyyyMMddHHmmss") + ".xlsx";
try(ExcelExport ee = new ExcelExport("发件", BizMailSent.class)){
ee.setDataList(list).write(response, fileName);
}
}
/**
* 获取数据
*/
@ModelAttribute
public BizMailSent get(String id, boolean isNewRecord) {
return bizMailSentService.get(id, isNewRecord);
}
/**
* 下载模板
*/
@RequiresPermissions("biz:mailSent:view")
@RequestMapping(value = "importTemplate")
public void importTemplate(HttpServletResponse response) {
BizMailSent bizMailSent = new BizMailSent();
List<BizMailSent> list = ListUtils.newArrayList(bizMailSent);
String fileName = "发件模板.xlsx";
try(ExcelExport ee = new ExcelExport("发件", BizMailSent.class, Type.IMPORT)){
ee.setDataList(list).write(response, fileName);
}
}
/**
* 查询列表
*/
@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<BizMailSent> listData(BizMailSent bizMailSent, HttpServletRequest request, HttpServletResponse response) {
bizMailSent.setPage(new Page<>(request, response));
Page<BizMailSent> 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) {
BizMailAccount account = accountService.get(bizMailSent.getAccountId());
bizMailSent.setFromAddress(account.getFromAddress());
bizMailSent.setUpdateTime(vDate.getUpdateTime(bizMailSent.getIsNewRecord()));
bizMailSentService.save(bizMailSent);
return renderResult(Global.TRUE, text("保存发件成功!"));
}
/**
* 导出数据
*/
@RequiresPermissions("biz:mailSent:view")
@RequestMapping(value = "exportData")
public void exportData(BizMailSent bizMailSent, HttpServletResponse response) {
List<BizMailSent> 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<BizMailSent> 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("删除发件成功!"));
}
@RequestMapping(value = "sent")
@ResponseBody
public String sent(BizMailSent bizMailSent) {
BizMailAccount account = accountService.get(bizMailSent.getAccountId());
List<FileUpload> fileUploads = FileUploadUtils.findFileUpload(bizMailSent.getId(), "bizMailSent_file");
BizMailSent sent = MailSendUtils.sendHtmlMail(account, bizMailSent, fileUploads);
bizMailSentService.save(sent);
return renderResult(Global.TRUE, text("邮件发件成功!"));
}
/**
* 导入数据
*/
@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("删除发件成功!"));
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

View File

@@ -30,6 +30,9 @@ export interface BizMailAttachments extends BasicModel<BizMailAttachments> {
export const bizMailAttachmentsList = (params?: BizMailAttachments | any) =>
defHttp.get<BizMailAttachments>({ url: adminPath + '/biz/mailAttachments/list', params });
export const bizMailAttachmentsListAll = (params?: BizMailAttachments | any) =>
defHttp.get<BizMailAttachments[]>({ url: adminPath + '/biz/mailAttachments/listAll', params });
export const bizMailAttachmentsListData = (params?: BizMailAttachments | any) =>
defHttp.post<Page<BizMailAttachments>>({ url: adminPath + '/biz/mailAttachments/listData', params });
@@ -53,3 +56,4 @@ export const bizMailAttachmentsImportData = (
export const bizMailAttachmentsDelete = (params?: BizMailAttachments | any) =>
defHttp.get<BizMailAttachments>({ url: adminPath + '/biz/mailAttachments/delete', params });

View File

@@ -58,3 +58,7 @@ export const bizMailSentImportData = (
export const bizMailSentDelete = (params?: BizMailSent | any) =>
defHttp.get<BizMailSent>({ url: adminPath + '/biz/mailSent/delete', params });
export const bizMailSent = (params?: BizMailSent | any) =>
defHttp.get<BizMailSent>({ url: adminPath + '/biz/mailSent/sent', params });

View File

@@ -236,6 +236,7 @@
confirm: handleDelete.bind(this, record),
},
auth: 'biz:mailAccount:edit',
ifShow: record.ustatus == '0'
},
{
icon: 'ant-design:undo-outlined',

View File

@@ -1,180 +0,0 @@
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<BizMailAccount> = {
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<BizMailAccount>[] = [
{
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,
};

View File

@@ -68,31 +68,11 @@
showTime: { format: 'HH:mm' },
},
},
{
label: t('收件标识'),
field: 'mailId',
component: 'Input',
},
{
label: t('附件名称'),
field: 'fileName',
component: 'Input',
},
{
label: t('文件扩展名'),
field: 'fileExt',
component: 'Input',
},
{
label: t('是否压缩'),
field: 'isCompressed',
component: 'Input',
},
{
label: t('是否加密'),
field: 'isEncrypted',
component: 'Input',
},
],
};
@@ -104,15 +84,7 @@
sorter: true,
width: 180,
align: 'left',
slot: 'firstColumn',
},
{
title: t('收件标识'),
dataIndex: 'mailId',
key: 'a.mail_id',
sorter: true,
width: 130,
align: 'center',
fixed: 'left'
},
{
title: t('附件名称'),
@@ -146,14 +118,6 @@
width: 130,
align: 'left',
},
{
title: t('存储路径'),
dataIndex: 'storagePath',
key: 'a.storage_path',
sorter: true,
width: 130,
align: 'left',
},
{
title: t('文件MD5'),
dataIndex: 'fileMd5',
@@ -177,6 +141,7 @@
sorter: true,
width: 130,
align: 'left',
dictType: 'is_compressed',
},
{
title: t('是否加密'),
@@ -185,11 +150,13 @@
sorter: true,
width: 130,
align: 'left',
dictType: 'is_encrypted',
},
];
const actionColumn: BasicColumn<BizMailAttachments> = {
width: 160,
align: 'center',
actions: (record: BizMailAttachments) => [
{
icon: 'i-ant-design:delete-outlined',

View File

@@ -15,7 +15,13 @@
<Icon icon="i-ant-design:download-outlined" /> {{ t('导出') }}
</a-button>
</template>
<template #slotBizKey="{ record }">
<a @click="openViewModal(true, record)" :title="record.subject">
{{ record.subject }}
</a>
</template>
</BasicTable>
<ViewModal @register="registerViewModal" @success="handleSuccess" />
<FormImport @register="registerImportModal" @success="handleSuccess" />
</div>
</template>
@@ -34,6 +40,7 @@
import { useModal } from '@jeesite/core/components/Modal';
import { FormProps } from '@jeesite/core/components/Form';
import FormImport from './formImport.vue';
import ViewModal from './view.vue';
const { t } = useI18n('biz.mailReceived');
const { showMessage } = useMessage();
@@ -71,7 +78,11 @@
{
label: t('账号名称'),
field: 'accountId',
component: 'Input',
fieldLabel: 'accountName',
component: 'ListSelect',
componentProps: {
selectType: 'bizMailAccountSelect',
},
},
{
label: t('发件人名称'),
@@ -86,12 +97,20 @@
{
label: t('是否有附件'),
field: 'hasAttachment',
component: 'Input',
component: 'Select',
componentProps: {
dictType: 'has_attachment',
allowClear: true,
},
},
{
label: t('状态'),
field: 'ustatus',
component: 'Input',
component: 'Select',
componentProps: {
dictType: 'send_status',
allowClear: true,
},
},
],
};
@@ -107,9 +126,9 @@
fixed: 'left',
},
{
title: t('账户标识'),
dataIndex: 'accountId',
key: 'a.account_id',
title: t('服务名称'),
dataIndex: 'accountName',
key: 'b.account_name',
sorter: true,
width: 130,
align: 'left',
@@ -122,21 +141,14 @@
width: 130,
align: 'left',
},
{
title: t('发件人名称'),
dataIndex: 'fromName',
key: 'a.from_name',
sorter: true,
width: 130,
align: 'left',
},
{
title: t('邮件主题'),
dataIndex: 'subject',
key: 'a.subject',
sorter: true,
width: 130,
width: 425,
align: 'left',
slot: 'slotBizKey',
},
{
title: t('接收时间'),
@@ -153,6 +165,7 @@
sorter: true,
width: 130,
align: 'left',
dictType: 'has_attachment',
},
];
@@ -197,6 +210,8 @@
function handleForm(record: Recordable) {
openDrawer(true, record);
}
const [registerViewModal, { openModal: openViewModal }] = useModal();
async function handleExport() {
loading.value = true;

View File

@@ -0,0 +1,614 @@
<template>
<BasicModal
v-bind="$attrs"
@register="register"
title="邮件详情"
:showOkBtn="false"
:showCancelBtn="false"
width="70%"
defaultFullscreen="true"
@cancel="handleCancel"
>
<div class="detail-container">
<div class="detail-title">{{ ReceivedList?.subject || '无标题' }}</div>
<div class="detail-info">
<span class="info-item">接收时间{{ ReceivedList?.createTime || '-' }}</span>
<span class="info-item">发件邮箱{{ ReceivedList?.fromAddress }}|{{ ReceivedList?.fromName }}</span>
</div>
<div class="detail-content">
<div class="content-header">
<span class="content-title">邮件内容</span>
<span class="content-tip" v-if="!ReceivedList?.mailContent">暂无邮件内容</span>
</div>
<div class="db-content" v-html="ReceivedList?.mailContent || ''"></div>
</div>
<!-- 附件列表区域 -->
<div class="attachments-section" v-if="MailAttachments.length > 0">
<div class="attachments-title">
附件列表 ({{ MailAttachments.length }})
</div>
<div class="attachments-vertical-container">
<div class="attachments-grid">
<div class="attachment-card" v-for="(item, index) in MailAttachments" :key="index">
<div class="attachment-icon-wrapper">
<img
class="attachment-icon"
:src="getAttachmentIconUrl(item)"
:alt="item.fileName + '图标'"
@error="handleIconLoadError"
/>
</div>
<div class="attachment-info-wrapper">
<div class="file-info-row">
<span class="attachment-name">{{ item.fileName }}</span>
<span class="attachment-size">({{ formatFileSize(item.fileSize) }})</span>
</div>
</div>
<div class="attachment-action-wrapper">
<button class="download-btn" @click="downloadAttachment(item)">
下载
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</BasicModal>
</template>
<script lang="ts">
import { defineComponent, ref, PropType } from 'vue';
import { useMessage } from '@jeesite/core/hooks/web/useMessage';
import { BasicModal, useModalInner } from '@jeesite/core/components/Modal';
import { BizMailReceived } from '@jeesite/biz/api/biz/mailReceived';
import { useGlobSetting } from '@jeesite/core/hooks/setting';
import { downloadByUrl } from '@jeesite/core/utils/file/download';
import { BizMailAttachments, bizMailAttachmentsListAll } from '@jeesite/biz/api/biz/mailAttachments';
import defaultIcon from '@jeesite/assets/images/file.png';
import docxIcon from '@jeesite/assets/images/docx.png';
import gzIcon from '@jeesite/assets/images/gz.png';
import pdfIcon from '@jeesite/assets/images/pdf.png';
import pptxIcon from '@jeesite/assets/images/pptx.png';
import pyIcon from '@jeesite/assets/images/py.png';
import sqlIcon from '@jeesite/assets/images/sql.png';
import wpsIcon from '@jeesite/assets/images/wps.png';
import xlsxIcon from '@jeesite/assets/images/xlsx.png';
import zipIcon from '@jeesite/assets/images/zip.png';
// 定义自定义图标配置类型
interface CustomIconConfig {
default?: string;
types?: Record<string, string>;
exts?: Record<string, string>;
}
export default defineComponent({
components: { BasicModal },
emits: ['modalClose'],
props: {
customIcons: {
type: Object as PropType<CustomIconConfig>,
default: () => ({
default: 'default-file.png',
types: {
docx: 'docx.png',
gz: 'gz.png',
pdf: 'pdf.png',
pptx: 'pptx.png',
py: 'py.png',
sql: 'sql.png',
wps: 'wps.png',
xlsx: 'xlsx.png',
zip: 'zip.png',
other: 'default-file.png'
},
exts: {}
})
},
iconBasePath: {
type: String,
default: '@jeesite/assets/images/'
}
},
setup(props, { emit }) {
const ReceivedList = ref<BizMailReceived>();
const MailAttachments = ref<BizMailAttachments[]>([]);
const { createMessage } = useMessage();
const iconMap = {
'default-file.png': defaultIcon,
'docx.png': docxIcon,
'gz.png': gzIcon,
'pdf.png': pdfIcon,
'pptx.png': pptxIcon,
'py.png': pyIcon,
'sql.png': sqlIcon,
'wps.png': wpsIcon,
'xlsx.png': xlsxIcon,
'zip.png': zipIcon
};
const [register, { closeModal }] = useModalInner(async (data: any) => {
if (!data) return;
if (data.messageId) {
await getAttachments({ messageId: data.messageId });
}
ReceivedList.value = data;
});
// 获取附件列表
const getAttachments = async (params: { messageId: any }) => {
try {
const result = await bizMailAttachmentsListAll(params);
MailAttachments.value = result;
} catch (error) {
console.error('获取附件信息失败:', error);
MailAttachments.value = [];
}
};
async function downloadAttachment(attachment: BizMailAttachments) {
const { ctxAdminPath } = useGlobSetting();
await downloadByUrl({
url: ctxAdminPath + '/biz/mailAttachments/downloadFile',
params: {
id : attachment.id
},
});
}
// 格式化文件大小
const formatFileSize = (size: number) => {
if (!size) return '0 B';
const units = ['B', 'KB', 'MB', 'GB'];
let unitIndex = 0;
let fileSize = size;
while (fileSize >= 1024 && unitIndex < units.length - 1) {
fileSize /= 1024;
unitIndex++;
}
return `${fileSize.toFixed(1)} ${units[unitIndex]}`;
};
// 第一步:根据文件扩展名获取图标文件名
const getAttachmentIconName = (file: BizMailAttachments) => {
const { customIcons } = props;
const ext = file.fileExt?.toLowerCase() || ''; // 统一转小写,避免大小写问题
let iconName = '';
// 1. 优先按扩展名配置匹配
if (customIcons.exts?.[ext]) {
iconName = customIcons.exts[ext];
}
// 2. 按文件类型映射匹配
else if (customIcons.types) {
// 扩展名 → 图标类型的映射(覆盖所有常见类型)
const typeMap: Record<string, string> = {
'doc': 'docx.png',
'docx': 'docx.png',
'gz': 'gz.png',
'pdf': 'pdf.png',
'ppt': 'pptx.png',
'pptx': 'pptx.png',
'py': 'py.png',
'sql': 'sql.png',
'wps': 'wps.png',
'xls': 'xlsx.png',
'xlsx': 'xlsx.png',
'zip': 'zip.png',
'rar': 'zip.png',
'7z': 'zip.png',
'tar': 'zip.png',
'jpg': 'default-file.png',
'png': 'default-file.png',
'txt': 'default-file.png',
'json': 'default-file.png'
};
// 匹配不到则用other类型
iconName = typeMap[ext] || customIcons.types['other'] || 'default-file.png';
}
// 3. 兜底用默认图标
iconName = iconName || customIcons.default || 'default-file.png';
return iconName;
};
// 第二步根据图标文件名获取打包后的真实URL核心
const getAttachmentIconUrl = (file: BizMailAttachments) => {
const iconName = getAttachmentIconName(file);
// 从映射表获取,兜底用默认图标
return iconMap[iconName] || iconMap['default-file.png'];
};
// 处理图标加载失败
const handleIconLoadError = (e: Event) => {
const target = e.target as HTMLImageElement;
// 避免无限循环
if (target.src === iconMap['default-file.png']) return;
target.src = iconMap['default-file.png'];
};
const handleCancel = () => {
emit('modalClose');
closeModal();
};
return {
register,
closeModal,
handleCancel,
ReceivedList,
MailAttachments,
downloadAttachment,
formatFileSize,
getAttachmentIconUrl,
handleIconLoadError
};
},
});
</script>
<style scoped>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.detail-container {
background-color: #f0f8ff;
padding: 20px;
border-radius: 8px;
font-size: 14px;
color: #333;
width: 100%;
height: 100%;
min-height: 0;
display: flex;
flex-direction: column;
}
.detail-title {
font-size: 18px;
font-weight: 600;
text-align: center;
margin-bottom: 16px;
color: #1f2937;
padding-bottom: 12px;
border-bottom: 1px solid #d1e7ff;
flex-shrink: 0;
}
.detail-info {
display: flex;
justify-content: space-between;
margin-bottom: 16px;
color: #4b5563;
font-size: 13px;
gap: 15px;
flex-wrap: wrap;
flex-shrink: 0;
}
.info-item {
background-color: #ffffff;
padding: 6px 12px;
border-radius: 6px;
border: 1px solid #d1e7ff;
box-shadow: 0 1px 2px rgba(0,0,0,0.03);
white-space: nowrap;
}
.detail-content {
font-size: 13px;
line-height: 1.6;
color: #374151;
margin-bottom: 20px;
padding: 0;
background-color: #ffffff;
border-radius: 8px;
border: 1px solid #d1e7ff;
flex: 1;
min-height: 100px;
overflow: hidden;
box-shadow: 0 1px 3px rgba(0,0,0,0.05);
display: flex;
flex-direction: column;
}
.content-header {
padding: 12px 14px;
border-bottom: 1px solid #f0f0f0;
display: flex;
justify-content: space-between;
align-items: center;
flex-shrink: 0;
}
.content-title {
font-size: 14px;
font-weight: 600;
color: #1f2937;
display: flex;
align-items: center;
}
.content-title::before {
content: '';
display: inline-block;
width: 4px;
height: 14px;
background-color: #4096ff;
border-radius: 2px;
margin-right: 6px;
}
.content-tip {
font-size: 12px;
color: #9ca3af;
font-style: italic;
}
.db-content {
padding: 14px;
margin: 0;
font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
white-space: pre-wrap;
word-break: break-all;
color: #333;
flex: 1;
overflow-y: auto;
min-height: 80px;
}
.attachments-section {
margin-top: auto;
width: 100%;
overflow: hidden;
flex-shrink: 0;
}
.attachments-title {
font-size: 14px;
font-weight: 600;
color: #1f2937;
margin-bottom: 12px;
display: flex;
align-items: center;
gap: 6px;
}
.attachments-vertical-container {
width: 100%;
--card-height: 70px;
--card-gap: 8px;
--container-padding: 4px;
max-height: calc(3 * var(--card-height) + 2 * var(--card-gap) + 2 * var(--container-padding));
overflow-y: auto;
overflow-x: hidden;
padding: 0 var(--container-padding) var(--container-padding) var(--container-padding);
box-sizing: border-box;
scrollbar-width: thin;
scrollbar-color: #d1e7ff #f8fbff;
}
.attachments-vertical-container::-webkit-scrollbar {
width: 6px;
}
.attachments-vertical-container::-webkit-scrollbar-track {
background: #f8fbff;
border-radius: 3px;
}
.attachments-vertical-container::-webkit-scrollbar-thumb {
background: #d1e7ff;
border-radius: 3px;
}
.attachments-vertical-container::-webkit-scrollbar-thumb:hover {
background: #4096ff;
}
.attachments-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(min(100%/4, max(150px, 100%/6)), 1fr));
gap: var(--card-gap);
padding-bottom: var(--card-gap);
width: 100%;
box-sizing: border-box;
}
.attachment-card {
width: 100%;
height: var(--card-height);
background: #ffffff;
border: 1px solid #d1e7ff;
border-radius: 6px;
padding: 8px 10px;
display: flex;
align-items: center;
gap: 8px;
box-shadow: 0 1px 2px rgba(0,0,0,0.03);
transition: all 0.2s ease;
box-sizing: border-box;
overflow: hidden;
}
.attachment-card:hover {
box-shadow: 0 3px 8px rgba(64, 150, 255, 0.1);
border-color: #4096ff;
transform: translateY(-1px);
}
.attachment-icon-wrapper {
width: 32px;
height: 32px;
background-color: #f8fbff;
border-radius: 6px;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
padding: 2px;
}
.attachment-icon {
width: 100%;
height: 100%;
object-fit: contain;
display: block;
border-radius: 2px;
opacity: 0;
transition: opacity 0.2s ease;
}
.attachment-icon[src] {
opacity: 1;
}
.attachment-info-wrapper {
flex: 1;
min-width: 0;
display: flex;
align-items: center;
width: calc(100% - 100px);
}
.file-info-row {
display: flex;
align-items: center;
gap: 4px;
width: 100%;
flex-wrap: nowrap;
}
.attachment-name {
font-size: 12px;
color: #1f2937;
font-weight: 500;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
flex: 1;
}
.attachment-size {
font-size: 10px;
color: #6b7280;
white-space: nowrap;
flex-shrink: 0;
min-width: 40px;
}
.attachment-action-wrapper {
flex-shrink: 0;
width: 60px;
display: flex;
justify-content: flex-end;
}
.download-btn {
padding: 3px 8px;
border: 1px solid #1890ff;
border-radius: 4px;
background-color: #ffffff;
color: #1890ff;
cursor: pointer;
font-size: 11px;
transition: all 0.2s ease;
white-space: nowrap;
width: 50px;
text-align: center;
}
.download-btn:hover {
background-color: #e6f7ff;
border-color: #40a9ff;
color: #40a9ff;
}
.download-btn:active {
background-color: #1890ff;
color: white;
border-color: #1890ff;
}
.db-content::-webkit-scrollbar {
width: 6px;
height: 6px;
}
.db-content::-webkit-scrollbar-track {
background: #f8fbff;
border-radius: 3px;
}
.db-content::-webkit-scrollbar-thumb {
background: #d1e7ff;
border-radius: 3px;
}
.db-content::-webkit-scrollbar-thumb:hover {
background: #4096ff;
}
@media (max-width: 1200px) {
.attachments-grid {
grid-template-columns: repeat(auto-fill, minmax(min(100%/4, max(120px, 100%/5)), 1fr));
}
}
@media (max-width: 992px) {
.attachments-grid {
grid-template-columns: repeat(auto-fill, minmax(min(100%/3, max(100px, 100%/4)), 1fr));
}
}
@media (max-width: 768px) {
.attachments-grid {
grid-template-columns: repeat(auto-fill, minmax(min(100%/2, max(150px, 100%/3)), 1fr));
}
.attachment-card {
padding: 6px 8px;
}
}
@media (max-width: 576px) {
.attachments-grid {
grid-template-columns: 1fr;
}
.attachment-info-wrapper {
width: calc(100% - 80px);
}
.detail-container {
padding: 15px;
}
.detail-title {
font-size: 16px;
}
.content-header {
padding: 10px 12px;
}
.content-title {
font-size: 13px;
}
}
:deep(.ant-modal-content) {
height: 100%;
display: flex;
flex-direction: column;
}
:deep(.ant-modal-body) {
height: 100%;
padding: 0;
overflow: hidden;
}
</style>

View File

@@ -54,18 +54,10 @@
{
label: t('账户名称'),
field: 'accountId',
component: 'Input',
fieldLabel: 'accountName',
component: 'ListSelect',
componentProps: {
maxlength: 52,
},
required: true,
},
{
label: t('发件人地址'),
field: 'fromAddress',
component: 'Input',
componentProps: {
maxlength: 255,
selectType: 'bizMailAccountSelect',
},
required: true,
},
@@ -74,7 +66,14 @@
field: 'toAddresses',
component: 'Input',
required: true,
colProps: { md: 24, lg: 24 },
},
{
label: t('抄送人地址'),
field: 'ccAddresses',
component: 'Input',
colProps: { md: 24, lg: 24 },
},
{
label: t('邮件内容'),
field: 'content',

View File

@@ -38,7 +38,7 @@
import { Icon } from '@jeesite/core/components/Icon';
import { BasicTable, BasicColumn, useTable } from '@jeesite/core/components/Table';
import { BizMailSent, bizMailSentList } from '@jeesite/biz/api/biz/mailSent';
import { bizMailSentDelete, bizMailSentListData } from '@jeesite/biz/api/biz/mailSent';
import { bizMailSentDelete, bizMailSent, bizMailSentListData } from '@jeesite/biz/api/biz/mailSent';
import { useModal } from '@jeesite/core/components/Modal';
import { FormProps } from '@jeesite/core/components/Form';
import InputForm from './form.vue';
@@ -80,7 +80,11 @@
{
label: t('账号名称'),
field: 'accountId',
component: 'Input',
fieldLabel: 'accountName',
component: 'ListSelect',
componentProps: {
selectType: 'bizMailAccountSelect',
},
},
{
label: t('发件地址'),
@@ -97,7 +101,7 @@
field: 'sendStatus',
component: 'Select',
componentProps: {
dictType: '',
dictType: 'send_status',
allowClear: true,
},
},
@@ -106,7 +110,7 @@
field: 'hasAttachment',
component: 'Select',
componentProps: {
dictType: '',
dictType: 'has_attachment',
allowClear: true,
},
},
@@ -121,7 +125,7 @@
sorter: true,
width: 180,
align: 'left',
slot: 'firstColumn',
fixed: 'left',
},
{
title: t('发件人地址'),
@@ -162,7 +166,7 @@
sorter: true,
width: 130,
align: 'left',
dictType: '',
dictType: 'send_status',
},
{
title: t('是否有附件'),
@@ -171,7 +175,7 @@
sorter: true,
width: 130,
align: 'left',
dictType: '',
dictType: 'has_attachment',
},
];
@@ -184,7 +188,7 @@
title: t('编辑'),
onClick: handleForm.bind(this, { id: record.id }),
auth: 'biz:mailSent:edit',
},
},
{
icon: 'i-ant-design:delete-outlined',
color: 'error',
@@ -195,6 +199,15 @@
},
auth: 'biz:mailSent:edit',
},
{
icon: 'simple-line-icons:action-redo',
color: 'success',
title: t('发送'),
popConfirm: {
title: t('是否确认发送邮件信息?'),
confirm: handleSent.bind(this, record),
},
},
],
};
@@ -245,6 +258,13 @@
showMessage(res.message);
await handleSuccess(record);
}
async function handleSent(record: Recordable) {
const params = { id: record.id };
const res = await bizMailSent(params);
showMessage(res.message);
await handleSuccess(record);
}
async function handleSuccess(record: Recordable) {
await reload({ record });

View File

@@ -1,196 +0,0 @@
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<BizMailSent> = {
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<BizMailSent>[] = [
{
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,
};

View File

@@ -0,0 +1,181 @@
import { useI18n } from '@jeesite/core/hooks/web/useI18n';
import { BasicColumn, BasicTableProps, FormProps } from '@jeesite/core/components/Table';
import { BizMailAccount, bizMailAccountListData } from '@jeesite/biz/api/biz/mailAccount';
const { t } = useI18n('biz.mailAccount');
const modalProps = {
title: t('邮件账号选择'),
};
const searchForm: FormProps<BizMailAccount> = {
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('SMTP服务'),
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: 'ustatus',
component: 'Select',
componentProps: {
dictType: 'ustatus',
allowClear: true,
},
},
],
};
const tableColumns: BasicColumn<BizMailAccount>[] = [
{
title: t('记录时间'),
dataIndex: 'createTime',
key: 'a.create_time',
sorter: true,
width: 180,
align: 'left',
fixed: 'left',
},
{
title: t('配置名称'),
dataIndex: 'accountName',
key: 'a.account_name',
sorter: true,
width: 130,
align: 'left',
slot: 'slotBizKey',
},
{
title: t('SMTP服务'),
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: 'imapHost',
key: 'a.imap_host',
sorter: true,
width: 130,
align: 'left',
},
{
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: '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: 'ustatus',
key: 'a.ustatus',
sorter: true,
width: 130,
align: 'center',
dictType: 'ustatus',
},
{
title: t('备注'),
dataIndex: 'remark',
key: 'a.remark',
sorter: true,
width: 130,
align: 'left',
},
];
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: 'accountName',
isShowCode: true,
};