diff --git a/download.md b/download.md index 45b7496b..b3ce3e25 100644 --- a/download.md +++ b/download.md @@ -3,6 +3,7 @@
Windows +[WePush-v4.4.0_210221-x64-Setup.exe](http://download.zhoubochina.com/exe/WePush-v4.4.0_210221-x64-Setup.exe) [WePush-v4.3.0_210123-x64-Setup.exe](http://download.zhoubochina.com/exe/WePush-v4.3.0_210123-x64-Setup.exe) [WePush-v4.2.5_210117-x64-Setup.exe](http://download.zhoubochina.com/exe/WePush-v4.2.5_210117-x64-Setup.exe) [WePush-v4.2.4_201222-x64-Setup.exe](http://download.zhoubochina.com/exe/WePush-v4.2.4_201222-x64-Setup.exe) @@ -80,6 +81,7 @@
Mac OS +[v_4.4.0_210221.app](http://download.zhoubochina.com/mac/4.4.0.zip) [v_4.3.0_210123.app](http://download.zhoubochina.com/mac/4.3.0.zip) [v_4.2.5_210117.app](http://download.zhoubochina.com/mac/4.2.5.zip) [v_4.2.4_201222.app](http://download.zhoubochina.com/mac/4.2.4.zip) @@ -137,6 +139,7 @@
Portable(各系统通用绿色便携版32/64位) +[v4.4.0_210221](http://download.zhoubochina.com/linux/WePush-4.4.0.zip) [v4.3.0_210123](http://download.zhoubochina.com/linux/WePush-4.3.0.zip) [v4.2.5_210117](http://download.zhoubochina.com/linux/WePush-4.2.5.zip) [v4.2.4_201222](http://download.zhoubochina.com/linux/WePush-4.2.4.zip) diff --git a/pom.xml b/pom.xml index d39e0dca..afc44587 100644 --- a/pom.xml +++ b/pom.xml @@ -47,7 +47,7 @@ 1.1.0 0.10.134 7.3.0 - 1.0-rc1 + 1.0 @@ -387,6 +387,10 @@ slf4j-log4j12 org.slf4j + + hbase-client + org.apache.hbase + diff --git a/src/main/java/com/fangxuele/tool/push/App.java b/src/main/java/com/fangxuele/tool/push/App.java index b10d45c9..0ec0a54a 100644 --- a/src/main/java/com/fangxuele/tool/push/App.java +++ b/src/main/java/com/fangxuele/tool/push/App.java @@ -39,13 +39,13 @@ public static void main(String[] args) { mainFrame.init(); JPanel loadingPanel = new LoadingForm().getLoadingPanel(); mainFrame.add(loadingPanel); + mainFrame.pack(); + mainFrame.setVisible(true); Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); - if (screenSize.getWidth() <= 1366) { + if (config.isDefaultMaxWindow() || screenSize.getWidth() <= 1366) { // 低分辨率下自动最大化窗口 mainFrame.setExtendedState(JFrame.MAXIMIZED_BOTH); } - mainFrame.pack(); - mainFrame.setVisible(true); UpgradeUtil.smoothUpgrade(); mainFrame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); @@ -56,7 +56,7 @@ public static void main(String[] args) { Init.initOthers(); mainFrame.addListeners(); mainFrame.remove(loadingPanel); - Init.initFontSize(); + Init.fontSizeGuide(); Init.initTray(); } } diff --git a/src/main/java/com/fangxuele/tool/push/bean/MailMsg.java b/src/main/java/com/fangxuele/tool/push/bean/MailMsg.java index 58f926b3..0beef0e2 100644 --- a/src/main/java/com/fangxuele/tool/push/bean/MailMsg.java +++ b/src/main/java/com/fangxuele/tool/push/bean/MailMsg.java @@ -4,7 +4,9 @@ import lombok.Setter; import lombok.ToString; +import java.io.File; import java.io.Serializable; +import java.util.List; /** *
@@ -34,7 +36,7 @@ public class MailMsg implements Serializable {
     /**
      * 附件
      */
-    private String mailFiles;
+    private List mailFiles;
 
     /**
      * 内容
diff --git a/src/main/java/com/fangxuele/tool/push/logic/PushControl.java b/src/main/java/com/fangxuele/tool/push/logic/PushControl.java
index 5fd9f676..11643e4b 100644
--- a/src/main/java/com/fangxuele/tool/push/logic/PushControl.java
+++ b/src/main/java/com/fangxuele/tool/push/logic/PushControl.java
@@ -282,7 +282,7 @@ static void savePushData() throws IOException {
             PushData.toSendList = new ArrayList<>(PushData.toSendConcurrentLinkedQueue);
         }
         MessageEditForm messageEditForm = MessageEditForm.getInstance();
-        File pushHisDir = new File(SystemUtil.configHome + "data" + File.separator + "push_his");
+        File pushHisDir = new File(SystemUtil.CONFIG_HOME + "data" + File.separator + "push_his");
         if (!pushHisDir.exists()) {
             boolean mkdirs = pushHisDir.mkdirs();
         }
@@ -295,7 +295,7 @@ static void savePushData() throws IOException {
         List fileList = new ArrayList<>();
         // 保存已发送
         if (PushData.sendSuccessList.size() > 0) {
-            File sendSuccessFile = new File(SystemUtil.configHome + "data" +
+            File sendSuccessFile = new File(SystemUtil.CONFIG_HOME + "data" +
                     File.separator + "push_his" + File.separator + MessageTypeEnum.getName(msgType) + "-" + msgName +
                     "-发送成功-" + nowTime + ".csv");
             FileUtil.touch(sendSuccessFile);
@@ -334,7 +334,7 @@ static void savePushData() throws IOException {
         }
 
         if (PushData.toSendList.size() > 0) {
-            File unSendFile = new File(SystemUtil.configHome + "data" + File.separator +
+            File unSendFile = new File(SystemUtil.CONFIG_HOME + "data" + File.separator +
                     "push_his" + File.separator + MessageTypeEnum.getName(msgType) + "-" + msgName + "-未发送-" + nowTime +
                     ".csv");
             FileUtil.touch(unSendFile);
@@ -350,7 +350,7 @@ static void savePushData() throws IOException {
 
         // 保存发送失败
         if (PushData.sendFailList.size() > 0) {
-            File failSendFile = new File(SystemUtil.configHome + "data" + File.separator +
+            File failSendFile = new File(SystemUtil.CONFIG_HOME + "data" + File.separator +
                     "push_his" + File.separator + MessageTypeEnum.getName(msgType) + "-" + msgName + "-发送失败-" + nowTime + ".csv");
             FileUtil.touch(failSendFile);
             writer = new CSVWriter(new FileWriter(failSendFile));
diff --git a/src/main/java/com/fangxuele/tool/push/logic/msgmaker/MailMsgMaker.java b/src/main/java/com/fangxuele/tool/push/logic/msgmaker/MailMsgMaker.java
index 2a8674af..9aceaee3 100644
--- a/src/main/java/com/fangxuele/tool/push/logic/msgmaker/MailMsgMaker.java
+++ b/src/main/java/com/fangxuele/tool/push/logic/msgmaker/MailMsgMaker.java
@@ -5,6 +5,9 @@
 import com.fangxuele.tool.push.util.TemplateUtil;
 import org.apache.velocity.VelocityContext;
 
+import java.io.File;
+import java.util.List;
+
 /**
  * 
  * E-Mail加工器
@@ -17,7 +20,7 @@ public class MailMsgMaker extends BaseMsgMaker implements IMsgMaker {
 
     public static String mailTitle;
     public static String mailCc;
-    public static String mailFiles;
+    public static List mailFiles;
     public static String mailContent;
 
     /**
@@ -27,7 +30,7 @@ public class MailMsgMaker extends BaseMsgMaker implements IMsgMaker {
     public void prepare() {
         mailTitle = MailMsgForm.getInstance().getMailTitleTextField().getText();
         mailCc = MailMsgForm.getInstance().getMailCcTextField().getText();
-        mailFiles = MailMsgForm.getInstance().getMailFilesTextField().getText();
+        mailFiles = MailMsgForm.getInstance().getAttachmentFiles();
         mailContent = MailMsgForm.getInstance().getMailContentPane().getText();
     }
 
@@ -43,11 +46,10 @@ public MailMsg makeMsg(String[] msgData) {
         VelocityContext velocityContext = getVelocityContext(msgData);
         String title = TemplateUtil.evaluate(mailTitle, velocityContext);
         String cc = TemplateUtil.evaluate(mailCc, velocityContext);
-        String files = TemplateUtil.evaluate(mailFiles, velocityContext);
         String content = TemplateUtil.evaluate(mailContent, velocityContext);
         mailMsg.setMailTitle(title);
         mailMsg.setMailCc(cc);
-        mailMsg.setMailFiles(files);
+        mailMsg.setMailFiles(mailFiles);
         mailMsg.setMailContent(content);
         return mailMsg;
     }
diff --git a/src/main/java/com/fangxuele/tool/push/logic/msgsender/MailMsgSender.java b/src/main/java/com/fangxuele/tool/push/logic/msgsender/MailMsgSender.java
index 27e53a0a..3b9bcf34 100644
--- a/src/main/java/com/fangxuele/tool/push/logic/msgsender/MailMsgSender.java
+++ b/src/main/java/com/fangxuele/tool/push/logic/msgsender/MailMsgSender.java
@@ -1,6 +1,5 @@
 package com.fangxuele.tool.push.logic.msgsender;
 
-import cn.hutool.core.io.FileUtil;
 import cn.hutool.extra.mail.MailAccount;
 import cn.hutool.extra.mail.MailUtil;
 import com.fangxuele.tool.push.App;
@@ -8,6 +7,7 @@
 import com.fangxuele.tool.push.logic.PushControl;
 import com.fangxuele.tool.push.logic.msgmaker.MailMsgMaker;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.compress.utils.Lists;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.exception.ExceptionUtils;
@@ -52,10 +52,10 @@ public SendResult send(String[] msgData) {
                     ccList = Lists.newArrayList();
                     ccList.add(mailMsg.getMailCc());
                 }
-                if (StringUtils.isEmpty(mailMsg.getMailFiles())) {
+                if (CollectionUtils.isEmpty(mailMsg.getMailFiles())) {
                     MailUtil.send(mailAccount, tos, ccList, null, mailMsg.getMailTitle(), mailMsg.getMailContent(), true);
                 } else {
-                    MailUtil.send(mailAccount, tos, ccList, null, mailMsg.getMailTitle(), mailMsg.getMailContent(), true, FileUtil.file(mailMsg.getMailFiles()));
+                    MailUtil.send(mailAccount, tos, ccList, null, mailMsg.getMailTitle(), mailMsg.getMailContent(), true, mailMsg.getMailFiles().toArray(new File[0]));
                 }
                 sendResult.setSuccess(true);
             }
diff --git a/src/main/java/com/fangxuele/tool/push/ui/Init.java b/src/main/java/com/fangxuele/tool/push/ui/Init.java
index caa2ca09..bd8096b8 100644
--- a/src/main/java/com/fangxuele/tool/push/ui/Init.java
+++ b/src/main/java/com/fangxuele/tool/push/ui/Init.java
@@ -18,7 +18,6 @@
 import com.fangxuele.tool.push.ui.form.PushHisForm;
 import com.fangxuele.tool.push.ui.form.ScheduleForm;
 import com.fangxuele.tool.push.ui.form.SettingForm;
-import com.fangxuele.tool.push.ui.form.UserCaseForm;
 import com.fangxuele.tool.push.ui.listener.AboutListener;
 import com.fangxuele.tool.push.util.SystemUtil;
 import com.fangxuele.tool.push.util.UIUtil;
@@ -53,7 +52,7 @@ public class Init {
     /**
      * 字号初始化KEY
      */
-    private static final String FONT_SIZE_INIT_PROP = "fontSizeInit";
+    public static final String FONT_SIZE_INIT_PROP = "fontSizeInit";
 
     /**
      * 设置全局字体
@@ -74,6 +73,7 @@ public static void initGlobalFont() {
                 fontSize = (int) (UIUtil.getScreenScale() * fontSize);
             }
             App.config.setFontSize(fontSize);
+            App.config.save();
         }
 
         Font font = new Font(App.config.getFont(), Font.PLAIN, App.config.getFontSize());
@@ -100,7 +100,7 @@ public static void initOthers() {
      * 初始化look and feel
      */
     public static void initTheme() {
-        if (SystemUtil.isMacM1()) {
+        if (SystemUtil.isMacM1() || SystemUtil.isLinuxOs()) {
             try {
                 UIManager.setLookAndFeel("com.formdev.flatlaf.FlatDarculaLaf");
                 logger.warn("FlatDarculaLaf theme set.");
@@ -125,35 +125,69 @@ public static void initTheme() {
                     UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                     break;
                 case "weblaf":
-                case "Darcula(推荐)":
+                case "Darcula":
+                    JFrame.setDefaultLookAndFeelDecorated(false);
+                    JDialog.setDefaultLookAndFeelDecorated(false);
                     UIManager.setLookAndFeel("com.bulenkov.darcula.DarculaLaf");
                     break;
                 case "Flat Light":
+                    if (SystemUtil.isJBR()) {
+                        JFrame.setDefaultLookAndFeelDecorated(true);
+                        JDialog.setDefaultLookAndFeelDecorated(true);
+                    }
                     FlatLightLaf.install();
                     break;
                 case "Flat IntelliJ":
+                    if (SystemUtil.isJBR()) {
+                        JFrame.setDefaultLookAndFeelDecorated(true);
+                        JDialog.setDefaultLookAndFeelDecorated(true);
+                    }
                     UIManager.setLookAndFeel("com.formdev.flatlaf.FlatIntelliJLaf");
                     break;
                 case "Flat Dark":
+                    if (SystemUtil.isJBR()) {
+                        JFrame.setDefaultLookAndFeelDecorated(true);
+                        JDialog.setDefaultLookAndFeelDecorated(true);
+                    }
                     UIManager.setLookAndFeel("com.formdev.flatlaf.FlatDarkLaf");
                     break;
-                case "Flat Darcula":
+                case "Flat Darcula(推荐)":
+                    if (SystemUtil.isJBR()) {
+                        JFrame.setDefaultLookAndFeelDecorated(true);
+                        JDialog.setDefaultLookAndFeelDecorated(true);
+                    }
                     UIManager.setLookAndFeel("com.formdev.flatlaf.FlatDarculaLaf");
                     break;
                 case "Dark purple":
+                    if (SystemUtil.isJBR()) {
+                        JFrame.setDefaultLookAndFeelDecorated(true);
+                        JDialog.setDefaultLookAndFeelDecorated(true);
+                    }
                     IntelliJTheme.install(App.class.getResourceAsStream(
                             "/theme/DarkPurple.theme.json"));
                     break;
                 case "IntelliJ Cyan":
+                    if (SystemUtil.isJBR()) {
+                        JFrame.setDefaultLookAndFeelDecorated(true);
+                        JDialog.setDefaultLookAndFeelDecorated(true);
+                    }
                     IntelliJTheme.install(App.class.getResourceAsStream(
                             "/theme/Cyan.theme.json"));
                     break;
                 case "IntelliJ Light":
+                    if (SystemUtil.isJBR()) {
+                        JFrame.setDefaultLookAndFeelDecorated(true);
+                        JDialog.setDefaultLookAndFeelDecorated(true);
+                    }
                     IntelliJTheme.install(App.class.getResourceAsStream(
                             "/theme/Light.theme.json"));
                     break;
 
                 default:
+                    if (SystemUtil.isJBR()) {
+                        JFrame.setDefaultLookAndFeelDecorated(true);
+                        JDialog.setDefaultLookAndFeelDecorated(true);
+                    }
                     UIManager.setLookAndFeel("com.formdev.flatlaf.FlatDarculaLaf");
             }
         } catch (Exception e) {
@@ -168,7 +202,7 @@ public static void initAllTab() {
         ThreadUtil.execute(AboutForm::init);
         MessageTypeForm.init();
         ThreadUtil.execute(HelpForm::init);
-        ThreadUtil.execute(UserCaseForm::init);
+//        ThreadUtil.execute(UserCaseForm::init);
         ThreadUtil.execute(() -> MessageEditForm.init(null));
         ThreadUtil.execute(MessageManageForm::init);
         ThreadUtil.execute(MemberForm::init);
@@ -191,7 +225,7 @@ public static void initAllTab() {
     /**
      * 引导用户调整字号
      */
-    public static void initFontSize() {
+    public static void fontSizeGuide() {
         if (StringUtils.isEmpty(App.config.getProps(FONT_SIZE_INIT_PROP))) {
             FontSizeAdjustDialog fontSizeAdjustDialog = new FontSizeAdjustDialog();
             fontSizeAdjustDialog.pack();
diff --git a/src/main/java/com/fangxuele/tool/push/ui/UiConsts.java b/src/main/java/com/fangxuele/tool/push/ui/UiConsts.java
index c9d03585..26049602 100644
--- a/src/main/java/com/fangxuele/tool/push/ui/UiConsts.java
+++ b/src/main/java/com/fangxuele/tool/push/ui/UiConsts.java
@@ -16,7 +16,7 @@ public class UiConsts {
      * 软件名称,版本
      */
     public final static String APP_NAME = "WePush";
-    public final static String APP_VERSION = "v_4.3.0_210123";
+    public final static String APP_VERSION = "v_4.4.0_210221";
 
     /**
      * Logo-1024*1024
@@ -104,11 +104,6 @@ public class UiConsts {
      */
     public final static String INTRODUCE_QRCODE_URL = "http://download.zhoubochina.com/qrcode/introduce-wepush-qrcode.png";
 
-    /**
-     * 日志文件路径
-     */
-    public final static String LOG_DIR = "./logs/";
-
     /**
      * 多账号切换账号类型:公众号
      */
diff --git a/src/main/java/com/fangxuele/tool/push/ui/form/MainWindow.form b/src/main/java/com/fangxuele/tool/push/ui/form/MainWindow.form
index 5da87e21..dfb5d09b 100644
--- a/src/main/java/com/fangxuele/tool/push/ui/form/MainWindow.form
+++ b/src/main/java/com/fangxuele/tool/push/ui/form/MainWindow.form
@@ -161,17 +161,6 @@
             
             
           
-          
-            
-            
-              
-            
-            
-              
-            
-            
-            
-          
         
       
     
diff --git a/src/main/java/com/fangxuele/tool/push/ui/form/MainWindow.java b/src/main/java/com/fangxuele/tool/push/ui/form/MainWindow.java
index ad96788f..38dc7be2 100644
--- a/src/main/java/com/fangxuele/tool/push/ui/form/MainWindow.java
+++ b/src/main/java/com/fangxuele/tool/push/ui/form/MainWindow.java
@@ -30,7 +30,6 @@ public class MainWindow {
     private JPanel settingPanel;
     private JPanel schedulePanel;
     private JPanel pushHisPanel;
-    private JPanel userCasePanel;
     private JPanel messageEditPanel;
     private JPanel messageManagePanel;
     private JPanel messageTypePanel;
@@ -49,23 +48,23 @@ public static MainWindow getInstance() {
         return mainWindow;
     }
 
-    private static GridConstraints gridConstraints = new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, new Dimension(200, 200), null, 0, false);
+    private static final GridConstraints GRID_CONSTRAINTS = new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, new Dimension(200, 200), null, 0, false);
 
     public void init() {
         mainWindow = getInstance();
         mainWindow.getMainPanel().updateUI();
-        mainWindow.getAboutPanel().add(AboutForm.getInstance().getAboutPanel(), gridConstraints);
-        mainWindow.getUserCasePanel().add(UserCaseForm.getInstance().getUserCasePanel(), gridConstraints);
-        mainWindow.getSchedulePanel().add(ScheduleForm.getInstance().getSchedulePanel(), gridConstraints);
-        mainWindow.getPushHisPanel().add(PushHisForm.getInstance().getPushHisPanel(), gridConstraints);
-        mainWindow.getSettingPanel().add(SettingForm.getInstance().getSettingPanel(), gridConstraints);
-        mainWindow.getMessageEditPanel().add(MessageEditForm.getInstance().getMessageEditPanel(), gridConstraints);
-        mainWindow.getMessageManagePanel().add(MessageManageForm.getInstance().getMessageManagePanel(), gridConstraints);
-        mainWindow.getMemberPanel().add(MemberForm.getInstance().getMemberPanel(), gridConstraints);
-        mainWindow.getPushPanel().add(PushForm.getInstance().getPushPanel(), gridConstraints);
-        mainWindow.getMessageTypePanel().add(MessageTypeForm.getInstance().getMessageTypePanel(), gridConstraints);
-        mainWindow.getBoostPanel().add(BoostForm.getInstance().getBoostPanel(), gridConstraints);
-        mainWindow.getInfinityPanel().add(InfinityForm.getInstance().getInfinityPanel(), gridConstraints);
+        mainWindow.getAboutPanel().add(AboutForm.getInstance().getAboutPanel(), GRID_CONSTRAINTS);
+//        mainWindow.getUserCasePanel().add(UserCaseForm.getInstance().getUserCasePanel(), GRID_CONSTRAINTS);
+        mainWindow.getSchedulePanel().add(ScheduleForm.getInstance().getSchedulePanel(), GRID_CONSTRAINTS);
+        mainWindow.getPushHisPanel().add(PushHisForm.getInstance().getPushHisPanel(), GRID_CONSTRAINTS);
+        mainWindow.getSettingPanel().add(SettingForm.getInstance().getSettingPanel(), GRID_CONSTRAINTS);
+        mainWindow.getMessageEditPanel().add(MessageEditForm.getInstance().getMessageEditPanel(), GRID_CONSTRAINTS);
+        mainWindow.getMessageManagePanel().add(MessageManageForm.getInstance().getMessageManagePanel(), GRID_CONSTRAINTS);
+        mainWindow.getMemberPanel().add(MemberForm.getInstance().getMemberPanel(), GRID_CONSTRAINTS);
+        mainWindow.getPushPanel().add(PushForm.getInstance().getPushPanel(), GRID_CONSTRAINTS);
+        mainWindow.getMessageTypePanel().add(MessageTypeForm.getInstance().getMessageTypePanel(), GRID_CONSTRAINTS);
+        mainWindow.getBoostPanel().add(BoostForm.getInstance().getBoostPanel(), GRID_CONSTRAINTS);
+        mainWindow.getInfinityPanel().add(InfinityForm.getInstance().getInfinityPanel(), GRID_CONSTRAINTS);
         mainWindow.getMessagePanel().setDividerLocation((int) (App.mainFrame.getWidth() / 5.6));
         mainWindow.getMainPanel().updateUI();
     }
@@ -150,10 +149,6 @@ public void init() {
         if (settingPanelFont != null) settingPanel.setFont(settingPanelFont);
         settingPanel.setMinimumSize(new Dimension(-1, -1));
         tabbedPane.addTab("设置", settingPanel);
-        userCasePanel = new JPanel();
-        userCasePanel.setLayout(new GridLayoutManager(1, 1, new Insets(0, 0, 10, 0), -1, -1));
-        userCasePanel.setMinimumSize(new Dimension(-1, -1));
-        tabbedPane.addTab("他们都在用", userCasePanel);
     }
 
     /**
diff --git a/src/main/java/com/fangxuele/tool/push/ui/form/SettingForm.form b/src/main/java/com/fangxuele/tool/push/ui/form/SettingForm.form
index 3f596b4d..5cc5d637 100644
--- a/src/main/java/com/fangxuele/tool/push/ui/form/SettingForm.form
+++ b/src/main/java/com/fangxuele/tool/push/ui/form/SettingForm.form
@@ -46,7 +46,7 @@
                     
                     
                     
-                      
+                      
                         
                         
                           
@@ -72,10 +72,18 @@
                               
                             
                           
+                          
+                            
+                              
+                            
+                            
+                              
+                            
+                          
                           
                             
                             
-                              
+                              
                             
                             
                             
@@ -1633,13 +1641,13 @@
                             
                             
                               
-                                
+                                
                                 
                                 
                                 
                                 
                                 
-                                
+                                
                                 
                                 
                                 
diff --git a/src/main/java/com/fangxuele/tool/push/ui/form/SettingForm.java b/src/main/java/com/fangxuele/tool/push/ui/form/SettingForm.java
index c933108e..95a423d6 100644
--- a/src/main/java/com/fangxuele/tool/push/ui/form/SettingForm.java
+++ b/src/main/java/com/fangxuele/tool/push/ui/form/SettingForm.java
@@ -129,6 +129,7 @@ public class SettingForm {
     private JButton systemEnvButton;
     private JTextField maxThreadsTextField;
     private JButton maxThreadsSaveButton;
+    private JCheckBox defaultMaxWindowCheckBox;
 
     private static SettingForm settingForm;
     private static TWxAccountMapper wxAccountMapper = MybatisUtil.getSqlSession().getMapper(TWxAccountMapper.class);
@@ -156,6 +157,7 @@ public static void init() {
         // 常规
         settingForm.getAutoCheckUpdateCheckBox().setSelected(App.config.isAutoCheckUpdate());
         settingForm.getUseTrayCheckBox().setSelected(App.config.isUseTray());
+        settingForm.getDefaultMaxWindowCheckBox().setSelected(App.config.isDefaultMaxWindow());
         settingForm.getMaxThreadsTextField().setText(String.valueOf(App.config.getMaxThreads()));
 
         // 微信公众号
@@ -389,7 +391,7 @@ public static void toggleMpOutSideAccessTokenPanel() {
         panel3.setLayout(new GridLayoutManager(17, 1, new Insets(40, 60, 0, 330), -1, -1));
         panel2.add(panel3, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, new Dimension(600, -1), null, 0, false));
         final JPanel panel4 = new JPanel();
-        panel4.setLayout(new GridLayoutManager(3, 1, new Insets(15, 15, 10, 0), -1, -1));
+        panel4.setLayout(new GridLayoutManager(4, 1, new Insets(15, 15, 10, 0), -1, -1));
         panel3.add(panel4, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
         panel4.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEmptyBorder(), "常规", TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.DEFAULT_POSITION, this.$$$getFont$$$(null, Font.BOLD, -1, panel4.getFont()), null));
         autoCheckUpdateCheckBox = new JCheckBox();
@@ -398,9 +400,12 @@ public static void toggleMpOutSideAccessTokenPanel() {
         useTrayCheckBox = new JCheckBox();
         useTrayCheckBox.setText("显示系统托盘图标");
         panel4.add(useTrayCheckBox, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        defaultMaxWindowCheckBox = new JCheckBox();
+        defaultMaxWindowCheckBox.setText("默认最大化窗口");
+        panel4.add(defaultMaxWindowCheckBox, new GridConstraints(2, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
         final JPanel panel5 = new JPanel();
         panel5.setLayout(new GridLayoutManager(1, 4, new Insets(0, 0, 0, 0), -1, -1));
-        panel4.add(panel5, new GridConstraints(2, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
+        panel4.add(panel5, new GridConstraints(3, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
         final JLabel label1 = new JLabel();
         label1.setText("最大线程数");
         panel5.add(label1, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
@@ -930,13 +935,13 @@ public static void toggleMpOutSideAccessTokenPanel() {
         panel35.add(label51, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
         settingThemeComboBox = new JComboBox();
         final DefaultComboBoxModel defaultComboBoxModel1 = new DefaultComboBoxModel();
-        defaultComboBoxModel1.addElement("Darcula(推荐)");
+        defaultComboBoxModel1.addElement("Darcula");
         defaultComboBoxModel1.addElement("BeautyEye");
         defaultComboBoxModel1.addElement("系统默认");
         defaultComboBoxModel1.addElement("Flat Light");
         defaultComboBoxModel1.addElement("Flat IntelliJ");
         defaultComboBoxModel1.addElement("Flat Dark");
-        defaultComboBoxModel1.addElement("Flat Darcula");
+        defaultComboBoxModel1.addElement("Flat Darcula(推荐)");
         defaultComboBoxModel1.addElement("Dark purple");
         defaultComboBoxModel1.addElement("IntelliJ Cyan");
         defaultComboBoxModel1.addElement("IntelliJ Light");
diff --git a/src/main/java/com/fangxuele/tool/push/ui/form/msg/KefuMsgForm.form b/src/main/java/com/fangxuele/tool/push/ui/form/msg/KefuMsgForm.form
index 50365337..bc73c62b 100644
--- a/src/main/java/com/fangxuele/tool/push/ui/form/msg/KefuMsgForm.form
+++ b/src/main/java/com/fangxuele/tool/push/ui/form/msg/KefuMsgForm.form
@@ -157,14 +157,6 @@
             
             
           
-          
-            
-              
-                
-              
-            
-            
-          
           
             
               
@@ -181,6 +173,32 @@
             
             
           
+          
+            
+            
+              
+            
+            
+            
+            
+              
+                
+                  
+                    
+                  
+                
+                
+              
+              
+                
+                  
+                
+                
+                  
+                
+              
+            
+          
         
       
     
diff --git a/src/main/java/com/fangxuele/tool/push/ui/form/msg/KefuMsgForm.java b/src/main/java/com/fangxuele/tool/push/ui/form/msg/KefuMsgForm.java
index d01ce4a0..f780c23e 100644
--- a/src/main/java/com/fangxuele/tool/push/ui/form/msg/KefuMsgForm.java
+++ b/src/main/java/com/fangxuele/tool/push/ui/form/msg/KefuMsgForm.java
@@ -1,9 +1,13 @@
 package com.fangxuele.tool.push.ui.form.msg;
 
+import cn.binarywang.wx.miniapp.constant.WxMaConstants;
+import cn.hutool.log.Log;
+import cn.hutool.log.LogFactory;
 import com.fangxuele.tool.push.App;
 import com.fangxuele.tool.push.dao.TMsgKefuMapper;
 import com.fangxuele.tool.push.domain.TMsgKefu;
 import com.fangxuele.tool.push.logic.MessageTypeEnum;
+import com.fangxuele.tool.push.logic.msgsender.WxMpTemplateMsgSender;
 import com.fangxuele.tool.push.ui.form.MainWindow;
 import com.fangxuele.tool.push.ui.form.MessageEditForm;
 import com.fangxuele.tool.push.util.MybatisUtil;
@@ -12,13 +16,17 @@
 import com.intellij.uiDesigner.core.GridLayoutManager;
 import com.intellij.uiDesigner.core.Spacer;
 import lombok.Getter;
+import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
 
 import javax.swing.*;
 import javax.swing.border.TitledBorder;
+import javax.swing.filechooser.FileFilter;
+import javax.swing.filechooser.FileNameExtensionFilter;
 import javax.swing.plaf.FontUIResource;
 import javax.swing.text.StyleContext;
 import java.awt.*;
 import java.awt.event.ItemEvent;
+import java.io.File;
 import java.util.List;
 import java.util.Locale;
 import java.util.Objects;
@@ -52,7 +60,10 @@ public class KefuMsgForm implements IMsgForm {
     private JLabel kefuMsgPagepathLabel;
     private JTextField msgKefuThumbMediaIdTextField;
     private JLabel kefuMsgThumbMediaIdLabel;
+    private JButton uploadImageButton;
+    private JPanel thumbMediaPanel;
 
+    private static final Log logger = LogFactory.get();
     private static KefuMsgForm kefuMsgForm;
 
     private static TMsgKefuMapper msgKefuMapper = MybatisUtil.getSqlSession().getMapper(TMsgKefuMapper.class);
@@ -64,6 +75,24 @@ public KefuMsgForm() {
                 switchKefuMsgType(e.getItem().toString());
             }
         });
+        uploadImageButton.addActionListener(e -> {
+            JFileChooser fileChooser = new JFileChooser();
+            FileFilter filter = new FileNameExtensionFilter("*.bmp,*.gif,*.jpeg,*.jpg,*.png", "bmp", "gif", "jpeg", "jpg", "png", "BMP", "GIF", "JPEG", "JPG", "PNG");
+            fileChooser.setFileFilter(filter);
+
+            int approve = fileChooser.showOpenDialog(MessageEditForm.getInstance().getMsgEditorPanel());
+            if (approve == JFileChooser.APPROVE_OPTION) {
+                try {
+                    File selectedFile = fileChooser.getSelectedFile();
+                    WxMediaUploadResult wxMediaUploadResult = WxMpTemplateMsgSender.getWxMpService().getMaterialService().mediaUpload(WxMaConstants.MediaType.IMAGE, selectedFile);
+                    msgKefuThumbMediaIdTextField.setText(wxMediaUploadResult.getMediaId());
+                } catch (Exception e1) {
+                    JOptionPane.showMessageDialog(kefuMsgPanel, "上传失败!\n\n" + e1.getMessage(), "失败",
+                            JOptionPane.ERROR_MESSAGE);
+                    logger.error(e1);
+                }
+            }
+        });
     }
 
     @Override
@@ -185,7 +214,7 @@ public static void switchKefuMsgType(String msgType) {
         getInstance().getKefuMsgPagepathLabel().setVisible(false);
         getInstance().getMsgKefuPagepathTextField().setVisible(false);
         getInstance().getKefuMsgThumbMediaIdLabel().setVisible(false);
-        getInstance().getMsgKefuThumbMediaIdTextField().setVisible(false);
+        getInstance().getThumbMediaPanel().setVisible(false);
         switch (msgType) {
             case "文本消息":
                 getInstance().getContentLabel().setVisible(true);
@@ -209,7 +238,7 @@ public static void switchKefuMsgType(String msgType) {
                 getInstance().getKefuMsgPagepathLabel().setVisible(true);
                 getInstance().getMsgKefuPagepathTextField().setVisible(true);
                 getInstance().getKefuMsgThumbMediaIdLabel().setVisible(true);
-                getInstance().getMsgKefuThumbMediaIdTextField().setVisible(true);
+                getInstance().getThumbMediaPanel().setVisible(true);
                 break;
             default:
                 break;
@@ -297,13 +326,19 @@ public static void clearAllField() {
         kefuMsgPanel.add(msgKefuAppidTextField, new GridConstraints(6, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED, null, new Dimension(150, -1), null, 0, false));
         msgKefuPagepathTextField = new JTextField();
         kefuMsgPanel.add(msgKefuPagepathTextField, new GridConstraints(7, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED, null, new Dimension(150, -1), null, 0, false));
-        msgKefuThumbMediaIdTextField = new JTextField();
-        kefuMsgPanel.add(msgKefuThumbMediaIdTextField, new GridConstraints(8, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED, null, new Dimension(150, -1), null, 0, false));
         contentLabel = new JLabel();
         contentLabel.setText("内容");
         kefuMsgPanel.add(contentLabel, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_NORTHWEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
         contentTextArea = new JTextArea();
         kefuMsgPanel.add(contentTextArea, new GridConstraints(1, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_WANT_GROW, null, new Dimension(150, 50), null, 0, false));
+        thumbMediaPanel = new JPanel();
+        thumbMediaPanel.setLayout(new GridLayoutManager(1, 2, new Insets(0, 0, 0, 0), -1, -1));
+        kefuMsgPanel.add(thumbMediaPanel, new GridConstraints(8, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
+        msgKefuThumbMediaIdTextField = new JTextField();
+        thumbMediaPanel.add(msgKefuThumbMediaIdTextField, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED, null, new Dimension(150, -1), null, 0, false));
+        uploadImageButton = new JButton();
+        uploadImageButton.setText("上传图片");
+        thumbMediaPanel.add(uploadImageButton, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
         kefuMsgTypeLabel.setLabelFor(msgKefuMsgTypeComboBox);
         kefuMsgTitleLabel.setLabelFor(msgKefuMsgTitleTextField);
         kefuMsgPicUrlLabel.setLabelFor(msgKefuPicUrlTextField);
diff --git a/src/main/java/com/fangxuele/tool/push/ui/form/msg/MailMsgForm.form b/src/main/java/com/fangxuele/tool/push/ui/form/msg/MailMsgForm.form
index d1bd249d..647d4099 100644
--- a/src/main/java/com/fangxuele/tool/push/ui/form/msg/MailMsgForm.form
+++ b/src/main/java/com/fangxuele/tool/push/ui/form/msg/MailMsgForm.form
@@ -59,7 +59,7 @@
           
         
         
-          
+          
         
       
       
@@ -68,17 +68,9 @@
         
         
           
-          
+          
         
       
-      
-        
-          
-            
-          
-        
-        
-      
       
         
           
@@ -95,6 +87,21 @@
           
         
       
+      
+        
+          
+            
+          
+        
+        
+        
+        
+          
+            
+            
+          
+        
+      
     
   
 
diff --git a/src/main/java/com/fangxuele/tool/push/ui/form/msg/MailMsgForm.java b/src/main/java/com/fangxuele/tool/push/ui/form/msg/MailMsgForm.java
index 5506ac72..661df67f 100644
--- a/src/main/java/com/fangxuele/tool/push/ui/form/msg/MailMsgForm.java
+++ b/src/main/java/com/fangxuele/tool/push/ui/form/msg/MailMsgForm.java
@@ -10,6 +10,7 @@
 import com.intellij.uiDesigner.core.GridConstraints;
 import com.intellij.uiDesigner.core.GridLayoutManager;
 import lombok.Getter;
+import org.apache.commons.lang3.StringUtils;
 
 import javax.swing.*;
 import java.awt.*;
@@ -19,6 +20,7 @@
 import java.io.IOException;
 import java.net.URI;
 import java.net.URISyntaxException;
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -34,29 +36,30 @@ public class MailMsgForm implements IMsgForm {
 
     private JPanel mailPanel;
     private JTextField mailTitleTextField;
-    private JTextField mailFilesTextField;
     private JEditorPane mailContentPane;
     private JButton fileExploreButton;
     private JLabel uEditorLabel;
     private JTextField mailCcTextField;
+    private JTextArea mailFilesTextArea;
 
     private static MailMsgForm mailMsgForm;
     private static TMsgMailMapper msgMailMapper = MybatisUtil.getSqlSession().getMapper(TMsgMailMapper.class);
 
     public MailMsgForm() {
         fileExploreButton.addActionListener(e -> {
-            File beforeFile = new File(mailFilesTextField.getText());
             JFileChooser fileChooser;
 
-            if (beforeFile.exists()) {
-                fileChooser = new JFileChooser(beforeFile);
+            if (getAttachmentFiles().size() > 0 && getAttachmentFiles().get(0).exists()) {
+                fileChooser = new JFileChooser(getAttachmentFiles().get(0));
             } else {
                 fileChooser = new JFileChooser();
             }
 
+            fileChooser.setMultiSelectionEnabled(true);
+
             int approve = fileChooser.showOpenDialog(MessageEditForm.getInstance().getMsgEditorPanel());
             if (approve == JFileChooser.APPROVE_OPTION) {
-                mailFilesTextField.setText(fileChooser.getSelectedFile().getAbsolutePath());
+                appendAttachmentFilePath(fileChooser);
             }
         });
         uEditorLabel.addMouseListener(new MouseAdapter() {
@@ -64,7 +67,7 @@ public MailMsgForm() {
             public void mousePressed(MouseEvent e) {
                 Desktop desktop = Desktop.getDesktop();
                 try {
-                    desktop.browse(new URI("https://ueditor.baidu.com/website/onlinedemo.html"));
+                    desktop.browse(new URI("http://kindeditor.net/demo.php"));
                 } catch (IOException | URISyntaxException e1) {
                     e1.printStackTrace();
                 }
@@ -87,7 +90,7 @@ public void init(String msgName) {
             TMsgMail tMsgMail = tMsgMailList.get(0);
             getInstance().getMailTitleTextField().setText(tMsgMail.getTitle());
             getInstance().getMailCcTextField().setText(tMsgMail.getCc());
-            getInstance().getMailFilesTextField().setText(tMsgMail.getFiles());
+            getInstance().getMailFilesTextArea().setText(tMsgMail.getFiles());
             getInstance().getMailContentPane().setText(tMsgMail.getContent());
 
             MessageEditForm messageEditForm = MessageEditForm.getInstance();
@@ -114,7 +117,7 @@ public void save(String msgName) {
         if (!existSameMsg || isCover == JOptionPane.YES_OPTION) {
             String mailTitle = getInstance().getMailTitleTextField().getText();
             String mailCc = getInstance().getMailCcTextField().getText();
-            String mailFiles = getInstance().getMailFilesTextField().getText();
+            String mailFiles = getInstance().getMailFilesTextArea().getText();
             String mailContent = getInstance().getMailContentPane().getText();
 
             String now = SqliteUtil.nowDateForSqlite();
@@ -143,6 +146,39 @@ public void save(String msgName) {
         }
     }
 
+    /**
+     * 获取附件文件数组
+     *
+     * @return
+     */
+    public List getAttachmentFiles() {
+        List files = new ArrayList<>();
+        String text = mailFilesTextArea.getText();
+        String[] strings = text.split("\\n");
+        for (String string : strings) {
+            string = string.trim();
+            if (StringUtils.isNotEmpty(string)) {
+                files.add(new File(string));
+            }
+        }
+        return files;
+    }
+
+    /**
+     * 添加附件文件路径到附件文本域
+     *
+     * @param fileChooser
+     */
+    public void appendAttachmentFilePath(JFileChooser fileChooser) {
+        File[] selectedFiles = fileChooser.getSelectedFiles();
+        for (File selectedFile : selectedFiles) {
+            if (StringUtils.isNotBlank(mailFilesTextArea.getText())) {
+                mailFilesTextArea.append("\n");
+            }
+            mailFilesTextArea.append(selectedFile.getAbsolutePath());
+        }
+    }
+
     public static MailMsgForm getInstance() {
         if (mailMsgForm == null) {
             mailMsgForm = new MailMsgForm();
@@ -156,7 +192,7 @@ public static MailMsgForm getInstance() {
     public static void clearAllField() {
         getInstance().getMailTitleTextField().setText("");
         getInstance().getMailCcTextField().setText("");
-        getInstance().getMailFilesTextField().setText("");
+        getInstance().getMailFilesTextArea().setText("");
         getInstance().getMailContentPane().setText("");
     }
 
@@ -195,19 +231,21 @@ public static void clearAllField() {
         label3.setText("邮件正文(HTML)");
         mailPanel.add(label3, new GridConstraints(3, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
         uEditorLabel = new JLabel();
-        uEditorLabel.setText("使用UEditor编辑HTML");
+        uEditorLabel.setText("使用KindEditor编辑HTML");
         mailPanel.add(uEditorLabel, new GridConstraints(3, 1, 1, 2, GridConstraints.ANCHOR_EAST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
         fileExploreButton = new JButton();
         fileExploreButton.setHorizontalAlignment(0);
-        fileExploreButton.setText("浏览");
+        fileExploreButton.setText("添加附件");
         mailPanel.add(fileExploreButton, new GridConstraints(2, 2, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, 1, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
-        mailFilesTextField = new JTextField();
-        mailPanel.add(mailFilesTextField, new GridConstraints(2, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED, null, new Dimension(150, -1), null, 0, false));
         mailCcTextField = new JTextField();
         mailPanel.add(mailCcTextField, new GridConstraints(1, 1, 1, 2, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED, null, new Dimension(150, -1), null, 0, false));
         final JLabel label4 = new JLabel();
         label4.setText("抄送");
         mailPanel.add(label4, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
+        final JScrollPane scrollPane1 = new JScrollPane();
+        mailPanel.add(scrollPane1, new GridConstraints(2, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, new Dimension(-1, 60), null, 0, false));
+        mailFilesTextArea = new JTextArea();
+        scrollPane1.setViewportView(mailFilesTextArea);
     }
 
     /**
diff --git a/src/main/java/com/fangxuele/tool/push/ui/listener/InfinityListener.java b/src/main/java/com/fangxuele/tool/push/ui/listener/InfinityListener.java
index c92f1f95..743cd282 100644
--- a/src/main/java/com/fangxuele/tool/push/ui/listener/InfinityListener.java
+++ b/src/main/java/com/fangxuele/tool/push/ui/listener/InfinityListener.java
@@ -56,7 +56,7 @@ public static void addListeners() {
         InfinityForm infinityForm = InfinityForm.getInstance();
 
         // 开始按钮事件
-        infinityForm.getPushStartButton().addActionListener((e) -> ThreadUtil.execute(() -> {
+        infinityForm.getPushStartButton().addActionListener((e) -> {
             if (PushControl.pushCheck()) {
                 int isPush = JOptionPane.showConfirmDialog(infinityForm.getInfinityPanel(),
                         "确定开始推送吗?\n\n推送消息:" +
@@ -69,7 +69,7 @@ public static void addListeners() {
                     ThreadUtil.execute(new InfinityPushRunThread());
                 }
             }
-        }));
+        });
 
         // 按计划执行按钮事件
         infinityForm.getScheduleRunButton().addActionListener((e -> ThreadUtil.execute(() -> {
diff --git a/src/main/java/com/fangxuele/tool/push/ui/listener/MessageManageListener.java b/src/main/java/com/fangxuele/tool/push/ui/listener/MessageManageListener.java
index 3d4dcd00..caad195d 100644
--- a/src/main/java/com/fangxuele/tool/push/ui/listener/MessageManageListener.java
+++ b/src/main/java/com/fangxuele/tool/push/ui/listener/MessageManageListener.java
@@ -69,15 +69,13 @@ public static void addListeners() {
         msgHistable.addMouseListener(new MouseAdapter() {
             @Override
             public void mousePressed(MouseEvent e) {
-                ThreadUtil.execute(() -> {
-                    PushHisForm.getInstance().getPushHisTextArea().setText("");
+                PushHisForm.getInstance().getPushHisTextArea().setText("");
 
-                    int selectedRow = msgHistable.getSelectedRow();
-                    String selectedMsgName = msgHistable
-                            .getValueAt(selectedRow, 0).toString();
+                int selectedRow = msgHistable.getSelectedRow();
+                String selectedMsgName = msgHistable
+                        .getValueAt(selectedRow, 0).toString();
 
-                    MessageEditForm.init(selectedMsgName);
-                });
+                MessageEditForm.init(selectedMsgName);
                 super.mousePressed(e);
             }
         });
diff --git a/src/main/java/com/fangxuele/tool/push/ui/listener/PushListener.java b/src/main/java/com/fangxuele/tool/push/ui/listener/PushListener.java
index 89b3e7ed..99f9c4fb 100644
--- a/src/main/java/com/fangxuele/tool/push/ui/listener/PushListener.java
+++ b/src/main/java/com/fangxuele/tool/push/ui/listener/PushListener.java
@@ -56,7 +56,7 @@ public static void addListeners() {
         JPanel pushPanel = pushForm.getPushPanel();
 
         // 开始按钮事件
-        pushForm.getPushStartButton().addActionListener((e) -> ThreadUtil.execute(() -> {
+        pushForm.getPushStartButton().addActionListener((e) -> {
             if (PushControl.pushCheck()) {
                 if ("0".equals(pushForm.getThreadCountTextField().getText()) || StringUtils.isEmpty(pushForm.getThreadCountTextField().getText())) {
                     JOptionPane.showMessageDialog(pushForm.getPushPanel(), "请设置每个线程分配的页数!", "提示",
@@ -75,7 +75,7 @@ public static void addListeners() {
                     ThreadUtil.execute(new PushRunThread());
                 }
             }
-        }));
+        });
 
         // 停止按钮事件
         pushForm.getPushStopButton().addActionListener((e) -> {
diff --git a/src/main/java/com/fangxuele/tool/push/ui/listener/SettingListener.java b/src/main/java/com/fangxuele/tool/push/ui/listener/SettingListener.java
index e66a433c..ef5e50be 100644
--- a/src/main/java/com/fangxuele/tool/push/ui/listener/SettingListener.java
+++ b/src/main/java/com/fangxuele/tool/push/ui/listener/SettingListener.java
@@ -23,7 +23,6 @@
 import com.fangxuele.tool.push.ui.dialog.SwitchWxAccountDialog;
 import com.fangxuele.tool.push.ui.dialog.SystemEnvResultDialog;
 import com.fangxuele.tool.push.ui.dialog.WxCpAppDialog;
-import com.fangxuele.tool.push.ui.form.MainWindow;
 import com.fangxuele.tool.push.ui.form.MessageManageForm;
 import com.fangxuele.tool.push.ui.form.SettingForm;
 import com.fangxuele.tool.push.ui.form.msg.DingMsgForm;
@@ -31,6 +30,7 @@
 import com.fangxuele.tool.push.util.HikariUtil;
 import com.fangxuele.tool.push.util.MybatisUtil;
 import com.fangxuele.tool.push.util.SqliteUtil;
+import com.fangxuele.tool.push.util.SystemUtil;
 import com.zaxxer.hikari.HikariDataSource;
 import org.apache.commons.lang3.StringUtils;
 
@@ -81,6 +81,11 @@ public static void addListeners() {
                 App.tray = null;
             }
         });
+        // 设置-常规-默认最大化窗口
+        settingForm.getDefaultMaxWindowCheckBox().addActionListener(e -> {
+            App.config.setDefaultMaxWindow(settingForm.getDefaultMaxWindowCheckBox().isSelected());
+            App.config.save();
+        });
 
         // 设置-常规-最大线程数
         settingForm.getMaxThreadsSaveButton().addActionListener(e -> {
@@ -603,16 +608,19 @@ public static void addListeners() {
         // 外观-保存
         settingForm.getSettingAppearanceSaveButton().addActionListener(e -> {
             try {
-                App.config.setTheme(Objects.requireNonNull(settingForm.getSettingThemeComboBox().getSelectedItem()).toString());
+                if (!App.config.getTheme().equals(settingForm.getSettingThemeComboBox().getSelectedItem().toString())) {
+                    App.config.setTheme(Objects.requireNonNull(settingForm.getSettingThemeComboBox().getSelectedItem()).toString());
+                    Init.initTheme();
+                    for (Window window : Window.getWindows()) {
+                        SwingUtilities.updateComponentTreeUI(window);
+                    }
+                }
+                Init.initGlobalFont();
+
                 App.config.setFont(Objects.requireNonNull(settingForm.getSettingFontNameComboBox().getSelectedItem()).toString());
                 App.config.setFontSize(Integer.parseInt(Objects.requireNonNull(settingForm.getSettingFontSizeComboBox().getSelectedItem()).toString()));
                 App.config.save();
 
-                Init.initTheme();
-                Init.initGlobalFont();
-                SwingUtilities.updateComponentTreeUI(App.mainFrame);
-                SwingUtilities.updateComponentTreeUI(MainWindow.getInstance().getTabbedPane());
-
                 JOptionPane.showMessageDialog(settingPanel, "保存成功!\n\n部分细节将在下次启动时生效!\n\n", "成功",
                         JOptionPane.INFORMATION_MESSAGE);
             } catch (Exception e1) {
@@ -626,7 +634,7 @@ public static void addListeners() {
         settingForm.getShowLogButton().addActionListener(e -> {
             try {
                 Desktop desktop = Desktop.getDesktop();
-                desktop.open(new File(UiConsts.LOG_DIR));
+                desktop.open(new File(SystemUtil.LOG_DIR));
             } catch (Exception e2) {
                 logger.error("查看日志打开失败", e2);
             }
diff --git a/src/main/java/com/fangxuele/tool/push/util/ConfigBaseUtil.java b/src/main/java/com/fangxuele/tool/push/util/ConfigBaseUtil.java
index 10fd92b9..e1b9a999 100644
--- a/src/main/java/com/fangxuele/tool/push/util/ConfigBaseUtil.java
+++ b/src/main/java/com/fangxuele/tool/push/util/ConfigBaseUtil.java
@@ -18,7 +18,7 @@ public class ConfigBaseUtil {
     /**
      * 设置文件路径
      */
-    private String settingFilePath = SystemUtil.configHome + "config" + File.separator + "config.setting";
+    private String settingFilePath = SystemUtil.CONFIG_HOME + "config" + File.separator + "config.setting";
 
     Setting setting;
 
diff --git a/src/main/java/com/fangxuele/tool/push/util/ConfigUtil.java b/src/main/java/com/fangxuele/tool/push/util/ConfigUtil.java
index 86cfadfa..02aed251 100644
--- a/src/main/java/com/fangxuele/tool/push/util/ConfigUtil.java
+++ b/src/main/java/com/fangxuele/tool/push/util/ConfigUtil.java
@@ -60,6 +60,8 @@ private ConfigUtil() {
 
     private boolean useTray;
 
+    private boolean defaultMaxWindow;
+
     private Integer maxThreads;
 
     private long pushTotal;
@@ -380,6 +382,14 @@ public void setUseTray(boolean useTray) {
         setting.put("setting.normal", "useTray", String.valueOf(useTray));
     }
 
+    public boolean isDefaultMaxWindow() {
+        return setting.getBool("defaultMaxWindow", "setting.normal", true);
+    }
+
+    public void setDefaultMaxWindow(boolean defaultMaxWindow) {
+        setting.put("setting.normal", "defaultMaxWindow", String.valueOf(defaultMaxWindow));
+    }
+
     public Integer getMaxThreads() {
         return setting.getInt("maxThreads", "setting.normal", 100);
     }
@@ -661,7 +671,11 @@ public void setTheme(String theme) {
     }
 
     public String getFont() {
-        return setting.getStr("font", "setting.appearance", "微软雅黑");
+        if (SystemUtil.isLinuxOs()) {
+            return setting.getStr("font", "setting.appearance", "Noto Sans CJK HK");
+        } else {
+            return setting.getStr("font", "setting.appearance", "微软雅黑");
+        }
     }
 
     public void setFont(String font) {
diff --git a/src/main/java/com/fangxuele/tool/push/util/MybatisUtil.java b/src/main/java/com/fangxuele/tool/push/util/MybatisUtil.java
index 7745d4ed..e8776f3b 100644
--- a/src/main/java/com/fangxuele/tool/push/util/MybatisUtil.java
+++ b/src/main/java/com/fangxuele/tool/push/util/MybatisUtil.java
@@ -34,7 +34,7 @@ public class MybatisUtil {
      */
     private static boolean needInit = false;
 
-    private static File dbFile = new File(SystemUtil.configHome + "WePush.db");
+    private static File dbFile = new File(SystemUtil.CONFIG_HOME + "WePush.db");
 
     static {
         try {
@@ -67,7 +67,7 @@ public static SqlSession getSqlSession() {
      * 初始化数据库文件
      */
     public static void initDbFile() throws SQLException {
-        File configHomeDir = new File(SystemUtil.configHome);
+        File configHomeDir = new File(SystemUtil.CONFIG_HOME);
         if (!configHomeDir.exists()) {
             configHomeDir.mkdirs();
         }
diff --git a/src/main/java/com/fangxuele/tool/push/util/SystemUtil.java b/src/main/java/com/fangxuele/tool/push/util/SystemUtil.java
index 35a68d50..cbc7dc7f 100644
--- a/src/main/java/com/fangxuele/tool/push/util/SystemUtil.java
+++ b/src/main/java/com/fangxuele/tool/push/util/SystemUtil.java
@@ -11,16 +11,29 @@
  * @since 2019/4/20.
  */
 public class SystemUtil {
-    private static String osName = System.getProperty("os.name");
-    private static String osArch = System.getProperty("os.arch");
-    public static String configHome = System.getProperty("user.home") + File.separator + ".wepush"
-            + File.separator;
+    private static final String OS_NAME = System.getProperty("os.name");
+    private static final String OS_ARCH = System.getProperty("os.arch");
+    private static final String VM_VENDOR = System.getProperty("java.vm.vendor");
+    private static final String USER_HOME = System.getProperty("user.home");
+    public static final String CONFIG_HOME = USER_HOME + File.separator + ".wepush" + File.separator;
+    /**
+     * 日志文件路径
+     */
+    public final static String LOG_DIR = USER_HOME + File.separator + ".wepush" + File.separator + "logs" + File.separator;
 
     public static boolean isMacOs() {
-        return osName.contains("Mac");
+        return OS_NAME.contains("Mac");
+    }
+
+    public static boolean isLinuxOs() {
+        return OS_NAME.contains("Linux");
     }
 
     public static boolean isMacM1() {
-        return osName.contains("Mac") && "aarch64".equals(osArch);
+        return OS_NAME.contains("Mac") && "aarch64".equals(OS_ARCH);
+    }
+
+    public static boolean isJBR() {
+        return VM_VENDOR.contains("JetBrains");
     }
 }
\ No newline at end of file
diff --git a/src/main/java/com/fangxuele/tool/push/util/UpgradeUtil.java b/src/main/java/com/fangxuele/tool/push/util/UpgradeUtil.java
index 7028c893..460f3044 100644
--- a/src/main/java/com/fangxuele/tool/push/util/UpgradeUtil.java
+++ b/src/main/java/com/fangxuele/tool/push/util/UpgradeUtil.java
@@ -8,6 +8,7 @@
 import com.fangxuele.tool.push.bean.VersionSummary;
 import com.fangxuele.tool.push.dao.TWxAccountMapper;
 import com.fangxuele.tool.push.domain.TWxAccount;
+import com.fangxuele.tool.push.ui.Init;
 import com.fangxuele.tool.push.ui.UiConsts;
 import com.fangxuele.tool.push.ui.dialog.UpdateInfoDialog;
 import com.fangxuele.tool.push.ui.form.MainWindow;
@@ -216,6 +217,12 @@ private static void upgrade(int versionIndex) {
                     App.config.save();
                 }
                 break;
+            case 46:
+            case 47:
+            case 48:
+                if(SystemUtil.isJBR()){
+                    App.config.setProps(Init.FONT_SIZE_INIT_PROP,"");
+                }
             default:
         }
         log.info("执行升级脚本结束,版本索引:{}", versionIndex);
diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml
index 3055c828..ee254413 100644
--- a/src/main/resources/logback.xml
+++ b/src/main/resources/logback.xml
@@ -8,7 +8,7 @@
 
     
         
-            ./logs/wechat-push.%d{yyyy-MM-dd}.log
+            ${user.home}/.wepush/logs/wechat-push.%d{yyyy-MM-dd}.log
         
         
             %date{HH:mm:ss.SSS} [%thread] %-5level %logger{36} :%line - %msg%n
diff --git a/src/main/resources/version_summary.json b/src/main/resources/version_summary.json
index 7de322d0..a20ddb4b 100644
--- a/src/main/resources/version_summary.json
+++ b/src/main/resources/version_summary.json
@@ -1,5 +1,5 @@
 {
-  "currentVersion": "v_4.3.0_210123",
+  "currentVersion": "v_4.4.0_210221",
   "versionIndex": {
     "v_1.1.0_170701": "0",
     "v_1.2.0_170831": "1",
@@ -46,7 +46,8 @@
     "v_4.2.3_201210": "42",
     "v_4.2.4_201222": "43",
     "v_4.2.5_210117": "44",
-    "v_4.3.0_210123": "45"
+    "v_4.3.0_210123": "45",
+    "v_4.4.0_210221": "46"
   },
   "versionDetailList": [
     {
@@ -278,6 +279,11 @@
       "version": "v_4.3.0_210123",
       "title": "新增变速模式",
       "log": "● feature:新增变速模式,可在发送过程中随时调整线程数\n● feature:新增了几套主题样式\n● optimization:优化了tps的计算逻辑\n"
+    },
+    {
+      "version": "v_4.4.0_210221",
+      "title": "客服消息小程序卡片类型支持上传图片",
+      "log": "● feature:客服消息小程序卡片类型支持上传图片\n● feature:邮件消息支持添加多个附件\n● optimization:调整邮件html在线编辑器为kindeditor\n● optimization:调整默认推荐主题,修复窗口自动最大化表现异常的问题,修复点击消息管理列表经常报错的问题,优化Linux系统兼容性等各种细节优化\n"
     }
   ]
 }
\ No newline at end of file