浏览代码

支持水印配置

AE86 1 年之前
父节点
当前提交
bd06950fb6
共有 63 个文件被更改,包括 462 次插入270 次删除
  1. 21 0
      dbsyncer-biz/src/main/java/org/dbsyncer/biz/AppConfigService.java
  2. 3 0
      dbsyncer-biz/src/main/java/org/dbsyncer/biz/BizException.java
  3. 3 0
      dbsyncer-biz/src/main/java/org/dbsyncer/biz/ConditionService.java
  4. 3 0
      dbsyncer-biz/src/main/java/org/dbsyncer/biz/ConnectorService.java
  5. 3 0
      dbsyncer-biz/src/main/java/org/dbsyncer/biz/ConvertService.java
  6. 3 0
      dbsyncer-biz/src/main/java/org/dbsyncer/biz/DataSyncService.java
  7. 3 0
      dbsyncer-biz/src/main/java/org/dbsyncer/biz/MappingService.java
  8. 3 0
      dbsyncer-biz/src/main/java/org/dbsyncer/biz/MonitorService.java
  9. 3 0
      dbsyncer-biz/src/main/java/org/dbsyncer/biz/PluginService.java
  10. 3 0
      dbsyncer-biz/src/main/java/org/dbsyncer/biz/ProjectGroupService.java
  11. 14 2
      dbsyncer-biz/src/main/java/org/dbsyncer/biz/SystemConfigService.java
  12. 3 0
      dbsyncer-biz/src/main/java/org/dbsyncer/biz/TableGroupService.java
  13. 3 0
      dbsyncer-biz/src/main/java/org/dbsyncer/biz/UserConfigService.java
  14. 5 0
      dbsyncer-biz/src/main/java/org/dbsyncer/biz/checker/AbstractChecker.java
  15. 3 0
      dbsyncer-biz/src/main/java/org/dbsyncer/biz/checker/impl/group/ProjectGroupChecker.java
  16. 0 3
      dbsyncer-biz/src/main/java/org/dbsyncer/biz/checker/impl/mapping/MappingChecker.java
  17. 11 2
      dbsyncer-biz/src/main/java/org/dbsyncer/biz/checker/impl/system/SystemConfigChecker.java
  18. 3 0
      dbsyncer-biz/src/main/java/org/dbsyncer/biz/checker/impl/user/UserConfigChecker.java
  19. 39 0
      dbsyncer-biz/src/main/java/org/dbsyncer/biz/impl/AppConfigServiceImpl.java
  20. 3 0
      dbsyncer-biz/src/main/java/org/dbsyncer/biz/impl/BaseServiceImpl.java
  21. 3 0
      dbsyncer-biz/src/main/java/org/dbsyncer/biz/impl/ConnectorServiceImpl.java
  22. 3 0
      dbsyncer-biz/src/main/java/org/dbsyncer/biz/impl/ConvertServiceImpl.java
  23. 3 0
      dbsyncer-biz/src/main/java/org/dbsyncer/biz/impl/DataSyncServiceImpl.java
  24. 3 3
      dbsyncer-biz/src/main/java/org/dbsyncer/biz/impl/MonitorServiceImpl.java
  25. 3 0
      dbsyncer-biz/src/main/java/org/dbsyncer/biz/impl/PluginServiceImpl.java
  26. 3 0
      dbsyncer-biz/src/main/java/org/dbsyncer/biz/impl/ProjectGroupServiceImpl.java
  27. 30 25
      dbsyncer-biz/src/main/java/org/dbsyncer/biz/impl/SystemConfigServiceImpl.java
  28. 3 0
      dbsyncer-biz/src/main/java/org/dbsyncer/biz/impl/UserConfigServiceImpl.java
  29. 12 0
      dbsyncer-biz/src/main/java/org/dbsyncer/biz/vo/VersionVo.java
  30. 12 0
      dbsyncer-common/src/main/java/org/dbsyncer/common/config/AppConfig.java
  31. 1 1
      dbsyncer-connector/dbsyncer-connector-base/src/test/java/ConnectionTest.java
  32. 2 8
      dbsyncer-connector/dbsyncer-connector-postgresql/src/main/resources/public/connector/addDqlPostgreSQL.html
  33. 2 8
      dbsyncer-connector/dbsyncer-connector-postgresql/src/main/resources/public/connector/addPostgreSQL.html
  34. 6 0
      dbsyncer-parser/pom.xml
  35. 1 1
      dbsyncer-parser/src/main/java/org/dbsyncer/parser/flush/impl/GeneralBufferActuator.java
  36. 1 5
      dbsyncer-parser/src/main/java/org/dbsyncer/parser/impl/LogServiceImpl.java
  37. 1 1
      dbsyncer-parser/src/main/java/org/dbsyncer/parser/impl/ParserComponentImpl.java
  38. 11 0
      dbsyncer-parser/src/main/java/org/dbsyncer/parser/model/AbstractConfigModel.java
  39. 0 11
      dbsyncer-parser/src/main/java/org/dbsyncer/parser/model/Mapping.java
  40. 50 24
      dbsyncer-parser/src/main/java/org/dbsyncer/parser/model/SystemConfig.java
  41. 5 8
      dbsyncer-parser/src/main/java/org/dbsyncer/parser/strategy/impl/FlushStrategyImpl.java
  42. 2 0
      dbsyncer-parser/src/main/java/org/dbsyncer/parser/util/PickerUtil.java
  43. 2 2
      dbsyncer-web/src/main/java/org/dbsyncer/web/controller/DefaultController.java
  44. 3 4
      dbsyncer-web/src/main/java/org/dbsyncer/web/controller/index/IndexController.java
  45. 6 8
      dbsyncer-web/src/main/java/org/dbsyncer/web/controller/monitor/MonitorController.java
  46. 3 12
      dbsyncer-web/src/main/java/org/dbsyncer/web/controller/system/SystemController.java
  47. 2 2
      dbsyncer-web/src/main/resources/application.properties
  48. 1 1
      dbsyncer-web/src/main/resources/public/mapping/add.html
  49. 2 1
      dbsyncer-web/src/main/resources/public/mapping/edit.html
  50. 4 4
      dbsyncer-web/src/main/resources/public/mapping/editIncrement.html
  51. 7 7
      dbsyncer-web/src/main/resources/public/mapping/editIncrementQuartz.html
  52. 3 2
      dbsyncer-web/src/main/resources/public/mapping/editParameter.html
  53. 3 3
      dbsyncer-web/src/main/resources/public/mapping/editPlugin.html
  54. 2 2
      dbsyncer-web/src/main/resources/public/mapping/editTableGroup.html
  55. 50 49
      dbsyncer-web/src/main/resources/public/system/system.html
  56. 1 2
      dbsyncer-web/src/main/resources/static/css/common.css
  57. 42 21
      dbsyncer-web/src/main/resources/static/js/common.js
  58. 2 0
      dbsyncer-web/src/main/resources/static/js/index.js
  59. 1 12
      dbsyncer-web/src/main/resources/static/js/mapping/add.js
  60. 0 18
      dbsyncer-web/src/main/resources/static/js/mapping/edit.js
  61. 2 13
      dbsyncer-web/src/main/resources/static/js/mapping/editIncrement.js
  62. 15 0
      dbsyncer-web/src/main/resources/static/js/mapping/editPlugin.js
  63. 22 5
      dbsyncer-web/src/main/resources/static/js/system/index.js

+ 21 - 0
dbsyncer-biz/src/main/java/org/dbsyncer/biz/AppConfigService.java

@@ -0,0 +1,21 @@
+/**
+ * DBSyncer Copyright 2020-2024 All Rights Reserved.
+ */
+package org.dbsyncer.biz;
+
+import org.dbsyncer.biz.vo.VersionVo;
+
+/**
+ * @Author AE86
+ * @Version 1.0.0
+ * @Date 2024-05-12 01:08
+ */
+public interface AppConfigService {
+
+    /**
+     * 获取版本信息
+     *
+     * @return
+     */
+    VersionVo getVersionInfo();
+}

+ 3 - 0
dbsyncer-biz/src/main/java/org/dbsyncer/biz/BizException.java

@@ -1,3 +1,6 @@
+/**
+ * DBSyncer Copyright 2020-2024 All Rights Reserved.
+ */
 package org.dbsyncer.biz;
 
 /**

+ 3 - 0
dbsyncer-biz/src/main/java/org/dbsyncer/biz/ConditionService.java

@@ -1,3 +1,6 @@
+/**
+ * DBSyncer Copyright 2020-2024 All Rights Reserved.
+ */
 package org.dbsyncer.biz;
 
 import org.dbsyncer.biz.vo.ConditionVo;

+ 3 - 0
dbsyncer-biz/src/main/java/org/dbsyncer/biz/ConnectorService.java

@@ -1,3 +1,6 @@
+/**
+ * DBSyncer Copyright 2020-2024 All Rights Reserved.
+ */
 package org.dbsyncer.biz;
 
 import org.dbsyncer.parser.model.Connector;

+ 3 - 0
dbsyncer-biz/src/main/java/org/dbsyncer/biz/ConvertService.java

@@ -1,3 +1,6 @@
+/**
+ * DBSyncer Copyright 2020-2024 All Rights Reserved.
+ */
 package org.dbsyncer.biz;
 
 import org.dbsyncer.parser.enums.ConvertEnum;

+ 3 - 0
dbsyncer-biz/src/main/java/org/dbsyncer/biz/DataSyncService.java

@@ -1,3 +1,6 @@
+/**
+ * DBSyncer Copyright 2020-2024 All Rights Reserved.
+ */
 package org.dbsyncer.biz;
 
 import com.google.protobuf.InvalidProtocolBufferException;

+ 3 - 0
dbsyncer-biz/src/main/java/org/dbsyncer/biz/MappingService.java

@@ -1,3 +1,6 @@
+/**
+ * DBSyncer Copyright 2020-2024 All Rights Reserved.
+ */
 package org.dbsyncer.biz;
 
 import org.dbsyncer.biz.vo.MappingVo;

+ 3 - 0
dbsyncer-biz/src/main/java/org/dbsyncer/biz/MonitorService.java

@@ -1,3 +1,6 @@
+/**
+ * DBSyncer Copyright 2020-2024 All Rights Reserved.
+ */
 package org.dbsyncer.biz;
 
 import org.dbsyncer.biz.vo.AppReportMetricVo;

+ 3 - 0
dbsyncer-biz/src/main/java/org/dbsyncer/biz/PluginService.java

@@ -1,3 +1,6 @@
+/**
+ * DBSyncer Copyright 2020-2024 All Rights Reserved.
+ */
 package org.dbsyncer.biz;
 
 import org.dbsyncer.biz.vo.PluginVo;

+ 3 - 0
dbsyncer-biz/src/main/java/org/dbsyncer/biz/ProjectGroupService.java

@@ -1,3 +1,6 @@
+/**
+ * DBSyncer Copyright 2020-2024 All Rights Reserved.
+ */
 package org.dbsyncer.biz;
 
 import org.dbsyncer.biz.vo.ProjectGroupVo;

+ 14 - 2
dbsyncer-biz/src/main/java/org/dbsyncer/biz/SystemConfigService.java

@@ -1,7 +1,11 @@
+/**
+ * DBSyncer Copyright 2020-2024 All Rights Reserved.
+ */
 package org.dbsyncer.biz;
 
 import org.dbsyncer.biz.vo.SystemConfigVo;
 import org.dbsyncer.parser.model.ConfigModel;
+import org.dbsyncer.parser.model.SystemConfig;
 
 import java.io.File;
 import java.util.List;
@@ -30,6 +34,13 @@ public interface SystemConfigService {
      */
     SystemConfigVo getSystemConfigVo();
 
+    /**
+     * 获取系统配置
+     *
+     * @return
+     */
+    SystemConfig getSystemConfig();
+
     /**
      * 获取所有配置(system、user、connector、mapping、tableGroup、meta、projectGroup)
      *
@@ -52,9 +63,10 @@ public interface SystemConfigService {
     void refreshConfig(File file);
 
     /**
-     * 是否启用CDN加速访问静态资源
+     * 获取水印信息
      *
+     * @param systemConfig
      * @return
      */
-    boolean isEnableCDN();
+    String getWatermark(SystemConfig systemConfig);
 }

+ 3 - 0
dbsyncer-biz/src/main/java/org/dbsyncer/biz/TableGroupService.java

@@ -1,3 +1,6 @@
+/**
+ * DBSyncer Copyright 2020-2024 All Rights Reserved.
+ */
 package org.dbsyncer.biz;
 
 import org.dbsyncer.parser.model.TableGroup;

+ 3 - 0
dbsyncer-biz/src/main/java/org/dbsyncer/biz/UserConfigService.java

@@ -1,3 +1,6 @@
+/**
+ * DBSyncer Copyright 2020-2024 All Rights Reserved.
+ */
 package org.dbsyncer.biz;
 
 import org.dbsyncer.biz.vo.UserInfoVo;

+ 5 - 0
dbsyncer-biz/src/main/java/org/dbsyncer/biz/checker/AbstractChecker.java

@@ -1,3 +1,6 @@
+/**
+ * DBSyncer Copyright 2020-2024 All Rights Reserved.
+ */
 package org.dbsyncer.biz.checker;
 
 import org.dbsyncer.biz.enums.SafeInfoEnum;
@@ -102,6 +105,8 @@ public abstract class AbstractChecker implements Checker {
             }
         }
         model.setPlugin(plugin);
+        // 插件参数
+        model.setPluginExtInfo(params.get("pluginExtInfo"));
     }
 
     /**

+ 3 - 0
dbsyncer-biz/src/main/java/org/dbsyncer/biz/checker/impl/group/ProjectGroupChecker.java

@@ -1,3 +1,6 @@
+/**
+ * DBSyncer Copyright 2020-2024 All Rights Reserved.
+ */
 package org.dbsyncer.biz.checker.impl.group;
 
 import org.dbsyncer.biz.checker.AbstractChecker;

+ 0 - 3
dbsyncer-biz/src/main/java/org/dbsyncer/biz/checker/impl/mapping/MappingChecker.java

@@ -3,7 +3,6 @@
  */
 package org.dbsyncer.biz.checker.impl.mapping;
 
-import org.apache.commons.lang3.StringUtils;
 import org.dbsyncer.biz.checker.AbstractChecker;
 import org.dbsyncer.biz.checker.MappingConfigChecker;
 import org.dbsyncer.biz.checker.impl.tablegroup.TableGroupChecker;
@@ -113,8 +112,6 @@ public class MappingChecker extends AbstractChecker {
 
         // 修改高级配置:过滤条件/转换配置/插件配置
         this.modifySuperConfigModel(mapping, params);
-        // 插件参数
-        mapping.setPluginExtInfo(params.get("pluginExtInfo"));
 
         // 更新meta
         String metaSnapshot = params.get("metaSnapshot");

+ 11 - 2
dbsyncer-biz/src/main/java/org/dbsyncer/biz/checker/impl/system/SystemConfigChecker.java

@@ -1,3 +1,6 @@
+/**
+ * DBSyncer Copyright 2020-2024 All Rights Reserved.
+ */
 package org.dbsyncer.biz.checker.impl.system;
 
 import org.dbsyncer.biz.checker.AbstractChecker;
@@ -48,10 +51,16 @@ public class SystemConfigChecker extends AbstractChecker {
     public ConfigModel checkEditConfigModel(Map<String, String> params) {
         logger.info("params:{}", params);
         Assert.notEmpty(params, "Config check params is null.");
-        params.put("enableCDN", StringUtil.isNotBlank(params.get("enableCDN")) ? "true" : "false");
-        params.put("enableStorageWriteFull", StringUtil.isNotBlank(params.get("enableStorageWriteFull")) ? "true" : "false");
         params.put("enableStorageWriteSuccess", StringUtil.isNotBlank(params.get("enableStorageWriteSuccess")) ? "true" : "false");
         params.put("enableStorageWriteFail", StringUtil.isNotBlank(params.get("enableStorageWriteFail")) ? "true" : "false");
+        params.put("enableStorageWriteFull", StringUtil.isNotBlank(params.get("enableStorageWriteFull")) ? "true" : "false");
+        params.put("enableCDN", StringUtil.isNotBlank(params.get("enableCDN")) ? "true" : "false");
+        params.put("enableWatermark", StringUtil.isNotBlank(params.get("enableWatermark")) ? "true" : "false");
+        String watermark = params.get("watermark");
+        if (StringUtil.isNotBlank(watermark)) {
+            Assert.isTrue(watermark.length() <= 64, "允许水印内容最多输入64个字.");
+        }
+        params.put("watermark", watermark);
 
         SystemConfig systemConfig = profileComponent.getSystemConfig();
         Assert.notNull(systemConfig, "配置文件为空.");

+ 3 - 0
dbsyncer-biz/src/main/java/org/dbsyncer/biz/checker/impl/user/UserConfigChecker.java

@@ -1,3 +1,6 @@
+/**
+ * DBSyncer Copyright 2020-2024 All Rights Reserved.
+ */
 package org.dbsyncer.biz.checker.impl.user;
 
 import org.dbsyncer.biz.BizException;

+ 39 - 0
dbsyncer-biz/src/main/java/org/dbsyncer/biz/impl/AppConfigServiceImpl.java

@@ -0,0 +1,39 @@
+/**
+ * DBSyncer Copyright 2020-2024 All Rights Reserved.
+ */
+package org.dbsyncer.biz.impl;
+
+import org.dbsyncer.biz.AppConfigService;
+import org.dbsyncer.biz.SystemConfigService;
+import org.dbsyncer.biz.vo.VersionVo;
+import org.dbsyncer.common.config.AppConfig;
+import org.dbsyncer.parser.model.SystemConfig;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+
+/**
+ * @Author AE86
+ * @Version 1.0.0
+ * @Date 2024-05-12 01:08
+ */
+@Component
+public class AppConfigServiceImpl implements AppConfigService {
+
+    @Resource
+    private AppConfig appConfig;
+
+    @Resource
+    private SystemConfigService systemConfigService;
+
+    @Override
+    public VersionVo getVersionInfo() {
+        VersionVo versionVo = new VersionVo(appConfig.getName(), appConfig.getCopyright());
+        // 是否启用水印
+        SystemConfig systemConfig = systemConfigService.getSystemConfig();
+        if (systemConfig.isEnableWatermark()) {
+            versionVo.setWatermark(systemConfigService.getWatermark(systemConfig));
+        }
+        return versionVo;
+    }
+}

+ 3 - 0
dbsyncer-biz/src/main/java/org/dbsyncer/biz/impl/BaseServiceImpl.java

@@ -1,3 +1,6 @@
+/**
+ * DBSyncer Copyright 2020-2024 All Rights Reserved.
+ */
 package org.dbsyncer.biz.impl;
 
 import org.dbsyncer.parser.LogService;

+ 3 - 0
dbsyncer-biz/src/main/java/org/dbsyncer/biz/impl/ConnectorServiceImpl.java

@@ -1,3 +1,6 @@
+/**
+ * DBSyncer Copyright 2020-2024 All Rights Reserved.
+ */
 package org.dbsyncer.biz.impl;
 
 import org.dbsyncer.biz.BizException;

+ 3 - 0
dbsyncer-biz/src/main/java/org/dbsyncer/biz/impl/ConvertServiceImpl.java

@@ -1,3 +1,6 @@
+/**
+ * DBSyncer Copyright 2020-2024 All Rights Reserved.
+ */
 package org.dbsyncer.biz.impl;
 
 import org.dbsyncer.biz.ConvertService;

+ 3 - 0
dbsyncer-biz/src/main/java/org/dbsyncer/biz/impl/DataSyncServiceImpl.java

@@ -1,3 +1,6 @@
+/**
+ * DBSyncer Copyright 2020-2024 All Rights Reserved.
+ */
 package org.dbsyncer.biz.impl;
 
 import com.google.protobuf.InvalidProtocolBufferException;

+ 3 - 3
dbsyncer-biz/src/main/java/org/dbsyncer/biz/impl/MonitorServiceImpl.java

@@ -37,6 +37,7 @@ import org.dbsyncer.parser.ProfileComponent;
 import org.dbsyncer.parser.enums.MetaEnum;
 import org.dbsyncer.parser.model.Mapping;
 import org.dbsyncer.parser.model.Meta;
+import org.dbsyncer.sdk.constant.ConfigConstant;
 import org.dbsyncer.sdk.enums.FilterEnum;
 import org.dbsyncer.sdk.enums.ModelEnum;
 import org.dbsyncer.sdk.enums.StorageEnum;
@@ -45,7 +46,6 @@ import org.dbsyncer.sdk.filter.FieldResolver;
 import org.dbsyncer.sdk.filter.Query;
 import org.dbsyncer.sdk.filter.impl.LongFilter;
 import org.dbsyncer.sdk.storage.StorageService;
-import org.dbsyncer.sdk.constant.ConfigConstant;
 import org.dbsyncer.storage.enums.StorageDataStatusEnum;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -285,7 +285,7 @@ public class MonitorServiceImpl extends BaseServiceImpl implements MonitorServic
         if (!CollectionUtils.isEmpty(metaAll)) {
             Query query = new Query();
             query.setType(StorageEnum.DATA);
-            int expireDataDays = systemConfigService.getSystemConfigVo().getExpireDataDays();
+            int expireDataDays = systemConfigService.getSystemConfig().getExpireDataDays();
             long expiredTime = Timestamp.valueOf(LocalDateTime.now().minusDays(expireDataDays)).getTime();
             LongFilter expiredFilter = new LongFilter(ConfigConstant.CONFIG_MODEL_CREATE_TIME, FilterEnum.LT, expiredTime);
             query.setBooleanFilter(new BooleanFilter().add(expiredFilter));
@@ -299,7 +299,7 @@ public class MonitorServiceImpl extends BaseServiceImpl implements MonitorServic
     private void deleteExpiredLog() {
         Query query = new Query();
         query.setType(StorageEnum.LOG);
-        int expireLogDays = systemConfigService.getSystemConfigVo().getExpireLogDays();
+        int expireLogDays = systemConfigService.getSystemConfig().getExpireLogDays();
         long expiredTime = Timestamp.valueOf(LocalDateTime.now().minusDays(expireLogDays)).getTime();
         LongFilter expiredFilter = new LongFilter(ConfigConstant.CONFIG_MODEL_CREATE_TIME, FilterEnum.LT, expiredTime);
         query.setBooleanFilter(new BooleanFilter().add(expiredFilter));

+ 3 - 0
dbsyncer-biz/src/main/java/org/dbsyncer/biz/impl/PluginServiceImpl.java

@@ -1,3 +1,6 @@
+/**
+ * DBSyncer Copyright 2020-2024 All Rights Reserved.
+ */
 package org.dbsyncer.biz.impl;
 
 import org.dbsyncer.biz.BizException;

+ 3 - 0
dbsyncer-biz/src/main/java/org/dbsyncer/biz/impl/ProjectGroupServiceImpl.java

@@ -1,3 +1,6 @@
+/**
+ * DBSyncer Copyright 2020-2024 All Rights Reserved.
+ */
 package org.dbsyncer.biz.impl;
 
 import org.dbsyncer.biz.ConnectorService;

+ 30 - 25
dbsyncer-biz/src/main/java/org/dbsyncer/biz/impl/SystemConfigServiceImpl.java

@@ -1,3 +1,6 @@
+/**
+ * DBSyncer Copyright 2020-2024 All Rights Reserved.
+ */
 package org.dbsyncer.biz.impl;
 
 import org.apache.commons.io.FileUtils;
@@ -5,7 +8,9 @@ import org.dbsyncer.biz.SystemConfigService;
 import org.dbsyncer.biz.UserConfigService;
 import org.dbsyncer.biz.checker.Checker;
 import org.dbsyncer.biz.vo.SystemConfigVo;
+import org.dbsyncer.common.config.AppConfig;
 import org.dbsyncer.common.util.CollectionUtils;
+import org.dbsyncer.common.util.StringUtil;
 import org.dbsyncer.parser.ProfileComponent;
 import org.dbsyncer.parser.LogService;
 import org.dbsyncer.parser.LogType;
@@ -49,6 +54,9 @@ public class SystemConfigServiceImpl implements SystemConfigService {
     @Resource
     private UserConfigService userConfigService;
 
+    @Resource
+    private AppConfig appConfig;
+
     @Override
     public String edit(Map<String, String> params) {
         ConfigModel model = systemConfigChecker.checkEditConfigModel(params);
@@ -58,7 +66,26 @@ public class SystemConfigServiceImpl implements SystemConfigService {
 
     @Override
     public SystemConfigVo getSystemConfigVo() {
-        return convertConfig2Vo(getSystemConfig());
+        SystemConfigVo systemConfigVo = new SystemConfigVo();
+        BeanUtils.copyProperties(getSystemConfig(), systemConfigVo);
+        systemConfigVo.setWatermark(getWatermark(systemConfigVo));
+        return systemConfigVo;
+    }
+
+    @Override
+    public SystemConfig getSystemConfig() {
+        SystemConfig config = profileComponent.getSystemConfig();
+        if (null != config) {
+            return config;
+        }
+
+        synchronized (this) {
+            config = profileComponent.getSystemConfig();
+            if (null == config) {
+                config = (SystemConfig) systemConfigChecker.checkAddConfigModel(new HashMap<>());
+            }
+            return config;
+        }
     }
 
     @Override
@@ -99,29 +126,7 @@ public class SystemConfigServiceImpl implements SystemConfigService {
     }
 
     @Override
-    public boolean isEnableCDN() {
-        return getSystemConfig().isEnableCDN();
-    }
-
-    private SystemConfig getSystemConfig() {
-        SystemConfig config = profileComponent.getSystemConfig();
-        if (null != config) {
-            return config;
-        }
-
-        synchronized (this) {
-            config = profileComponent.getSystemConfig();
-            if (null == config) {
-                config = (SystemConfig) systemConfigChecker.checkAddConfigModel(new HashMap<>());
-            }
-            return config;
-        }
+    public String getWatermark(SystemConfig systemConfig) {
+        return StringUtil.isNotBlank(systemConfig.getWatermark()) ? systemConfig.getWatermark() : appConfig.getName() + "<br />" + appConfig.getCompany();
     }
-
-    private SystemConfigVo convertConfig2Vo(SystemConfig systemConfig) {
-        SystemConfigVo systemConfigVo = new SystemConfigVo();
-        BeanUtils.copyProperties(systemConfig, systemConfigVo);
-        return systemConfigVo;
-    }
-
 }

+ 3 - 0
dbsyncer-biz/src/main/java/org/dbsyncer/biz/impl/UserConfigServiceImpl.java

@@ -1,3 +1,6 @@
+/**
+ * DBSyncer Copyright 2020-2024 All Rights Reserved.
+ */
 package org.dbsyncer.biz.impl;
 
 import org.dbsyncer.biz.BizException;

+ 12 - 0
dbsyncer-biz/src/main/java/org/dbsyncer/biz/vo/VersionVo.java

@@ -15,6 +15,10 @@ public class VersionVo {
      * 版权详细
      */
     private String appCopyRight;
+    /**
+     * 水印
+     */
+    private String watermark;
 
     public VersionVo(String appName, String appCopyRight) {
         this.appName = appName;
@@ -28,4 +32,12 @@ public class VersionVo {
     public String getAppCopyRight() {
         return appCopyRight;
     }
+
+    public String getWatermark() {
+        return watermark;
+    }
+
+    public void setWatermark(String watermark) {
+        this.watermark = watermark;
+    }
 }

+ 12 - 0
dbsyncer-common/src/main/java/org/dbsyncer/common/config/AppConfig.java

@@ -1,3 +1,6 @@
+/**
+ * DBSyncer Copyright 2020-2024 All Rights Reserved.
+ */
 package org.dbsyncer.common.config;
 
 import org.dbsyncer.common.util.StringUtil;
@@ -21,6 +24,8 @@ public class AppConfig {
 
     private String copyright;
 
+    private String company = "四川星河同步科技有限公司";
+
     public String getName() {
         return name;
     }
@@ -53,4 +58,11 @@ public class AppConfig {
         this.copyright = copyright;
     }
 
+    public String getCompany() {
+        return company;
+    }
+
+    public void setCompany(String company) {
+        this.company = company;
+    }
 }

+ 1 - 1
dbsyncer-connector/dbsyncer-connector-base/src/test/java/ConnectionTest.java

@@ -235,7 +235,7 @@ public class ConnectionTest {
 
         long begin = Instant.now().toEpochMilli();
         final int threadSize = 1000;
-        final int num = 100;
+        final int num = 300;
         final ExecutorService pool = Executors.newFixedThreadPool(threadSize);
         final CountDownLatch latch = new CountDownLatch(threadSize);
         final String insert = "INSERT INTO `vote_records_test` (`id`, `user_id`, `vote_num`, `group_id`, `status`, `create_time`) VALUES (?, ?, ?, ?, ?, ?)";

+ 2 - 8
dbsyncer-connector/dbsyncer-connector-postgresql/src/main/resources/public/connector/addDqlPostgreSQL.html

@@ -35,7 +35,7 @@
         <label class="col-sm-2 control-label">删除Slot<i aria-hidden="true" class="fa fa-question-circle fa_gray"
                                                         title="增量同步,停止驱动自动删除Slot"></i></label>
         <div class="col-sm-4">
-            <input id="dropSlotOnCloseSwitch" name="dropSlotOnClose"
+            <input class="dbsyncer_switch" name="dropSlotOnClose"
                    th:checked="${#maps.isEmpty(connector?.config?.properties) or connector?.config?.properties?.dropSlotOnClose eq 'true'}"
                    type="checkbox">
         </div>
@@ -67,13 +67,7 @@
 
     <script type="text/javascript">
         $(function () {
-            $('#dropSlotOnCloseSwitch').bootstrapSwitch({
-                onText: "Yes",
-                offText: "No",
-                onColor: "success",
-                offColor: "info",
-                size: "normal"
-            });
+            initSwitch();
             // 初始化select插件
             initSelectIndex($(".select-control"), 1);
         })

+ 2 - 8
dbsyncer-connector/dbsyncer-connector-postgresql/src/main/resources/public/connector/addPostgreSQL.html

@@ -35,7 +35,7 @@
     <div class="form-group">
         <label class="col-sm-2 control-label">删除Slot<i aria-hidden="true" class="fa fa-question-circle fa_gray" title="增量同步,停止驱动自动删除Slot"></i></label>
         <div class="col-sm-4">
-            <input id="dropSlotOnCloseSwitch" name="dropSlotOnClose"
+            <input class="dbsyncer_switch" name="dropSlotOnClose"
                    th:checked="${#maps.isEmpty(connector?.config?.properties) or connector?.config?.properties?.dropSlotOnClose eq 'true'}"
                    type="checkbox">
         </div>
@@ -56,13 +56,7 @@
 
     <script type="text/javascript">
         $(function () {
-            $('#dropSlotOnCloseSwitch').bootstrapSwitch({
-                onText: "Yes",
-                offText: "No",
-                onColor: "success",
-                offColor: "info",
-                size: "normal"
-            });
+            initSwitch();
             // 初始化select插件
             initSelectIndex($(".select-control"), 1);
         })

+ 6 - 0
dbsyncer-parser/pom.xml

@@ -30,6 +30,12 @@
             <artifactId>jsqlparser</artifactId>
         </dependency>
 
+        <dependency>
+            <groupId>com.scxhtb</groupId>
+            <artifactId>dbsyncer-parser-plus</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
         <!-- antlr4-runtime -->
         <dependency>
             <groupId>org.antlr</groupId>

+ 1 - 1
dbsyncer-parser/src/main/java/org/dbsyncer/parser/flush/impl/GeneralBufferActuator.java

@@ -146,7 +146,7 @@ public class GeneralBufferActuator extends AbstractBufferActuator<WriterRequest,
         // 4、插件转换
         final ConnectorInstance sConnectorInstance = connectorFactory.connect(getConnectorConfig(mapping.getSourceConnectorId()));
         final ConnectorInstance tConnectorInstance = connectorFactory.connect(getConnectorConfig(mapping.getTargetConnectorId()));
-        final IncrementPluginContext context = new IncrementPluginContext(sConnectorInstance, tConnectorInstance, sourceTableName, targetTableName, event, sourceDataList, targetDataList, mapping.getPluginExtInfo());
+        final IncrementPluginContext context = new IncrementPluginContext(sConnectorInstance, tConnectorInstance, sourceTableName, targetTableName, event, sourceDataList, targetDataList, group.getPluginExtInfo());
         pluginFactory.convert(group.getPlugin(), context);
 
         // 5、批量执行同步

+ 1 - 5
dbsyncer-parser/src/main/java/org/dbsyncer/parser/impl/LogServiceImpl.java

@@ -7,7 +7,6 @@ import org.dbsyncer.common.util.StringUtil;
 import org.dbsyncer.parser.LogService;
 import org.dbsyncer.parser.LogType;
 import org.dbsyncer.parser.ProfileComponent;
-import org.dbsyncer.parser.model.SystemConfig;
 import org.dbsyncer.sdk.constant.ConfigConstant;
 import org.dbsyncer.sdk.enums.StorageEnum;
 import org.dbsyncer.sdk.storage.StorageService;
@@ -60,13 +59,10 @@ public class LogServiceImpl implements LogService {
             Map<String, Object> params = new HashMap();
             params.put(ConfigConstant.CONFIG_MODEL_ID, String.valueOf(snowflakeIdWorker.nextId()));
             params.put(ConfigConstant.CONFIG_MODEL_TYPE, type);
-            params.put(ConfigConstant.CONFIG_MODEL_JSON, StringUtil.substring(error, 0, getSystemConfig().getMaxStorageErrorLength()));
+            params.put(ConfigConstant.CONFIG_MODEL_JSON, StringUtil.substring(error, 0, profileComponent.getSystemConfig().getMaxStorageErrorLength()));
             params.put(ConfigConstant.CONFIG_MODEL_CREATE_TIME, Instant.now().toEpochMilli());
             storageService.add(StorageEnum.LOG, params);
         });
     }
 
-    private SystemConfig getSystemConfig() {
-        return profileComponent.getSystemConfig();
-    }
 }

+ 1 - 1
dbsyncer-parser/src/main/java/org/dbsyncer/parser/impl/ParserComponentImpl.java

@@ -147,7 +147,7 @@ public class ParserComponentImpl implements ParserComponent {
         final ConnectorInstance sConnectorInstance = connectorFactory.connect(sConfig);
         final ConnectorInstance tConnectorInstance = connectorFactory.connect(tConfig);
         final String event = ConnectorConstant.OPERTION_INSERT;
-        final FullPluginContext context = new FullPluginContext(sConnectorInstance, tConnectorInstance, sTableName, tTableName, event, mapping.getPluginExtInfo());
+        final FullPluginContext context = new FullPluginContext(sConnectorInstance, tConnectorInstance, sTableName, tTableName, event, group.getPluginExtInfo());
 
         for (; ; ) {
             if (!task.isRunning()) {

+ 11 - 0
dbsyncer-parser/src/main/java/org/dbsyncer/parser/model/AbstractConfigModel.java

@@ -25,6 +25,9 @@ public abstract class AbstractConfigModel extends ConfigModel {
     // 插件配置
     private Plugin plugin;
 
+    // 插件参数
+    private String pluginExtInfo;
+
     public Map<String, String> getParams() {
         return params;
     }
@@ -58,4 +61,12 @@ public abstract class AbstractConfigModel extends ConfigModel {
         this.plugin = plugin;
     }
 
+    public String getPluginExtInfo() {
+        return pluginExtInfo;
+    }
+
+    public void setPluginExtInfo(String pluginExtInfo) {
+        this.pluginExtInfo = pluginExtInfo;
+    }
+
 }

+ 0 - 11
dbsyncer-parser/src/main/java/org/dbsyncer/parser/model/Mapping.java

@@ -57,9 +57,6 @@ public class Mapping extends AbstractConfigModel {
     // 覆盖写入
     private boolean forceUpdate = true;
 
-    // 插件参数
-    private String pluginExtInfo;
-
     public String getSourceConnectorId() {
         return sourceConnectorId;
     }
@@ -151,12 +148,4 @@ public class Mapping extends AbstractConfigModel {
     public void setForceUpdate(boolean forceUpdate) {
         this.forceUpdate = forceUpdate;
     }
-
-    public String getPluginExtInfo() {
-        return pluginExtInfo;
-    }
-
-    public void setPluginExtInfo(String pluginExtInfo) {
-        this.pluginExtInfo = pluginExtInfo;
-    }
 }

+ 50 - 24
dbsyncer-parser/src/main/java/org/dbsyncer/parser/model/SystemConfig.java

@@ -35,9 +35,19 @@ public class SystemConfig extends ConfigModel {
     private int refreshIntervalSeconds = 5;
 
     /**
-     * 是否启用CDN加速访问静态资源(false-关闭; true-开启)
+     * 是否记录同步成功数据(false-关闭; true-开启)
      */
-    private boolean enableCDN;
+    private boolean enableStorageWriteSuccess;
+
+    /**
+     * 是否记录同步失败数据(false-关闭; true-开启)
+     */
+    private boolean enableStorageWriteFail = true;
+
+    /**
+     * 记录同步失败日志最大长度
+     */
+    private int maxStorageErrorLength = 2048;
 
     /**
      * 是否记录全量数据(false-关闭; true-开启)
@@ -45,19 +55,19 @@ public class SystemConfig extends ConfigModel {
     private boolean enableStorageWriteFull;
 
     /**
-     * 是否记录同步成功数据(false-关闭; true-开启)
+     * 是否启用CDN加速访问静态资源(false-关闭; true-开启)
      */
-    private boolean enableStorageWriteSuccess;
+    private boolean enableCDN;
 
     /**
-     * 是否记录同步失败数据(false-关闭; true-开启)
+     * 是否启用水印
      */
-    private boolean enableStorageWriteFail = true;
+    private boolean enableWatermark;
 
     /**
-     * 记录同步失败日志最大长度
+     * 水印内容
      */
-    private int maxStorageErrorLength = 2048;
+    private String watermark;
 
     public int getExpireDataDays() {
         return expireDataDays;
@@ -83,22 +93,6 @@ public class SystemConfig extends ConfigModel {
         this.refreshIntervalSeconds = refreshIntervalSeconds;
     }
 
-    public boolean isEnableCDN() {
-        return enableCDN;
-    }
-
-    public void setEnableCDN(boolean enableCDN) {
-        this.enableCDN = enableCDN;
-    }
-
-    public boolean isEnableStorageWriteFull() {
-        return enableStorageWriteFull;
-    }
-
-    public void setEnableStorageWriteFull(boolean enableStorageWriteFull) {
-        this.enableStorageWriteFull = enableStorageWriteFull;
-    }
-
     public boolean isEnableStorageWriteSuccess() {
         return enableStorageWriteSuccess;
     }
@@ -122,4 +116,36 @@ public class SystemConfig extends ConfigModel {
     public void setMaxStorageErrorLength(int maxStorageErrorLength) {
         this.maxStorageErrorLength = maxStorageErrorLength;
     }
+
+    public boolean isEnableStorageWriteFull() {
+        return enableStorageWriteFull;
+    }
+
+    public void setEnableStorageWriteFull(boolean enableStorageWriteFull) {
+        this.enableStorageWriteFull = enableStorageWriteFull;
+    }
+
+    public boolean isEnableCDN() {
+        return enableCDN;
+    }
+
+    public void setEnableCDN(boolean enableCDN) {
+        this.enableCDN = enableCDN;
+    }
+
+    public boolean isEnableWatermark() {
+        return enableWatermark;
+    }
+
+    public void setEnableWatermark(boolean enableWatermark) {
+        this.enableWatermark = enableWatermark;
+    }
+
+    public String getWatermark() {
+        return watermark;
+    }
+
+    public void setWatermark(String watermark) {
+        this.watermark = watermark;
+    }
 }

+ 5 - 8
dbsyncer-parser/src/main/java/org/dbsyncer/parser/strategy/impl/FlushStrategyImpl.java

@@ -58,7 +58,7 @@ public final class FlushStrategyImpl implements FlushStrategy {
     @Override
     public void flushFullData(String metaId, Result result, String event) {
         // 不记录全量数据, 只记录增量同步数据, 将异常记录到系统日志中
-        if (!getSystemConfig().isEnableStorageWriteFull()) {
+        if (!profileComponent.getSystemConfig().isEnableStorageWriteFull()) {
             // 不记录全量数据,只统计成功失败总数
             refreshTotal(metaId, result);
 
@@ -112,20 +112,17 @@ public final class FlushStrategyImpl implements FlushStrategy {
     private void flush(String metaId, Result result, String event) {
         refreshTotal(metaId, result);
 
+        SystemConfig systemConfig = profileComponent.getSystemConfig();
         // 是否写失败数据
-        if (getSystemConfig().isEnableStorageWriteFail() && !CollectionUtils.isEmpty(result.getFailData())) {
-            final String error = StringUtil.substring(result.getError().toString(), 0, getSystemConfig().getMaxStorageErrorLength());
+        if (systemConfig.isEnableStorageWriteFail() && !CollectionUtils.isEmpty(result.getFailData())) {
+            final String error = StringUtil.substring(result.getError().toString(), 0, systemConfig.getMaxStorageErrorLength());
             asyncWrite(metaId, result.getTableGroupId(), result.getTargetTableGroupName(), event, false, result.getFailData(), error);
         }
 
         // 是否写成功数据
-        if (getSystemConfig().isEnableStorageWriteSuccess() && !CollectionUtils.isEmpty(result.getSuccessData())) {
+        if (systemConfig.isEnableStorageWriteSuccess() && !CollectionUtils.isEmpty(result.getSuccessData())) {
             asyncWrite(metaId, result.getTableGroupId(), result.getTargetTableGroupName(), event, true, result.getSuccessData(), "");
         }
     }
 
-    private SystemConfig getSystemConfig() {
-        return profileComponent.getSystemConfig();
-    }
-
 }

+ 2 - 0
dbsyncer-parser/src/main/java/org/dbsyncer/parser/util/PickerUtil.java

@@ -34,6 +34,8 @@ public abstract class PickerUtil {
         group.setConvert(CollectionUtils.isEmpty(tableGroup.getConvert()) ? mapping.getConvert() : tableGroup.getConvert());
         // 插件配置(默认使用全局)
         group.setPlugin(null == tableGroup.getPlugin() ? mapping.getPlugin() : tableGroup.getPlugin());
+        // 插件参数(默认使用全局)
+        group.setPluginExtInfo(StringUtil.isNotBlank(tableGroup.getPluginExtInfo()) ? mapping.getPluginExtInfo() : tableGroup.getPluginExtInfo());
 
         // 合并增量配置/过滤条件/转换配置字段
         appendFieldMapping(mapping, group);

+ 2 - 2
dbsyncer-web/src/main/java/org/dbsyncer/web/controller/DefaultController.java

@@ -21,13 +21,13 @@ public class DefaultController implements ErrorPageRegistrar {
 
     @RequestMapping("")
     public String index(HttpServletRequest request, ModelMap model) {
-        model.put("enableCDN", systemConfigService.isEnableCDN());
+        model.put("enableCDN", systemConfigService.getSystemConfig().isEnableCDN());
         return "index.html";
     }
 
     @RequestMapping({"/login", "/login.html"})
     public String index(ModelMap model) {
-        model.put("enableCDN", systemConfigService.isEnableCDN());
+        model.put("enableCDN", systemConfigService.getSystemConfig().isEnableCDN());
         return "login.html";
     }
 

+ 3 - 4
dbsyncer-web/src/main/java/org/dbsyncer/web/controller/index/IndexController.java

@@ -3,11 +3,10 @@
  */
 package org.dbsyncer.web.controller.index;
 
+import org.dbsyncer.biz.AppConfigService;
 import org.dbsyncer.biz.ProjectGroupService;
 import org.dbsyncer.biz.vo.ProjectGroupVo;
 import org.dbsyncer.biz.vo.RestResult;
-import org.dbsyncer.biz.vo.VersionVo;
-import org.dbsyncer.common.config.AppConfig;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Controller;
@@ -28,7 +27,7 @@ public class IndexController {
     private ProjectGroupService projectGroupService;
 
     @Resource
-    private AppConfig appConfig;
+    private AppConfigService appConfigService;
 
     @GetMapping("")
     public String index(ModelMap model, String projectGroupId) {
@@ -48,6 +47,6 @@ public class IndexController {
     @GetMapping("/version.json")
     @ResponseBody
     public RestResult version() {
-        return RestResult.restSuccess(new VersionVo(appConfig.getName(), appConfig.getCopyright()));
+        return RestResult.restSuccess(appConfigService.getVersionInfo());
     }
 }

+ 6 - 8
dbsyncer-web/src/main/java/org/dbsyncer/web/controller/monitor/MonitorController.java

@@ -4,17 +4,16 @@ import org.dbsyncer.biz.ConnectorService;
 import org.dbsyncer.biz.DataSyncService;
 import org.dbsyncer.biz.MonitorService;
 import org.dbsyncer.biz.SystemConfigService;
-import org.dbsyncer.biz.vo.AppReportMetricVo;
-import org.dbsyncer.biz.vo.HistoryStackVo;
-import org.dbsyncer.biz.vo.RestResult;
-import org.dbsyncer.biz.vo.SystemConfigVo;
-import org.dbsyncer.common.util.CollectionUtils;
-import org.dbsyncer.common.util.DateFormatUtil;
 import org.dbsyncer.biz.enums.DiskMetricEnum;
 import org.dbsyncer.biz.enums.MetricEnum;
 import org.dbsyncer.biz.enums.StatisticEnum;
 import org.dbsyncer.biz.model.MetricResponse;
 import org.dbsyncer.biz.model.Sample;
+import org.dbsyncer.biz.vo.AppReportMetricVo;
+import org.dbsyncer.biz.vo.HistoryStackVo;
+import org.dbsyncer.biz.vo.RestResult;
+import org.dbsyncer.common.util.CollectionUtils;
+import org.dbsyncer.common.util.DateFormatUtil;
 import org.dbsyncer.manager.impl.PreloadTemplate;
 import org.dbsyncer.web.controller.BaseController;
 import org.slf4j.Logger;
@@ -196,8 +195,7 @@ public class MonitorController extends BaseController {
     @GetMapping("/getRefreshIntervalSeconds")
     public RestResult getRefreshInterval() {
         try {
-            SystemConfigVo config = systemConfigService.getSystemConfigVo();
-            return RestResult.restSuccess(config.getRefreshIntervalSeconds());
+            return RestResult.restSuccess(systemConfigService.getSystemConfig().getRefreshIntervalSeconds());
         } catch (Exception e) {
             logger.error(e.getLocalizedMessage(), e.getClass());
             return RestResult.restFail(e.getMessage());

+ 3 - 12
dbsyncer-web/src/main/java/org/dbsyncer/web/controller/system/SystemController.java

@@ -1,3 +1,6 @@
+/**
+ * DBSyncer Copyright 2020-2024 All Rights Reserved.
+ */
 package org.dbsyncer.web.controller.system;
 
 import org.dbsyncer.biz.SystemConfigService;
@@ -7,7 +10,6 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Controller;
 import org.springframework.ui.ModelMap;
-import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.ResponseBody;
@@ -43,15 +45,4 @@ public class SystemController extends BaseController {
         }
     }
 
-    @GetMapping("/queryConfig")
-    @ResponseBody
-    public RestResult queryConfig() {
-        try {
-            return RestResult.restSuccess(systemConfigService.getSystemConfigVo());
-        } catch (Exception e) {
-            logger.error(e.getLocalizedMessage(), e.getClass());
-            return RestResult.restFail(e.getMessage());
-        }
-    }
-
 }

+ 2 - 2
dbsyncer-web/src/main/resources/application.properties

@@ -50,8 +50,8 @@ dbsyncer.parser.table.group.buffer-period-millisecond=300
 #storage
 # 数据存储类型:disk(默认)/mysql(推荐生产环境使用)
 # disk-磁盘:/data/config(驱动配置)|data(按驱动分别存储增量数据)|log(系统日志)
-dbsyncer.storage.type=disk
-dbsyncer.storage.mysql.url=jdbc:mysql://127.0.0.1:3306/dbsyncer?rewriteBatchedStatements=true&seUnicode=true&characterEncoding=UTF8&serverTimezone=Asia/Shanghai&useSSL=false&verifyServerCertificate=false&autoReconnect=true
+dbsyncer.storage.type=mysql
+dbsyncer.storage.mysql.url=jdbc:mysql://127.0.0.1:3305/dbsyncer?rewriteBatchedStatements=true&seUnicode=true&characterEncoding=UTF8&serverTimezone=Asia/Shanghai&useSSL=false&verifyServerCertificate=false&autoReconnect=true
 dbsyncer.storage.mysql.username=root
 dbsyncer.storage.mysql.password=123
 # [StorageBufferActuator]线程数

+ 1 - 1
dbsyncer-web/src/main/resources/public/mapping/add.html

@@ -61,7 +61,7 @@
                             <div class="form-group">
                                 <div class="col-sm-2 text-right"><label>匹配相似表</label></div>
                                 <div class="col-sm-10">
-                                    <input id="autoMatchTableSwitch" name="autoMatchTable" type="checkbox">
+                                    <input class="dbsyncer_switch" name="autoMatchTable" type="checkbox">
                                 </div>
                             </div>
 

+ 2 - 1
dbsyncer-web/src/main/resources/public/mapping/edit.html

@@ -106,7 +106,7 @@
                                 <u data-toggle="collapse" class="dbsyncer_pointer" href="#mappingSuperConfig" title="该配置使所有映射关系都生效">高级配置</u>
                             </h4>
                         </div>
-                        <div id="mappingSuperConfig" class="panel-body panel-collapse collapse">
+                        <div id="mappingSuperConfig" class="panel-body panel-collapse collapse in">
                             <!-- 全量配置 -->
                             <div th:id="mappingFullConfig" class="hidden" th:fragment="content">
                                 <div th:replace="mapping/editFull :: content"></div>
@@ -141,4 +141,5 @@
 <script th:src="@{/js/mapping/edit.js}"></script>
 <script th:src="@{/js/mapping/editFilterAndConvert.js}"></script>
 <script th:src="@{/js/mapping/editIncrement.js}"></script>
+<script th:src="@{/js/mapping/editPlugin.js}"></script>
 </html>

+ 4 - 4
dbsyncer-web/src/main/resources/public/mapping/editIncrement.html

@@ -50,19 +50,19 @@
     <div class="form-group">
         <div class="row">
             <div class="col-md-4">
-                <label class="col-sm-3 control-label text-right">新增*</label>
+                <label class="col-sm-3 control-label text-right">新增</label>
                 <div class="col-sm-9">
                     <input name="enableInsert" class="dbsyncer_switch" th:checked="${mapping?.listener?.enableInsert}" type="checkbox">
                 </div>
             </div>
             <div class="col-md-4">
-                <label class="col-sm-3 control-label text-right">修改*</label>
+                <label class="col-sm-3 control-label text-right">修改</label>
                 <div class="col-sm-9">
                     <input name="enableUpdate" class="dbsyncer_switch" th:checked="${mapping?.listener?.enableUpdate}" type="checkbox">
                 </div>
             </div>
             <div class="col-md-4">
-                <label class="col-sm-3 control-label text-right">删除*</label>
+                <label class="col-sm-3 control-label text-right">删除</label>
                 <div class="col-sm-9">
                     <input name="enableDelete" class="dbsyncer_switch" th:checked="${mapping?.listener?.enableDelete}" type="checkbox">
                 </div>
@@ -72,7 +72,7 @@
     <div class="form-group">
         <div class="row">
             <div class="col-md-4">
-                <label class="col-sm-3 control-label text-right">ddl*</label>
+                <label class="col-sm-3 control-label text-right">ddl</label>
                 <div class="col-sm-9">
                     <input name="enableDDL" class="dbsyncer_switch" th:checked="${mapping?.listener?.enableDDL}" type="checkbox">
                 </div>

+ 7 - 7
dbsyncer-web/src/main/resources/public/mapping/editIncrementQuartz.html

@@ -6,21 +6,21 @@
     <div class="form-group">
         <div class="row">
             <div class="col-md-4">
-                <label class="col-sm-3 control-label text-right">Insert*</label>
+                <label class="col-sm-3 control-label text-right">Insert</label>
                 <div class="col-sm-9">
-                    <input name="timingInsert" type="text" class="form-control" data-role="tagsinput" dbsyncer-valid="require" th:value="${mapping?.listener?.insert}?:'I'" />
+                    <input name="timingInsert" type="text" class="form-control" data-role="tagsinput" th:value="${mapping?.listener?.insert}?:'I'" />
                 </div>
             </div>
             <div class="col-md-4">
-                <label class="col-sm-3 control-label text-right">Update*</label>
+                <label class="col-sm-3 control-label text-right">Update</label>
                 <div class="col-sm-9">
-                    <input name="timingUpdate" type="text" class="form-control" data-role="tagsinput" dbsyncer-valid="require" th:value="${mapping?.listener?.update}?:'U'"/>
+                    <input name="timingUpdate" type="text" class="form-control" data-role="tagsinput" th:value="${mapping?.listener?.update}?:'U'"/>
                 </div>
             </div>
             <div class="col-md-4">
-                <label class="col-sm-3 control-label text-right">Delete*</label>
+                <label class="col-sm-3 control-label text-right">Delete</label>
                 <div class="col-sm-9">
-                    <input name="timingDelete" type="text" class="form-control" data-role="tagsinput" dbsyncer-valid="require" th:value="${mapping?.listener?.delete?:'D'}"/>
+                    <input name="timingDelete" type="text" class="form-control" data-role="tagsinput" th:value="${mapping?.listener?.delete?:'D'}"/>
                 </div>
             </div>
         </div>
@@ -29,7 +29,7 @@
     <div class="form-group">
         <div class="row">
             <div class="col-md-4">
-                <label class="col-sm-3 control-label text-right">Cron*</label>
+                <label class="col-sm-3 control-label text-right">Cron<strong class="text-primary">*</strong></label>
                 <div class="col-sm-9">
                     <input class="form-control" dbsyncer-valid="require" name="timingCronExpression"
                            th:value="${mapping?.listener?.cron}?:'*/30 * * * * ?'" type="text"/>

+ 3 - 2
dbsyncer-web/src/main/resources/public/mapping/editParameter.html

@@ -3,9 +3,10 @@
       xmlns:th="http://www.thymeleaf.org" lang="zh-CN">
 
 <div th:fragment="content">
-    <p class="text-muted">策略配置</p>
 
-    <div class="form-group">
+    <p th:if="${tableGroup} == null" class="text-muted">策略配置</p>
+
+    <div th:if="${tableGroup} == null" class="form-group">
         <div class="row">
             <div class="col-md-4">
                 <label class="col-sm-3 control-label text-right">覆盖<i class="fa fa-question-circle fa_gray" aria-hidden="true" title="Yes-目标表不存在数据时, 执行insert,存在会执行update; No-不生效"></i></label>

+ 3 - 3
dbsyncer-web/src/main/resources/public/mapping/editPlugin.html

@@ -8,7 +8,7 @@
     <div class="form-group">
         <div class="row">
             <div class="col-md-4">
-                <label class="col-sm-3 control-label text-right">插件名称</label>
+                <label class="col-sm-3 control-label text-right">插件</label>
                 <div class="col-sm-9">
                     <select id="pluginId" name="pluginId" class="form-control select-control-default">
                         <option value="" selected="selected">无</option>
@@ -17,9 +17,9 @@
                 </div>
             </div>
             <div id="pluginExtInfo" class="col-md-4 hidden">
-                <label class="col-sm-3 control-label">插件参数<i class="fa fa-question-circle fa_gray" aria-hidden="true" title="用于插件内部使用,推荐填写JSON格式"></i></label>
+                <label class="col-sm-3 control-label">参数<i class="fa fa-question-circle fa_gray" aria-hidden="true" title="用于插件内部使用,推荐填写JSON格式"></i></label>
                 <div class="col-sm-9">
-                    <textarea name="pluginExtInfo" class="form-control dbsyncer_textarea_resize_none" maxlength="512" rows="2" th:text="${mapping?.pluginExtInfo}"></textarea>
+                    <input name="pluginExtInfo" class="form-control dbsyncer_textarea_resize_none" maxlength="512" rows="2" th:value="${tableGroup eq null ? mapping?.pluginExtInfo : tableGroup?.pluginExtInfo}" />
                 </div>
             </div>
             <div class="col-md-8"></div>

+ 2 - 2
dbsyncer-web/src/main/resources/public/mapping/editTableGroup.html

@@ -165,7 +165,7 @@
                                 <u data-toggle="collapse" class="dbsyncer_pointer" href="#tableGroupSuperConfig" title="该配置只对当前映射关系生效, 上一级的高级配置将失效">高级配置</u>
                             </h4>
                         </div>
-                        <div id="tableGroupSuperConfig" class="panel-body panel-collapse collapse">
+                        <div id="tableGroupSuperConfig" class="panel-body panel-collapse collapse in">
                             <!-- 参数配置 -->
                             <div th:replace="mapping/editParameter :: content"></div>
 
@@ -187,6 +187,6 @@
 </div>
 
 <script th:src="@{/js/mapping/editTableGroup.js}"></script>
-<script th:src="@{/js/mapping/editParam.js}"></script>
+<script th:src="@{/js/mapping/editPlugin.js}"></script>
 <script th:src="@{/js/mapping/editFilterAndConvert.js}"></script>
 </html>

+ 50 - 49
dbsyncer-web/src/main/resources/public/system/system.html

@@ -13,66 +13,67 @@
         <!-- 操作 -->
         <div class="row">
             <!-- 系统参数配置 -->
-            <div class="col-md-3"></div>
-            <div class="col-md-6">
-                <div class="form-group">
-                    <label class="col-sm-4 control-label">同步数据过期时间(天)<strong class="text-primary">*</strong></label>
-                    <div class="col-sm-8">
-                        <input type="number" class="form-control" min="1" max="180" dbsyncer-valid="require" name="expireDataDays" th:value="${config?.expireDataDays}"/>
-                    </div>
+            <div class="form-group">
+                <div class="text-right col-sm-4"></div>
+                <div class="text-right col-sm-8">
+                    <button id="updateSystemSubBtn" type="button" class="btn btn-primary">
+                        <span class="fa fa-save"></span>保存
+                    </button>
                 </div>
-                <div class="form-group">
-                    <label class="col-sm-4 control-label">系统日志过期时间(天)<strong class="text-primary">*</strong></label>
-                    <div class="col-sm-8">
-                        <input type="number" class="form-control" min="1" max="180" dbsyncer-valid="require" name="expireLogDays" th:value="${config?.expireLogDays}"/>
-                    </div>
+            </div>
+
+            <div class="form-group">
+                <label class="col-sm-2 control-label">同步数据过期时间(天)<strong class="text-primary">*</strong></label>
+                <div class="col-sm-4">
+                    <input type="number" class="form-control" min="1" max="180" dbsyncer-valid="require" name="expireDataDays" th:value="${config?.expireDataDays}"/>
                 </div>
-                <div class="form-group">
-                    <label class="col-sm-4 control-label">刷新监控频率(秒)<strong class="text-primary">*</strong></label>
-                    <div class="col-sm-8">
-                        <input type="number" class="form-control" min="1" max="60" dbsyncer-valid="require" name="refreshIntervalSeconds" th:value="${config?.refreshIntervalSeconds}"/>
-                    </div>
+                <label class="col-sm-2 control-label">系统日志过期时间(天)<strong class="text-primary">*</strong></label>
+                <div class="col-sm-4">
+                    <input type="number" class="form-control" min="1" max="180" dbsyncer-valid="require" name="expireLogDays" th:value="${config?.expireLogDays}"/>
                 </div>
-                <div class="form-group">
-                    <label class="col-sm-4 control-label">记录同步成功数据</label>
-                    <div class="col-sm-8">
-                        <input class="systemConfigSwitch" name="enableStorageWriteSuccess" th:checked="${config?.enableStorageWriteSuccess}" type="checkbox" />
-                    </div>
+            </div>
+            <div class="form-group">
+                <label class="col-sm-2 control-label">记录同步成功数据</label>
+                <div class="col-sm-4">
+                    <input class="dbsyncer_switch" name="enableStorageWriteSuccess" th:checked="${config?.enableStorageWriteSuccess}" type="checkbox" />
                 </div>
-                <div class="form-group">
-                    <label class="col-sm-4 control-label">记录同步失败数据</label>
-                    <div class="col-sm-8">
-                        <input class="systemConfigSwitch" name="enableStorageWriteFail" th:checked="${config?.enableStorageWriteFail}" type="checkbox" />
-                    </div>
+                <label class="col-sm-2 control-label">记录同步失败数据</label>
+                <div class="col-sm-4">
+                    <input class="dbsyncer_switch" name="enableStorageWriteFail" th:checked="${config?.enableStorageWriteFail}" type="checkbox" />
                 </div>
-                <div class="form-group">
-                    <label class="col-sm-4 control-label">记录同步失败日志长度<strong class="text-primary">*</strong></label>
-                    <div class="col-sm-8">
-                        <input type="number" class="form-control" min="1024" max="8192" dbsyncer-valid="require" name="maxStorageErrorLength" th:value="${config?.maxStorageErrorLength}"/>
-                    </div>
+            </div>
+            <div class="form-group">
+                <label class="col-sm-2 control-label">刷新监控频率(秒)<strong class="text-primary">*</strong></label>
+                <div class="col-sm-4">
+                    <input type="number" class="form-control" min="1" max="60" dbsyncer-valid="require" name="refreshIntervalSeconds" th:value="${config?.refreshIntervalSeconds}"/>
                 </div>
-                <div class="form-group">
-                    <label class="col-sm-4 control-label">记录全量数据<i class="fa fa-question-circle fa_gray" aria-hidden="true" title="不推荐在生产环境下开启,可在源库数据量较少时使用,一般用于测试"></i></label>
-                    <div class="col-sm-8">
-                        <input class="systemConfigSwitch" name="enableStorageWriteFull" th:checked="${config?.enableStorageWriteFull}" type="checkbox" />
-                    </div>
+                <label class="col-sm-2 control-label">记录同步失败日志长度<strong class="text-primary">*</strong></label>
+                <div class="col-sm-4">
+                    <input type="number" class="form-control" min="1024" max="8192" dbsyncer-valid="require" name="maxStorageErrorLength" th:value="${config?.maxStorageErrorLength}"/>
                 </div>
-                <div class="form-group">
-                    <label class="col-sm-4 control-label">CDN静态资源</label>
-                    <div class="col-sm-8">
-                        <input class="systemConfigSwitch" name="enableCDN" th:checked="${config?.enableCDN}" type="checkbox" />
-                    </div>
+            </div>
+            <div class="form-group">
+                <label class="col-sm-2 control-label">记录全量数据<i class="fa fa-question-circle fa_gray" aria-hidden="true" title="不推荐在生产环境下开启,可在源库数据量较少时使用,一般用于测试"></i></label>
+                <div class="col-sm-4">
+                    <input class="dbsyncer_switch" name="enableStorageWriteFull" th:checked="${config?.enableStorageWriteFull}" type="checkbox" />
+                </div>
+                <label class="col-sm-2 control-label">CDN静态资源</label>
+                <div class="col-sm-4">
+                    <input class="dbsyncer_switch" name="enableCDN" th:checked="${config?.enableCDN}" type="checkbox" />
+                </div>
+            </div>
+            <div class="form-group">
+                <label class="col-sm-2 control-label">水印<i class="fa fa-question-circle fa_gray" aria-hidden="true" title="刷新页面生效"></i></label>
+                <div class="col-sm-4">
+                    <input id="enableWatermark" name="enableWatermark" th:checked="${config?.enableWatermark}" type="checkbox" />
                 </div>
-                <div class="form-group">
-                    <div class="text-right col-sm-4"></div>
-                    <div class="text-right col-sm-8">
-                        <button id="updateSystemSubBtn" type="button" class="btn btn-primary">
-                            <span class="fa fa-save"></span>保存
-                        </button>
+                <div id="watermark" class="hidden">
+                    <label class="col-sm-2 control-label">水印内容</label>
+                    <div class="col-sm-4">
+                        <input type="text" class="form-control" maxlength="64" name="watermark" placeholder="请输入水印(最多64个字)." th:value="${config?.watermark}"/>
                     </div>
                 </div>
             </div>
-            <div class="col-md-3"></div>
         </div>
     </form>
 </div>

+ 1 - 2
dbsyncer-web/src/main/resources/static/css/common.css

@@ -10,8 +10,7 @@
 .driver_hidden_word {white-space: nowrap; overflow: hidden; text-overflow: ellipsis}
 .fa_gray {color: gray}
 .fa_blueviolet {color: blueviolet}
-.dbsyncer_btn-info { background-color: #E7EDF8;}
-.dbsyncer_btn-info.active, .dbsyncer_btn-info.focus, .dbsyncer_btn-info:active, .dbsyncer_btn-info:focus, .dbsyncer_btn-info:hover, .open>.dropdown-toggle.dbsyncer_btn-info {background-color: #D4DDED;}
+.dbsyncer_btn-info {background-color:#F9F9FD; -moz-box-shadow:1px 1px 2px lightblue; -webkit-box-shadow:1px 1px 2px lightblue; box-shadow:1px 1px 2px lightblue;}
 .dbsyncer_textarea_resize_none {resize: none; }
 /* 弹出提示框样式修改 */
 .tooltip.top .tooltip-inner{background-color: #f50505 !important;}

+ 42 - 21
dbsyncer-web/src/main/resources/static/js/common.js

@@ -90,31 +90,52 @@ function initMultipleInputTags() {
     });
 }
 
+// 初始化开关
+function initSwitch() {
+    $('.dbsyncer_switch').bootstrapSwitch({
+        onText: "Yes",
+        offText: "No",
+        onColor: "success",
+        offColor: "info",
+        size: "normal"
+    });
+}
+
 // ******************* 水印 ***************************
 window.onresize = function() {
     watermark();
 }
-
+window.onscroll = function() {
+    watermark();
+}
+//水印样式默认设置
+const settings={
+    watermark_txt:"",
+    watermark_x:50,//水印起始位置x轴坐标
+    watermark_y:55,//水印起始位置Y轴坐标
+    watermark_rows:2000,//水印行数
+    watermark_cols:2000,//水印列数
+    watermark_x_space:70,//水印x轴间隔
+    watermark_y_space:30,//水印y轴间隔
+    watermark_color:'#aaaaaa',//水印字体颜色
+    watermark_alpha:0.2,//水印透明度
+    watermark_fontsize:'15px',//水印字体大小
+    watermark_font:'微软雅黑',//水印字体
+    watermark_width:210,//水印宽度
+    watermark_height:80,//水印长度
+    watermark_angle:15//水印倾斜度数
+};
+let timestampWatermark;
 function watermark() {
-    $(".mask_div").remove();
-
-    //水印样式默认设置
-    const settings={
-        watermark_txt:"DBSyncer",
-        watermark_x:50,//水印起始位置x轴坐标
-        watermark_y:50,//水印起始位置Y轴坐标
-        watermark_rows:2000,//水印行数
-        watermark_cols:2000,//水印列数
-        watermark_x_space:70,//水印x轴间隔
-        watermark_y_space:30,//水印y轴间隔
-        watermark_color:'#aaaaaa',//水印字体颜色
-        watermark_alpha:0.25,//水印透明度
-        watermark_fontsize:'15px',//水印字体大小
-        watermark_font:'微软雅黑',//水印字体
-        watermark_width:210,//水印宽度
-        watermark_height:80,//水印长度
-        watermark_angle:15//水印倾斜度数
-    };
+    const now = Date.now();
+    if (timestampWatermark != null && now - timestampWatermark < 200) {
+        return;
+    }
+    if(isBlank(settings.watermark_txt)){
+        return;
+    }
+    timestampWatermark = now;
+    $(".dbsyncer_mask").remove();
 
     const water = document.body;
     //获取页面最大宽度
@@ -131,7 +152,7 @@ function watermark() {
         for (let j = 0; j < settings.watermark_cols; j++) {
             x = settings.watermark_x + (settings.watermark_width + settings.watermark_x_space) * j;
             let mask_div = document.createElement('div');
-            mask_div.className = 'mask_div';
+            mask_div.className = 'dbsyncer_mask';
             mask_div.innerHTML=(settings.watermark_txt);
             mask_div.style.webkitTransform = "rotate(-" + settings.watermark_angle + "deg)";
             mask_div.style.MozTransform = "rotate(-" + settings.watermark_angle + "deg)";

+ 2 - 0
dbsyncer-web/src/main/resources/static/js/index.js

@@ -9,6 +9,8 @@ $(function () {
         if (data.success == true) {
             // 获取底部版权信息
             $("#appCopyRight").html(data.resultValue.appCopyRight);
+            settings.watermark_txt = data.resultValue.watermark;
+            watermark();
         }
     });
 

+ 1 - 12
dbsyncer-web/src/main/resources/static/js/mapping/add.js

@@ -9,17 +9,6 @@ function submit(data) {
     });
 }
 
-// 绑定匹配相似表复选框事件
-function bindAutoMatchTableCheckBoxClick(){
-    $('#autoMatchTableSwitch').bootstrapSwitch({
-        onText: "Yes",
-        offText: "No",
-        onColor: "success",
-        offColor: "info",
-        size: "normal"
-    });
-}
-
 $(function () {
     // 兼容IE PlaceHolder
     $('input[type="text"],input[type="password"],textarea').PlaceHolder();
@@ -28,7 +17,7 @@ $(function () {
     initSelectIndex($(".select-control"), 1);
 
     // 绑定匹配相似表复选框事件
-    bindAutoMatchTableCheckBoxClick();
+    initSwitch();
 
     //保存
     $("#mappingSubmitBtn").click(function () {

+ 0 - 18
dbsyncer-web/src/main/resources/static/js/mapping/edit.js

@@ -217,22 +217,6 @@ function bindRefreshTablesClick() {
     });
 }
 
-// 绑定插件下拉选择事件
-function bindPluginSelect() {
-    const $pluginExtInfo = $("#pluginExtInfo");
-    const $pluginId = $("#pluginId");
-    $pluginId.on('changed.bs.select',function(e){
-        if(isBlank($(this).selectpicker('val'))){
-            $pluginExtInfo.addClass("hidden");
-        }else{
-            $pluginExtInfo.removeClass("hidden");
-        }
-    });
-    if(!isBlank($pluginId.selectpicker('val'))){
-        $pluginExtInfo.removeClass("hidden");
-    }
-}
-
 $(function () {
     // 绑定同步方式切换事件
     bindMappingModelChange();
@@ -249,8 +233,6 @@ $(function () {
     bindMappingTableGroupDelClick();
     //绑定刷新数据表按钮点击事件
     bindRefreshTablesClick();
-    // 绑定插件下拉选择事件
-    bindPluginSelect();
 
     // 初始化select插件
     initSelectIndex($(".select-control-table"), -1);

+ 2 - 13
dbsyncer-web/src/main/resources/static/js/mapping/editIncrement.js

@@ -49,17 +49,6 @@ function bindMappingMetaSnapshotModifyClick(){
     })
 }
 
-// 绑定监听配置事件开关切换事件
-function bindMappingListenerConfigSwitchClick(){
-    $('.dbsyncer_switch').bootstrapSwitch({
-        onText: "Yes",
-        offText: "No",
-        onColor: "success",
-        offColor: "info",
-        size: "normal"
-    });
-}
-
 // 生成增量点配置参数
 function createMetaSnapshotParams(){
     var snapshot = {};
@@ -74,8 +63,8 @@ function createMetaSnapshotParams(){
 $(function() {
     // 绑定增量策略切换事件
     bindMappingIncrementStrategyConfigChange();
-    // 绑定监听配置事件开关切换事件
-    bindMappingListenerConfigSwitchClick();
+    // 绑定开关切换事件
+    initSwitch();
     // 绑定增量点配置修改事件
     bindMappingMetaSnapshotModifyClick();
 });

+ 15 - 0
dbsyncer-web/src/main/resources/static/js/mapping/editPlugin.js

@@ -0,0 +1,15 @@
+$(function () {
+    const $pluginId = initSelect($("#pluginId"));
+    // 绑定插件下拉选择事件
+    const $pluginExtInfo = $("#pluginExtInfo");
+    $pluginId.on('changed.bs.select',function(e){
+        if(isBlank($(this).selectpicker('val'))){
+            $pluginExtInfo.addClass("hidden");
+        }else{
+            $pluginExtInfo.removeClass("hidden");
+        }
+    });
+    if(!isBlank($pluginId.selectpicker('val'))){
+        $pluginExtInfo.removeClass("hidden");
+    }
+})

+ 22 - 5
dbsyncer-web/src/main/resources/static/js/system/index.js

@@ -9,19 +9,36 @@ function submit(data) {
     });
 }
 
-$(function () {
-    $('.systemConfigSwitch').bootstrapSwitch({
+// 绑定水印开关切换事件
+function bindWatermarkSwitch() {
+    const $watermark = $("#watermark");
+    let $switch = $("#enableWatermark").bootstrapSwitch({
         onText: "Yes",
         offText: "No",
         onColor: "success",
         offColor: "info",
-        size: "normal"
+        size: "normal",
+        onSwitchChange: function (event, state) {
+            if (state) {
+                $watermark.removeClass("hidden");
+            } else {
+                $watermark.addClass("hidden");
+            }
+        }
     });
+    if ($switch.bootstrapSwitch('state')) {
+        $watermark.removeClass("hidden");
+    }
+}
+
+$(function () {
+    initSwitch();
+    bindWatermarkSwitch();
     //保存
     $("#updateSystemSubBtn").click(function () {
-        var $form = $("#configEditForm");
+        const $form = $("#configEditForm");
         if ($form.formValidate() == true) {
-            var data = $form.serializeJson();
+            const data = $form.serializeJson();
             submit(data);
         }
     });