Browse Source

Merge branch 'refs/heads/master' into dev-zenas-20241018

# Conflicts:
#	jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/site/entity/AdwebSite.java
zq940222 5 months ago
parent
commit
58394ca6ac
100 changed files with 7309 additions and 238 deletions
  1. 5 1
      .gitignore
  2. 39 2
      jeecg-module-system/jeecg-system-biz/pom.xml
  3. 42 2
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/common/constant/AdwebConstant.java
  4. 0 158
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/common/constant/CompConstants.java
  5. 93 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/common/constant/RobotMsgTemplate.java
  6. 17 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/common/dto/CountryAreaApiDto.java
  7. 219 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/common/dto/RobotDto.java
  8. 122 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/common/service/FeishuService.java
  9. 679 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/common/util/AdwebRedisUtil.java
  10. 34 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/common/util/CommonUtil.java
  11. 122 9
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/common/util/DateUtil.java
  12. 49 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/common/util/EnglishAnalyzer.java
  13. 150 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/common/util/GeoIpUtil.java
  14. 132 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/common/util/JedisUtil.java
  15. 139 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/common/util/SnowflakeIdUtil.java
  16. 14 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/constant/EnquiryConstants.java
  17. 12 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/constant/EnquirySendStatus.java
  18. 3 3
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/controller/AdwebEnquiryController.java
  19. 20 5
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/dto/EnquiryDTO.java
  20. 26 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/dto/IndependentEnquiryDto.java
  21. 16 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/dto/param/EffectiveEnquiryParamDto.java
  22. 18 9
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/entity/AdwebEnquiry.java
  23. 73 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/entity/AdwebEnquiryBlacklist.java
  24. 46 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/entity/AdwebEnquiryForm.java
  25. 64 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/entity/AdwebPublicBlackEmail.java
  26. 65 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/entity/AdwebPublicBlackIp.java
  27. 72 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/entity/AdwebPublicEnquiryRule.java
  28. 86 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/entity/AdwebSiteBlackEmail.java
  29. 68 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/entity/AdwebSiteBlackIp.java
  30. 67 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/entity/AdwebSiteEnquiryRule.java
  31. 75 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/entity/EnquiryEmailMessage.java
  32. 14 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/mapper/AdwebEnquiryBlacklistMapper.java
  33. 14 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/mapper/AdwebEnquiryFormMapper.java
  34. 16 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/mapper/AdwebPublicBlackEmailMapper.java
  35. 16 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/mapper/AdwebPublicBlackIpMapper.java
  36. 15 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/mapper/AdwebPublicEnquiryRuleMapper.java
  37. 26 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/mapper/AdwebSiteBlackEmailMapper.java
  38. 19 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/mapper/AdwebSiteBlackIpMapper.java
  39. 18 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/mapper/AdwebSiteEnquiryRuleMapper.java
  40. 27 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/mapper/EnquiryEmailMessageMapper.java
  41. 5 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/mapper/xml/AdwebEnquiryFormMapper.xml
  42. 39 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/mapper/xml/AdwebEnquirySiteRuleMapper.xml
  43. 31 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/mapper/xml/AdwebPublicBlackEmailMapper.xml
  44. 32 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/mapper/xml/AdwebPublicBlackIpMapper.xml
  45. 44 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/mapper/xml/AdwebPublicEnquiryRuleMapper.xml
  46. 61 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/mapper/xml/AdwebSiteBlackEmailMapper.xml
  47. 45 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/mapper/xml/AdwebSiteBlackIpMapper.xml
  48. 19 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/mapper/xml/EnquiryEmailMessageMapper.xml
  49. 81 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/service/AdwebOpenApiService.java
  50. 21 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/service/IAdwebEnquiryBlacklistService.java
  51. 15 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/service/IAdwebEnquiryFormService.java
  52. 10 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/service/IAdwebEnquiryService.java
  53. 21 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/service/IAdwebPublicBlackEmailService.java
  54. 16 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/service/IAdwebPublicBlackIpService.java
  55. 24 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/service/IAdwebPublicEnquiryRuleService.java
  56. 43 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/service/IAdwebSiteBlackEmailService.java
  57. 33 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/service/IAdwebSiteBlackIpService.java
  58. 20 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/service/IAdwebSiteEnquiryRuleService.java
  59. 38 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/service/IEnquiryEmailMessageService.java
  60. 48 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/service/impl/AdwebEnquiryBlacklistServiceImpl.java
  61. 26 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/service/impl/AdwebEnquiryFormServiceImpl.java
  62. 1747 4
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/service/impl/AdwebEnquiryServiceImpl.java
  63. 177 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/service/impl/AdwebPublicBlackEmailServiceImpl.java
  64. 28 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/service/impl/AdwebPublicBlackIpServiceImpl.java
  65. 61 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/service/impl/AdwebPublicEnquiryRuleServiceImpl.java
  66. 195 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/service/impl/AdwebSiteBlackEmailServiceImpl.java
  67. 121 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/service/impl/AdwebSiteBlackIpServiceImpl.java
  68. 63 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/service/impl/AdwebSiteEnquiryRuleServiceImpl.java
  69. 417 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/service/impl/EnquiryEmailMessageServiceImpl.java
  70. 1 1
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/seo/entity/SeoKeywordsSerp.java
  71. 2 2
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/seo/mapper/SeoKeywordsMapper.java
  72. 5 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/seo/mapper/SeoKeywordsSerpMapper.java
  73. 9 10
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/seo/mapper/xml/SeoKeywordsMapper.xml
  74. 12 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/seo/mapper/xml/SeoKeywordsSerpMapper.xml
  75. 2 1
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/seo/service/ISeoKeywordsSerpService.java
  76. 278 20
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/seo/service/dataforseo/DataForSEOService.java
  77. 66 6
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/seo/service/impl/SeoKeywordsSerpServiceImpl.java
  78. 6 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/site/entity/AdwebSite.java
  79. 20 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/site/service/IAdwebSiteService.java
  80. 61 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/site/service/impl/AdwebSiteServiceImpl.java
  81. 58 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/system/entity/MasterSubAccountRelation.java
  82. 81 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/system/entity/SysException.java
  83. 11 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/system/mapper/MasterSubAccountRelationMapper.java
  84. 14 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/system/mapper/SysExceptionMapper.java
  85. 46 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/system/service/IMasterSubAccountRelationService.java
  86. 14 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/system/service/ISysExceptionService.java
  87. 12 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/system/service/SysAdwebApi.java
  88. 129 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/system/service/impl/MasterSubAccountRelationServiceImpl.java
  89. 30 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/system/service/impl/SysAdwebApiImpl.java
  90. 18 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/system/service/impl/SysExceptionServiceImpl.java
  91. 33 2
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/mq/EnquiryReceiver.java
  92. 10 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysDictItemMapper.java
  93. 10 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysDictMapper.java
  94. 15 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysDictMapper.xml
  95. 10 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/ISysDictService.java
  96. 12 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysDictServiceImpl.java
  97. 65 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/xxl/DataForSEOJob.java
  98. 4 1
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/xxl/GAReportJob.java
  99. 31 1
      jeecg-module-system/jeecg-system-start/src/main/resources/application-dev.yml
  100. 31 1
      jeecg-module-system/jeecg-system-start/src/main/resources/application-prod.yml

+ 5 - 1
.gitignore

@@ -13,4 +13,8 @@ os_del.cmd
 os_del_doc.cmd
 .svn
 derby.log
-*.log
+*.log
+
+## DS_Store
+.DS_Store
+**/.DS_Store

+ 39 - 2
jeecg-module-system/jeecg-system-biz/pom.xml

@@ -44,6 +44,39 @@
 			<artifactId>hutool-all</artifactId>
 			<version>5.8.25</version>
 		</dependency>
+
+		<dependency>
+			<groupId>com.maxmind.geoip2</groupId>
+			<artifactId>geoip2</artifactId>
+			<version>2.12.0</version>
+			<scope>compile</scope>
+		</dependency>
+
+		<!-- https://mvnrepository.com/artifact/org.apache.lucene/lucene-core -->
+		<dependency>
+			<groupId>org.apache.lucene</groupId>
+			<artifactId>lucene-core</artifactId>
+			<version>7.7.3</version>
+		</dependency>
+		<!-- https://mvnrepository.com/artifact/org.apache.lucene/lucene-analyzers-common -->
+		<dependency>
+			<groupId>org.apache.lucene</groupId>
+			<artifactId>lucene-analyzers-common</artifactId>
+			<version>7.7.3</version>
+		</dependency>
+		<!-- https://mvnrepository.com/artifact/org.apache.lucene/lucene-queryparser -->
+		<dependency>
+			<groupId>org.apache.lucene</groupId>
+			<artifactId>lucene-queryparser</artifactId>
+			<version>7.7.3</version>
+		</dependency>
+
+		<dependency>
+			<groupId>redis.clients</groupId>
+			<artifactId>jedis</artifactId>
+			<version>2.9.0</version>
+		</dependency>
+
 	<!-- 积木报表 mongo redis 支持包
 		<dependency>
 			<groupId>org.jeecgframework.jimureport</groupId>
@@ -61,14 +94,18 @@
             <groupId>org.jeecgframework.boot</groupId>
             <artifactId>jeecg-boot-starter3-rabbitmq</artifactId>
         </dependency>
-
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-all</artifactId>
+            <version>5.8.25</version>
+            <scope>compile</scope>
+        </dependency>
 		<!--dataforseo client https://docs.dataforseo.com/v3/-->
 		<dependency>
 			<groupId>io.github.dataforseo</groupId>
 			<artifactId>dataforseo-client</artifactId>
 			<version>1.0.19</version>
 		</dependency>
-
     </dependencies>
 
 </project>

+ 42 - 2
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/common/constant/AdwebConstant.java

@@ -14,10 +14,10 @@ public interface AdwebConstant {
     public static final Integer SITE_UNPUBLISH = 2;
 
     /*菜单状态*/
-    public static final Integer MENU_DEL = 1;
+    public static final Integer MENU_DEL  = 1;
 
     /*模板配置状态*/
-    public static final Integer TEMPLATE_SETTING_DEL = 1;
+    public static final Integer TEMPLATE_SETTING_DEL  = 1;
 
     /*模板上架状态*/
     public static final Integer TEMPLATE_PUTAWAY = 1;
@@ -39,6 +39,46 @@ public interface AdwebConstant {
 
     public static final String PRODUCTCTALOG = "productCatalog";
 
+    /**
+     * 缓存前缀
+     */
+    public static final String CACHE_PREFIX = "AdWeb3::";
+
+    //询盘阶段,字典条目
+    public static final String ENQUIRY_PHASE = "enquiry_phase";
+    //询盘跟进状态,字典条目
+    public static final String ENQUIRY_TRACK_STATUS = "enquiry_track_status";
+    //询盘用户有效性,字典条目
+    public static final String ENQUIRY_EFFECTIVE = "enquiry_effective";
+    //询盘回复状态,字典条目
+    public static final String ENQUIRY_REPLAY_STATUS = "enquiry_replay_status";
+    //ADMP dictService
+    public static final String CUSTOMER_ORDER_CURRENCY = "customer_order_currency";
+
+    public static final String ENQUIRY_PARAM_NAME = "enquiry_param_name";
+    public static final String ENQUIRY_PARAM_EMAIL = "enquiry_param_email";
+    public static final String ENQUIRY_PARAM_PHONE = "enquiry_param_phone";
+    public static final String ENQUIRY_PARAM_MESSAGE = "enquiry_param_message";
+    public static final String ENQUIRY_PARAM_COMPANY = "enquiry_param_company";
+    public static final String ENQUIRY_PARAM_FROM_PAGE = "enquiry_param_from_page";
+
+    /**
+     * 页面code
+     */
+    public static final String HOME_PAGE_CODE = "home";
+    public static final String ABOUT_US_PAGE_CODE = "aboutUs";
+    public static final String PRODUCTS_PAGE_CODE = "products";
+    public static final String PRODUCT_DETAIL_PAGE_CODE = "productDetail";
+    public static final String NEWS_PAGE_CODE = "news";
+    public static final String NEWS_DETAIL_PAGE_CODE = "newsDetail";
+    public static final String CONTACT_US_PAGE_CODE = "contactUs";
+    public static final String FAQ_PAGE_CODE = "faq";
+
+    /**
+     * 模板标签
+     */
+    public static final String TEMPLATE_TAGS = "template_tags";
+
     /*SEO关键字类型 1 - 指定词 2 - 长尾词 */
     public static final int KEYWORD_TYPE_APPOINT = 1;
     public static final int KEYWORD_TYPE_LONG_TAIL = 2;

+ 0 - 158
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/common/constant/CompConstants.java

@@ -1,158 +0,0 @@
-package org.jeecg.modules.adweb.common.constant;
-
-/**
- * @Author: 汤星鹏, Jeecg
- * @Description: 物料收集常量
- * @Date: 2020/4/2 10:04
- */
-public class CompConstants {
-    /**
-     * 临时公告分类code
-     */
-    public static final String INTERIM_ANNOUNCEMENT = "interimAnnouncement";
-    /**
-     * 交流园地文章
-     */
-    public static final String CORNER = "corner";
-    /**
-     * 物料收集类别字典表catalog
-     */
-    public static final String SITE_COMP_CATALOG = "site_comp_catalog";
-    /**
-     * 物料收集添加失败
-     */
-    public static final String COMP_ADD_FAIL = "添加失败";
-    /**
-     * 物料收集字典表catalog头部分,用于拼接catalogCode查询属性名称,如:"site_code_baseInfo"
-     */
-    public static final String SITE_COMP_HEAD = "site_comp_";
-    /**
-     * 产品
-     */
-    public static final String PRODUCT = "product";
-    /**
-     * 基础信息
-     */
-    public static final String BASEINFO = "baseInfo";
-    /**
-     * 内容
-     */
-    public static final String NEWS = "news";
-    /**
-     * 荣誉资质
-     */
-    public static final String HONNOR = "honor";
-    /**
-     * 服务保障
-     */
-    public static final String SERVICE_ASSURANCE="serviceGuarantee";
-    /**
-     * 内容分类
-     */
-    public static final String NEWS_CATALOG = "newsCatalog";
-    /**
-     * 社交媒体
-     */
-    public static final String SOCIAL_MEDIA = "socialMedia";
-    /**
-     * 产品分类
-     */
-    public static final String PRODUCT_CATALOG = "productCatalog";
-    /**
-     * 客户评价
-     */
-    public static final String CUSTOMS_FEEDBACK = "customerReviews";
-    /**
-     * 合作商
-     */
-    public static final String C00PERATIVE_PARTNER = "partner";
-    /**
-     * 首页焦点图
-     */
-    public static final String HOMEPAGE_FOCUS = "homeFocusMap";
-
-    /**
-     * 其他页面的banner图
-     */
-    public static final String BANNERPRODUCTS = "banner-products";
-    public static final String BANNERPABOUTUS = "'banner-aboutUs'";
-    public static final String BANNERNEWS = "banner-news";
-    public static final String BANNERPQUESTION = "banner-question";
-    public static final String BANNERPCONTACTUS = "banner-contactUs";
-    public static final String BANNERPJOINUS = "banner-joinUs";
-    /**
-     * FAQ
-     */
-    public static final String FREQUENT_ASKED_QUESTION = "FAQ";
-    /**
-     * 参展信息
-     */
-    public static final String EXHIBITION_INFO = "exhibitionInfo";
-    /**
-     * 物流包装付款
-     */
-    public static final String LOGISTICS_PACKAGE_PAYMENT  = "logisticsPackagingPayment";
-    /**
-     * 公司风采
-     */
-    public static final String COMPANY_APPEARANCE = "enterpriseStyle";
-    /**
-     * 地图
-     */
-    public static final String MAP = "map";
-    /**
-     * 优势数据
-     */
-    public static final String ADVANTAGEDATA = "advantageData";
-    /**
-     * 多语言
-     */
-    public static final String ADWEB_LANGUAGE = "adweb_language";
-    /**
-     * 站点状态
-     */
-    public static final String SITE_STATUS = "site_status";
-    /**
-     * 站点运行状态
-     */
-    public static final String SITE_RUM_STATUS = "site_run_status";
-    /**
-     * 缓存前缀
-     */
-    public static final String CACHE_PREFIX = "AdWeb3::";
-
-    //询盘阶段,字典条目
-    public static final String ENQUIRY_PHASE = "enquiry_phase";
-    //询盘跟进状态,字典条目
-    public static final String ENQUIRY_TRACK_STATUS = "enquiry_track_status";
-    //询盘用户有效性,字典条目
-    public static final String ADMP_ENQUIRY_EFFECTIVE = "admp_enquiry_effective";
-    //询盘回复状态,字典条目
-    public static final String ENQUIRY_REPLAY_STATUS = "enquiry_replay_status";
-    //ADMP dictService
-    public static final String ADMP_CUSTOMER_ORDER_CURRENCY = "admp_customer_order_currency";
-
-    public static final String ADMP_ENQUIRY_PARAM_NAME = "admp_enquiry_param_name";
-    public static final String ADMP_ENQUIRY_PARAM_EMAIL = "admp_enquiry_param_email";
-    public static final String ADMP_ENQUIRY_PARAM_PHONE = "admp_enquiry_param_phone";
-    public static final String ADMP_ENQUIRY_PARAM_MESSAGE = "admp_enquiry_param_message";
-    public static final String ADMP_ENQUIRY_PARAM_COMPANY = "admp_enquiry_param_company";
-    public static final String ADMP_ENQUIRY_PARAM_FROM_PAGE = "admp_enquiry_param_from_page";
-
-    /**
-     * 页面code
-     */
-    public static final String HOME_PAGE_CODE = "home";
-    public static final String ABOUT_US_PAGE_CODE = "aboutUs";
-    public static final String PRODUCTS_PAGE_CODE = "products";
-    public static final String PRODUCT_DETAIL_PAGE_CODE = "productDetail";
-    public static final String NEWS_PAGE_CODE = "news";
-    public static final String NEWS_DETAIL_PAGE_CODE = "newsDetail";
-    public static final String CONTACT_US_PAGE_CODE = "contactUs";
-    public static final String FAQ_PAGE_CODE = "faq";
-
-    /**
-     * 模板标签
-     */
-    public static final String TEMPLATE_TAGS = "template_tags";
-}

+ 93 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/common/constant/RobotMsgTemplate.java

@@ -0,0 +1,93 @@
+package org.jeecg.modules.adweb.common.constant;
+
+/**
+ * @Description:
+ * @Author: wrk
+ * @date 2022/7/18 18:02
+ */
+public class RobotMsgTemplate {
+
+    public static final String EXCEPTION_MSG = "{\n" +
+            "  \"config\": {\n" +
+            "    \"wide_screen_mode\": true\n" +
+            "  },\n" +
+            "  \"elements\": [\n" +
+            "    {\n" +
+            "      \"fields\": [\n" +
+            "        {\n" +
+            "          \"is_short\": true,\n" +
+            "          \"text\": {\n" +
+            "            \"content\": \"** 询盘耗时:**\\n{consumeTime}\",\n" +
+            "            \"tag\": \"lark_md\"\n" +
+            "          }\n" +
+            "        },\n" +
+            "        {\n" +
+            "          \"is_short\": false,\n" +
+            "          \"text\": {\n" +
+            "            \"content\": \"\",\n" +
+            "            \"tag\": \"lark_md\"\n" +
+            "          }\n" +
+            "        },\n" +
+            "        {\n" +
+            "          \"is_short\": true,\n" +
+            "          \"text\": {\n" +
+            "            \"content\": \"** 发生时间:**\\n{time}\",\n" +
+            "            \"tag\": \"lark_md\"\n" +
+            "          }\n" +
+            "        },\n" +
+            "        {\n" +
+            "          \"is_short\": false,\n" +
+            "          \"text\": {\n" +
+            "            \"content\": \"\",\n" +
+            "            \"tag\": \"lark_md\"\n" +
+            "          }\n" +
+            "        },\n" +
+            "        {\n" +
+            "          \"is_short\": true,\n" +
+            "          \"text\": {\n" +
+            "            \"content\": \"** 系统模块:**\\n{title}\",\n" +
+            "            \"tag\": \"lark_md\"\n" +
+            "          }\n" +
+            "        },\n" +
+            "        {\n" +
+            "          \"is_short\": false,\n" +
+            "          \"text\": {\n" +
+            "            \"content\": \"\",\n" +
+            "            \"tag\": \"lark_md\"\n" +
+            "          }\n" +
+            "        },\n" +
+            "        {\n" +
+            "          \"is_short\": true,\n" +
+            "          \"text\": {\n" +
+            "            \"content\": \"** 异常方法:**\\n{methodName}\",\n" +
+            "            \"tag\": \"lark_md\"\n" +
+            "          }\n" +
+            "        },\n" +
+            "        {\n" +
+            "          \"is_short\": false,\n" +
+            "          \"text\": {\n" +
+            "            \"content\": \"\",\n" +
+            "            \"tag\": \"lark_md\"\n" +
+            "          }\n" +
+            "        },\n" +
+            "        {\n" +
+            "          \"is_short\": true,\n" +
+            "          \"text\": {\n" +
+            "            \"content\": \"** 错误消息:**\\n{errorMsg}\",\n" +
+            "            \"tag\": \"lark_md\"\n" +
+            "          }\n" +
+            "        }\n" +
+            "      ],\n" +
+            "      \"tag\": \"div\"\n" +
+            "    }\n" +
+            "  ],\n" +
+            "  \"header\": {\n" +
+            "    \"template\": \"red\",\n" +
+            "    \"title\": {\n" +
+            "      \"content\": \"Adweb询盘报警-{environment}\",\n" +
+            "      \"tag\": \"plain_text\"\n" +
+            "    }\n" +
+            "  }\n" +
+            "}";
+
+}

+ 17 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/common/dto/CountryAreaApiDto.java

@@ -0,0 +1,17 @@
+package org.jeecg.modules.adweb.common.dto;
+
+import lombok.Data;
+
+/**
+ * @description: 国家区域Api实体类
+ * @author: Cyan
+ * @time: 2019/12/16 11:17
+ */
+@Data
+public class CountryAreaApiDto {
+    private String countryZhCN;
+    private String countryIsoCode;
+    private String subdivisionZhCN;
+    private String subdivisionIsoCode;
+    private String timeZone;
+}

+ 219 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/common/dto/RobotDto.java

@@ -0,0 +1,219 @@
+package org.jeecg.modules.adweb.common.dto;
+
+import java.util.List;
+
+/**
+ * @Description:
+ * @Author: wrk
+ * @date 2022/6/23 14:01
+ */
+public class RobotDto {
+
+
+    /**
+     * msg_type : interactive
+     * card : {"config":{"wide_screen_mode":true},"elements":[{"fields":[{"is_short":true,"text":{"content":"** 时间:**\n2022-06-23 15:07:04","tag":"lark_md"}},{"is_short":true,"text":{"content":"** 事件等级: **\nERROR","tag":"lark_md"}},{"is_short":false,"text":{"content":"","tag":"lark_md"}},{"is_short":true,"text":{"content":"** 异常模块:**\n系统管理","tag":"lark_md"}},{"is_short":true,"text":{"content":"** 异常方法:**\ncom.advich.adcloud.controller.LogController.getSmsLogListData()","tag":"lark_md"}},{"is_short":false,"text":{"content":"","tag":"lark_md"}},{"is_short":true,"text":{"content":"** 异常栈消息:**\n{}","tag":"lark_md"}}],"tag":"div"}],"header":{"template":"red","title":{"content":"1 级报警 - CRM管理后台","tag":"plain_text"}}}
+     */
+
+    private String msg_type;
+    private CardBean card;
+
+    public String getMsg_type() {
+        return msg_type;
+    }
+
+    public void setMsg_type(String msg_type) {
+        this.msg_type = msg_type;
+    }
+
+    public CardBean getCard() {
+        return card;
+    }
+
+    public void setCard(CardBean card) {
+        this.card = card;
+    }
+
+    public static class CardBean {
+        /**
+         * config : {"wide_screen_mode":true}
+         * elements : [{"fields":[{"is_short":true,"text":{"content":"** 时间:**\n2022-06-23 15:07:04","tag":"lark_md"}},{"is_short":true,"text":{"content":"** 事件等级: **\nERROR","tag":"lark_md"}},{"is_short":false,"text":{"content":"","tag":"lark_md"}},{"is_short":true,"text":{"content":"** 异常模块:**\n系统管理","tag":"lark_md"}},{"is_short":true,"text":{"content":"** 异常方法:**\ncom.advich.adcloud.controller.LogController.getSmsLogListData()","tag":"lark_md"}},{"is_short":false,"text":{"content":"","tag":"lark_md"}},{"is_short":true,"text":{"content":"** 异常栈消息:**\n{}","tag":"lark_md"}}],"tag":"div"}]
+         * header : {"template":"red","title":{"content":"1 级报警 - CRM管理后台","tag":"plain_text"}}
+         */
+
+        private ConfigBean config;
+        private HeaderBean header;
+        private List<ElementsBean> elements;
+
+        public ConfigBean getConfig() {
+            return config;
+        }
+
+        public void setConfig(ConfigBean config) {
+            this.config = config;
+        }
+
+        public HeaderBean getHeader() {
+            return header;
+        }
+
+        public void setHeader(HeaderBean header) {
+            this.header = header;
+        }
+
+        public List<ElementsBean> getElements() {
+            return elements;
+        }
+
+        public void setElements(List<ElementsBean> elements) {
+            this.elements = elements;
+        }
+
+        public static class ConfigBean {
+            /**
+             * wide_screen_mode : true
+             */
+
+            private boolean wide_screen_mode;
+
+            public boolean isWide_screen_mode() {
+                return wide_screen_mode;
+            }
+
+            public void setWide_screen_mode(boolean wide_screen_mode) {
+                this.wide_screen_mode = wide_screen_mode;
+            }
+        }
+
+        public static class HeaderBean {
+            /**
+             * template : red
+             * title : {"content":"1 级报警 - CRM管理后台","tag":"plain_text"}
+             */
+
+            private String template;
+            private TitleBean title;
+
+            public String getTemplate() {
+                return template;
+            }
+
+            public void setTemplate(String template) {
+                this.template = template;
+            }
+
+            public TitleBean getTitle() {
+                return title;
+            }
+
+            public void setTitle(TitleBean title) {
+                this.title = title;
+            }
+
+            public static class TitleBean {
+                /**
+                 * content : 1 级报警 - CRM管理后台
+                 * tag : plain_text
+                 */
+
+                private String content;
+                private String tag;
+
+                public String getContent() {
+                    return content;
+                }
+
+                public void setContent(String content) {
+                    this.content = content;
+                }
+
+                public String getTag() {
+                    return tag;
+                }
+
+                public void setTag(String tag) {
+                    this.tag = tag;
+                }
+            }
+        }
+
+        public static class ElementsBean {
+            /**
+             * fields : [{"is_short":true,"text":{"content":"** 时间:**\n2022-06-23 15:07:04","tag":"lark_md"}},{"is_short":true,"text":{"content":"** 事件等级: **\nERROR","tag":"lark_md"}},{"is_short":false,"text":{"content":"","tag":"lark_md"}},{"is_short":true,"text":{"content":"** 异常模块:**\n系统管理","tag":"lark_md"}},{"is_short":true,"text":{"content":"** 异常方法:**\ncom.advich.adcloud.controller.LogController.getSmsLogListData()","tag":"lark_md"}},{"is_short":false,"text":{"content":"","tag":"lark_md"}},{"is_short":true,"text":{"content":"** 异常栈消息:**\n{}","tag":"lark_md"}}]
+             * tag : div
+             */
+
+            private String tag;
+            private List<FieldsBean> fields;
+
+            public String getTag() {
+                return tag;
+            }
+
+            public void setTag(String tag) {
+                this.tag = tag;
+            }
+
+            public List<FieldsBean> getFields() {
+                return fields;
+            }
+
+            public void setFields(List<FieldsBean> fields) {
+                this.fields = fields;
+            }
+
+            public static class FieldsBean {
+                /**
+                 * is_short : true
+                 * text : {"content":"** 时间:**\n2022-06-23 15:07:04","tag":"lark_md"}
+                 */
+
+                private boolean is_short;
+                private TextBean text;
+
+                public boolean isIs_short() {
+                    return is_short;
+                }
+
+                public void setIs_short(boolean is_short) {
+                    this.is_short = is_short;
+                }
+
+                public TextBean getText() {
+                    return text;
+                }
+
+                public void setText(TextBean text) {
+                    this.text = text;
+                }
+
+                public static class TextBean {
+                    /**
+                     * content : ** 时间:**
+                     2022-06-23 15:07:04
+                     * tag : lark_md
+                     */
+
+                    private String content;
+                    private String tag;
+
+                    public String getContent() {
+                        return content;
+                    }
+
+                    public void setContent(String content) {
+                        this.content = content;
+                    }
+
+                    public String getTag() {
+                        return tag;
+                    }
+
+                    public void setTag(String tag) {
+                        this.tag = tag;
+                    }
+                }
+            }
+        }
+    }
+}

+ 122 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/common/service/FeishuService.java

@@ -0,0 +1,122 @@
+package org.jeecg.modules.adweb.common.service;
+
+import cn.hutool.http.HttpRequest;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.xkcoding.http.util.StringUtil;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.jeecg.modules.adweb.common.constant.RobotMsgTemplate;
+import org.jeecg.modules.adweb.common.dto.RobotDto;
+import org.jeecg.modules.adweb.site.service.IAdwebSiteService;
+import org.jeecg.modules.system.entity.SysDictItem;
+import org.jeecg.modules.system.service.ISysDictService;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * @Description:
+ * @Author: wrk
+ * @date 2022/7/18 16:30
+ */
+@Slf4j
+@Service
+public class FeishuService {
+
+    @Resource
+    private ISysDictService sysDictService;
+
+    @Resource
+    private IAdwebSiteService adwebSiteService;
+
+    /**
+     * url
+     */
+    @Value("${robot.enquiry-url}")
+    private String enquiryUrl;
+    @Value("${robot.market-plan-missing-url}")
+    private String marketPlanMissingUrl;
+    @Value("${robot.flow-abnormal-url}")
+    private String flowAbnormalUrl;
+
+    @Value("${robot.keyword-preOrSuffix-url}")
+    private String keywordPreOrSuffixUrl;
+
+    @Value("${robot.gtm-url}")
+    private String gtmUrl;
+
+
+
+    /**
+     * 本地属性
+     */
+    public static String PROFILES_ACTIVE;
+
+    @Value("${spring.profiles.active}")
+    public void setCustomName(String customName) {
+        PROFILES_ACTIVE = customName;
+    }
+
+    /**
+     * 异常栈发送机器人消息
+     *
+     * @param consumeTime
+     * @param title
+     * @param errorMsg
+     */
+    public void sendRobot(float consumeTime, String title, String classNameInit, String methodNameInit, String errorMsg) {
+        //HttpServletRequest request = ContextHolderUtils.getRequest();
+        String requestIp = "";
+        String className = classNameInit == null ? "未知类名" : classNameInit;
+        String methodName = methodNameInit == null ? "未知方法名" : methodNameInit;
+        /*if (request != null){
+            requestIp = IpUtil.getIpAddr(request);
+            //className = request.getClass().getName();
+            //methodName = request.getMethod();
+        }*/
+        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        String timeStr = simpleDateFormat.format(new Date());
+        String text = RobotMsgTemplate.EXCEPTION_MSG;
+        text = text.replaceAll("\\{environment\\}", PROFILES_ACTIVE);
+        text = text.replaceAll("\\{consumeTime\\}", consumeTime + "秒");
+        text = text.replaceAll("\\{time\\}", timeStr);
+        //text = text.replaceAll("\\{requestIp\\}", "".equals(requestIp) ? "0:0:0:0:0:0:0:1" : requestIp);
+        text = text.replaceAll("\\{title\\}", title);
+        text = text.replaceAll("\\{methodName\\}", className + "." + methodName + "()");
+        text = text.replaceAll("\\{errorMsg\\}", errorMsg);
+        RobotDto robotDto = new RobotDto();
+        robotDto.setMsg_type("interactive");
+        robotDto.setCard(JSON.parseObject(text, RobotDto.CardBean.class));
+        String json = JSON.toJSONString(robotDto);
+
+        HttpRequest.post(enquiryUrl).body(json).execute(true);
+    }
+
+    /**
+     * 邮件发送失败通知
+     */
+    public void sendEnquiryEmailFailMsg(Long enquiryId, String siteCode, String email, String content) {
+        SysDictItem dictItem = sysDictService.getDictItemByCodeAndText("feishu_msg_template", "enquiry_email_fail_msg");
+        if (dictItem == null || StringUtil.isEmpty(dictItem.getItemValue())) {
+            return;
+        }
+
+        String siteName = adwebSiteService.getSiteNameByCode(siteCode);
+
+        String template = dictItem.getItemValue();
+        template = template.replace("{{siteName}}", siteName);
+        template = template.replace("{{enquiryId}}", Long.toString(enquiryId));
+        template = template.replace("{{email}}", email);
+        template = template.replace("{{content}}", content);
+
+        JSONObject object = new JSONObject();
+        object.put("msg_type", "interactive");
+        object.put("card", template);
+
+        HttpRequest.post(enquiryUrl).body(object.toJSONString()).execute(true);
+    }
+
+}

+ 679 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/common/util/AdwebRedisUtil.java

@@ -0,0 +1,679 @@
+package org.jeecg.modules.adweb.common.util;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.PropertyAccessor;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import lombok.extern.slf4j.Slf4j;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisCallback;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
+import org.springframework.data.redis.serializer.RedisSerializer;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+import org.springframework.stereotype.Component;
+import org.springframework.util.CollectionUtils;
+
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * redis 工具类
+ *
+ * @author Scott
+ */
+@Component
+@Slf4j
+public class AdwebRedisUtil {
+
+    @Autowired private RedisTemplate<String, Object> redisTemplate;
+
+    @Autowired(required = false)
+    public void setRedisTemplate(RedisTemplate redisTemplate) {
+        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = jacksonSerializer();
+        RedisSerializer stringSerializer = new StringRedisSerializer();
+        redisTemplate.setKeySerializer(stringSerializer);
+        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
+        redisTemplate.setHashKeySerializer(stringSerializer);
+        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
+        this.redisTemplate = redisTemplate;
+    }
+
+    private Jackson2JsonRedisSerializer jacksonSerializer() {
+        ObjectMapper objectMapper = new ObjectMapper();
+        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer =
+                new Jackson2JsonRedisSerializer(objectMapper, Object.class);
+        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
+        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
+
+        return jackson2JsonRedisSerializer;
+    }
+
+    /**
+     * 指定缓存失效时间
+     *
+     * @param key 键
+     * @param time 时间(秒)
+     * @return
+     */
+    public boolean expire(String key, long time) {
+        try {
+            if (time > 0) {
+                redisTemplate.expire(key, time, TimeUnit.SECONDS);
+            }
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 根据key 获取过期时间
+     *
+     * @param key 键 不能为null
+     * @return 时间(秒) 返回0代表为永久有效
+     */
+    public long getExpire(String key) {
+        return redisTemplate.getExpire(key, TimeUnit.SECONDS);
+    }
+
+    /**
+     * 判断key是否存在
+     *
+     * @param key 键
+     * @return true 存在 false不存在
+     */
+    public boolean hasKey(String key) {
+        try {
+            return redisTemplate.hasKey(key);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 删除缓存
+     *
+     * @param key 可以传一个值 或多个
+     */
+    @SuppressWarnings("unchecked")
+    public void del(String... key) {
+        if (key != null && key.length > 0) {
+            if (key.length == 1) {
+                redisTemplate.delete(key[0]);
+            } else {
+                redisTemplate.delete((Collection<String>) CollectionUtils.arrayToList(key));
+            }
+        }
+    }
+
+    /**
+     * 根据pattern查询所有keys
+     *
+     * @param pattern 如key_prefix.*
+     * @return
+     */
+    public Set<String> keys(String pattern) {
+        return redisTemplate.keys(pattern);
+    }
+
+    // ============================String=============================
+
+    /**
+     * 普通缓存获取
+     *
+     * @param key 键
+     * @return 值
+     */
+    public Object get(String key) {
+        return key == null ? null : redisTemplate.opsForValue().get(key);
+    }
+
+    /**
+     * 普通缓存获取
+     *
+     * @param key 键
+     * @return 值
+     */
+    public String getString(String key) {
+        Object valueObj = get(key);
+        return valueObj == null ? "" : valueObj.toString();
+    }
+
+    /**
+     * 普通缓存放入
+     *
+     * @param key 键
+     * @param value 值
+     * @return true成功 false失败
+     */
+    public boolean set(String key, Object value) {
+        try {
+            redisTemplate.opsForValue().set(key, value);
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 普通缓存放入并设置时间
+     *
+     * @param key 键
+     * @param value 值
+     * @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期
+     * @return true成功 false 失败
+     */
+    public boolean set(String key, Object value, long time) {
+        try {
+            if (time > 0) {
+                redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
+            } else {
+                set(key, value);
+            }
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 递增
+     *
+     * @param key 键
+     * @param delta 要增加几(大于0)
+     * @return
+     */
+    public long incr(String key, long delta) {
+        if (delta < 0) {
+            throw new RuntimeException("递增因子必须大于0");
+        }
+        return redisTemplate.opsForValue().increment(key, delta);
+    }
+
+    /**
+     * 递减
+     *
+     * @param key 键
+     * @param delta 要减少几(小于0)
+     * @return
+     */
+    public long decr(String key, long delta) {
+        if (delta < 0) {
+            throw new RuntimeException("递减因子必须大于0");
+        }
+        return redisTemplate.opsForValue().increment(key, -delta);
+    }
+
+    // ================================Map=================================
+
+    /**
+     * HashGet
+     *
+     * @param key 键 不能为null
+     * @param item 项 不能为null
+     * @return 值
+     */
+    public Object hget(String key, String item) {
+        return redisTemplate.opsForHash().get(key, item);
+    }
+
+    /**
+     * 获取hashKey对应的所有键值
+     *
+     * @param key 键
+     * @return 对应的多个键值
+     */
+    public Map<Object, Object> hmget(String key) {
+        return redisTemplate.opsForHash().entries(key);
+    }
+
+    /**
+     * HashSet
+     *
+     * @param key 键
+     * @param map 对应多个键值
+     * @return true 成功 false 失败
+     */
+    public boolean hmset(String key, Map<String, Object> map) {
+        try {
+            redisTemplate.opsForHash().putAll(key, map);
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * HashSet 并设置时间
+     *
+     * @param key 键
+     * @param map 对应多个键值
+     * @param time 时间(秒)
+     * @return true成功 false失败
+     */
+    public boolean hmset(String key, Map<String, Object> map, long time) {
+        try {
+            redisTemplate.opsForHash().putAll(key, map);
+            if (time > 0) {
+                expire(key, time);
+            }
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 向一张hash表中放入数据,如果不存在将创建
+     *
+     * @param key 键
+     * @param item 项
+     * @param value 值
+     * @return true 成功 false失败
+     */
+    public boolean hset(String key, String item, Object value) {
+        try {
+            redisTemplate.opsForHash().put(key, item, value);
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 向一张hash表中放入数据,如果不存在将创建
+     *
+     * @param key 键
+     * @param item 项
+     * @param value 值
+     * @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
+     * @return true 成功 false失败
+     */
+    public boolean hset(String key, String item, Object value, long time) {
+        try {
+            redisTemplate.opsForHash().put(key, item, value);
+            if (time > 0) {
+                expire(key, time);
+            }
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 删除hash表中的值
+     *
+     * @param key 键 不能为null
+     * @param item 项 可以使多个 不能为null
+     */
+    public void hdel(String key, Object... item) {
+        redisTemplate.opsForHash().delete(key, item);
+    }
+
+    /**
+     * 判断hash表中是否有该项的值
+     *
+     * @param key 键 不能为null
+     * @param item 项 不能为null
+     * @return true 存在 false不存在
+     */
+    public boolean hHasKey(String key, String item) {
+        return redisTemplate.opsForHash().hasKey(key, item);
+    }
+
+    /**
+     * hash递增 如果不存在,就会创建一个 并把新增后的值返回
+     *
+     * @param key 键
+     * @param item 项
+     * @param by 要增加几(大于0)
+     * @return
+     */
+    public double hincr(String key, String item, double by) {
+        return redisTemplate.opsForHash().increment(key, item, by);
+    }
+
+    /**
+     * hash递减
+     *
+     * @param key 键
+     * @param item 项
+     * @param by 要减少记(小于0)
+     * @return
+     */
+    public double hdecr(String key, String item, double by) {
+        return redisTemplate.opsForHash().increment(key, item, -by);
+    }
+
+    // ============================set=============================
+
+    /**
+     * 根据key获取Set中的所有值
+     *
+     * @param key 键
+     * @return
+     */
+    public Set<Object> sGet(String key) {
+        try {
+            return redisTemplate.opsForSet().members(key);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    /**
+     * 根据value从一个set中查询,是否存在
+     *
+     * @param key 键
+     * @param value 值
+     * @return true 存在 false不存在
+     */
+    public boolean sHasKey(String key, Object value) {
+        try {
+            return redisTemplate.opsForSet().isMember(key, value);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 将数据放入set缓存
+     *
+     * @param key 键
+     * @param values 值 可以是多个
+     * @return 成功个数
+     */
+    public long sSet(String key, Object... values) {
+        try {
+            return redisTemplate.opsForSet().add(key, values);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return 0;
+        }
+    }
+
+    /**
+     * 将set数据放入缓存
+     *
+     * @param key 键
+     * @param time 时间(秒)
+     * @param values 值 可以是多个
+     * @return 成功个数
+     */
+    public long sSetAndTime(String key, long time, Object... values) {
+        try {
+            Long count = redisTemplate.opsForSet().add(key, values);
+            if (time > 0) {
+                expire(key, time);
+            }
+            return count;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return 0;
+        }
+    }
+
+    /**
+     * 获取set缓存的长度
+     *
+     * @param key 键
+     * @return
+     */
+    public long sGetSetSize(String key) {
+        try {
+            return redisTemplate.opsForSet().size(key);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return 0;
+        }
+    }
+
+    /**
+     * 移除值为value的
+     *
+     * @param key 键
+     * @param values 值 可以是多个
+     * @return 移除的个数
+     */
+    public long setRemove(String key, Object... values) {
+        try {
+            Long count = redisTemplate.opsForSet().remove(key, values);
+            return count;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return 0;
+        }
+    }
+
+    // ===============================list=================================
+
+    /**
+     * 获取list缓存的内容
+     *
+     * @param key 键
+     * @param start 开始
+     * @param end 结束 0 到 -1代表所有值
+     * @return
+     */
+    public List<Object> lGet(String key, long start, long end) {
+        try {
+            return redisTemplate.opsForList().range(key, start, end);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    /**
+     * 获取list缓存的长度
+     *
+     * @param key 键
+     * @return
+     */
+    public long lGetListSize(String key) {
+        try {
+            return redisTemplate.opsForList().size(key);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return 0;
+        }
+    }
+
+    /**
+     * 通过索引 获取list中的值
+     *
+     * @param key 键
+     * @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
+     * @return
+     */
+    public Object lGetIndex(String key, long index) {
+        try {
+            return redisTemplate.opsForList().index(key, index);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    /**
+     * 将list放入缓存
+     *
+     * @param key 键
+     * @param value 值
+     * @return
+     */
+    public boolean lSet(String key, Object value) {
+        try {
+            redisTemplate.opsForList().rightPush(key, value);
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 将list放入缓存
+     *
+     * @param key 键
+     * @param value 值
+     * @param time 时间(秒)
+     * @return
+     */
+    public boolean lSet(String key, Object value, long time) {
+        try {
+            redisTemplate.opsForList().rightPush(key, value);
+            if (time > 0) {
+                expire(key, time);
+            }
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 将list放入缓存
+     *
+     * @param key 键
+     * @param value 值
+     * @return
+     */
+    public boolean lSet(String key, List<Object> value) {
+        try {
+            redisTemplate.opsForList().rightPushAll(key, value);
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 将list放入缓存
+     *
+     * @param key 键
+     * @param value 值
+     * @param time 时间(秒)
+     * @return
+     */
+    public boolean lSet(String key, List<Object> value, long time) {
+        try {
+            redisTemplate.opsForList().rightPushAll(key, value);
+            if (time > 0) {
+                expire(key, time);
+            }
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 根据索引修改list中的某条数据
+     *
+     * @param key 键
+     * @param index 索引
+     * @param value 值
+     * @return
+     */
+    public boolean lUpdateIndex(String key, long index, Object value) {
+        try {
+            redisTemplate.opsForList().set(key, index, value);
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 移除N个值为value
+     *
+     * @param key 键
+     * @param count 移除多少个
+     * @param value 值
+     * @return 移除的个数
+     */
+    public long lRemove(String key, long count, Object value) {
+        try {
+            Long remove = redisTemplate.opsForList().remove(key, count, value);
+            return remove;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return 0;
+        }
+    }
+
+    /**
+     * 获取锁
+     *
+     * @param lockKey 锁的键
+     * @param lockExpireMils 获取锁的时间
+     * @return 是否获取到锁
+     */
+    public boolean lock(String lockKey, long lockExpireMils) {
+        return (Boolean)
+                redisTemplate.execute(
+                        (RedisCallback)
+                                connection -> {
+                                    long nowTime = System.currentTimeMillis();
+                                    Boolean acquire =
+                                            connection.setNX(
+                                                    lockKey.getBytes(),
+                                                    String.valueOf(nowTime + lockExpireMils + 1)
+                                                            .getBytes());
+                                    if (acquire) {
+                                        return Boolean.TRUE;
+                                    } else {
+                                        byte[] value = connection.get(lockKey.getBytes());
+                                        if (Objects.nonNull(value) && value.length > 0) {
+                                            long oldTime = Long.parseLong(new String(value));
+                                            if (oldTime < nowTime) {
+                                                // connection.getSet:返回这个key的旧值并设置新值。
+                                                byte[] oldValue =
+                                                        connection.getSet(
+                                                                lockKey.getBytes(),
+                                                                String.valueOf(
+                                                                                nowTime
+                                                                                        + lockExpireMils
+                                                                                        + 1)
+                                                                        .getBytes());
+                                                // 当key不存时会返回空,表示key不存在或者已在管道中使用
+                                                return oldValue == null
+                                                        ? false
+                                                        : Long.parseLong(new String(oldValue))
+                                                                < nowTime;
+                                            }
+                                        }
+                                    }
+                                    return Boolean.FALSE;
+                                });
+    }
+
+    /**
+     * 释放锁
+     *
+     * @param lockKey 锁的键
+     */
+    public void unlock(String lockKey) {
+        if (this.hasKey(lockKey)) {
+            this.del(lockKey);
+        }
+    }
+}

+ 34 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/common/util/CommonUtil.java

@@ -0,0 +1,34 @@
+package org.jeecg.modules.adweb.common.util;
+
+import com.google.common.net.InternetDomainName;
+
+import lombok.extern.slf4j.Slf4j;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+/**
+ * 常用工具类
+ *
+ * @author wfansh
+ */
+@Slf4j
+public class CommonUtil {
+
+    /**
+     * 解析URL的顶级域名
+     *
+     * @param url 例如 https://www.essaynerdie.com, www.essaynerdie.com,
+     *     https://www.essaynerdie.com/products
+     * @return essaynerdie.com
+     */
+    public static String getTopPrivateDomain(String url) {
+        String host = url;
+        try {
+            host = new URL(url).getHost();
+        } catch (MalformedURLException e) {
+        } finally {
+            return InternetDomainName.from(host).topPrivateDomain().toString();
+        }
+    }
+}

+ 122 - 9
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/common/util/DateUtil.java

@@ -1,5 +1,11 @@
 package org.jeecg.modules.adweb.common.util;
 
+import com.xkcoding.http.util.StringUtil;
+
+import lombok.extern.slf4j.Slf4j;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
 import java.time.LocalDate;
 import java.time.ZoneId;
 import java.time.temporal.ChronoUnit;
@@ -12,21 +18,39 @@ import java.util.*;
  *
  * @author wfansh
  */
+@Slf4j
 public class DateUtil {
 
-    /**
-     * 时间格式(yyyy-MM-dd)
-     */
-    public final static String DATE_PATTERN = "yyyy-MM-dd";
-    /**
-     * 时间格式(yyyy-MM-dd HH:mm:ss)
-     */
-    public final static String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
+    /** 时间格式(yyyy-MM-dd) */
+    public static final String DATE_PATTERN = "yyyy-MM-dd";
+
+    /** 时间格式(yyyy-MM-dd HH:mm:ss) */
+    public static final String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
 
-    public final static String SUBJECT_DATE = "yyyy/MM/dd";
+    /** 带时区的时间格式(yyyy-MM-dd HH:mm:ss +00:00) */
+    public static final String ZONED_DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss X";
+
+    public static final String SUBJECT_DATE = "yyyy/MM/dd";
 
     public static final ZoneId DEFAULT_ZONE_ID = ZoneId.of("Asia/Shanghai");
 
+    /** yyyy-MM-dd HH:mm:ss. */
+    public static final String DATE_FORMAT_FIVE = "yyyy-MM-dd HH:mm:ss";
+
+    /** yyyyMMdd. */
+    public static final String DATE_FORMAT_THREE = "yyyyMMdd";
+
+    /** yyyyMMddHHmm */
+    public static final String DATE_FORMAT = "yyyyMMddHHmmss";
+
+    public static Date plusDays(Date date, int daysToAdd) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(date);
+
+        calendar.add(Calendar.DAY_OF_MONTH, daysToAdd);
+        return calendar.getTime();
+    }
+
     /**
      * 特殊时间数据处理
      *
@@ -106,6 +130,63 @@ public class DateUtil {
     }
 
     /**
+     * 按指定格式转化字符串为Date
+     *
+     * @param strDate String
+     * @param strFormat String
+     * @return FormatDate
+     * @throws ParseException ParseException
+     */
+    public static Date getFormatDate(String strDate, String strFormat) throws ParseException {
+        if (StringUtil.isEmpty(strDate) || StringUtil.isEmpty(strFormat)) {
+            return null;
+        }
+
+        SimpleDateFormat df = new SimpleDateFormat(strFormat);
+        df.setLenient(false);
+        return df.parse(strDate);
+    }
+
+    /**
+     * 按指定格式转化Date为字符串
+     *
+     * @param date Date
+     * @param toFormat String
+     * @return FormatDate String
+     */
+    public static String dateToString(Date date, String toFormat) {
+
+        if (date == null) {
+            return "";
+        }
+
+        SimpleDateFormat df = new SimpleDateFormat(toFormat);
+        df.setLenient(false);
+        return df.format(date);
+    }
+
+    /**
+     * 转换为指定格式Date
+     *
+     * @param date String
+     * @param strFormat String
+     * @return FormatDate
+     * @throws ParseException ParseException
+     */
+    public static Date formatDate(Date date, String strFormat) {
+        if (date == null) {
+            return null;
+        }
+        Date reDate = null;
+        try {
+            reDate = getFormatDate(dateToString(date, strFormat), strFormat);
+        } catch (ParseException e) {
+            date = null;
+        }
+        return reDate;
+    }
+
+    /**
      * 计算两个Date的日期差
      *
      * @param start
@@ -118,4 +199,36 @@ public class DateUtil {
                         LocalDate.ofInstant(end.toInstant(), DEFAULT_ZONE_ID),
                         LocalDate.ofInstant(start.toInstant(), DEFAULT_ZONE_ID));
     }
+
+    /**
+     * 根据指定格式,将Date转化为为字符串
+     *
+     * @param date
+     * @param format
+     * @return
+     */
+    public static String formatDateStr(Date date, String format) {
+        SimpleDateFormat dateFormat = new SimpleDateFormat(format);
+        dateFormat.setLenient(false);
+        return dateFormat.format(date);
+    }
+
+    /**
+     * 根据指定格式,将字符串解析为Date
+     *
+     * @param dateStr
+     * @param format
+     * @return
+     * @throws ParseException
+     */
+    public static Date parseDate(String dateStr, String format) {
+        try {
+            SimpleDateFormat dateFormat = new SimpleDateFormat(format);
+            dateFormat.setLenient(false);
+            return dateFormat.parse(dateStr);
+        } catch (ParseException e) {
+            log.error(e.getMessage(), e);
+            return null;
+        }
+    }
 }

+ 49 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/common/util/EnglishAnalyzer.java

@@ -0,0 +1,49 @@
+package org.jeecg.modules.adweb.common.util;
+
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.analysis.TokenStream;
+import org.apache.lucene.analysis.standard.StandardAnalyzer;
+import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 英文分词器
+ */
+public class EnglishAnalyzer {
+
+    public static List<String> analyze(String text, Analyzer analyzer) throws IOException {
+        List<String> result = new ArrayList<>();
+        TokenStream tokenStream = analyzer.tokenStream("", text);
+        CharTermAttribute attr = tokenStream.addAttribute(CharTermAttribute.class);
+        tokenStream.reset();
+        while (tokenStream.incrementToken()) {
+            result.add(attr.toString());
+        }
+        return result;
+    }
+
+    public static int getLongestSize(String text) {
+        if (StringUtils.isEmpty(text)) {
+            return 0;
+        }
+
+        List<String> result;
+        try {
+            result = analyze(text, new StandardAnalyzer());
+        } catch (Exception e) {
+            return 0;
+        }
+
+        if(ListUtil.isEmpty(result)){
+            return 0;
+        }
+
+        return result.stream().mapToInt(String::length).max().getAsInt();
+    }
+
+}

+ 150 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/common/util/GeoIpUtil.java

@@ -0,0 +1,150 @@
+package org.jeecg.modules.adweb.common.util;
+
+
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
+import com.maxmind.db.CHMCache;
+import com.maxmind.geoip2.DatabaseReader;
+import com.maxmind.geoip2.exception.GeoIp2Exception;
+import com.maxmind.geoip2.model.CityResponse;
+import com.maxmind.geoip2.record.Country;
+import com.maxmind.geoip2.record.Location;
+import com.maxmind.geoip2.record.Subdivision;
+import org.jeecg.modules.adweb.common.dto.CountryAreaApiDto;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.TimeZone;
+
+/**
+ * @description:
+ * @author: Cyan
+ * @time: 2019/12/16 10:33
+ */
+@Service
+public class GeoIpUtil {
+
+    private static final Logger log = LoggerFactory.getLogger(GeoIpUtil.class);
+    //GEOIp数据库实例
+    private static DatabaseReader reader = null;
+
+    @Value("${geoip.static.city.mmdb}")
+    private String geoipCityMmdb;
+
+    /**
+     * 获取数据库实例
+     *
+     * @param cityMmdb 可配的geoip城市静态数据库
+     * @return
+     * @author Cyan -- 2019/12/16 10:49
+     */
+    public DatabaseReader getDatabaseReader(String cityMmdb) {
+        if (null == reader) {
+            File database = new File(cityMmdb);
+            try {
+                reader = new DatabaseReader.Builder(database).withCache(new CHMCache()).build();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+        return reader;
+    }
+
+    /**
+     * 根据ip解析国家/区域
+     *
+     * @param ip
+     * @return 国家区域api对象
+     * @author Cyan -- 2019/12/16 12:15
+     */
+    public CountryAreaApiDto getCountryAndAreaByIp(String ip) {
+        CountryAreaApiDto dto = new CountryAreaApiDto();
+        try {
+            DatabaseReader reader = getDatabaseReader(geoipCityMmdb);
+            if(reader == null){
+                return dto;
+            }
+            InetAddress ipAddress = InetAddress.getByName(ip);
+            CityResponse response = reader.city(ipAddress);
+            //国家
+            Country country = response.getCountry();
+            dto.setCountryZhCN(country.getNames().get("zh-CN"));
+            if ("香港".equals(country.getNames().get("zh-CN"))) {
+                dto.setCountryZhCN("中国香港");
+            }
+            if ("台湾".equals(country.getNames().get("zh-CN"))) {
+                dto.setCountryZhCN("中国台湾");
+            }
+            if ("澳门".equals(country.getNames().get("zh-CN"))) {
+                dto.setCountryZhCN("中国澳门");
+            }
+            dto.setCountryIsoCode(country.getIsoCode());
+            //省份
+            Subdivision subdivision = response.getMostSpecificSubdivision();
+            dto.setSubdivisionIsoCode(subdivision.getIsoCode());
+            dto.setSubdivisionZhCN(subdivision.getNames().get("zh-CN"));
+            Location location = response.getLocation();
+            location.getTimeZone();
+            if (StringUtils.isNotBlank(location.getTimeZone())) {
+                dto.setTimeZone(location.getTimeZone());
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        } catch (GeoIp2Exception e) {
+            e.printStackTrace();
+        }
+        return dto;
+    }
+
+    /**
+     * 根据ip获取时区
+     * @param ip
+     * @return 时区
+     * @author Cyan -- 2020/3/9 10:58
+     */
+    public String getTimeZone(String ip) {
+        String timeZero = "";
+        try {
+            DatabaseReader reader = getDatabaseReader(geoipCityMmdb);
+            InetAddress ipAddress = InetAddress.getByName(ip);
+            CityResponse response = reader.city(ipAddress);
+            Location location = response.getLocation();
+            timeZero = location.getTimeZone();
+        } catch (Exception e) {
+            e.printStackTrace();
+            log.error("获取ip时区失败", e);
+        }
+        return timeZero;
+    }
+
+    /**
+     * 根据ip获取当地时区时间
+     * @param ip
+     * @return
+     * @author Cyan -- 2020/3/9 11:06
+     */
+    public Date getLocalhostTime(String ip,Date date) {
+        SimpleDateFormat sdf = new SimpleDateFormat(DateUtil.DATE_FORMAT_FIVE);
+        String timeZone = getTimeZone(ip);
+        if(StringUtils.isEmpty(timeZone)){
+            timeZone = "Asia/Shanghai";
+        }
+        sdf.setTimeZone(TimeZone.getTimeZone(timeZone));
+        String dateStr = sdf.format(date);
+        Date res = new Date();
+        try {
+            res = DateUtil.getFormatDate(dateStr,DateUtil.DATE_FORMAT_FIVE);
+        }catch (Exception e){
+            log.error("获取ip时区时间失败", e);
+        }
+        return res;
+    }
+
+
+}

+ 132 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/common/util/JedisUtil.java

@@ -0,0 +1,132 @@
+package org.jeecg.modules.adweb.common.util;
+
+import redis.clients.jedis.Jedis;
+import redis.clients.jedis.JedisPool;
+import redis.clients.jedis.JedisPoolConfig;
+import redis.clients.jedis.JedisPubSub;
+
+public class JedisUtil {
+    private static JedisPool jedisPool;
+
+    public static void initJedisPool(String jedisIp, int jedisPort, String jedisPassword) {
+
+        JedisPoolConfig config = new JedisPoolConfig();
+        config.setMaxIdle(256);
+        config.setTestOnBorrow(true);
+        config.setTestOnReturn(true);
+        config.setTestWhileIdle(true);
+        config.setMinEvictableIdleTimeMillis(60000L);
+        config.setTimeBetweenEvictionRunsMillis(3000L);
+        config.setNumTestsPerEvictionRun(-1);
+        if(jedisPassword == null || "".equals(jedisPassword)){
+            jedisPool=new JedisPool(config, jedisIp, jedisPort, 60000);
+        } else {
+            jedisPool=new JedisPool(config, jedisIp, jedisPort, 60000, jedisPassword);
+        }
+    }
+
+    /**
+     * 存储REDIS队列 顺序存储
+     * @param  key reids键名
+     * @param  value 键值
+     */
+    public static void lpush(byte[] key, byte[] value) {
+
+        Jedis jedis = null;
+        try {
+            jedis = jedisPool.getResource();
+            jedis.lpush(key, value);
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            //返还到连接池
+            if (jedis != null) {
+                jedis.close();
+            }
+        }
+    }
+
+    /**
+     * 存储REDIS队列 反向存储
+     * @param  key reids键名
+     * @param  value 键值
+     */
+    public static void rpush(byte[] key, byte[] value) {
+
+        Jedis jedis = null;
+        try {
+            jedis = jedisPool.getResource();
+            jedis.rpush(key, value);
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            //返还到连接池
+            if (jedis != null) {
+                jedis.close();
+            }
+        }
+    }
+
+    /**
+     * 获取队列数据
+     * @param  key 键名
+     * @return
+     */
+    public static byte[] rpop(byte[] key) {
+
+        byte[] bytes = null;
+        Jedis jedis = null;
+        try {
+            jedis = jedisPool.getResource();
+            bytes = jedis.rpop(key);
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            //返还到连接池
+            if (jedis != null) {
+                jedis.close();
+            }
+        }
+        return bytes;
+    }
+
+    /**
+     * 发送消息
+     * @param channel
+     * @param message
+     */
+    public static void publishMsg(String channel, String message) {
+        Jedis jedis = null;
+        try {
+            jedis = jedisPool.getResource();
+            jedis.publish(channel, message);
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            //返还到连接池
+            if (jedis != null) {
+                jedis.close();
+            }
+        }
+    }
+
+    /**
+     * 接收消息
+     * @param jedisPubSub
+     * @param channels
+     */
+    public static void subscribeMsg(JedisPubSub jedisPubSub, String channels) {
+        Jedis jedis = null;
+        try {
+            jedis = jedisPool.getResource();
+            jedis.subscribe(jedisPubSub, channels);
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            //返还到连接池
+            if (jedis != null) {
+                jedis.close();
+            }
+        }
+    }
+}

+ 139 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/common/util/SnowflakeIdUtil.java

@@ -0,0 +1,139 @@
+package org.jeecg.modules.adweb.common.util;
+
+
+import org.springframework.stereotype.Component;
+
+import java.util.Random;
+
+/**
+ * 自动生成雪花唯一id
+ */
+@Component
+public class SnowflakeIdUtil {
+
+    /**
+     * 开始时间截 (2015-01-01)
+     */
+    private final long twepoch = 1420041600000L;
+
+    /**
+     * 机器id所占的位数
+     */
+    private final long workerIdBits = 5L;
+
+    /**
+     * 数据标识id所占的位数
+     */
+    private final long datacenterIdBits = 5L;
+
+    /**
+     * 支持的最大机器id,结果是31 (这个移位算法可以很快的计算出几位二进制数所能表示的最大十进制数)
+     */
+    private final long maxWorkerId = -1L ^ (-1L << workerIdBits);
+
+    /**
+     * 支持的最大数据标识id,结果是31
+     */
+    private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
+
+    /**
+     * 序列在id中占的位数
+     */
+    private final long sequenceBits = 12L;
+
+    /**
+     * 机器ID向左移12位
+     */
+    private final long workerIdShift = sequenceBits;
+
+    /**
+     * 数据标识id向左移17位(12+5)
+     */
+    private final long datacenterIdShift = sequenceBits + workerIdBits;
+
+    /**
+     * 时间截向左移22位(5+5+12)
+     */
+    private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
+
+    /**
+     * 生成序列的掩码,这里为4095 (0b111111111111=0xfff=4095)
+     */
+    private final long sequenceMask = -1L ^ (-1L << sequenceBits);
+
+    /**
+     * 毫秒内序列(0~4095)
+     */
+    private long sequence = 0L;
+
+    /**
+     * 上次生成ID的时间截
+     */
+    private long lastTimestamp = -1L;
+
+    /**
+     * 获得下一个ID (该方法是线程安全的)
+     *
+     * @return SnowflakeId
+     */
+    public synchronized long nextId() {
+        long timestamp = timeGen();
+
+        //如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退过这个时候应当抛出异常
+        if (timestamp < lastTimestamp) {
+            throw new RuntimeException(
+                    String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
+        }
+
+        //如果是同一时间生成的,则进行毫秒内序列
+        if (lastTimestamp == timestamp) {
+            sequence = (sequence + 1) & sequenceMask;
+            //毫秒内序列溢出
+            if (sequence == 0) {
+                //阻塞到下一个毫秒,获得新的时间戳
+                timestamp = tilNextMillis(lastTimestamp);
+            }
+        }
+        //时间戳改变,毫秒内序列重置
+        else {
+            sequence = 0L;
+        }
+
+        //上次生成ID的时间截
+        lastTimestamp = timestamp;
+
+        Random random = new Random();
+        long workerId = random.nextInt(30);
+        long datacenterId = random.nextInt(30);
+
+        //移位并通过或运算拼到一起组成64位的ID
+        return ((timestamp - twepoch) << timestampLeftShift) //
+                | (datacenterId << datacenterIdShift) //
+                | (workerId << workerIdShift) //
+                | sequence;
+    }
+
+    /**
+     * 阻塞到下一个毫秒,直到获得新的时间戳
+     *
+     * @param lastTimestamp 上次生成ID的时间截
+     * @return 当前时间戳
+     */
+    protected long tilNextMillis(long lastTimestamp) {
+        long timestamp = timeGen();
+        while (timestamp <= lastTimestamp) {
+            timestamp = timeGen();
+        }
+        return timestamp;
+    }
+
+    /**
+     * 返回以毫秒为单位的当前时间
+     *
+     * @return 当前时间(毫秒)
+     */
+    protected long timeGen() {
+        return System.currentTimeMillis();
+    }
+
+}

+ 14 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/constant/EnquiryConstants.java

@@ -0,0 +1,14 @@
+package org.jeecg.modules.adweb.enquiry.constant;
+
+public class EnquiryConstants {
+    public static final String ENQUIRY_SITE = "enquirySite";
+
+    public static final String ENQUIRY_CHANNEL = "enquiry_channel";
+
+    public static final String ENQUIRY_EMAIL = "enquiry_email";
+
+    public static final String ENQUIRY_EMAIL_CHANNEL = "enquiry_email_channel";
+
+    //独立询盘
+    public static final String ENQUIRY_MODULAR_INDEPENDENT = "independent";
+}

+ 12 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/constant/EnquirySendStatus.java

@@ -0,0 +1,12 @@
+package org.jeecg.modules.adweb.enquiry.constant;
+
+public class EnquirySendStatus {
+
+    public static final String WAIT_SEND = "WAIT_SEND";
+
+    public static final String SENDING = "SENDING";
+
+    public static final String SEND_SUCCESS = "SEND_SUCCESS";
+
+    public static final String SEND_FAIL = "SEND_FAIL";
+}

+ 3 - 3
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/controller/AdwebEnquiryController.java

@@ -21,7 +21,7 @@ import org.jeecg.common.system.base.controller.JeecgController;
 import org.jeecg.common.system.vo.DictModel;
 import org.jeecg.common.system.vo.LoginUser;
 import org.jeecg.common.util.FastJsonUtil;
-import org.jeecg.modules.adweb.common.constant.CompConstants;
+import org.jeecg.modules.adweb.common.constant.AdwebConstant;
 import org.jeecg.modules.adweb.common.util.DateUtil;
 import org.jeecg.modules.adweb.common.util.ListUtil;
 import org.jeecg.modules.adweb.enquiry.dto.param.AdmpEnquirySearchDto;
@@ -86,7 +86,7 @@ public class AdwebEnquiryController extends JeecgController<AdwebEnquiry, IAdweb
      * @param searchDto
      * @param pageNo
      * @param pageSize
-     * @param req
+     * @param principalUid
      * @return
      */
     //@AutoLog(value = "询盘信息存储表单-分页列表查询")
@@ -180,7 +180,7 @@ public class AdwebEnquiryController extends JeecgController<AdwebEnquiry, IAdweb
             return;
         }
         LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
-        List<DictModel> userEffectiveDict = sysDictService.queryDictItemsByCode(CompConstants.ADMP_ENQUIRY_EFFECTIVE);
+        List<DictModel> userEffectiveDict = sysDictService.queryDictItemsByCode(AdwebConstant.ENQUIRY_EFFECTIVE);
         AtomicInteger atomicInteger = new AtomicInteger();
 
         enquiryList.forEach(enquiry -> {

+ 20 - 5
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/dto/EnquiryDTO.java

@@ -1,16 +1,31 @@
 package org.jeecg.modules.adweb.enquiry.dto;
 
+import com.fasterxml.jackson.annotation.JsonFormat;
 import lombok.Data;
 
+import java.util.Date;
+
 /**
  * @author wfansh
  */
 @Data
 public class EnquiryDTO {
+    //站点code,关联站点表
+    private String siteCode;
+    private String fromEmail;
+    private Object forms;
+    private String pluginName;
+    private String fromIp;
+    private String siteHost;
 
-    private long id;
-
-    private String msg;
-
-    // TODO
+    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date recordCtime;
+    private String recordId;
+    //访问人id
+    private String visitId;
+    //站点id
+    private Integer siteId;
+    private String siteToken;
+    private String formName;
+    private Object cartItems;
 }

+ 26 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/dto/IndependentEnquiryDto.java

@@ -0,0 +1,26 @@
+package org.jeecg.modules.adweb.enquiry.dto;
+
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class IndependentEnquiryDto {
+    private String name;
+    private String email;
+    private String company;
+    private String phone;
+    private String message;
+    private String siteCode;
+    private String pageHref;
+    private String pageTitle;
+    private String fromPage;
+    private List<String> job;
+    // 简历路径
+    private String path;
+    private String country;
+    private String whatsApp;
+    public String dealFromPage() {
+        return this.pageTitle + " " + this.pageHref;
+    }
+}

+ 16 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/dto/param/EffectiveEnquiryParamDto.java

@@ -0,0 +1,16 @@
+package org.jeecg.modules.adweb.enquiry.dto.param;
+
+import lombok.Data;
+
+/**
+ * 有效询盘参数
+ */
+@Data
+public class EffectiveEnquiryParamDto {
+    private String id;
+    private Integer siteId;
+    private String siteCode;
+    private Integer userEffective;
+    private String wasteEnquiryType;
+    private String wasteEnquirySeason;
+}

+ 18 - 9
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/entity/AdwebEnquiry.java

@@ -4,10 +4,8 @@ import java.io.Serializable;
 import java.io.UnsupportedEncodingException;
 import java.util.Date;
 import java.math.BigDecimal;
-import com.baomidou.mybatisplus.annotation.IdType;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
-import com.baomidou.mybatisplus.annotation.TableLogic;
+
+import com.baomidou.mybatisplus.annotation.*;
 import lombok.Data;
 import com.fasterxml.jackson.annotation.JsonFormat;
 import org.springframework.format.annotation.DateTimeFormat;
@@ -47,9 +45,9 @@ public class AdwebEnquiry implements Serializable {
 	@Excel(name = "询盘发送者邮箱账号", width = 15)
     @Schema(description = "询盘发送者邮箱账号")
     private String fromEmail;
-	/**询盘模块:admp_web:admp网站询盘 ;email:邮件询盘  ;diy_element:自定义组件询盘*/
-	@Excel(name = "询盘模块:admp_web:admp网站询盘 ;email:邮件询盘  ;diy_element:自定义组件询盘", width = 15)
-    @Schema(description = "询盘模块:admp_web:admp网站询盘 ;email:邮件询盘  ;diy_element:自定义组件询盘")
+	/**询盘模块:web:网站询盘 ;email:邮件询盘  ;diy_element:自定义组件询盘*/
+	@Excel(name = "询盘模块:web:网站询盘 ;email:邮件询盘  ;diy_element:自定义组件询盘", width = 15)
+    @Schema(description = "询盘模块:web:网站询盘 ;email:邮件询盘  ;diy_element:自定义组件询盘")
     private String modular;
 	/**发送人姓名*/
 	@Excel(name = "发送人姓名", width = 15)
@@ -248,8 +246,7 @@ public class AdwebEnquiry implements Serializable {
     @Schema(description = "手机号")
     private String phone;
 	/**whatsapp*/
-	@Excel(name = "whatsapp", width = 15)
-    @Schema(description = "whatsapp")
+
     private String whatsapp;
 	/**阅读状态,0是未阅读,1是已阅读*/
 	@Excel(name = "阅读状态,0是未阅读,1是已阅读", width = 15)
@@ -295,4 +292,16 @@ public class AdwebEnquiry implements Serializable {
 	@Excel(name = "询盘关联产品", width = 15)
     @Schema(description = "询盘关联产品")
     private String cartItems;
+
+    /**
+     * 用于判断是否是·产品询盘·
+     * */
+    @TableField(exist = false)
+    private Integer  existProductEnquiry;
+
+    /**
+     * 用于判断是否是同步询盘进行发送询盘邮件
+     * */
+    @TableField(exist = false)
+    private String isEnquirySync;
 }

+ 73 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/entity/AdwebEnquiryBlacklist.java

@@ -0,0 +1,73 @@
+package org.jeecg.modules.adweb.enquiry.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.jeecgframework.poi.excel.annotation.Excel;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * @Description: adweb_enquiry_blacklist
+ * @Author: jeecg-boot
+ * @Date:   2022-08-05
+ * @Version: V1.0
+ */
+@Data
+@TableName("adweb_enquiry_blacklist")
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = false)
+@Schema(description="adweb_enquiry_blacklist")
+public class AdwebEnquiryBlacklist implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+	/**id*/
+	@TableId(type = IdType.AUTO)
+    @Schema(description = "id")
+    private Integer id;
+    private Integer siteId;
+	/**来源询盘*/
+	@Excel(name = "来源询盘", width = 15)
+    @Schema(description = "来源询盘")
+    private Long enquiryId;
+	/**姓名*/
+	@Excel(name = "姓名", width = 15)
+    @Schema(description = "姓名")
+    private String name;
+	/**邮箱*/
+	@Excel(name = "邮箱", width = 15)
+    @Schema(description = "邮箱")
+    private String email;
+	/**电话*/
+	@Excel(name = "电话", width = 15)
+    @Schema(description = "电话")
+    private String phone;
+	/**whatsapp*/
+	@Excel(name = "whatsapp", width = 15)
+    @Schema(description = "whatsapp")
+    private String whatsapp;
+	/**国家编码*/
+	@Excel(name = "国家编码", width = 15)
+    @Schema(description = "国家编码")
+    private String countryCode;
+	/**国家名称*/
+	@Excel(name = "国家名称", width = 15)
+    @Schema(description = "国家名称")
+    private String countryName;
+	/**0删除状态,1正常状态*/
+	@Excel(name = "0删除状态,1正常状态", width = 15)
+    @Schema(description = "0删除状态,1正常状态")
+    private Integer status;
+	/**创建时间*/
+	@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern="yyyy-MM-dd")
+    @Schema(description = "创建时间")
+    private Date createTime;
+}

+ 46 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/entity/AdwebEnquiryForm.java

@@ -0,0 +1,46 @@
+package org.jeecg.modules.adweb.enquiry.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.jeecgframework.poi.excel.annotation.Excel;
+
+import java.io.Serializable;
+
+/**
+ * @Description: adweb_enquiry_form
+ * @Author: jeecg-boot
+ * @Date:   2022-08-03
+ * @Version: V1.0
+ */
+@Data
+@TableName("adweb_enquiry_form")
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = false)
+@Schema(description="adweb_enquiry_form")
+public class AdwebEnquiryForm implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+	/**id*/
+	@TableId(type = IdType.AUTO)
+    @Schema(description = "id")
+    private Integer id;
+	/**询盘id*/
+	@Excel(name = "询盘id", width = 15)
+    @Schema(description = "询盘id")
+    private Long enquiryId;
+	/**询盘的表单内容*/
+	@Excel(name = "询盘的表单内容", width = 15)
+    @Schema(description = "询盘的表单内容")
+    private String form;
+    /**询盘插件名称*/
+    @Excel(name = "询盘插件名称", width = 15)
+    @Schema(description = "询盘插件名称")
+    private String pluginName;
+
+    private String country;
+}

+ 64 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/entity/AdwebPublicBlackEmail.java

@@ -0,0 +1,64 @@
+package org.jeecg.modules.adweb.enquiry.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.jeecgframework.poi.excel.annotation.Excel;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * @Description: 询盘公共邮箱黑名单
+ * @Author: jeecg-boot
+ * @Date:   2023-02-15
+ * @Version: V1.0
+ */
+@Data
+@TableName("adweb_public_black_email")
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = false)
+@Schema(description="询盘公共邮箱黑名单")
+public class AdwebPublicBlackEmail implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+	/**主键*/
+	@TableId(type = IdType.ASSIGN_ID)
+    @Schema(description = "主键")
+    private String id;
+	/**创建日期*/
+	@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+    @Schema(description = "创建日期")
+    private Date createTime;
+	/**邮箱*/
+	@Excel(name = "邮箱", width = 15)
+    @Schema(description = "邮箱")
+    private String email;
+    @Excel(name = "黑名单或白名单", width = 15)
+    @Schema(description = "黑名单或白名单")
+    private Integer blackOrWhite;
+	/**0为已删除,1为使用中*/
+	@Excel(name = "0为已删除,1为使用中", width = 15)
+    @Schema(description = "0为已删除,1为使用中")
+    private Integer status;
+
+    @TableField(exist = false)
+    private Integer wasteEnquiryNum;
+
+    public AdwebPublicBlackEmail() {
+    }
+
+    public AdwebPublicBlackEmail(String email, Integer status, Integer blackOrWhite) {
+        this.email = email;
+        this.status = status;
+        this.blackOrWhite = blackOrWhite;
+    }
+}

+ 65 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/entity/AdwebPublicBlackIp.java

@@ -0,0 +1,65 @@
+package org.jeecg.modules.adweb.enquiry.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.jeecgframework.poi.excel.annotation.Excel;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * @Description: IP黑名单
+ * @Author: jeecg-boot
+ * @Date:   2023-02-20
+ * @Version: V1.0
+ */
+@Data
+@TableName("adweb_public_black_ip")
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = false)
+@Schema(description="IP黑名单")
+public class AdwebPublicBlackIp implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+	/**主键*/
+	@TableId(type = IdType.ASSIGN_ID)
+    @Schema(description = "主键")
+    private String id;
+	/**创建日期*/
+	@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+    @Schema(description = "创建日期")
+    private Date createTime;
+	/**状态*/
+	@Excel(name = "状态", width = 15)
+    @Schema(description = "状态")
+    private Integer status;
+	/**ip*/
+	@Excel(name = "ip", width = 15)
+    @Schema(description = "ip")
+    private String ip;
+	/**黑名单或白名单*/
+	@Excel(name = "黑名单或白名单", width = 15)
+    @Schema(description = "黑名单或白名单")
+    private Integer blackOrWhite;
+
+	@TableField(exist = false)
+    private Integer wasteEnquiryNum;
+
+    public AdwebPublicBlackIp() {
+    }
+
+    public AdwebPublicBlackIp(String ip, Integer status, Integer blackOrWhite) {
+        this.status = status;
+        this.ip = ip;
+        this.blackOrWhite = blackOrWhite;
+    }
+}

+ 72 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/entity/AdwebPublicEnquiryRule.java

@@ -0,0 +1,72 @@
+package org.jeecg.modules.adweb.enquiry.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.jeecgframework.poi.excel.annotation.Excel;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * @Description: 用于询盘公共规则过滤
+ * @Author: jeecg-boot
+ * @Date:   2024-10-17
+ * @Version: V1.0
+ */
+@Data
+@TableName("adweb_public_enquiry_rule")
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = false)
+@Schema(description="用于询盘规则过滤")
+public class AdwebPublicEnquiryRule implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+	/**主键*/
+	@TableId(type = IdType.ASSIGN_ID)
+    @Schema(description = "主键")
+    private String id;
+	/**创建日期*/
+	@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm")
+    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm")
+    @Schema(description = "创建日期")
+    private Date createTime;
+	/**状态0为删除1为使用中*/
+	@Excel(name = "状态0为删除1为使用中", width = 15)
+    @Schema(description = "状态0为删除1为使用中")
+    private Integer status;
+	/**关键词*/
+	@Excel(name = "关键词", width = 15)
+    @Schema(description = "关键词")
+    private String word;
+
+    /**
+     * 关键词翻译
+     */
+    @Excel(name = "关键词翻译", width = 15)
+    @Schema(description = "关键词翻译")
+	private String translateWord;
+
+	/**黑名单或白名单0为黑名单,1为白名单*/
+	@Excel(name = "黑名单或白名单0为黑名单,1为白名单", width = 15)
+    @Schema(description = "黑名单或白名单0为黑名单,1为白名单")
+    private Integer blackOrWhiteList;
+	/**是否启用该字段1为启用0为停用*/
+	@Excel(name = "是否启用该字段1为启用0为停用", width = 15)
+    @Schema(description = "是否启用该字段1为启用0为停用")
+    private Integer isEnable;
+
+    @Excel(name = "1为openAi0为询盘关键词", width = 15)
+    @Schema(description = "1为openAi0为询盘关键词")
+    private Integer useStatus;
+
+    @TableField(exist = false)
+    private Integer wasteEnquiryNum;
+}

+ 86 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/entity/AdwebSiteBlackEmail.java

@@ -0,0 +1,86 @@
+package org.jeecg.modules.adweb.enquiry.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.jeecgframework.poi.excel.annotation.Excel;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * @Description: adweb_site_black_email
+ * @Author: jeecg-boot
+ * @Date:   2024-10-17
+ * @Version: V1.0
+ */
+@Data
+@TableName("adweb_site_black_email")
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = false)
+@Schema(description="adweb_site_black_email")
+public class AdwebSiteBlackEmail implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+	/**id*/
+	@TableId(type = IdType.ASSIGN_ID)
+    @Schema(description = "id")
+    private String id;
+	/**站点id*/
+	@Excel(name = "站点id", width = 15)
+    @Schema(description = "站点id")
+    private Integer siteId;
+    /**站点code*/
+    @Excel(name = "站点code", width = 15)
+    @Schema(description = "站点code")
+    private String siteCode;
+	/**邮箱*/
+	@Excel(name = "邮箱", width = 15)
+    @Schema(description = "邮箱")
+    private String email;
+	/**黑名单类型,0:通配,1:完全匹配*/
+	@Excel(name = "黑名单类型,0:通配,1:完全匹配", width = 15)
+    @Schema(description = "黑名单类型,0:通配,1:完全匹配")
+    private String type;
+	/**0为已删除,1为使用中*/
+	@Excel(name = "0为已删除,1为使用中", width = 15)
+    @Schema(description = "0为已删除,1为使用中")
+    private Integer status;
+	/**0黑名单,1白名单*/
+	@Excel(name = "0黑名单,1白名单", width = 15)
+    @Schema(description = "0黑名单,1白名单")
+    private Integer blackOrWhite;
+	/**创建日期*/
+	@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern="yyyy-MM-dd")
+    @Schema(description = "创建日期")
+    private Date createTime;
+	/**更新时间*/
+	@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern="yyyy-MM-dd")
+    @Schema(description = "更新时间")
+    private Date updateTime;
+
+    /**站点名称*/
+    @TableField(exist = false)
+    private String siteName;
+
+    /**
+     * 完全匹配
+     */
+    @TableField(exist = false)
+    private Integer wasteEnquiryNum;
+
+    /**
+     * 通配
+     */
+    @TableField(exist = false)
+    private Integer wasteGeneralEnquiryNum;
+}

+ 68 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/entity/AdwebSiteBlackIp.java

@@ -0,0 +1,68 @@
+package org.jeecg.modules.adweb.enquiry.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.jeecgframework.poi.excel.annotation.Excel;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * @Description: adweb_site_black_ip
+ * @Author: jeecg-boot
+ * @Date:   2023-08-31
+ * @Version: V1.0
+ */
+@Data
+@TableName("adweb_site_black_ip")
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = false)
+@Schema(description="adweb_site_black_ip")
+public class AdwebSiteBlackIp implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+	/**id*/
+	@TableId(type = IdType.ASSIGN_ID)
+    @Schema(description = "id")
+    private String id;
+	/**站点id*/
+	@Excel(name = "站点id", width = 15)
+    @Schema(description = "站点id")
+    private Integer siteId;
+	/**站点code*/
+	@Excel(name = "站点code", width = 15)
+    @Schema(description = "站点code")
+    private String siteCode;
+	/**状态*/
+	@Excel(name = "状态", width = 15)
+    @Schema(description = "状态")
+    private Integer status;
+	/**ip*/
+	@Excel(name = "ip", width = 15)
+    @Schema(description = "ip")
+    private String ip;
+	/**黑名单或白名单*/
+	@Excel(name = "黑名单或白名单", width = 15)
+    @Schema(description = "黑名单或白名单")
+    private Integer blackOrWhite;
+	/**创建日期*/
+	@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+    @Schema(description = "创建日期")
+    private Date createTime;
+
+    /**站点名称*/
+    @TableField(exist = false)
+    private String siteName;
+
+    @TableField(exist = false)
+    private Integer wasteEnquiryNum;
+}

+ 67 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/entity/AdwebSiteEnquiryRule.java

@@ -0,0 +1,67 @@
+package org.jeecg.modules.adweb.enquiry.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.jeecgframework.poi.excel.annotation.Excel;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * @Description: adweb_enquiry_site_rule
+ * @Author: jeecg-boot
+ * @Date:   2023-08-31
+ * @Version: V1.0
+ */
+@Data
+@TableName("adweb_site_enquiry_rule")
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = false)
+@Schema(description="adweb_site_enquiry_rule")
+public class AdwebSiteEnquiryRule implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+	/**id*/
+	@TableId(type = IdType.ASSIGN_ID)
+    @Schema(description = "id")
+    private String id;
+	/**站点id*/
+	@Excel(name = "站点id", width = 15)
+    @Schema(description = "站点id")
+    private Integer siteId;
+	/**站点code*/
+	@Excel(name = "站点code", width = 15)
+    @Schema(description = "站点code")
+    private String siteCode;
+	/**状态0为删除1为使用中*/
+	@Excel(name = "状态0为删除1为使用中", width = 15)
+    @Schema(description = "状态0为删除1为使用中")
+    private Integer status;
+	/**关键词*/
+	@Excel(name = "关键词", width = 15)
+    @Schema(description = "关键词")
+    private String word;
+	/**黑名单或白名单0为黑名单,1为白名单*/
+	@Excel(name = "黑名单或白名单0为黑名单,1为白名单", width = 15)
+    @Schema(description = "黑名单或白名单0为黑名单,1为白名单")
+    private Integer blackOrWhite;
+	/**创建日期*/
+	@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+    @Schema(description = "创建日期")
+    private Date createTime;
+
+    @TableField(exist = false)
+    private Integer wasteEnquiryNum;
+
+    @TableField(exist = false)
+    private String siteName;
+}

+ 75 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/entity/EnquiryEmailMessage.java

@@ -0,0 +1,75 @@
+package org.jeecg.modules.adweb.enquiry.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.jeecgframework.poi.excel.annotation.Excel;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * @Description: adweb_enquiry_email_message
+ * @Author: jeecg-boot
+ * @Date:   2023-02-01
+ * @Version: V1.0
+ */
+@Data
+@TableName("adweb_enquiry_email_message")
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = false)
+@Schema(description="adweb_enquiry_email_message")
+public class EnquiryEmailMessage implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+	/**id*/
+	@TableId(type = IdType.AUTO)
+    @Schema(description = "id")
+    private Integer id;
+	/**询盘id*/
+	@Excel(name = "询盘id", width = 15)
+    @Schema(description = "询盘id")
+    private Long enquiryId;
+	/**站点code*/
+	@Excel(name = "站点code", width = 15)
+    @Schema(description = "站点code")
+    private String siteCode;
+	/**邮箱*/
+	@Excel(name = "邮箱", width = 15)
+    @Schema(description = "邮箱")
+    private String email;
+    /**原始询盘发送人邮箱*/
+    @Excel(name = "原始询盘发送人邮箱", width = 15)
+    @Schema(description = "邮箱")
+    private String fromEmail;
+	/**发送状态*/
+	@Excel(name = "发送状态", width = 15)
+    @Schema(description = "发送状态")
+    private String sendStatus;
+	/**发送错误数量*/
+	@Excel(name = "发送错误数量", width = 15)
+    @Schema(description = "发送错误数量")
+    private Integer sendErrorNum;
+	/**开始处理时间*/
+	@Excel(name = "开始处理时间", width = 15, format = "yyyy-MM-dd")
+	@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern="yyyy-MM-dd")
+    @Schema(description = "开始处理时间")
+    private Date sendStartTime;
+	/**发送错误*/
+	@Excel(name = "发送错误", width = 15)
+    @Schema(description = "发送错误")
+    private String sendErrorMsg;
+	/**创建时间*/
+	@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern="yyyy-MM-dd")
+    @Schema(description = "创建时间")
+    private Date createTime;
+
+}

+ 14 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/mapper/AdwebEnquiryBlacklistMapper.java

@@ -0,0 +1,14 @@
+package org.jeecg.modules.adweb.enquiry.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.jeecg.modules.adweb.enquiry.entity.AdwebEnquiryBlacklist;
+
+/**
+ * @Description: adweb_enquiry_blacklist
+ * @Author: jeecg-boot
+ * @Date:   2022-08-05
+ * @Version: V1.0
+ */
+public interface AdwebEnquiryBlacklistMapper extends BaseMapper<AdwebEnquiryBlacklist> {
+
+}

+ 14 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/mapper/AdwebEnquiryFormMapper.java

@@ -0,0 +1,14 @@
+package org.jeecg.modules.adweb.enquiry.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.jeecg.modules.adweb.enquiry.entity.AdwebEnquiryForm;
+
+/**
+ * @Description: adweb_enquiry_form
+ * @Author: jeecg-boot
+ * @Date:   2022-08-03
+ * @Version: V1.0
+ */
+public interface AdwebEnquiryFormMapper extends BaseMapper<AdwebEnquiryForm> {
+
+}

+ 16 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/mapper/AdwebPublicBlackEmailMapper.java

@@ -0,0 +1,16 @@
+package org.jeecg.modules.adweb.enquiry.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.jeecg.modules.adweb.enquiry.entity.AdwebPublicBlackEmail;
+
+/**
+ * @Description: 询盘公共邮箱黑名单
+ * @Author: jeecg-boot
+ * @Date:   2023-02-15
+ * @Version: V1.0
+ */
+public interface AdwebPublicBlackEmailMapper extends BaseMapper<AdwebPublicBlackEmail> {
+    IPage<AdwebPublicBlackEmail> pageList(Page<AdwebPublicBlackEmail> page, String email, Integer blackOrWhite,String column,String order);
+}

+ 16 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/mapper/AdwebPublicBlackIpMapper.java

@@ -0,0 +1,16 @@
+package org.jeecg.modules.adweb.enquiry.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.jeecg.modules.adweb.enquiry.entity.AdwebPublicBlackIp;
+
+/**
+ * @Description: IP黑名单
+ * @Author: jeecg-boot
+ * @Date:   2023-02-20
+ * @Version: V1.0
+ */
+public interface AdwebPublicBlackIpMapper extends BaseMapper<AdwebPublicBlackIp> {
+    IPage<AdwebPublicBlackIp> pageList(Page<AdwebPublicBlackIp> page, String ip, Integer blackOrWhite,String column,String order);
+}

+ 15 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/mapper/AdwebPublicEnquiryRuleMapper.java

@@ -0,0 +1,15 @@
+package org.jeecg.modules.adweb.enquiry.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.jeecg.modules.adweb.enquiry.entity.AdwebPublicEnquiryRule;
+
+/**
+ * @Description: 用于询盘规则过滤
+ *
+ */
+
+public interface AdwebPublicEnquiryRuleMapper extends BaseMapper<AdwebPublicEnquiryRule> {
+    IPage<AdwebPublicEnquiryRule> pageList(Page<AdwebPublicEnquiryRule> page, String word, Integer blackOrWhiteList, Integer isEnable, Integer useStatus,String column,String order);
+}

+ 26 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/mapper/AdwebSiteBlackEmailMapper.java

@@ -0,0 +1,26 @@
+package org.jeecg.modules.adweb.enquiry.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.jeecg.modules.adweb.enquiry.entity.AdwebSiteBlackEmail;
+
+import java.util.List;
+
+/**
+ * @Description: enquiry_site_black_email
+ * @Author: jeecg-boot
+ * @Date:   2023-06-28
+ * @Version: V1.0
+ */
+public interface AdwebSiteBlackEmailMapper extends BaseMapper<AdwebSiteBlackEmail> {
+
+    /**
+     * 获取分页列表数据
+     * @param page
+     * @param enquirySiteBlackEmail
+     * @param codeList
+     * @return
+     */
+    IPage<AdwebSiteBlackEmail> getPageList(Page<AdwebSiteBlackEmail> page, AdwebSiteBlackEmail enquirySiteBlackEmail, List<String> codeList,String column,String order);
+}

+ 19 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/mapper/AdwebSiteBlackIpMapper.java

@@ -0,0 +1,19 @@
+package org.jeecg.modules.adweb.enquiry.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.jeecg.modules.adweb.enquiry.entity.AdwebSiteBlackIp;
+
+import java.util.List;
+
+/**
+ * @Description: adweb_site_black_ip
+ * @Author: jeecg-boot
+ * @Date:   2023-08-31
+ * @Version: V1.0
+ */
+public interface AdwebSiteBlackIpMapper extends BaseMapper<AdwebSiteBlackIp> {
+
+    IPage<AdwebSiteBlackIp> getPageList(Page<AdwebSiteBlackIp> page, AdwebSiteBlackIp adwebSiteBlackIp, List<String> codeList, String column, String order);
+}

+ 18 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/mapper/AdwebSiteEnquiryRuleMapper.java

@@ -0,0 +1,18 @@
+package org.jeecg.modules.adweb.enquiry.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.jeecg.modules.adweb.enquiry.entity.AdwebSiteEnquiryRule;
+
+import java.util.List;
+
+/**
+ * @Description: adweb_enquiry_site_rule
+ * @Author: jeecg-boot
+ * @Date:   2023-08-31
+ * @Version: V1.0
+ */
+public interface AdwebSiteEnquiryRuleMapper extends BaseMapper<AdwebSiteEnquiryRule> {
+    IPage<AdwebSiteEnquiryRule> pageList(Page<AdwebSiteEnquiryRule> page, AdwebSiteEnquiryRule adwebEnquirySiteRule,List<String> codeList);
+}

+ 27 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/mapper/EnquiryEmailMessageMapper.java

@@ -0,0 +1,27 @@
+package org.jeecg.modules.adweb.enquiry.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.jeecg.modules.adweb.enquiry.entity.EnquiryEmailMessage;
+
+import java.util.List;
+
+/**
+ * @Description: adweb_enquiry_email_message
+ * @Author: jeecg-boot
+ * @Date:   2023-02-01
+ * @Version: V1.0
+ */
+public interface EnquiryEmailMessageMapper extends BaseMapper<EnquiryEmailMessage> {
+
+    /**
+     * 获取待发送询盘
+     * 1、首次发送失败的
+     * 2、超过timeout分钟未处理的
+     *
+     * @param timeout 留给首次实时处理的时间,单位分钟,超过这个时间则认为首次邮件发送失败,应该由定时器处理
+     * @param num     获取邮件数量
+     * @return 邮件列表
+     */
+    List<EnquiryEmailMessage> getWaitSendEmail(int timeout, int num);
+
+}

+ 5 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/mapper/xml/AdwebEnquiryFormMapper.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.jeecg.modules.adweb.enquiry.mapper.AdwebEnquiryFormMapper">
+
+</mapper>

+ 39 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/mapper/xml/AdwebEnquirySiteRuleMapper.xml

@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.jeecg.modules.adweb.enquiry.mapper.AdwebSiteEnquiryRuleMapper">
+    <select id="pageList" resultType="org.jeecg.modules.adweb.enquiry.entity.AdwebSiteEnquiryRule">
+        SELECT t1.*, t2.num wasteEnquiryNum,t3.`name` siteName
+        FROM `adweb_enquiry_site_rule` t1
+        LEFT JOIN (
+            SELECT
+                   t1.reason,t1.site_code,count(*) num
+            FROM
+            (
+                SELECT SUBSTRING_INDEX(effective_reason,'-',-1) reason,site_code
+                FROM `adweb_enquiry`
+                WHERE `status` = 1 AND user_effective = 0 AND sys_effective = 1 AND waste_enquiry_type = 'keyword'
+            ) t1 GROUP BY t1.reason,t1.site_code
+        ) t2 ON t2.reason LIKE CONCAT('%',t1.word,'%') AND t2.site_code = t1.site_code,adweb_site t3
+        WHERE t1.site_id = t3.id
+        AND t1.status = 1
+        <if test="codeList != null">
+            <choose>
+                <when test="codeList.size() != 0">
+                    AND t1.site_code IN
+                    <foreach collection="codeList" item="code" open="(" close=")" separator=",">
+                        #{code}
+                    </foreach>
+                </when>
+            </choose>
+        </if>
+        <if test = "adwebEnquirySiteRule.siteId != null and adwebEnquirySiteRule.siteId != ''" >
+            AND t1.site_id = #{adwebEnquirySiteRule.siteId}
+        </if>
+        <if test="adwebEnquirySiteRule.word != null and adwebEnquirySiteRule.word != ''">
+            AND t1.word like CONCAT('%', #{adwebEnquirySiteRule.word}, '%')
+        </if>
+        <if test="adwebEnquirySiteRule.blackOrWhite != null">
+            AND t1.black_or_white = #{adwebEnquirySiteRule.blackOrWhite}
+        </if>
+    </select>
+</mapper>

+ 31 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/mapper/xml/AdwebPublicBlackEmailMapper.xml

@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.jeecg.modules.adweb.enquiry.mapper.AdwebPublicBlackEmailMapper">
+    <select id="pageList" resultType="org.jeecg.modules.adweb.enquiry.entity.AdwebPublicBlackEmail">
+        SELECT t1.*, t2.num wasteEnquiryNum
+        FROM `enquiry_public_black_email` t1
+                 LEFT JOIN (SELECT COUNT(*) num, from_email
+                            FROM adweb_enquiry
+                            WHERE `status` = 1
+                              AND user_effective = 0
+                              AND sys_effective = 1
+                              AND waste_enquiry_type = 'email'
+                            GROUP BY from_email) t2 ON t1.email = t2.from_email
+        WHERE t1.`status` != 0
+        <if test="email != null and email != ''">
+            AND t1.email like CONCAT('%', #{email}, '%')
+        </if>
+        <if test="blackOrWhite != null">
+            AND t1.black_or_white = #{blackOrWhite}
+        </if>
+        <if test = "column != null and column != ''">
+          ORDER BY
+          <if test = "column == 'createTime'">
+            t1.create_time ${order}
+          </if>
+           <if test = "column == 'email'">
+            t1.email ${order}
+          </if>
+        </if>
+    </select>
+</mapper>

+ 32 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/mapper/xml/AdwebPublicBlackIpMapper.xml

@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.jeecg.modules.adweb.enquiry.mapper.AdwebPublicBlackIpMapper">
+    <select id="pageList" resultType="org.jeecg.modules.adweb.enquiry.entity.AdwebPublicBlackIp">
+        SELECT t1.*, t2.num wasteEnquiryNum
+        FROM `adweb_black_ip` t1
+                 LEFT JOIN (SELECT from_ip, COUNT(*) num
+                            FROM `adweb_enquiry`
+                            WHERE `status` = 1
+                              AND user_effective = 0
+                              AND sys_effective = 1
+                              AND waste_enquiry_type = 'ip'
+                            GROUP BY from_ip) t2
+                           ON t1.ip = t2.from_ip
+        WHERE t1.`status` = 1
+        <if test="ip != null and ip != ''">
+            AND t1.ip like CONCAT('%', #{ip}, '%')
+        </if>
+        <if test="blackOrWhite != null">
+            AND t1.black_or_white = #{blackOrWhite}
+        </if>
+        <if test = "column != null and column != ''">
+              ORDER BY
+              <if test = "column == 'createTime'">
+                t1.create_time ${order}
+              </if>
+               <if test = "column == 'ip'">
+                t1.ip ${order}
+              </if>
+        </if>
+    </select>
+</mapper>

+ 44 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/mapper/xml/AdwebPublicEnquiryRuleMapper.xml

@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.jeecg.modules.adweb.enquiry.mapper.AdwebPublicEnquiryRuleMapper">
+    <select id="pageList" resultType="org.jeecg.modules.adweb.enquiry.entity.AdwebPublicEnquiryRule">
+        SELECT t1.*, t2.num wasteEnquiryNum
+        FROM `adweb_enquiry_rule` t1
+                 LEFT JOIN (SELECT
+                                t1.reason,count(*) num
+                            FROM
+                            (
+                                SELECT SUBSTRING_INDEX(effective_reason,'-',-1) reason
+                                FROM `adweb_enquiry`
+                                WHERE `status` = 1 AND user_effective = 0 AND sys_effective = 1 AND waste_enquiry_type = 'keyword'
+                            ) t1 GROUP BY t1.reason) t2
+                           ON t2.reason = t1.word WHERE t1.`status` != 0
+        <if test="word != null and word != ''">
+            AND t1.word like CONCAT('%', #{word}, '%')
+        </if>
+        <if test="blackOrWhiteList != null">
+            AND t1.black_or_white_list = #{blackOrWhiteList}
+        </if>
+        <if test="isEnable != null">
+            AND t1.is_enable = #{isEnable}
+        </if>
+        <if test="useStatus != null">
+            AND t1.use_status = #{useStatus}
+        </if>
+        <if test = "column != null and column != ''">
+              ORDER BY
+              <if test = "column == 'createTime'">
+                t1.create_time ${order}
+              </if>
+              <if test = "column == 'isEnable'">
+                t1.is_enable ${order}
+              </if>
+              <if test = "column == 'useStatus'">
+                t1.use_status ${order}
+              </if>
+              <if test = "column == 'blackOrWhiteList'">
+                t1.black_or_white_list ${order}
+              </if>
+        </if>
+    </select>
+</mapper>

+ 61 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/mapper/xml/AdwebSiteBlackEmailMapper.xml

@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.jeecg.modules.adweb.enquiry.mapper.AdwebSiteBlackEmailMapper">
+
+    <select id="getPageList" resultType="org.jeecg.modules.adweb.enquiry.entity.AdwebSiteBlackEmail">
+        SELECT t1.*,t2.`name` siteName,t3.num wasteEnquiryNum,t4.num wasteGeneralEnquiryNum
+        FROM enquiry_site_black_email t1
+        LEFT JOIN (SELECT from_email, COUNT(*) num, site_id
+        FROM `adweb_enquiry`
+        WHERE `status` = 1
+        AND user_effective = 0
+        AND sys_effective = 1
+        AND waste_enquiry_type = 'email'
+        GROUP BY from_email) t3
+        ON t1.email = t3.from_email AND t1.site_id = t3.site_id
+        LEFT JOIN (
+        SELECT t1.email,SUM(t2.num) num,t1.site_id FROM enquiry_site_black_email t1
+        LEFT JOIN (SELECT from_email, COUNT(*) num, site_id
+        FROM `adweb_enquiry`
+        WHERE `status` = 1
+        AND user_effective = 0
+        AND sys_effective = 1
+        AND waste_enquiry_type = 'email'
+        GROUP BY from_email,site_id) t2
+        ON (t1.email != t2.from_email AND t2.from_email LIKE CONCAT('%',t1.email,'%') AND t1.site_id = t2.site_id)
+        WHERE t1.`status` = 1
+        GROUP BY t1.email, t1.site_id) t4
+        ON t1.email = t4.email AND t1.site_id = t4.site_id
+        ,adweb_site t2
+        WHERE t1.site_id = t2.id
+        AND t1.status = 1
+        <if test="enquirySiteBlackEmail.siteId != null and enquirySiteBlackEmail.siteId != ''">
+            AND t1.site_id = #{enquirySiteBlackEmail.siteId}
+        </if>
+        <if test="enquirySiteBlackEmail.email != null and enquirySiteBlackEmail.email != ''">
+            AND t1.email like concat('%',#{enquirySiteBlackEmail.email},'%')
+        </if>
+        <if test="enquirySiteBlackEmail.blackOrWhite != null">
+            AND t1.black_or_white = #{enquirySiteBlackEmail.blackOrWhite}
+        </if>
+        <if test="codeList != null">
+            <choose>
+                <when test="codeList.size() != 0">
+                    AND t1.site_code IN
+                    <foreach collection="codeList" item="code" open="(" close=")" separator=",">
+                        #{code}
+                    </foreach>
+                </when>
+            </choose>
+        </if>
+        <if test="column != null and column != ''">
+            ORDER BY
+            <if test="column == 'createTime'">
+                t1.create_time ${order}
+            </if>
+            <if test="column == 'email'">
+                t1.email ${order}
+            </if>
+        </if>
+    </select>
+</mapper>

+ 45 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/mapper/xml/AdwebSiteBlackIpMapper.xml

@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.jeecg.modules.adweb.enquiry.mapper.AdwebSiteBlackIpMapper">
+
+ <select id="getPageList" resultType="org.jeecg.modules.adweb.enquiry.entity.AdwebSiteBlackIp">
+    SELECT t1.*,t3.`name` siteName, t2.num wasteEnquiryNum
+    FROM adweb_site_black_ip t1
+     LEFT JOIN (SELECT customer_ip, site_code,COUNT(*) num
+     FROM `adweb_enquiry`
+     WHERE `status` = 1
+     AND user_effective = 0
+     AND sys_effective = 1
+     AND waste_enquiry_type = 'ip'
+     GROUP BY customer_ip,site_code) t2
+     ON t1.ip = t2.customer_ip AND t2.site_code = t1.site_code
+       ,adweb_site t3
+    WHERE t1.site_id = t3.id
+      AND t1.status = 1
+    <if test = "adwebSiteBlackIp.siteId != null and adwebSiteBlackIp.siteId != ''" >
+        AND t1.site_id = #{adwebSiteBlackIp.siteId}
+    </if>
+    <if test = "adwebSiteBlackIp.ip != null and adwebSiteBlackIp.ip != ''" >
+        AND t1.ip like concat('%',#{adwebSiteBlackIp.ip},'%')
+    </if>
+    <if test = "adwebSiteBlackIp.blackOrWhite != null">
+        AND t1.black_or_white = #{adwebSiteBlackIp.blackOrWhite}
+    </if>
+    <if test="codeList != null">
+        <choose>
+            <when test="codeList.size() != 0">
+                AND t1.site_code IN
+                <foreach collection="codeList" item="code" open="(" close=")" separator=",">
+                    #{code}
+                </foreach>
+            </when>
+        </choose>
+    </if>
+    <if test = "column != null and column != ''">
+      ORDER BY
+      <if test = "column == 'createTime'">
+        t1.create_time ${order}
+      </if>
+    </if>
+ </select>
+</mapper>

+ 19 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/mapper/xml/EnquiryEmailMessageMapper.xml

@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.jeecg.modules.adweb.enquiry.mapper.EnquiryEmailMessageMapper">
+
+    <select id="getWaitSendEmail" resultType="org.jeecg.modules.adweb.enquiry.entity.EnquiryEmailMessage">
+        SELECT
+            *
+        FROM
+            adweb_enquiry_email_message
+        WHERE
+            send_status = 'WAIT_SEND'
+            AND
+            (
+                send_error_num >= 1
+                OR (send_error_num = 0 AND create_time &lt; DATE_SUB(NOW(), INTERVAL #{timeout} MINUTE))
+            )
+        LIMIT #{num}
+    </select>
+</mapper>

+ 81 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/service/AdwebOpenApiService.java

@@ -0,0 +1,81 @@
+package org.jeecg.modules.adweb.enquiry.service;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang.StringUtils;
+import org.jeecg.common.util.FastJsonUtil;
+import org.jeecg.modules.adweb.common.constant.NumConstant;
+import org.jeecg.modules.adweb.common.util.DateUtil;
+import org.jeecg.modules.adweb.common.util.ListUtil;
+import org.jeecg.modules.adweb.common.util.SnowflakeIdUtil;
+import org.jeecg.modules.adweb.enquiry.constant.EnquiryConstants;
+import org.jeecg.modules.adweb.enquiry.dto.IndependentEnquiryDto;
+import org.jeecg.modules.adweb.enquiry.entity.AdwebEnquiry;
+import org.jeecg.modules.adweb.enquiry.entity.AdwebEnquiryForm;
+import org.jeecg.modules.adweb.site.entity.AdwebSite;
+import org.jeecg.modules.adweb.site.service.IAdwebSiteService;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * @Author: cyan
+ * @Date: 2021-04-25
+ * @Version: V1.0
+ */
+@Service
+@Slf4j
+public class AdwebOpenApiService {
+    @Resource
+    private IAdwebSiteService adwebSiteService;
+
+    @Value("${server.servlet.context-path}")
+    public String contextPath;
+
+
+    /**
+     * @param siteCode
+     * @return
+     */
+    public List<AdwebSite> selectBySiteCode(String siteCode) {
+        QueryWrapper<AdwebSite> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("code", siteCode);
+        return adwebSiteService.list(queryWrapper);
+    }
+
+    /**
+     * 获取4位编号
+     *
+     * @param siteCode
+     * @return
+     */
+    public String loadNo(String siteCode) {
+        int code = 0;
+        List<AdwebSite> adwebSites = selectBySiteCode(siteCode);
+        if (ListUtil.notEmpty(adwebSites)) {
+            AdwebSite adwebSite = adwebSites.get(0);
+            if(adwebSite.getDayEnquiryCount()!= null){
+                code = adwebSite.getDayEnquiryCount() + 1;
+            } else {
+                code = 1;
+            }
+        } else {
+            code = 1;
+        }
+        return String.format("%04d", code);
+    }
+
+//    public String loadOutNoByUser(String uid) {
+//        if (StringUtils.isEmpty(uid)) {
+//            return "000";
+//        }
+//        Date todayZero = DateUtil.formatDate(new Date(), DateUtil.DATE_PATTERN);
+//        QueryWrapper<AdwebEnquiry> queryWrapper = new QueryWrapper<>();
+//        queryWrapper.eq("uid", uid).gt("ctime", todayZero);
+//        int count = (int) adwebEnquiryService.count(queryWrapper);
+//        return String.format("%03d", count + 1);
+//    }
+}

+ 21 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/service/IAdwebEnquiryBlacklistService.java

@@ -0,0 +1,21 @@
+package org.jeecg.modules.adweb.enquiry.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.jeecg.modules.adweb.enquiry.entity.AdwebEnquiry;
+import org.jeecg.modules.adweb.enquiry.entity.AdwebEnquiryBlacklist;
+
+/**
+ * @Description: adweb_enquiry_blacklist
+ * @Author: jeecg-boot
+ * @Date:   2022-08-05
+ * @Version: V1.0
+ */
+public interface IAdwebEnquiryBlacklistService extends IService<AdwebEnquiryBlacklist> {
+    /**
+     * 判断询盘是否是处于黑名单中,根据手机号和邮箱进行匹配,两个都不为空且都相同才算匹配上
+     *
+     * @param adwebEnquiry 询盘
+     * @return true表示在黑名单中,false表示不在黑名单中
+     */
+    boolean isBlackEnquiry(AdwebEnquiry adwebEnquiry);
+}

+ 15 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/service/IAdwebEnquiryFormService.java

@@ -0,0 +1,15 @@
+package org.jeecg.modules.adweb.enquiry.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.jeecg.modules.adweb.enquiry.entity.AdwebEnquiryForm;
+
+/**
+ * @Description: adweb_enquiry_form
+ * @Author: jeecg-boot
+ * @Date:   2022-08-03
+ * @Version: V1.0
+ */
+public interface IAdwebEnquiryFormService extends IService<AdwebEnquiryForm> {
+
+    AdwebEnquiryForm getByEnquiryId(long enquiryId);
+}

+ 10 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/service/IAdwebEnquiryService.java

@@ -1,7 +1,11 @@
 package org.jeecg.modules.adweb.enquiry.service;
 
+import org.jeecg.modules.adweb.enquiry.dto.EnquiryDTO;
 import org.jeecg.modules.adweb.enquiry.entity.AdwebEnquiry;
 import com.baomidou.mybatisplus.extension.service.IService;
+import org.jeecg.modules.adweb.site.entity.AdwebSite;
+
+import java.util.List;
 
 /**
  * @Description: 询盘信息存储表单
@@ -11,4 +15,10 @@ import com.baomidou.mybatisplus.extension.service.IService;
  */
 public interface IAdwebEnquiryService extends IService<AdwebEnquiry> {
 
+    void addEnquiry(EnquiryDTO enquiryDTO, String plugin, List<AdwebSite> adwebSites);
+
+    /**
+     * 返回用户名称
+     */
+    void returnSalesperson (String siteCode,String inquiryId,String sales);
 }

+ 21 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/service/IAdwebPublicBlackEmailService.java

@@ -0,0 +1,21 @@
+package org.jeecg.modules.adweb.enquiry.service;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.jeecg.modules.adweb.enquiry.entity.AdwebPublicBlackEmail;
+
+/**
+ * @Description: 询盘公共邮箱黑名单
+ * @Author: jeecg-boot
+ * @Date:   2024-10-17
+ * @Version: V1.0
+ *
+ */
+public interface IAdwebPublicBlackEmailService extends IService<AdwebPublicBlackEmail> {
+    IPage<AdwebPublicBlackEmail> pageList(Page<AdwebPublicBlackEmail> page, String email, Integer blackOrWhite,String column,String order);
+
+//    void updateBlackListByEmailAndIp();
+//
+//    void updateEnquiryBlackList();
+}

+ 16 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/service/IAdwebPublicBlackIpService.java

@@ -0,0 +1,16 @@
+package org.jeecg.modules.adweb.enquiry.service;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.jeecg.modules.adweb.enquiry.entity.AdwebPublicBlackIp;
+
+/**
+ * @Description: IP黑名单
+ * @Author: jeecg-boot
+ * @Date:   2023-02-20
+ * @Version: V1.0
+ */
+public interface IAdwebPublicBlackIpService extends IService<AdwebPublicBlackIp> {
+    IPage<AdwebPublicBlackIp> pageList(Page<AdwebPublicBlackIp> page, String ip, Integer blackOrWhite,String column,String order);
+}

+ 24 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/service/IAdwebPublicEnquiryRuleService.java

@@ -0,0 +1,24 @@
+package org.jeecg.modules.adweb.enquiry.service;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.jeecg.modules.adweb.enquiry.entity.AdwebPublicEnquiryRule;
+
+import java.util.List;
+
+/**
+ * @Description: 用于询盘规则过滤
+ * @Author: jeecg-boot
+ * @Date:   2024-10-17
+ * @Version: V1.0
+ */
+public interface IAdwebPublicEnquiryRuleService extends IService<AdwebPublicEnquiryRule> {
+
+    List<String> getOpenAiBlackList();
+
+    List<String> getEnquiryBlackList();
+
+    IPage<AdwebPublicEnquiryRule> pageList(Page<AdwebPublicEnquiryRule> page, String word, Integer blackOrWhiteList, Integer isEnable, Integer useStatus, String column, String order);
+
+}

+ 43 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/service/IAdwebSiteBlackEmailService.java

@@ -0,0 +1,43 @@
+package org.jeecg.modules.adweb.enquiry.service;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.jeecg.modules.adweb.enquiry.dto.param.EffectiveEnquiryParamDto;
+import org.jeecg.modules.adweb.enquiry.entity.AdwebSiteBlackEmail;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @Description: enquiry_site_black_email
+ * @Author: jeecg-boot
+ * @Date:   2023-06-28
+ * @Version: V1.0
+ */
+public interface IAdwebSiteBlackEmailService extends IService<AdwebSiteBlackEmail> {
+    /**
+     * 根据站点id获取并存取黑名单数据到redis
+     */
+    void saveRedisSiteBlackEmailBySiteId(Integer siteId,Integer blackOrWhite);
+
+    /**
+     * 根据站点id获取对应所有的黑白名单数据
+     */
+    Map<String, List<String>> getSiteBlackEmailListBySiteId(Integer siteId);
+
+    /**
+     * 获取分页列表数据
+     * @param page
+     * @param enquirySiteBlackEmail
+     * @param codeList
+     * @return
+     */
+    IPage<AdwebSiteBlackEmail> pageList(Page<AdwebSiteBlackEmail> page, AdwebSiteBlackEmail enquirySiteBlackEmail, List<String> codeList,String column,String order);
+
+    /**
+     * 更改为垃圾询盘处理邮箱黑名单
+     * @param effectiveEnquiryParamDto
+     */
+    void addBlackEmailByContent(EffectiveEnquiryParamDto effectiveEnquiryParamDto);
+}

+ 33 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/service/IAdwebSiteBlackIpService.java

@@ -0,0 +1,33 @@
+package org.jeecg.modules.adweb.enquiry.service;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.jeecg.modules.adweb.enquiry.dto.param.EffectiveEnquiryParamDto;
+import org.jeecg.modules.adweb.enquiry.entity.AdwebSiteBlackIp;
+
+import java.util.List;
+
+/**
+ * @Description: adweb_site_black_ip
+ * @Author: jeecg-boot
+ * @Date:   2023-08-31
+ * @Version: V1.0
+ */
+public interface IAdwebSiteBlackIpService extends IService<AdwebSiteBlackIp> {
+
+    /**
+     * 更改为垃圾询盘处理ip黑名单
+     * @param effectiveEnquiryParamDto
+     */
+    void addBlackIpByContent(EffectiveEnquiryParamDto effectiveEnquiryParamDto);
+
+    /**
+     * 获取分页列表数据
+     * @param page
+     * @param adwebSiteBlackIp
+     * @param codeList
+     * @return
+     */
+    IPage<AdwebSiteBlackIp> pageList(Page<AdwebSiteBlackIp> page, AdwebSiteBlackIp adwebSiteBlackIp, List<String> codeList, String column, String order);
+}

+ 20 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/service/IAdwebSiteEnquiryRuleService.java

@@ -0,0 +1,20 @@
+package org.jeecg.modules.adweb.enquiry.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.jeecg.modules.adweb.enquiry.dto.param.EffectiveEnquiryParamDto;
+import org.jeecg.modules.adweb.enquiry.entity.AdwebSiteEnquiryRule;
+
+/**
+ * @Description: adweb_enquiry_site_rule
+ * @Author: jeecg-boot
+ * @Date:   2023-08-31
+ * @Version: V1.0
+ */
+public interface IAdwebSiteEnquiryRuleService extends IService<AdwebSiteEnquiryRule> {
+
+    /**
+     * 更改为垃圾询盘处理关键词黑名单
+     * @param effectiveEnquiryParamDto
+     */
+    void addBlackKeywordByContent(EffectiveEnquiryParamDto effectiveEnquiryParamDto);
+}

+ 38 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/service/IEnquiryEmailMessageService.java

@@ -0,0 +1,38 @@
+package org.jeecg.modules.adweb.enquiry.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.modules.adweb.enquiry.entity.AdwebEnquiry;
+import org.jeecg.modules.adweb.enquiry.entity.EnquiryEmailMessage;
+
+import java.util.List;
+
+/**
+ * @Description: adweb_enquiry_email_message
+ * @Author: jeecg-boot
+ * @Date:   2023-02-01
+ * @Version: V1.0
+ */
+public interface IEnquiryEmailMessageService extends IService<EnquiryEmailMessage> {
+
+     void sendEnquiryEmail(Long enquiryId);
+
+     void sendEmailByMessage(EnquiryEmailMessage message);
+
+     /**
+      * 获取待发送询盘
+      * 1、首次发送失败的
+      * 2、超过timeout分钟未处理的
+      *
+      * @param timeout 留给首次实时处理的时间,单位分钟,超过这个时间则认为首次邮件发送失败,应该由定时器处理
+      * @param num     获取邮件数量
+      * @return 邮件列表
+      */
+     List<EnquiryEmailMessage> getWaitSendEmail(int timeout, int num);
+
+    /**
+     * 添加并发送询盘邮件
+     * @param adwebEnquiry
+     */
+    Result<?> addAndEnquiryEmailMsg(AdwebEnquiry adwebEnquiry, String uid);
+}

+ 48 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/service/impl/AdwebEnquiryBlacklistServiceImpl.java

@@ -0,0 +1,48 @@
+package org.jeecg.modules.adweb.enquiry.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.xkcoding.http.util.StringUtil;
+import jakarta.annotation.Resource;
+import org.jeecg.modules.adweb.enquiry.entity.AdwebEnquiry;
+import org.jeecg.modules.adweb.enquiry.entity.AdwebEnquiryBlacklist;
+import org.jeecg.modules.adweb.enquiry.mapper.AdwebEnquiryBlacklistMapper;
+import org.jeecg.modules.adweb.enquiry.service.IAdwebEnquiryBlacklistService;
+import org.jeecg.modules.adweb.site.service.IAdwebSiteService;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * @Description: adweb_enquiry_blacklist
+ * @Author: jeecg-boot
+ * @Date:   2022-08-05
+ * @Version: V1.0
+ */
+@Service
+public class AdwebEnquiryBlacklistServiceImpl extends ServiceImpl<AdwebEnquiryBlacklistMapper, AdwebEnquiryBlacklist> implements IAdwebEnquiryBlacklistService {
+
+    @Resource
+    private IAdwebSiteService adwebSiteService;
+
+    /**
+     * 判断询盘是否是处于黑名单中,根据手机号和邮箱进行匹配,两个都不为空且都相同才算匹配上
+     *
+     * @param adwebEnquiry 询盘
+     * @return true表示在黑名单中,false表示不在黑名单中
+     */
+    @Override
+    public boolean isBlackEnquiry(AdwebEnquiry adwebEnquiry) {
+        String email = adwebEnquiry.getEmail();
+        String phone = adwebEnquiry.getPhone();
+        if (StringUtil.isEmpty(email) || StringUtil.isEmpty(phone)) {
+            return false;
+        }
+        List<Integer> siteIds = adwebSiteService.getAllSiteIdBySiteId(adwebEnquiry.getSiteId());
+        QueryWrapper<AdwebEnquiryBlacklist> queryWrapper = new QueryWrapper<>();
+        queryWrapper.in("site_id", siteIds);
+        queryWrapper.eq("status", 1);
+        queryWrapper.and(wrapper -> wrapper.eq("email", email).or().eq("phone", phone));
+        return this.count(queryWrapper) > 0;
+    }
+}

+ 26 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/service/impl/AdwebEnquiryFormServiceImpl.java

@@ -0,0 +1,26 @@
+package org.jeecg.modules.adweb.enquiry.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.jeecg.modules.adweb.enquiry.entity.AdwebEnquiryForm;
+import org.jeecg.modules.adweb.enquiry.mapper.AdwebEnquiryFormMapper;
+import org.jeecg.modules.adweb.enquiry.service.IAdwebEnquiryFormService;
+import org.springframework.stereotype.Service;
+
+/**
+ * @Description: adweb_enquiry_form
+ * @Author: jeecg-boot
+ * @Date:   2022-08-03
+ * @Version: V1.0
+ */
+@Service
+public class AdwebEnquiryFormServiceImpl extends ServiceImpl<AdwebEnquiryFormMapper, AdwebEnquiryForm> implements IAdwebEnquiryFormService {
+
+    @Override
+    public AdwebEnquiryForm getByEnquiryId(long enquiryId) {
+        QueryWrapper<AdwebEnquiryForm> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("enquiry_id", enquiryId);
+        return getOne(queryWrapper);
+    }
+
+}

+ 1747 - 4
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/service/impl/AdwebEnquiryServiceImpl.java

@@ -1,19 +1,1762 @@
 package org.jeecg.modules.adweb.enquiry.service.impl;
 
-import org.jeecg.modules.adweb.enquiry.entity.AdwebEnquiry;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.xkcoding.http.util.StringUtil;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang.StringUtils;
+import org.jeecg.common.constant.CacheConstant;
+import org.jeecg.common.system.vo.DictModel;
+import org.jeecg.common.system.vo.DictPropertyModel;
+import org.jeecg.common.util.FastJsonUtil;
+
+import org.jeecg.modules.adweb.common.constant.NumConstant;
+import org.jeecg.modules.adweb.common.dto.CountryAreaApiDto;
+import org.jeecg.modules.adweb.common.service.FeishuService;
+import org.jeecg.modules.adweb.common.util.*;
+import org.jeecg.modules.adweb.enquiry.constant.EnquiryConstants;
+import org.jeecg.modules.adweb.enquiry.constant.EnquirySendStatus;
+import org.jeecg.modules.adweb.enquiry.dto.EnquiryDTO;
+import org.jeecg.modules.adweb.enquiry.dto.param.EffectiveEnquiryParamDto;
+import org.jeecg.modules.adweb.enquiry.dto.result.EnquirySpecialFields;
+import org.jeecg.modules.adweb.enquiry.entity.*;
 import org.jeecg.modules.adweb.enquiry.mapper.AdwebEnquiryMapper;
-import org.jeecg.modules.adweb.enquiry.service.IAdwebEnquiryService;
+import org.jeecg.modules.adweb.enquiry.service.*;
+import org.jeecg.modules.adweb.site.entity.AdwebSite;
+import org.jeecg.modules.adweb.site.service.IAdwebSiteService;
+import org.jeecg.modules.adweb.system.entity.SysException;
+import org.jeecg.modules.adweb.system.service.IMasterSubAccountRelationService;
+import org.jeecg.modules.adweb.system.service.ISysExceptionService;
+import org.jeecg.modules.adweb.system.service.impl.SysAdwebApiImpl;
+import org.jeecg.modules.system.entity.SysDictItem;
+import org.jeecg.modules.system.entity.SysUser;
+import org.jeecg.modules.system.service.ISysDictService;
+import org.jeecg.modules.system.service.ISysUserService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpMethod;
 import org.springframework.stereotype.Service;
+import org.springframework.web.client.RestTemplate;
 
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import java.util.*;
+import java.util.function.BiConsumer;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
 
 /**
  * @Description: 询盘信息存储表单
  * @Author: jeecg-boot
- * @Date:   2024-10-12
+ * @Date: 2024-10-12
  * @Version: V1.0
  */
+@Slf4j
 @Service
 public class AdwebEnquiryServiceImpl extends ServiceImpl<AdwebEnquiryMapper, AdwebEnquiry> implements IAdwebEnquiryService {
 
+    @Resource
+    @Lazy
+    private ISysUserService sysUserService;
+
+    @Resource
+    private IMasterSubAccountRelationService masterSubAccountRelationService;
+
+    @Resource
+    private GeoIpUtil geoIpUtil;
+
+    @Resource
+    private IAdwebPublicEnquiryRuleService AdwebPublicEnquiryRuleService;
+
+    @Resource
+    private GeoIpUtil geoIpService;
+
+    @Resource
+    private ISysDictService dictService;
+
+    @Resource
+    private SnowflakeIdUtil snowflakeIdUtil;
+
+    @Resource
+    private AdwebRedisUtil adwebRedisUtil;
+
+    @Resource
+    private ISysExceptionService sysExceptionService;
+
+    @Resource
+    private FeishuService feishuService;
+
+    @Resource
+    private IAdwebEnquiryBlacklistService adwebEnquiryBlacklistService;
+
+    @Resource
+    private IAdwebSiteBlackEmailService enquirySiteBlackEmailService;
+
+    @Resource
+    private IAdwebPublicBlackEmailService adwebPublicBlackEmailService;
+
+    @Resource
+    private IAdwebPublicBlackIpService adwebPublicBlackIpService;
+
+    @Resource
+    private IAdwebSiteBlackIpService adwebSiteBlackIpService;
+
+    @Resource
+    private IAdwebSiteEnquiryRuleService adwebSiteEnquiryRuleService;
+
+    @Resource
+    private IEnquiryEmailMessageService enquiryEmailMessageService;
+
+    @Resource
+    private IAdwebSiteService adwebSiteService;
+
+    @Resource
+    private AdwebOpenApiService adwebOpenApiService;
+
+    @Resource
+    private IAdwebEnquiryFormService adwebEnquiryFormService;
+
+    private static final byte[] redisKey = EnquiryConstants.ENQUIRY_EMAIL.getBytes();
+
+    private static final byte[] siteRedisKey = EnquiryConstants.ENQUIRY_SITE.getBytes();
+
+    // Email Redis key
+    private static final String EmailTenMinKey = "JUDGE_WASTE_ENQUIRY_EMAIL_BY_10_MIN::";
+    private static final String EmailOneDayKey = "JUDGE_WASTE_ENQUIRY_EMAIL_BY_ONE_DAY::";
+    private static final String BlackEmailKey = "BLACK_EMAIL_LIST";
+    private static final String WhiteEmailListKey = "WHITE_EMAIL_LIST";
+    private static final String NotBlackEmailWasteEnquiryKey = "NOT_BLACK_EMAIL_WASTE_ENQUIRY_MAP::";
+
+    // site Email Redis key
+    private static final String SiteEmailTenMinKey = "JUDGE_WASTE_SITE_ENQUIRY_EMAIL_BY_10_MIN::";
+    private static final String SiteEmailOneDayKey = "JUDGE_WASTE_SITE_ENQUIRY_EMAIL_BY_ONE_DAY::";
+    private static final String SiteBlackEmailKey = "SITE_BLACK_EMAIL_LIST";
+    private static final String SiteWhiteEmailListKey = "SITE_WHITE_EMAIL_LIST";
+    private static final String NotBlackEmailWasteSiteEnquiryKey = "NOT_BLACK_EMAIL_WASTE_SITE_ENQUIRY_MAP::";
+
+    //ip Reids Key
+    private static final String IpTenMinKey = "JUDGE_WASTE_ENQUIRY_IP_BY_10_MIN::";
+    private static final String IpOneDayKey = "JUDGE_WASTE_ENQUIRY_IP_BY_ONE_DAY::";
+    private static final String BlackIpKey = "BLACK_IP_LIST";
+    private static final String WhiteIpListKey = "WHITE_IP_LIST";
+    private static final String NotBlackIpWasteEnquiryKey = "NOT_BLACK_IP_WASTE_ENQUIRY_MAP::";
+
+    //site ip Reids Key
+    private static final String SiteIpTenMinKey = "JUDGE_WASTE_ENQUIRY_SITE_IP_BY_10_MIN::";
+    private static final String SiteIpOneDayKey = "JUDGE_WASTE_ENQUIRY_SITE_IP_BY_ONE_DAY::";
+    private static final String NotSiteBlackIpWasteEnquiryKey = "NOT_SITE_BLACK_IP_WASTE_ENQUIRY_MAP::";
+    private static final String SiteBlackIpKey = "SITE_BLACK_IP_LIST";
+    private static final String SiteWhiteIpListKey = "SITE_WHITE_IP_LIST";
+
+    @Value("${judge_waste_enquiry.email.tenMinNum}")
+    private Integer emailTenMinNum;
+    @Value("${judge_waste_enquiry.email.oneDayNum}")
+    private Integer emailOneDayNum;
+    @Value("${judge_waste_enquiry.ip.tenMinNum}")
+    private Integer ipTenMinNum;
+    @Value("${judge_waste_enquiry.ip.oneDayNum}")
+    private Integer ipOneDayNum;
+    @Value("${judge_waste_enquiry.email.notBlackListNum}")
+    private Integer emailNotBlackListNum;
+    @Value("${judge_waste_enquiry.ip.notBlackListNum}")
+    private Integer ipNotBlackListNum;
+    @Value("${judge_waste_enquiry.email.notBlackListDate}")
+    private Integer emailNotBlackListDate;
+    @Value("${judge_waste_enquiry.ip.notBlackListDate}")
+    private Integer ipNotBlackListDate;
+    @Autowired
+    private SysAdwebApiImpl sysAdwebApiImpl;
+
+    // 获取有效公共询盘规则
+    private List<String> getPublicEnquiryRules(int blackOrWhite, int useStatus) {
+
+        List<String> blackWordList = null;
+        try {
+            List<AdwebPublicEnquiryRule> AdwebPublicEnquiryRuleList = AdwebPublicEnquiryRuleService.list(new LambdaQueryWrapper<AdwebPublicEnquiryRule>()
+                    .eq(AdwebPublicEnquiryRule::getStatus, 1)
+                    .eq(AdwebPublicEnquiryRule::getIsEnable, 1)
+                    .eq(AdwebPublicEnquiryRule::getBlackOrWhiteList, blackOrWhite)
+                    .eq(AdwebPublicEnquiryRule::getUseStatus, useStatus));
+            if (ListUtil.notEmpty(AdwebPublicEnquiryRuleList)) {
+                blackWordList = AdwebPublicEnquiryRuleList.stream().map(AdwebPublicEnquiryRule::getWord).toList();
+            }
+        } catch (Exception e) {
+            log.error("读取询盘黑名单关键词失败", e);
+        }
+
+        return blackWordList;
+    }
+
+    /**
+     * 添加询盘
+     *
+     * @param enquiryDto 询盘对象
+     * @return
+     */
+    public void addEnquiry(EnquiryDTO enquiryDto, String plugin, List<AdwebSite> adwebSites) {
+
+        // 获取公共黑名单关键词
+        List<String> blackWordList = getPublicEnquiryRules(0, 0);
+
+        AdwebSite adwebSite = adwebSites.get(0);
+
+        //获取子账户
+        Map<String, String> principalEmailMap = new HashMap<>();
+        List<String> subAccountIdList = masterSubAccountRelationService.getSubAccountIdByMaster(String.valueOf(adwebSite.getUid()));
+        log.info("获取的子账户id:{}", FastJsonUtil.toJSONString(subAccountIdList));
+        if (ListUtil.notEmpty(subAccountIdList)) {
+            subAccountIdList.add(String.valueOf(adwebSite.getUid()));
+            List<SysUser> principalEmailList = sysUserService.list(new QueryWrapper<SysUser>().in("id", subAccountIdList).eq("del_flag", 0).isNotNull("email").ne("email", "").select("id", "email"));
+            if (ListUtil.notEmpty(principalEmailList)) {
+                principalEmailMap = principalEmailList.stream().collect(Collectors.toMap(SysUser::getId, SysUser::getEmail));
+
+            }
+        }
+
+        List<AdwebEnquiry> adwebEnquiryList = new ArrayList<>();
+        AdwebEnquiryForm form = new AdwebEnquiryForm();
+
+        try {
+            AdwebEnquiry adwebEnquiry = createEnquiry(enquiryDto, adwebSite);
+
+            String forms = FastJsonUtil.toJSONString(enquiryDto.getForms());
+            parseFormAndSetFields(adwebEnquiry, forms, adwebSite);
+            setCountryByIp(adwebEnquiry);
+
+            adwebEnquiryList.add(adwebEnquiry);
+
+
+            form.setEnquiryId(adwebEnquiry.getId());
+            form.setForm(forms);
+            form.setCountry(adwebEnquiry.getCountry());
+            form.setPluginName(plugin);
+
+
+        } catch (Exception e) {
+            log.error("消费站点为:{}, recordId为:{} 的询盘出现问题", adwebSite.getName(), enquiryDto.getRecordId(), e);
+        }
+
+        // 公共黑名单,站点黑名单过滤
+        judgeWasteEnquiryBySiteId(adwebEnquiryList, adwebSite, blackWordList);
+
+        // 客户黑名单过滤
+        judgeBlacklist(adwebEnquiryList);
+
+        if (!adwebEnquiryList.isEmpty()) {
+            try {
+                AdwebEnquiry target = adwebEnquiryList.get(0);
+                this.save(target);
+                adwebEnquiryFormService.save(form);
+            } catch (Exception e) {
+                log.error("站点为:{},  recordId为:{} 保存询盘到数据库失败,原因是:{}", adwebSite.getName(), enquiryDto.getRecordId(), e.getMessage());
+            }
+
+            // 发送询盘邮件
+            sendValidateEmail(adwebEnquiryList, adwebSite, principalEmailMap);
+        }
+    }
+
+
+    /**
+     * 发送询盘邮件
+     *
+     * @param enquiryList       待发送询盘列表
+     * @param adwebSite         接收邮箱集合
+     * @param principalEmailMap
+     */
+    private void sendValidateEmail(List<AdwebEnquiry> enquiryList, AdwebSite adwebSite, Map<String, String> principalEmailMap) {
+        if (ListUtil.isEmpty(enquiryList)) {
+            log.info("未获取到需要发送邮件的询盘");
+            return;
+        }
+        log.info("需要发送邮件的询盘:{}", FastJsonUtil.toJSONString(enquiryList));
+
+        //特殊站点发送邮件
+        List<DictPropertyModel> siteRes = sysAdwebApiImpl.queryDictInfoByDictCode("turn_inquiry_site_code");
+        if (ListUtil.notEmpty(siteRes) && siteRes.get(0).getValue().equals(adwebSite.getCode())) {
+            specialSendEmail(enquiryList, adwebSite, principalEmailMap);
+        } else {
+            String emailStr = adwebSite.getEnquiryEmailList();
+            if (StringUtil.isEmpty(emailStr)) {
+                log.info("未获取到站点邮箱");
+                return;
+            }
+            log.info("发送询盘邮件--站点邮箱:{}", emailStr);
+            log.info("发送询盘邮件--子账户邮箱:{}", FastJsonUtil.toJSONString(principalEmailMap));
+
+            List<String> emailList = JSON.parseArray(emailStr, String.class);
+            if (ListUtil.isEmpty(emailList)) {
+                return;
+            }
+
+
+            List<EnquiryEmailMessage> enquiryEmailMessageList = new ArrayList<>();
+            for (AdwebEnquiry adwebEnquiry : enquiryList) {
+                if (adwebEnquiry.getWasteEnquiry() != 1 && adwebEnquiry.getStatus() != 0) {
+                    HashSet<String> emailSet = new HashSet<>();
+                    String priUid = adwebEnquiry.getPrincipalUid();
+
+                    if (principalEmailMap.isEmpty()) {
+                        for (String e : emailList) {
+                            if (emailSet.contains(e)) {
+                                continue;
+                            }
+                            enquiryEmailMessageList.add(newEmail(adwebEnquiry, e));
+                            emailSet.add(e);
+                        }
+                    }
+                    //1 如果选择发送全部 2.不是产品页面 全发
+                    else if (StringUtil.isEmpty(adwebEnquiry.getPrincipalUid()) || adwebEnquiry.getExistProductEnquiry() == null || adwebEnquiry.getExistProductEnquiry() == 0 || adwebEnquiry.getPrincipalUid().equals("ALL")) {
+                        if (adwebSite.getEnquirySendEmailType().equals("ALL")) {
+                            log.info("发送询盘邮件--不是产品--进行所有账号发送规则");
+                            for (String e : principalEmailMap.values()) {
+                                if (emailSet.contains(e)) {
+                                    continue;
+                                }
+                                enquiryEmailMessageList.add(newEmail(adwebEnquiry, e));
+                                emailSet.add(e);
+                            }
+                        } else {
+                            //询盘邮件规则 主账号和添加了的负责人,如果负责人选择了all取所有人
+                            log.info("发送询盘邮件--不是产品--进行只有主账号发送规则--负责人不为all");
+                            if (!"ALL".equals(adwebEnquiry.getPrincipalUid())) {
+                                //主账号
+                                SysUser masterUserAccount = sysUserService.getById(adwebEnquiry.getUid());
+                                if (masterUserAccount != null && StringUtils.isNotBlank(masterUserAccount.getEmail())) {
+                                    emailSet.add(masterUserAccount.getEmail());
+                                    enquiryEmailMessageList.add(newEmail(adwebEnquiry, masterUserAccount.getEmail()));
+                                }
+                                //负责人
+                                for (String key : principalEmailMap.keySet()) {
+                                    if (adwebEnquiry.getPrincipalUid().equals(key) && !emailSet.contains(principalEmailMap.get(key))) {
+                                        enquiryEmailMessageList.add(newEmail(adwebEnquiry, principalEmailMap.get(key)));
+                                        emailSet.add(principalEmailMap.get(key));
+                                    }
+                                }
+                            } else {
+                                //判断是否走同步询盘,同步询盘不进行全部处理
+                                log.info("发送询盘邮件--不是产品--进行只有主账号发送规则--负责人为all");
+                                if (StringUtil.isEmpty(adwebEnquiry.getIsEnquirySync())) {
+                                    for (String e : principalEmailMap.values()) {
+                                        if (emailSet.contains(e)) {
+                                            continue;
+                                        }
+                                        enquiryEmailMessageList.add(newEmail(adwebEnquiry, e));
+                                        emailSet.add(e);
+                                    }
+                                } else {
+                                    //主账号
+                                    SysUser masterUserAccount = sysUserService.getById(adwebEnquiry.getUid());
+                                    if (masterUserAccount != null && StringUtils.isNotBlank(masterUserAccount.getEmail())) {
+                                        emailSet.add(masterUserAccount.getEmail());
+                                        enquiryEmailMessageList.add(newEmail(adwebEnquiry, masterUserAccount.getEmail()));
+                                    }
+                                }
+                            }
+                        }
+                        for (String e : emailList) {
+                            if (emailSet.contains(e)) {
+                                continue;
+                            }
+                            enquiryEmailMessageList.add(newEmail(adwebEnquiry, e));
+                            emailSet.add(e);
+                        }
+                    }
+                    //当主站为空
+                    else if (StringUtil.isEmpty(principalEmailMap.get(adwebEnquiry.getUid())) && adwebEnquiry.getExistProductEnquiry() == 1) {
+                        log.info("发送询盘邮件--产品询盘--当主站为空");
+                        String email = principalEmailMap.get(priUid);
+                        List<String> subSiteEmailList = null;
+                        if (StringUtils.isNotBlank(email)) {
+                            enquiryEmailMessageList.add(newEmail(adwebEnquiry, email));
+                            emailSet.add(email);
+                            //筛选出子站点,不给子站点发,给配置询盘的地方发
+                            subSiteEmailList = principalEmailMap.entrySet()
+                                    .stream()
+                                    .filter(entry -> !email.equals(entry.getKey()))
+                                    .map(Map.Entry::getValue)
+                                    .collect(Collectors.toList());
+                        } else {
+                            subSiteEmailList = new ArrayList<>(principalEmailMap.values());
+                        }
+
+
+                        //遍历emailList 不包含subSiteEmailList
+                        for (String e : emailList) {
+                            if (subSiteEmailList.contains(e) || emailSet.contains(e)) {
+                                continue;
+                            }
+                            enquiryEmailMessageList.add(newEmail(adwebEnquiry, e));
+                            emailSet.add(e);
+                        }
+                    }
+                    //如果当前询盘配置的为子账户 则给子账户和主账户发
+                    else if (adwebEnquiry.getExistProductEnquiry() == 1 && !adwebEnquiry.getUid().equals(priUid)) {
+                        log.info("发送询盘邮件--产品询盘--如果当前询盘配置的为子账户 则给子账户和主账户发");
+                        String email = principalEmailMap.get(priUid);
+                        if (StringUtils.isNotBlank(email)) {
+                            enquiryEmailMessageList.add(newEmail(adwebEnquiry, email));
+                            emailSet.add(email);
+                        }
+
+                        //给主账户发
+                        String masterEmail = principalEmailMap.get(adwebEnquiry.getUid());
+                        if (emailSet.contains(masterEmail)) {
+                            continue;
+                        }
+                        enquiryEmailMessageList.add(newEmail(adwebEnquiry, masterEmail));
+                        emailSet.add(masterEmail);
+
+                        //筛选出子站点,不给子站点发,给配置询盘的地方发
+                        List<String> subSiteEmailList = principalEmailMap.entrySet()
+                                .stream()
+                                .filter(entry -> !Arrays.asList(email, masterEmail).contains(entry.getKey()))
+                                .map(Map.Entry::getValue)
+                                .collect(Collectors.toList());
+
+                        //遍历emailList 不包含subSiteEmailList
+                        for (String e : emailList) {
+                            if (subSiteEmailList.contains(e) || emailSet.contains(e)) {
+                                continue;
+                            }
+                            enquiryEmailMessageList.add(newEmail(adwebEnquiry, e));
+                            emailSet.add(e);
+                        }
+                    }
+                    //如果当前询盘配置的为主账户 则只给主账户发 //还有一种情况 子账户为空 只给主站发
+                    else if (adwebEnquiry.getUid().equals(priUid) && adwebEnquiry.getExistProductEnquiry() == 1) {
+                        log.info("发送询盘邮件--产品询盘--如果当前询盘配置的为主账户 则只给主账户发 //还有一种情况 子账户为空 只给主站发");
+                        String email = principalEmailMap.get(priUid);
+                        enquiryEmailMessageList.add(newEmail(adwebEnquiry, email));
+                        emailSet.add(email);
+
+                        //筛选出子站点,不给子站点发,给配置询盘的地方发
+                        List<String> subSiteEmailList = principalEmailMap.entrySet()
+                                .stream()
+                                .filter(entry -> !entry.getKey().equals(priUid))
+                                .map(Map.Entry::getValue)
+                                .collect(Collectors.toList());
+
+                        //遍历emailList 不包含subSiteEmailList
+                        for (String e : emailList) {
+                            if (subSiteEmailList.contains(e) || emailSet.contains(e)) {
+                                continue;
+                            }
+                            enquiryEmailMessageList.add(newEmail(adwebEnquiry, e));
+                            emailSet.add(e);
+                        }
+                    }
+                }
+            }
+            log.info("=======发送询盘邮件======");
+            log.info("=======发送询盘邮件======");
+            enquiryEmailMessageList.forEach(e -> System.out.println(e.getEmail()));
+            log.info("需要添加的询盘邮件:{}", FastJsonUtil.toJSONString(enquiryEmailMessageList));
+            if (ListUtil.notEmpty(enquiryEmailMessageList)) {
+                QueryWrapper<EnquiryEmailMessage> enquiryEmailMessageQueryWrapper = new QueryWrapper<>();
+                enquiryEmailMessageQueryWrapper.eq("site_code", adwebSite.getCode());
+                List<EnquiryEmailMessage> enquiryEmailMessages = enquiryEmailMessageService.list(enquiryEmailMessageQueryWrapper);
+                List<EnquiryEmailMessage> sameEnquiryEmailMessageList = new ArrayList<>();
+                if (ListUtil.notEmpty(enquiryEmailMessages)) {
+                    for (EnquiryEmailMessage enquiryEmailMessage : enquiryEmailMessages) {
+                        for (EnquiryEmailMessage enquiryEmailMessage1 : enquiryEmailMessageList) {
+                            if (enquiryEmailMessage.getEnquiryId().equals(enquiryEmailMessage1.getEnquiryId()) && enquiryEmailMessage.getEmail().equals(enquiryEmailMessage1.getEmail())) {
+                                sameEnquiryEmailMessageList.add(enquiryEmailMessage1);
+                            }
+                        }
+                    }
+                    enquiryEmailMessageList.removeAll(sameEnquiryEmailMessageList);
+                }
+                log.info("最终添加的询盘邮件:{}", FastJsonUtil.toJSONString(enquiryEmailMessageList));
+                enquiryEmailMessageService.saveBatch(enquiryEmailMessageList);
+                try {
+                    for (EnquiryEmailMessage message : enquiryEmailMessageList) {
+                        ObjectMapper objectMapper = new ObjectMapper();
+                        JedisUtil.lpush(redisKey, objectMapper.writeValueAsBytes(message.getEnquiryId()));
+                        JedisUtil.publishMsg(EnquiryConstants.ENQUIRY_EMAIL_CHANNEL, EnquiryConstants.ENQUIRY_EMAIL);
+                    }
+                } catch (Exception e) {
+                    log.info("推送发送询盘邮件的消息失败", e);
+                }
+            }
+        }
+    }
+
+    /**
+     * 特殊账号发送邮件
+     *
+     * @param enquiryList
+     * @param adwebSite
+     * @param principalEmailMap
+     */
+    private void specialSendEmail(List<AdwebEnquiry> enquiryList, AdwebSite adwebSite, Map<String, String> principalEmailMap) {
+        //通过主账号id获取子账号id集合
+        List<String> idList = masterSubAccountRelationService.getSubAccountIdByMaster(adwebSite.getUid());
+
+        //获取子账号信息
+        QueryWrapper<SysUser> sysUserQueryWrapper = new QueryWrapper<>();
+        sysUserQueryWrapper.eq("is_inquiry", 2);
+        sysUserQueryWrapper.eq("status", 1);
+        if (ListUtil.notEmpty(idList)) {
+            sysUserQueryWrapper.in("id", idList);
+        }
+        List<SysUser> sysUsers = sysUserService.list(sysUserQueryWrapper);
+
+
+        for (AdwebEnquiry adwebEnquiry : enquiryList) {
+            List<EnquiryEmailMessage> enquiryEmailMessageList = new ArrayList<>();
+            if (adwebEnquiry.getWasteEnquiry() != 1 && adwebEnquiry.getStatus() != 0) {
+                //当前发送邮件的账号
+                SysUser sysUser = new SysUser();
+
+                //如果没有子账号,则只给主账号发送邮件
+                if (ListUtil.isEmpty(sysUsers)) {
+                    //获取主账号
+                    SysUser mainUser = sysUserService.getById(adwebSite.getUid());
+                    //主账号邮件信息添加
+                    if (mainUser != null && StringUtils.isNotBlank(mainUser.getEmail())) {
+                        enquiryEmailMessageList.add(newEmail(adwebEnquiry, mainUser.getEmail()));
+                    }
+                }
+
+                enquiryEmailMessageList.forEach(e -> System.out.println(e.getEmail()));
+
+                log.info("需要添加的询盘邮件:{}", FastJsonUtil.toJSONString(enquiryEmailMessageList));
+                if (ListUtil.notEmpty(enquiryEmailMessageList)) {
+                    QueryWrapper<EnquiryEmailMessage> enquiryEmailMessageQueryWrapper = new QueryWrapper<>();
+                    enquiryEmailMessageQueryWrapper.eq("site_code", adwebSite.getCode());
+                    List<EnquiryEmailMessage> enquiryEmailMessages = enquiryEmailMessageService.list(enquiryEmailMessageQueryWrapper);
+                    List<EnquiryEmailMessage> sameEnquiryEmailMessageList = new ArrayList<>();
+                    if (ListUtil.notEmpty(enquiryEmailMessages)) {
+                        for (EnquiryEmailMessage enquiryEmailMessage : enquiryEmailMessages) {
+                            for (EnquiryEmailMessage enquiryEmailMessage1 : enquiryEmailMessageList) {
+                                if (enquiryEmailMessage.getEnquiryId().equals(enquiryEmailMessage1.getEnquiryId()) && enquiryEmailMessage.getEmail().equals(enquiryEmailMessage1.getEmail())) {
+                                    sameEnquiryEmailMessageList.add(enquiryEmailMessage1);
+                                }
+                            }
+                        }
+                        enquiryEmailMessageList.removeAll(sameEnquiryEmailMessageList);
+                    }
+                    log.info("最终添加的询盘邮件:{}", FastJsonUtil.toJSONString(enquiryEmailMessageList));
+                    enquiryEmailMessageService.saveBatch(enquiryEmailMessageList);
+                    try {
+                        for (EnquiryEmailMessage message : enquiryEmailMessageList) {
+                            ObjectMapper objectMapper = new ObjectMapper();
+                            JedisUtil.lpush(redisKey, objectMapper.writeValueAsBytes(message.getEnquiryId()));
+                            JedisUtil.publishMsg(EnquiryConstants.ENQUIRY_EMAIL_CHANNEL, EnquiryConstants.ENQUIRY_EMAIL);
+                        }
+                        SysUser user = sysUserService.getById(adwebEnquiry.getPrincipalUid());
+                        if (StringUtils.isNotBlank(adwebEnquiry.getRecordId())) {
+                            returnSalesperson(adwebSite.getCode(), adwebEnquiry.getRecordId(), user.getUsername());
+                        }
+                    } catch (Exception e) {
+                        log.info("推送发送询盘邮件的消息失败", e);
+                    }
+                }
+
+            }
+        }
+    }
+
+
+    /**
+     * 根据询盘信息创建邮件发送记录
+     *
+     * @param adwebEnquiry 询盘信息
+     * @param email        接收邮箱
+     * @return
+     */
+    private static EnquiryEmailMessage newEmail(AdwebEnquiry adwebEnquiry, String email) {
+        EnquiryEmailMessage enquiryEmailMessage = new EnquiryEmailMessage();
+        enquiryEmailMessage.setEnquiryId(adwebEnquiry.getId());
+        enquiryEmailMessage.setEmail(email);
+        enquiryEmailMessage.setFromEmail(adwebEnquiry.getFromEmail());
+        enquiryEmailMessage.setCreateTime(new Date());
+        enquiryEmailMessage.setSiteCode(adwebEnquiry.getSiteCode());
+        enquiryEmailMessage.setSendStatus(EnquirySendStatus.WAIT_SEND);
+        enquiryEmailMessage.setSendErrorNum(0);
+
+        return enquiryEmailMessage;
+    }
+
+
+    /**
+     * 通过询盘中的ip字段,获取国家信息并放在询盘对象种
+     *
+     * @param enquiry 询盘对象
+     */
+    private void setCountryByIp(AdwebEnquiry enquiry) {
+        CountryAreaApiDto countryAreaApiDto = geoIpUtil.getCountryAndAreaByIp(enquiry.getFromIp());
+        if (countryAreaApiDto != null) {
+            String countryCode = countryAreaApiDto.getCountryIsoCode();
+            if ("TW".equals(countryCode)) {
+                countryCode = "CN";
+            }
+            String countryName = countryAreaApiDto.getCountryZhCN();
+            if ("中华民国".equals(countryName)) {
+                countryName = "中国";
+            }
+            enquiry.setCountryCode(countryCode);
+            enquiry.setCountryName(countryName);
+            if (StringUtils.isBlank(enquiry.getCountry())) {
+                enquiry.setCountry(countryName);
+            }
+        } else {
+            enquiry.setCountryCode("0000");
+            enquiry.setCountryName("其它");
+        }
+    }
+
+    /**
+     * 根据询盘对象和站点,构建一个本系统中的询盘对象
+     *
+     * @param enquiryDto 询盘对象
+     * @param adwebSite  询盘所属站点
+     * @return 本系统中的询盘队形
+     */
+    private AdwebEnquiry createEnquiry(EnquiryDTO enquiryDto, AdwebSite adwebSite) {
+        AdwebEnquiry adwebEnquiry = new AdwebEnquiry();
+        adwebEnquiry.setId(snowflakeIdUtil.nextId());
+        adwebEnquiry.setCtime(new Date());
+        adwebEnquiry.setStatus(1);
+        adwebEnquiry.setVisitId(enquiryDto.getVisitId());
+        adwebEnquiry.setSiteId(adwebSite.getId());
+        adwebEnquiry.setUid(adwebSite.getUid());
+        adwebEnquiry.setFromIp(enquiryDto.getFromIp());
+        adwebEnquiry.setFromEmail(enquiryDto.getFromEmail());
+        adwebEnquiry.setPluginName(enquiryDto.getPluginName());
+        adwebEnquiry.setRecordId(enquiryDto.getRecordId());
+        adwebEnquiry.setModifyRecordCtime(geoIpService.getLocalhostTime(enquiryDto.getFromIp(), enquiryDto.getRecordCtime()));
+        adwebEnquiry.setRecordCtime(enquiryDto.getRecordCtime());
+        adwebEnquiry.setSiteCode(adwebSite.getCode());
+        adwebEnquiry.setModular(enquiryDto.getPluginName());
+        adwebEnquiry.setSysEffective(NumConstant.ONE);
+        adwebEnquiry.setUserEffective(NumConstant.TWO);
+        adwebEnquiry.setSiteHost(enquiryDto.getSiteHost());
+        adwebEnquiry.setNo("xp" + DateUtil.dateToString(new Date(), DateUtil.DATE_FORMAT) + adwebOpenApiService.loadNo(adwebSite.getCode()));
+
+        // 外部编号暂无作用,且多查询一次数据库,暂时注释
+//        adwebEnquiry.setNoOut(DateUtil.dateToString(new Date(), DateUtil.DATE_FORMAT_THREE) + adwebOpenApiService.loadOutNoByUser(adwebSite.getUid()));
+        adwebEnquiry.setWasteEnquiry(0);
+        adwebEnquiry.setRequestTime( new Date());
+        adwebEnquiry.setAcquireMessageTime(adwebSite.getEnquiryMessageTime());
+        adwebEnquiry.setIsEnquirySync("enquirySync");
+
+        ObjectMapper objectMapper = new ObjectMapper();
+        try {
+            String jsonString = objectMapper.writeValueAsString(enquiryDto.getCartItems());
+            adwebEnquiry.setCartItems(jsonString);
+        } catch (JsonProcessingException e) {
+            // 记录异常信息
+            System.err.println("Error serializing cart items to JSON: " + e.getMessage());
+            // 可以选择记录更详细的堆栈跟踪信息
+            log.error(e.getMessage(), e);
+        }
+        return adwebEnquiry;
+    }
+
+    /**
+     * 解析form,将form中的字段加入到询盘对象种
+     *
+     * @param enquiry 询盘对象
+     * @param form    询盘表单信息
+     */
+    private void parseFormAndSetFields(AdwebEnquiry enquiry, String form, AdwebSite adwebSite) {
+        long startTime = System.currentTimeMillis();
+
+        List<String> nameKeys = this.getFormKeys("wp-name");
+        List<String> emailKeys = this.getFormKeys("wp-email");
+        List<String> messageKeys = this.getFormKeys("wp-content");
+        List<String> companyKeys = this.getFormKeys("wp-company");
+        List<String> fromPageKeys = this.getFormKeys("wp-page");
+        List<String> phoneKeys = this.getFormKeys("wp-phone");
+        List<String> whatsAppKeys = this.getFormKeys("wp-whatsapp");
+        List<String> countryKeys = this.getFormKeys("wp-country");
+        List<String> customerIpKeys = this.getFormKeys("wp-customerip");
+        List<String> addressKeys = this.getFormKeys("wp-address");
+
+        List<String> errorObjNames = new ArrayList<>();
+        Collection<JSONObject> formItems = null;
+        Map<String, JSONObject> formObj = FastJsonUtil.parseObject(form, Map.class);
+        if (formObj == null || formObj.size() == 0) {
+            List<JSONObject> formList = FastJsonUtil.parseObject(form, List.class);
+            if (ListUtil.notEmpty(formList)) {
+                formItems = formList;
+            }
+        } else {
+            formItems = formObj.values();
+        }
+
+        List<EnquirySpecialFields> specialFieldsList = new ArrayList<>();
+        for (JSONObject formItem : formItems) {
+            String formItemName = formItem.getString("name");
+            String formItemValue = formItem.getString("value");
+
+            if (contains(nameKeys, formItemName)) {
+                enquiry.setName(formItemValue);
+            } else if (contains(emailKeys, formItemName)) {
+                enquiry.setEmail(formItemValue);
+            } else if (contains(messageKeys, formItemName)) {
+                enquiry.setMessage(formItemValue);
+            } else if (contains(companyKeys, formItemName)) {
+                enquiry.setCompany(formItemValue);
+            } else if (contains(fromPageKeys, formItemName)) {
+                enquiry.setFromPage(formItemValue);
+            } else if (contains(phoneKeys, formItemName)) {
+                enquiry.setPhone(formItemValue);
+            } else if (contains(whatsAppKeys, formItemName)) {
+                enquiry.setWhatsApp(formItemValue);
+            } else if (contains(countryKeys, formItemName)) {
+                enquiry.setCountry(formItemValue);
+            } else if (contains(customerIpKeys, formItemName)) {
+                enquiry.setCustomerIp(formItemValue);
+            } else if (contains(addressKeys, formItemName)) {
+                enquiry.setAddress(formItemValue);
+            } else {
+                // 异常字段
+                errorObjNames.add(formItemName);
+                EnquirySpecialFields enquirySpecialFields = new EnquirySpecialFields();
+                enquirySpecialFields.setField(formItemName);
+                enquirySpecialFields.setValue(formItemValue);
+                specialFieldsList.add(enquirySpecialFields);
+            }
+        }
+
+        String specialField = FastJsonUtil.toJSONString(specialFieldsList);
+        enquiry.setSpecialField(specialField);
+
+        if (errorObjNames.size() > 0 || enquiry.getRecordCtime() == null || StringUtil.isEmpty(enquiry.getMessage()) || StringUtil.isEmpty(enquiry.getEmail()) || StringUtil.isEmpty(enquiry.getFromPage())) {
+            //发送飞书告警
+            StringBuilder msg = new StringBuilder("询盘异常,\n询盘id:" + enquiry.getId() + ",\n站点名称:" + adwebSite.getName() + ",\n站点域名:" + enquiry.getSiteHost() + ",\n来源ip:" + enquiry.getFromIp());
+            if (errorObjNames.size() > 0) {
+                msg.append(",\n字段异常,存在异常字段:");
+                for (String errorObjName : errorObjNames) {
+                    msg.append(errorObjName).append("、");
+                }
+                msg.deleteCharAt(msg.length() - 1);
+            }
+            if (enquiry.getRecordCtime() == null) {
+                msg.append(",\n询盘发送时间为空");
+            }
+            if (StringUtil.isEmpty(enquiry.getMessage())) {
+                msg.append(",\n询盘内容为空");
+            }
+            if (StringUtil.isEmpty(enquiry.getEmail())) {
+                msg.append(",\n邮箱内容为空");
+            }
+            if (StringUtil.isEmpty(enquiry.getFromPage())) {
+                msg.append(",\n来源页面为空");
+            }
+            // 同一个站点,一天最多报错一次
+            String flag = adwebRedisUtil.getString("forbidden_send_error_msg_by_enquiry_field_" + adwebSite.getDomain());
+            if (StringUtils.isNotBlank(flag)) {
+                log.info("同一个站点,一天最多报错一次,站点域名:" + adwebSite.getDomain());
+                return;
+            }
+            adwebRedisUtil.set("forbidden_send_error_msg_by_enquiry_field_" + adwebSite.getDomain(), "forbidden", 60 * 60 * 24);
+
+            // 异常入库
+            SysException exception = new SysException();
+            exception.setType(0);
+            exception.setFunctionModule("询盘字段配置异常");
+            exception.setExceptionDetail(msg.toString());
+            exception.setCreateTime(new Date());
+            exception.setStatus(1);
+            exception.setHandle(0);
+            exception.setPriority(1);
+            sysExceptionService.save(exception);
+
+            long diffTime = System.currentTimeMillis() - startTime;
+            String className = this.getClass().getName();
+            String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();
+            feishuService.sendRobot((float) diffTime / 1000, "wpforms-询盘警告:" + 0,
+                    className, methodName, String.valueOf(msg));
+        }
+    }
+
+    private boolean contains(List<String> keys, String key) {
+        if (ListUtil.isEmpty(keys) || StringUtil.isEmpty(key)) {
+            return false;
+        }
+        key = key.replace(":", "").replace(":", "").replaceAll(" {2,}", " ").toLowerCase().trim();
+        return keys.contains(key);
+    }
+
+    /**
+     * 根据字典code,获取相应数据在json中所有可能的key,用来解析json
+     *
+     * @param dictCode 字典code
+     * @return key的集合
+     */
+    private List<String> getFormKeys(String dictCode) {
+        String formKey = CacheConstant.SYS_DICT_CACHE + "::" + dictCode;
+        Object obj = adwebRedisUtil.get(formKey);
+        if (obj != null) {
+            List<String> keys = (List<String>) obj;
+            return keys;
+        }
+        List<SysDictItem> dictItems = sysAdwebApiImpl.selectItemsByDictCode(dictCode);
+        List<String> keys = new ArrayList<>();
+        if (ListUtil.notEmpty(dictItems)) {
+            for (SysDictItem item : dictItems) {
+                String value = item.getItemValue();
+                if (StringUtil.isEmpty(value)) {
+                    continue;
+                }
+                value = value.replaceAll(" {2,}", " ").toLowerCase().trim();
+                if (!keys.contains(value)) {
+                    keys.add(value);
+                }
+            }
+        }
+        adwebRedisUtil.set(formKey, keys, 60 * 60);
+        return keys;
+    }
+
+    /**
+     * 判断邮件是否是垃圾询盘
+     * 1、邮件过滤
+     * 2、根据邮件是否包含外部url过滤
+     * 3、根据关键词过滤
+     *
+     * @param adwebEnquiryList 询盘列表
+     */
+    private void judgeWasteEnquiryBySiteId(List<AdwebEnquiry> adwebEnquiryList, AdwebSite adwebSite, List<String> blackWordList) {
+
+        //邮箱 黑名单
+        //先获取对应站点的邮箱黑名单
+        List<String> siteBlackEmailList = (List<String>) adwebRedisUtil.get(SiteBlackEmailKey + "::" + adwebSite.getId());
+        if (ListUtil.isEmpty(siteBlackEmailList)) {
+            enquirySiteBlackEmailService.saveRedisSiteBlackEmailBySiteId(adwebSite.getId(), 0);
+            siteBlackEmailList = (List<String>) adwebRedisUtil.get(SiteBlackEmailKey + "::" + adwebSite.getId());
+            if (ListUtil.isEmpty(siteBlackEmailList)) {
+                siteBlackEmailList = new ArrayList<>();
+            }
+        }
+
+        //邮箱 公共黑名单
+        List<String> publicBlackEmailList = (List<String>) adwebRedisUtil.get(BlackEmailKey);
+        if (ListUtil.isEmpty(publicBlackEmailList)) {
+            List<AdwebPublicBlackEmail> enquiryPublicBlackEmailList = adwebPublicBlackEmailService
+                    .list(new LambdaQueryWrapper<AdwebPublicBlackEmail>()
+                            .ne(AdwebPublicBlackEmail::getStatus, 0)
+                            .eq(AdwebPublicBlackEmail::getBlackOrWhite, 0)
+                            .isNotNull(AdwebPublicBlackEmail::getEmail)
+                            .select(AdwebPublicBlackEmail::getEmail));
+
+            if (ListUtil.notEmpty(enquiryPublicBlackEmailList)) {
+                publicBlackEmailList = enquiryPublicBlackEmailList.stream().map(AdwebPublicBlackEmail::getEmail).filter(StringUtil::isNotEmpty).collect(Collectors.toList());
+                adwebRedisUtil.set(BlackEmailKey, publicBlackEmailList, 60 * 60 * 24);
+            } else {
+                publicBlackEmailList = new ArrayList<>();
+            }
+        } else {
+            publicBlackEmailList = publicBlackEmailList.stream().filter(s -> !s.isEmpty()).collect(Collectors.toList());
+        }
+        List<String> allBlackEmailList = new ArrayList<>();
+        if (ListUtil.notEmpty(siteBlackEmailList)) {
+            allBlackEmailList = new ArrayList<>(siteBlackEmailList);
+        }
+        allBlackEmailList.addAll(publicBlackEmailList);
+        List<String> blackEmailList = new ArrayList<>();
+        if (ListUtil.notEmpty(allBlackEmailList)) {
+            HashSet<String> blackEmailHashSet = new HashSet<String>(allBlackEmailList);
+            blackEmailList = new ArrayList<>(blackEmailHashSet);
+        }
+        log.info("公共邮箱黑名单:" + publicBlackEmailList.size());
+        log.info("站点邮箱黑名单:" + siteBlackEmailList.size());
+
+        //邮箱 白名单
+        //先获取对应站点的邮箱白名单
+        List<String> siteWhiteEmailList = (List<String>) adwebRedisUtil.get(SiteWhiteEmailListKey + "::" + adwebSite.getId());
+        if (ListUtil.isEmpty(siteWhiteEmailList)) {
+            enquirySiteBlackEmailService.saveRedisSiteBlackEmailBySiteId(adwebSite.getId(), 1);
+            siteWhiteEmailList = (List<String>) adwebRedisUtil.get(SiteWhiteEmailListKey + "::" + adwebSite.getId());
+        }
+        //公共邮箱白名单数据
+        List<String> publicWhiteEmailList = (List<String>) adwebRedisUtil.get(WhiteEmailListKey);
+        if (ListUtil.isEmpty(publicWhiteEmailList)) {
+            List<AdwebPublicBlackEmail> enquiryPublicWhiteEmailList = adwebPublicBlackEmailService
+                    .list(new LambdaQueryWrapper<AdwebPublicBlackEmail>()
+                            .ne(AdwebPublicBlackEmail::getStatus, 0)
+                            .eq(AdwebPublicBlackEmail::getBlackOrWhite, 1)
+                            .isNotNull(AdwebPublicBlackEmail::getEmail)
+                            .select(AdwebPublicBlackEmail::getEmail));
+
+            if (ListUtil.notEmpty(enquiryPublicWhiteEmailList)) {
+                publicWhiteEmailList = enquiryPublicWhiteEmailList.stream().map(AdwebPublicBlackEmail::getEmail).filter(StringUtil::isNotEmpty).collect(Collectors.toList());
+                adwebRedisUtil.set(WhiteEmailListKey, publicWhiteEmailList, 60 * 60 * 24);
+            } else {
+                publicWhiteEmailList = new ArrayList<>();
+            }
+        } else {
+            publicWhiteEmailList = publicWhiteEmailList.stream().filter(s -> !s.isEmpty()).collect(Collectors.toList());
+        }
+        List<String> allWhiteEmailList = new ArrayList<>();
+        if (ListUtil.notEmpty(siteWhiteEmailList)) {
+            allWhiteEmailList = new ArrayList<>(siteWhiteEmailList);
+        }
+        allWhiteEmailList.addAll(publicWhiteEmailList);
+        List<String> whiteEmailList = new ArrayList<>();
+        if (ListUtil.notEmpty(allWhiteEmailList)) {
+            HashSet<String> whiteEmailHashSet = new HashSet<String>(allWhiteEmailList);
+            whiteEmailList = new ArrayList<>(whiteEmailHashSet);
+        }
+
+        log.info("公共邮箱白名单:" + FastJsonUtil.toJSONString(publicWhiteEmailList));
+        log.info("站点邮箱白名单:" + FastJsonUtil.toJSONString(siteWhiteEmailList));
+
+        //Ip黑名单
+        //公共ip黑名单
+        List<String> publicBlackIpList = (List<String>) adwebRedisUtil.get(BlackIpKey);
+        if (ListUtil.isEmpty(publicBlackIpList)) {
+            List<AdwebPublicBlackIp> enquiryPublicBlackIpList = adwebPublicBlackIpService
+                    .list(new LambdaQueryWrapper<AdwebPublicBlackIp>()
+                            .ne(AdwebPublicBlackIp::getStatus, 0)
+                            .eq(AdwebPublicBlackIp::getBlackOrWhite, 0)
+                            .select(AdwebPublicBlackIp::getIp));
+            if (ListUtil.notEmpty(enquiryPublicBlackIpList)) {
+                publicBlackIpList = enquiryPublicBlackIpList.stream().map(AdwebPublicBlackIp::getIp).collect(Collectors.toList());
+                adwebRedisUtil.set(BlackIpKey, publicBlackIpList, 60 * 60 * 24);
+            } else {
+                publicBlackIpList = new ArrayList<>();
+            }
+        }
+        //站点ip黑名单
+        List<String> siteBlackIpList = (List<String>) adwebRedisUtil.get(SiteBlackIpKey + "::" + adwebSite.getId());
+        if (ListUtil.isEmpty(siteBlackIpList)) {
+            List<AdwebSiteBlackIp> enquirySiteBlackIpList = adwebSiteBlackIpService
+                    .list(new LambdaQueryWrapper<AdwebSiteBlackIp>()
+                            .ne(AdwebSiteBlackIp::getStatus, 0)
+                            .eq(AdwebSiteBlackIp::getBlackOrWhite, 0)
+                            .eq(AdwebSiteBlackIp::getSiteId, adwebSite.getId())
+                            .select(AdwebSiteBlackIp::getIp));
+            if (ListUtil.notEmpty(enquirySiteBlackIpList)) {
+                siteBlackIpList = enquirySiteBlackIpList.stream().map(AdwebSiteBlackIp::getIp).collect(Collectors.toList());
+                adwebRedisUtil.set(SiteBlackIpKey + "::" + adwebSite.getId(), siteBlackIpList, 60 * 60 * 24);
+            } else {
+                siteBlackIpList = new ArrayList<>();
+            }
+        }
+        List<String> allBlackIpList = new ArrayList<>();
+        if (ListUtil.notEmpty(siteBlackIpList)) {
+            allBlackIpList = new ArrayList<>(siteBlackIpList);
+        }
+        allBlackIpList.addAll(publicBlackIpList);
+        List<String> blackIpList = new ArrayList<>();
+        if (ListUtil.notEmpty(allBlackIpList)) {
+            HashSet<String> blackIpHashSet = new HashSet<String>(allBlackIpList);
+            blackIpList = new ArrayList<>(blackIpHashSet);
+        }
+
+        log.info("公共ip黑名单:{} 个", publicBlackIpList.size());
+        log.info("站点ip黑名单:{} 个", siteBlackIpList.size());
+
+        //Ip白名单
+        //公共Ip白名单
+        List<String> publicWhiteIpList = (List<String>) adwebRedisUtil.get(WhiteIpListKey);
+        if (publicWhiteIpList == null) {
+            List<AdwebPublicBlackIp> enquiryPublicWhiteIpList = adwebPublicBlackIpService
+                    .list(new LambdaQueryWrapper<AdwebPublicBlackIp>()
+                            .ne(AdwebPublicBlackIp::getStatus, 0)
+                            .eq(AdwebPublicBlackIp::getBlackOrWhite, 1)
+                            .select(AdwebPublicBlackIp::getIp));
+            if (ListUtil.notEmpty(enquiryPublicWhiteIpList)) {
+                publicWhiteIpList = enquiryPublicWhiteIpList.stream().map(AdwebPublicBlackIp::getIp).collect(Collectors.toList());
+                adwebRedisUtil.set(WhiteIpListKey, publicWhiteIpList, 60 * 60 * 24);
+            } else {
+                publicWhiteIpList = new ArrayList<>();
+            }
+        }
+        //站点Ip白名单, 基于站点查询
+        List<String> siteWhiteIpList = (List<String>) adwebRedisUtil.get(SiteWhiteIpListKey + "::" + adwebSite.getId());
+        if (ListUtil.isEmpty(siteWhiteIpList)) {
+            List<AdwebSiteBlackIp> enquirySiteWhiteIpList = adwebSiteBlackIpService
+                    .list(new LambdaQueryWrapper<AdwebSiteBlackIp>()
+                            .ne(AdwebSiteBlackIp::getStatus, 0)
+                            .eq(AdwebSiteBlackIp::getBlackOrWhite, 1)
+                            .eq(AdwebSiteBlackIp::getSiteId, adwebSite.getId())
+                            .select(AdwebSiteBlackIp::getIp));
+            if (ListUtil.notEmpty(enquirySiteWhiteIpList)) {
+                siteWhiteIpList = enquirySiteWhiteIpList.stream().map(AdwebSiteBlackIp::getIp).collect(Collectors.toList());
+                adwebRedisUtil.set(SiteWhiteIpListKey + "::" + adwebSite.getId(), siteWhiteIpList, 60 * 60 * 24);
+            } else {
+                siteWhiteIpList = new ArrayList<>();
+            }
+        }
+        List<String> allWhiteIpList = new ArrayList<>();
+        if (ListUtil.notEmpty(siteWhiteIpList)) {
+            allWhiteIpList = new ArrayList<>(siteWhiteIpList);
+        }
+        allWhiteIpList.addAll(publicWhiteIpList);
+        List<String> whiteIpList = new ArrayList<>();
+        if (ListUtil.notEmpty(allWhiteIpList)) {
+            HashSet<String> whiteIpHashSet = new HashSet<String>(allWhiteIpList);
+            whiteIpList = new ArrayList<>(whiteIpHashSet);
+        }
+
+        log.info("公共ip白名单:" + FastJsonUtil.toJSONString(publicWhiteIpList));
+        log.info("站点ip白名单:" + FastJsonUtil.toJSONString(siteWhiteIpList));
+
+        //站点询盘规则黑名单
+        QueryWrapper<AdwebSiteEnquiryRule> adwebEnquirySiteRuleQueryWrapper = new QueryWrapper<>();
+        adwebEnquirySiteRuleQueryWrapper.eq("site_id", adwebSite.getId());
+        adwebEnquirySiteRuleQueryWrapper.eq("status", 1);
+        adwebEnquirySiteRuleQueryWrapper.eq("black_or_white", 0);
+        List<AdwebSiteEnquiryRule> siteBlackRuleList = adwebSiteEnquiryRuleService.list(adwebEnquirySiteRuleQueryWrapper);
+        log.info("站点关键词黑名单:" + FastJsonUtil.toJSONString(siteBlackRuleList));
+
+        //判断上一封询盘是否是垃圾询盘
+        AdwebEnquiry isJudgeWasteEnquiry = new AdwebEnquiry();
+
+        // 判断是否垃圾询盘
+        outerloop:
+        for (AdwebEnquiry adwebEnquiry : adwebEnquiryList) {
+            // 没有message的无法判断,认为是普通询盘
+            if (StringUtil.isEmpty(adwebEnquiry.getMessage())) {
+                adwebEnquiry.setWasteEnquiry(1);
+                adwebEnquiry.setUserEffective(0);
+                log.info("询盘id是:{}, 站点code是:{}, 通过——询盘内容为空——检测到垃圾询盘",
+                        adwebEnquiry.getId(), adwebEnquiry.getSiteCode());
+                continue;
+            }
+
+            //该分支用于判断上一封邮件是否为垃圾询盘
+            dealMultipleRepeatInfoEnquiry(siteBlackEmailList, siteBlackIpList, isJudgeWasteEnquiry, adwebSite);
+            isJudgeWasteEnquiry = adwebEnquiry;
+
+            // 判断 询盘邮箱黑名单
+            if (ListUtil.notEmpty(blackEmailList) || StringUtils.isNotBlank(adwebEnquiry.getEmail())) {
+
+                String email = adwebEnquiry.getEmail().toLowerCase();
+
+                String message = adwebEnquiry.getMessage().replaceAll("[\\n\\t]", " ").replaceAll(" {2,}", " ").toLowerCase();
+
+
+                //公共黑白名单
+//                boolean isContainPublicWhite = false;
+//                String containPublicWhiteStr = "";
+                //白名单
+//                for(String publicWhiteEmail : publicWhiteEmailList){
+//                    log.info("judgeWasteEnquiry -- 当前询盘Id:{},!whiteEmailList.contains(email):{}",adwebEnquiry.getId(),!whiteEmailList.contains(email));
+//                    if(email.equals(publicWhiteEmail) || message.equals(publicWhiteEmail)){
+//                        containPublicWhiteStr = publicWhiteEmail;
+//                        isContainPublicWhite = true;
+//                        break;
+//                    }
+//                }
+
+                //黑名单
+                String containPublicBlackStr = "";
+                boolean isContainPublicBlack = false;
+                if (ListUtil.notEmpty(publicBlackEmailList)) {
+                    for (String blackEmail : publicBlackEmailList) {
+                        String allBlackEmail = blackEmail;
+                        if (allBlackEmail.contains("*")) {
+                            allBlackEmail = allBlackEmail.substring(1, allBlackEmail.length() - 1);
+                            if (email.contains(allBlackEmail) || message.contains(allBlackEmail)) {
+                                containPublicBlackStr = blackEmail;
+                                isContainPublicBlack = true;
+                                break;
+                            }
+                        } else {
+                            if (email.equals(allBlackEmail) || message.equals(allBlackEmail)) {
+                                containPublicBlackStr = blackEmail;
+                                isContainPublicBlack = true;
+                                break;
+                            }
+                        }
+                    }
+                }
+                log.info("是否是公共黑名单:" + isContainPublicBlack);
+                log.info("匹配的公共黑名单:" + containPublicBlackStr);
+                //站点黑白名单
+                boolean isContainSiteWhite = false;
+                boolean isSiteAllContain = true;
+                String containSiteWhiteStr = "";
+                //白名单
+                if (ListUtil.notEmpty(siteWhiteEmailList)) {
+                    for (String whiteEmail : siteWhiteEmailList) {
+                        String compareWhiteEmail = whiteEmail;
+                        if (compareWhiteEmail.contains("*")) {
+                            compareWhiteEmail = whiteEmail.substring(1, whiteEmail.length() - 1);
+                            if (email.contains(compareWhiteEmail) || message.contains(compareWhiteEmail)) {
+                                containSiteWhiteStr = compareWhiteEmail;
+                                isContainSiteWhite = true;
+                                isSiteAllContain = false;
+                                break;
+                            }
+                        } else {
+                            if (email.equals(compareWhiteEmail) || message.equals(compareWhiteEmail)) {
+                                containSiteWhiteStr = compareWhiteEmail;
+                                isContainSiteWhite = true;
+                                isSiteAllContain = false;
+                                break;
+                            }
+                        }
+                    }
+                }
+
+
+                log.info("是否是站点白名单:" + isContainSiteWhite);
+                log.info("匹配的站点白名单:" + containSiteWhiteStr);
+                //黑名单
+                boolean isContainSiteBlack = false;
+                String containSiteBlackStr = "";
+                if (ListUtil.notEmpty(siteBlackEmailList)) {
+                    for (String blackEmail : siteBlackEmailList) {
+                        String allBlackEmail = blackEmail;
+                        if (allBlackEmail.contains("*")) {
+                            allBlackEmail = allBlackEmail.substring(1, allBlackEmail.length() - 1);
+                            if (email.contains(allBlackEmail) || message.contains(allBlackEmail)) {
+                                containSiteBlackStr = allBlackEmail;
+                                isContainSiteBlack = true;
+                                isSiteAllContain = false;
+                                break;
+                            }
+                        } else {
+                            if (email.equals(allBlackEmail) || message.equals(allBlackEmail)) {
+                                containSiteBlackStr = allBlackEmail;
+                                isContainSiteBlack = true;
+                                isSiteAllContain = false;
+                                break;
+                            }
+                        }
+                    }
+                }
+
+
+                log.info("是否是站点黑名单:" + isContainSiteBlack);
+                log.info("匹配的站点黑名单:" + containSiteBlackStr);
+                //判断邮箱或者内容即在黑名单里又在白名单里,特殊处理
+                if (isContainSiteBlack && isContainSiteWhite) {
+                    if (containSiteBlackStr.length() <= containSiteWhiteStr.length()) {
+                        isContainSiteBlack = false;
+                    }
+                }
+
+                log.info("第二次处理是否是站点黑名单:" + isContainSiteBlack);
+                if (isContainPublicBlack || !isSiteAllContain) {
+                    if (isContainPublicBlack && isContainSiteBlack) {
+                        adwebEnquiry.setWasteEnquiry(1);
+                        adwebEnquiry.setUserEffective(0);
+                        adwebEnquiry.setWasteEnquiryType("email");
+                        adwebEnquiry.setEffectiveReason("系统操作-通过公共和站点的询盘邮箱黑名单检测到垃圾询盘-" + containSiteBlackStr);
+                        log.info("询盘id是:{}, 站点code是:{}, 通过——询盘邮箱黑名单——检测到垃圾询盘, 黑名单邮箱是:{}",
+                                adwebEnquiry.getId(), adwebEnquiry.getSiteCode(), containSiteBlackStr);
+                        continue outerloop;
+                    }
+                    if (isContainPublicBlack && isSiteAllContain) {
+                        adwebEnquiry.setWasteEnquiry(1);
+                        adwebEnquiry.setUserEffective(0);
+                        adwebEnquiry.setWasteEnquiryType("email");
+                        adwebEnquiry.setEffectiveReason("系统操作-通过公共的询盘邮箱黑名单检测到垃圾询盘-" + containPublicBlackStr);
+                        log.info("询盘id是:{}, 站点code是:{}, 通过——询盘邮箱黑名单——检测到垃圾询盘, 黑名单邮箱是:{}",
+                                adwebEnquiry.getId(), adwebEnquiry.getSiteCode(), containPublicBlackStr);
+                        continue outerloop;
+                    }
+                    if (!isContainPublicBlack && isContainSiteBlack) {
+                        adwebEnquiry.setWasteEnquiry(1);
+                        adwebEnquiry.setUserEffective(0);
+                        adwebEnquiry.setWasteEnquiryType("email");
+                        adwebEnquiry.setEffectiveReason("系统操作-通过站点的询盘邮箱黑名单检测到垃圾询盘-" + containSiteBlackStr);
+                        log.info("询盘id是:{}, 站点code是:{}, 通过——询盘邮箱黑名单——检测到垃圾询盘, 黑名单邮箱是:{}",
+                                adwebEnquiry.getId(), adwebEnquiry.getSiteCode(), containSiteBlackStr);
+                        continue outerloop;
+                    }
+                }
+            }
+
+            // @see http://52.83.154.198:8082/browse/ADWEBV2-12
+            // 垃圾询盘过滤时IP按照客户IP去使用黑名单过滤而不再使用来源IP
+            // 判断是否为ip黑名单
+            if (ListUtil.notEmpty(blackIpList) || StringUtils.isNotBlank(adwebEnquiry.getCustomerIp())) {
+                String ip = adwebEnquiry.getCustomerIp();
+                //公共ip黑名单
+                boolean isPublicIp = false;
+                if (publicBlackIpList.contains(ip) && !publicWhiteIpList.contains(ip)) {
+                    isPublicIp = true;
+                }
+
+                //站点ip黑名单
+                boolean isSiteIp = false;
+                if (siteBlackIpList.contains(ip) && !siteWhiteIpList.contains(ip)) {
+                    isSiteIp = true;
+                }
+                if (isPublicIp || isSiteIp) {
+                    adwebEnquiry.setWasteEnquiry(1);
+                    adwebEnquiry.setUserEffective(0);
+                    adwebEnquiry.setWasteEnquiryType("ip");
+                }
+                if (isPublicIp && isSiteIp) {
+                    adwebEnquiry.setEffectiveReason("系统操作-通过询盘公共和站点ip黑名单检测到垃圾询盘-" + ip);
+                    log.info("询盘id是:{}, 站点code是:{}, 通过——询盘公共和站点ip黑名单——检测到垃圾询盘, ip是:{}",
+                            adwebEnquiry.getId(), adwebEnquiry.getSiteCode(), ip);
+                    continue;
+                }
+                if (isPublicIp) {
+                    adwebEnquiry.setEffectiveReason("系统操作-通过询盘公共ip黑名单检测到垃圾询盘-" + ip);
+                    log.info("询盘id是:{}, 站点code是:{}, 通过——询盘公共ip黑名单——检测到垃圾询盘, ip是:{}",
+                            adwebEnquiry.getId(), adwebEnquiry.getSiteCode(), ip);
+                    continue;
+                }
+                if (isSiteIp) {
+                    adwebEnquiry.setEffectiveReason("系统操作-通过询盘站点ip黑名单检测到垃圾询盘-" + ip);
+                    log.info("询盘id是:{}, 站点code是:{}, 通过——询盘站点ip黑名单——检测到垃圾询盘, ip是:{}",
+                            adwebEnquiry.getId(), adwebEnquiry.getSiteCode(), ip);
+                    continue;
+                }
+
+            }
+
+            // 判断邮箱是否包含外部链接
+            List<String> urlList = parser(adwebEnquiry.getMessage());
+            if (StringUtils.isNotBlank(adwebSite.getDomain())) {
+                for (String url : urlList) {
+                    if (!adwebSite.getDomain().contains(url)) {
+                        adwebEnquiry.setWasteEnquiry(1);
+                        adwebEnquiry.setUserEffective(0);
+                        adwebEnquiry.setWasteEnquiryType("other");
+                        adwebEnquiry.setEffectiveReason("系统操作-通过站点url检测到垃圾询盘-" + url);
+                        log.info("询盘id是:{}, 站点code是:{}, 通过——站点url——检测到垃圾询盘",
+                                adwebEnquiry.getId(), adwebEnquiry.getSiteCode());
+                        continue outerloop;
+                    }
+                }
+            } else {
+                if (ListUtil.notEmpty(urlList)) {
+                    adwebEnquiry.setWasteEnquiry(1);
+                    adwebEnquiry.setUserEffective(0);
+                    adwebEnquiry.setWasteEnquiryType("other");
+                    adwebEnquiry.setEffectiveReason("系统操作-通过站点url检测到垃圾询盘-空");
+                    log.info("询盘id是:{}, 站点code是:{}, 通过——站点url——检测到垃圾询盘",
+                            adwebEnquiry.getId(), adwebEnquiry.getSiteCode());
+                    continue;
+                }
+            }
+
+            // 判断询盘是否包含关键词
+            String message = adwebEnquiry.getMessage().replaceAll("[\\n\\t]",
+                    " ").replaceAll(" {2,}", " ").toLowerCase();
+            if (ListUtil.notEmpty(blackWordList) || ListUtil.notEmpty(siteBlackRuleList)) {
+                //公共关键词黑名单
+                boolean isPublicWord = false;
+                String isBlackWord = "";
+                for (String blackWord : blackWordList) {
+                    if (message.contains(blackWord)) {
+                        isPublicWord = true;
+                        isBlackWord = blackWord;
+                    }
+                }
+                //站点关键词黑名单
+                boolean isSiteWord = false;
+                for (AdwebSiteEnquiryRule siteBlackRule : siteBlackRuleList) {
+                    if (message.contains(siteBlackRule.getWord())) {
+                        isSiteWord = true;
+                        isBlackWord = siteBlackRule.getWord();
+                    }
+                }
+                if (isPublicWord || isSiteWord) {
+                    adwebEnquiry.setWasteEnquiry(1);
+                    adwebEnquiry.setUserEffective(0);
+                    adwebEnquiry.setWasteEnquiryType("keyword");
+                }
+                if (isPublicWord && isSiteWord) {
+                    adwebEnquiry.setEffectiveReason("系统操作-通过公共和站点关键词黑名单检测到垃圾询盘-" + isBlackWord);
+                    log.info("询盘id是:{}, 站点code是:{}, 通过——公共和站点关键词黑名单——检测到垃圾询盘, 关键词是:{}",
+                            adwebEnquiry.getId(), adwebEnquiry.getSiteCode(), isBlackWord);
+                    continue outerloop;
+                }
+                if (isPublicWord) {
+                    adwebEnquiry.setEffectiveReason("系统操作-通过公共关键词黑名单检测到垃圾询盘-" + isBlackWord);
+                    log.info("询盘id是:{}, 站点code是:{}, 通过——公共关键词黑名单——检测到垃圾询盘, 关键词是:{}",
+                            adwebEnquiry.getId(), adwebEnquiry.getSiteCode(), isBlackWord);
+                    continue outerloop;
+                }
+                if (isSiteWord) {
+                    adwebEnquiry.setEffectiveReason("系统操作-通过站点关键词黑名单检测到垃圾询盘-" + isBlackWord);
+                    log.info("询盘id是:{}, 站点code是:{}, 通过——站点关键词黑名单——检测到垃圾询盘, 关键词是:{}",
+                            adwebEnquiry.getId(), adwebEnquiry.getSiteCode(), isBlackWord);
+                    continue outerloop;
+                }
+            }
+
+            // 分词判断
+            if (validateWordLength(adwebEnquiry.getMessage())) {
+                adwebEnquiry.setWasteEnquiry(1);
+                adwebEnquiry.setUserEffective(0);
+                adwebEnquiry.setWasteEnquiryType("other");
+                adwebEnquiry.setEffectiveReason("系统操作-通过单词长度超过50个字符检测到垃圾询盘");
+                log.info("询盘id是:{}, 站点code是:{}, 通过——单词长度超过50个字符——检测到垃圾询盘",
+                        adwebEnquiry.getId(), adwebEnquiry.getSiteCode());
+                continue;
+            }
+
+            boolean isBlackFlag = false;
+
+            // 询盘为正常询盘
+            // 判断十分钟和一天内同个站点是否有相同的邮箱
+            if (StringUtils.isNotBlank(adwebEnquiry.getEmail()) && !whiteEmailList.contains(adwebEnquiry.getEmail().toLowerCase())) {
+                isBlackFlag = dealShortSameEmail(adwebEnquiry, blackEmailList, adwebSite, siteBlackEmailList);
+            }
+
+            // 判断十分钟和一天内同个站点是否有相同的Ip
+            if (StringUtils.isNotBlank(adwebEnquiry.getFromIp()) && !whiteIpList.contains(adwebEnquiry.getFromIp())) {
+                isBlackFlag = dealShortSameIp(adwebEnquiry, blackIpList, adwebSite, siteBlackIpList);
+            }
+            if (isBlackFlag) {
+                continue;
+            }
+            adwebEnquiry.setWasteEnquiry(0);
+            adwebEnquiry.setUserEffective(2);
+            // 此处为正常询盘,清除疑似垃圾询盘可能性
+            isJudgeWasteEnquiry = null;
+            log.info("询盘id是:{}, 站点code是:{}, 不是垃圾询盘", adwebEnquiry.getId(), adwebEnquiry.getSiteCode());
+        }
+
+        //判断最后一个询盘是否为垃圾询盘
+        isPreviousOneWasteEnquiry(blackEmailList, blackIpList, isJudgeWasteEnquiry);
+
+        //更新redis
+        //站点
+        if (ListUtil.notEmpty(siteBlackEmailList)) {
+            adwebRedisUtil.set(SiteBlackEmailKey + "::" + adwebSite.getId(), siteBlackEmailList, 86400);
+        }
+        if (ListUtil.notEmpty(siteBlackIpList)) {
+            adwebRedisUtil.set(SiteBlackIpKey + "::" + adwebSite.getId(), siteBlackIpList, 86400);
+        }
+        if (ListUtil.notEmpty(siteWhiteEmailList)) {
+            adwebRedisUtil.set(SiteWhiteEmailListKey + "::" + adwebSite.getId(), siteWhiteEmailList, 86400);
+        }
+        if (ListUtil.notEmpty(siteWhiteIpList)) {
+            adwebRedisUtil.set(SiteWhiteIpListKey + "::" + adwebSite.getId(), siteWhiteIpList, 86400);
+        }
+        //公共
+        if (ListUtil.notEmpty(publicBlackEmailList)) {
+            adwebRedisUtil.set(BlackEmailKey, publicBlackEmailList, 86400);
+        }
+        if (ListUtil.notEmpty(publicBlackIpList)) {
+            adwebRedisUtil.set(BlackIpKey, publicBlackIpList, 86400);
+        }
+        if (ListUtil.notEmpty(publicWhiteEmailList)) {
+            adwebRedisUtil.set(WhiteEmailListKey, publicWhiteEmailList, 86400);
+        }
+        if (ListUtil.notEmpty(publicWhiteIpList)) {
+            adwebRedisUtil.set(WhiteIpListKey, publicWhiteIpList, 86400);
+        }
+    }
+
+    private boolean validateWordLength(String text) {
+        if (StringUtil.isEmpty(text)) {
+            return false;
+        }
+        int maxWordLength = EnglishAnalyzer.getLongestSize(text);
+        int limit;
+        SysDictItem dictItem = dictService.getDictItemByCodeAndText("max_word_length", "default");
+        if (dictItem == null || StringUtil.isEmpty(dictItem.getItemValue())) {
+            limit = 50;
+        } else {
+            limit = Integer.parseInt(dictItem.getItemValue());
+        }
+        return (maxWordLength > limit);
+    }
+
+
+    private List<String> parser(String text) {
+        Pattern pattern1 = Pattern.compile("(https?|ftp|file)://([-a-zA-Z0-9]+\\.)+[a-zA-Z0-9]+");
+        List<String> domainPatterns = getFormKeys("enquiry_domain_pattern");
+        String domainPattern = "";
+        if (ListUtil.notEmpty(domainPatterns)) {
+            domainPattern = domainPatterns.get(0);
+        }
+        if (StringUtil.isEmpty(domainPattern)) {
+            domainPattern = "([-a-zA-Z0-9]+\\.)+(com|cn|net|org|edu|hk|fr|de|uk|eu|tw|ph|my|id|in|ind|co|pk|mx|us" +
+                    "|ve|ar|eg|online|xyz|me|jp|ly|baz|io|cc|tv|club|xxx|host|ltd|vip|work|fit|pub|love|xin|info|pro|post|coop|int|jobs|cat|travel" +
+                    "|ru|onion|site|it)+";
+        } else {
+            domainPattern = "([-a-zA-Z0-9]+\\.)+" + domainPattern;
+        }
+        Pattern pattern2 = Pattern.compile(domainPattern);
+
+        // 邮箱正则
+        Pattern pattern3 = Pattern.compile("[a-zA-Z0-9_\\-\\.]+@[a-zA-Z0-9_\\-\\.]+\\.[a-zA-Z0-9_\\-\\.]+");
+
+        //判断正文中是否存在邮箱
+        Matcher matcher = pattern3.matcher(text);
+        List<String> emailList = new ArrayList<>();
+        while (matcher.find()) {
+            String keyWord = matcher.group();
+            String lastWord = keyWord.substring(keyWord.length() - 1);
+            if (".".equals(lastWord)) {
+                keyWord = keyWord.substring(0, keyWord.length() - 1);
+            }
+            emailList.add(keyWord);
+            if (keyWord.lastIndexOf("@") > -1) {
+                emailList.add(keyWord.substring(keyWord.lastIndexOf("@") + 1));
+                emailList.add(keyWord.substring(0, keyWord.lastIndexOf("@")));
+            }
+        }
+
+        List<String> urls = new ArrayList<>();
+
+        Matcher matcher1 = pattern1.matcher(text);
+        while (matcher1.find()) {
+            urls.add(matcher1.group());
+        }
+
+        Matcher matcher2 = pattern2.matcher(text);
+        while (matcher2.find()) {
+            urls.add(matcher2.group());
+        }
+
+        // 如果邮箱和 URL 都存在,并且 URL 中不包含 http 和 https,则从 URL 中删除邮箱
+        if (ListUtil.notEmpty(emailList)) {
+            Set<String> urlSet = new HashSet<>(urls);
+            urlSet.removeAll(emailList.stream()
+                    .filter(email -> urlSet.contains(email) && !email.contains("http") && !email.contains("https"))
+                    .collect(Collectors.toSet()));
+            urls = new ArrayList<>(urlSet);
+        }
+
+        urls = urls.stream().distinct().collect(Collectors.toList());
+        return urls;
+    }
+
+    /**
+     * 判断是否时垃圾询盘
+     */
+    private void isPreviousOneWasteEnquiry(List<String> blackEmailList, List<String> blackIpList, AdwebEnquiry isJudgeWasteEnquiry) {
+        if (isJudgeWasteEnquiry != null && StringUtils.isNotBlank(isJudgeWasteEnquiry.getSiteCode())) {
+            log.info("上一封邮件为垃圾询盘,处理中...");
+            boolean emailFlag = false;
+            String isJudgeWasteEnquiryEmail = isJudgeWasteEnquiry.getEmail().toLowerCase();
+            if (StringUtils.isNotBlank(isJudgeWasteEnquiryEmail) && ListUtil.notEmpty(blackEmailList)) {
+                for (String blackEmail : blackEmailList) {
+                    if (isJudgeWasteEnquiry.getEmail().equals(blackEmail)) {
+                        emailFlag = false;
+                        break;
+                    } else if (blackEmail.contains("*")) {
+                        String generalBlackEmail = blackEmail.substring(1, blackEmail.length() - 1 - 1);
+                        if (isJudgeWasteEnquiry.getEmail().contains(generalBlackEmail)) {
+                            emailFlag = false;
+                            break;
+                        }
+                    } else {
+                        emailFlag = true;
+                    }
+                }
+            }
+
+            boolean ipFlag = StringUtils.isNotBlank(isJudgeWasteEnquiry.getFromIp()) && blackIpList != null && !blackIpList.contains(isJudgeWasteEnquiry.getFromIp());
+
+            //该分支用于判断上一封垃圾询盘 不在邮箱黑名单中
+            if (emailFlag) {
+                Integer notBlackEmailWasteListCount = null;
+                if (adwebRedisUtil.hasKey(NotBlackEmailWasteEnquiryKey + isJudgeWasteEnquiry.getEmail())) {
+                    notBlackEmailWasteListCount = (Integer) adwebRedisUtil.get(NotBlackEmailWasteEnquiryKey + isJudgeWasteEnquiry.getEmail()) + 1;
+                } else {
+                    notBlackEmailWasteListCount = 1;
+                }
+                adwebRedisUtil.set(NotBlackEmailWasteEnquiryKey + isJudgeWasteEnquiry.getEmail(), notBlackEmailWasteListCount, 60L * 60 * 24 * emailNotBlackListDate);
+
+                //该分支用于判断是否超过
+                if (notBlackEmailWasteListCount > emailNotBlackListNum) {
+                    AdwebPublicBlackEmail blackEmail = new AdwebPublicBlackEmail(isJudgeWasteEnquiry.getEmail(), NumConstant.ONE, NumConstant.ZERO);
+                    if (adwebPublicBlackEmailService.count(new QueryWrapper<AdwebPublicBlackEmail>().eq("email", isJudgeWasteEnquiry.getEmail()).ne("status", 0)) == 0) {
+                        adwebPublicBlackEmailService.save(blackEmail);
+                        blackEmailList.add(isJudgeWasteEnquiry.getEmail());
+                        log.info("询盘id是:{}, 站点code是:{}, 检测重复,已标记邮箱, 邮箱是:{}", isJudgeWasteEnquiry.getId(), isJudgeWasteEnquiry.getSiteCode(), isJudgeWasteEnquiry.getEmail());
+                    }
+                    adwebRedisUtil.del(NotBlackEmailWasteEnquiryKey + isJudgeWasteEnquiry.getEmail());
+                }
+            }
+            if (ipFlag) {
+                Integer notBlackIpWasteListCount = null;
+                if (adwebRedisUtil.hasKey(NotBlackIpWasteEnquiryKey + isJudgeWasteEnquiry.getFromIp())) {
+                    notBlackIpWasteListCount = (Integer) adwebRedisUtil.get(NotBlackIpWasteEnquiryKey + isJudgeWasteEnquiry.getFromIp()) + 1;
+                } else {
+                    notBlackIpWasteListCount = 1;
+                }
+                adwebRedisUtil.set(NotBlackIpWasteEnquiryKey + isJudgeWasteEnquiry.getFromIp(), notBlackIpWasteListCount, 60L * 60 * 24 * ipNotBlackListDate);
+
+                //该分支用于判断是否出现超过
+                if (notBlackIpWasteListCount > ipNotBlackListNum) {
+                    AdwebPublicBlackIp blackIp = new AdwebPublicBlackIp(isJudgeWasteEnquiry.getFromIp(), NumConstant.ONE, NumConstant.ZERO);
+                    if (adwebPublicBlackIpService.count(new QueryWrapper<AdwebPublicBlackIp>().eq("ip", isJudgeWasteEnquiry.getFromIp()).ne("status", 0)) == 0) {
+                        adwebPublicBlackIpService.save(blackIp);
+                        blackIpList.add(isJudgeWasteEnquiry.getFromIp());
+                        log.info("询盘id是:{}, 站点code是:{}, 检测重复,已标记ip, ip是:{}", isJudgeWasteEnquiry.getId(), isJudgeWasteEnquiry.getSiteCode(), isJudgeWasteEnquiry.getFromIp());
+                    }
+                    adwebRedisUtil.del(NotBlackIpWasteEnquiryKey + isJudgeWasteEnquiry.getFromIp());
+                }
+            }
+        }
+    }
+
+    /**
+     * 当同步询盘拉取时,处理同个邮箱或者同个ip的询盘达到一定数量后置为黑名单
+     * 如果是公共黑名单
+     */
+    private void dealMultipleRepeatInfoEnquiry(List<String> siteBlackEmailList, List<String> siteBlackIpList, AdwebEnquiry isJudgeWasteEnquiry, AdwebSite adwebSite) {
+        if (isJudgeWasteEnquiry != null && StringUtils.isNotBlank(isJudgeWasteEnquiry.getSiteCode())) {
+            log.info("上一封邮件为垃圾询盘,处理中...");
+            boolean emailFlag = false;
+            String isJudgeWasteEnquiryEmail = isJudgeWasteEnquiry.getEmail().toLowerCase();
+            if (StringUtils.isNotBlank(isJudgeWasteEnquiryEmail) && ListUtil.notEmpty(siteBlackEmailList)) {
+                for (String blackEmail : siteBlackEmailList) {
+                    if (isJudgeWasteEnquiry.getEmail().equals(blackEmail)) {
+                        emailFlag = false;
+                        break;
+                    } else if (blackEmail.contains("*")) {
+                        String generalBlackEmail = blackEmail.substring(1, blackEmail.length() - 1 - 1);
+                        if (isJudgeWasteEnquiry.getEmail().contains(generalBlackEmail)) {
+                            emailFlag = false;
+                            break;
+                        }
+                    } else {
+                        emailFlag = true;
+                    }
+                }
+            }
+
+            boolean ipFlag = StringUtils.isNotBlank(isJudgeWasteEnquiry.getFromIp()) && siteBlackIpList != null && !siteBlackIpList.contains(isJudgeWasteEnquiry.getFromIp());
+
+            //该分支用于判断上一封垃圾询盘 不在邮箱黑名单中
+            if (emailFlag) {
+                Integer notBlackEmailWasteListCount = null;
+                if (adwebRedisUtil.hasKey(NotBlackEmailWasteSiteEnquiryKey + adwebSite.getId() + "::" + isJudgeWasteEnquiry.getEmail())) {
+                    notBlackEmailWasteListCount = (Integer) adwebRedisUtil.get(NotBlackEmailWasteSiteEnquiryKey + adwebSite.getId() + "::" + isJudgeWasteEnquiry.getEmail()) + 1;
+                } else {
+                    notBlackEmailWasteListCount = 1;
+                }
+                adwebRedisUtil.set(NotBlackEmailWasteSiteEnquiryKey + adwebSite.getId() + "::" + isJudgeWasteEnquiry.getEmail(), notBlackEmailWasteListCount, 60L * 60 * 24 * emailNotBlackListDate);
+
+                //该分支用于判断是否超过
+                if (notBlackEmailWasteListCount > emailNotBlackListNum) {
+                    if (enquirySiteBlackEmailService.count(new QueryWrapper<AdwebSiteBlackEmail>().eq("email", isJudgeWasteEnquiry.getEmail()).ne("status", 0).eq("site_id", adwebSite.getId()).eq("black_or_white", 0)) == 0) {
+                        siteBlackEmailList.add(isJudgeWasteEnquiry.getEmail());
+                        log.info("询盘id是:{}, 站点code是:{}, 检测重复,已标记邮箱, 邮箱是:{}", isJudgeWasteEnquiry.getId(), isJudgeWasteEnquiry.getSiteCode(), isJudgeWasteEnquiry.getEmail());
+                    }
+                    EffectiveEnquiryParamDto effectiveEnquiryParamDto = new EffectiveEnquiryParamDto();
+                    effectiveEnquiryParamDto.setSiteId(adwebSite.getId());
+                    effectiveEnquiryParamDto.setSiteCode(adwebSite.getCode());
+                    effectiveEnquiryParamDto.setWasteEnquirySeason(isJudgeWasteEnquiry.getEmail());
+                    enquirySiteBlackEmailService.addBlackEmailByContent(effectiveEnquiryParamDto);
+                    adwebRedisUtil.del(NotBlackEmailWasteSiteEnquiryKey + adwebSite.getId() + "::" + isJudgeWasteEnquiry.getEmail());
+                }
+            }
+            if (ipFlag) {
+                Integer notBlackIpWasteListCount = null;
+                if (adwebRedisUtil.hasKey(NotSiteBlackIpWasteEnquiryKey + adwebSite.getId() + "::" + isJudgeWasteEnquiry.getFromIp())) {
+                    notBlackIpWasteListCount = (Integer) adwebRedisUtil.get(NotSiteBlackIpWasteEnquiryKey + adwebSite.getId() + "::" + isJudgeWasteEnquiry.getFromIp()) + 1;
+                } else {
+                    notBlackIpWasteListCount = 1;
+                }
+                adwebRedisUtil.set(NotSiteBlackIpWasteEnquiryKey + adwebSite.getId() + "::" + isJudgeWasteEnquiry.getFromIp(), notBlackIpWasteListCount, 60L * 60 * 24 * ipNotBlackListDate);
+
+                //该分支用于判断是否出现超过
+                if (notBlackIpWasteListCount > ipNotBlackListNum) {
+                    if (adwebSiteBlackIpService.count(new QueryWrapper<AdwebSiteBlackIp>().eq("ip", isJudgeWasteEnquiry.getFromIp()).ne("status", 0).eq("site_id", adwebSite.getId()).eq("black_or_white", 0)) == 0) {
+                        siteBlackIpList.add(isJudgeWasteEnquiry.getFromIp());
+                        log.info("询盘id是:{}, 站点code是:{}, 检测重复,已标记ip, ip是:{}", isJudgeWasteEnquiry.getId(), isJudgeWasteEnquiry.getSiteCode(), isJudgeWasteEnquiry.getFromIp());
+                    }
+                    EffectiveEnquiryParamDto effectiveEnquiryParamDto = new EffectiveEnquiryParamDto();
+                    effectiveEnquiryParamDto.setWasteEnquirySeason(isJudgeWasteEnquiry.getFromIp());
+                    effectiveEnquiryParamDto.setSiteId(adwebSite.getId());
+                    effectiveEnquiryParamDto.setSiteCode(adwebSite.getCode());
+                    adwebSiteBlackIpService.addBlackIpByContent(effectiveEnquiryParamDto);
+                    adwebRedisUtil.del(NotSiteBlackIpWasteEnquiryKey + adwebSite.getId() + "::" + isJudgeWasteEnquiry.getFromIp());
+                }
+            }
+        }
+    }
+
+    /**
+     * 当同步询盘拉取时,处理10分钟或一天同个邮箱的询盘达到一定数量后置为黑名单
+     */
+    private boolean dealShortSameEmail(AdwebEnquiry adwebEnquiry, List<String> blackEmailList, AdwebSite adwebSite, List<String> siteBlackEmailList) {
+        Integer tenMin = null;
+        String TenMinKey = SiteEmailTenMinKey + adwebSite.getId() + "::" + adwebEnquiry.getEmail();
+        String oneDayKey = SiteEmailOneDayKey + adwebSite.getId() + "::" + adwebEnquiry.getEmail();
+        if (adwebRedisUtil.hasKey(TenMinKey)) {
+            tenMin = (Integer) adwebRedisUtil.get(TenMinKey) + 1;
+        } else {
+            tenMin = 1;
+        }
+        adwebRedisUtil.set(TenMinKey, tenMin, 10 * 60);
+
+        if (tenMin > emailTenMinNum) {
+            adwebEnquiry.setWasteEnquiry(1);
+            adwebEnquiry.setUserEffective(0);
+            adwebEnquiry.setWasteEnquiryType("email");
+            adwebEnquiry.setEffectiveReason("系统操作-通过十分钟内重复邮箱检测到垃圾询盘-" + adwebEnquiry.getEmail());
+            log.info("询盘id是:{}, 站点code是:{}, 通过——十分钟内—重复邮箱—检测到垃圾询盘",
+                    adwebEnquiry.getId(), adwebEnquiry.getSiteCode());
+            if (enquirySiteBlackEmailService.count(new QueryWrapper<AdwebSiteBlackEmail>().eq("email", adwebEnquiry.getEmail()).ne("status", 0).eq("site_id", adwebSite.getId()).eq("black_or_white", 0)) == 0) {
+                siteBlackEmailList.add(adwebEnquiry.getEmail());
+                blackEmailList.add(adwebEnquiry.getEmail());
+                log.info("询盘id是:{}, 站点code是:{}, 检测十分钟内重复,已标记邮箱, 邮箱是:{}", adwebEnquiry.getId(), adwebEnquiry.getSiteCode(), adwebEnquiry.getEmail());
+            }
+            // 存储到数据库中
+            EffectiveEnquiryParamDto effectiveEnquiryParamDto = new EffectiveEnquiryParamDto();
+            effectiveEnquiryParamDto.setSiteId(adwebSite.getId());
+            effectiveEnquiryParamDto.setSiteCode(adwebSite.getCode());
+            effectiveEnquiryParamDto.setWasteEnquirySeason(adwebEnquiry.getEmail());
+            enquirySiteBlackEmailService.addBlackEmailByContent(effectiveEnquiryParamDto);
+            // 清除map中的数据
+            adwebRedisUtil.del(TenMinKey);
+            adwebRedisUtil.del(oneDayKey);
+            return true;
+        }
+
+        //如果10分钟内发送了则1天用判断了
+        Integer oneDay = null;
+        if (adwebRedisUtil.hasKey(oneDayKey)) {
+            oneDay = (Integer) adwebRedisUtil.get(oneDayKey) + 1;
+        } else {
+            oneDay = 1;
+        }
+        adwebRedisUtil.set(oneDayKey, oneDay, 24 * 60 * 60);
+
+        if (oneDay > emailOneDayNum) {
+            adwebEnquiry.setWasteEnquiry(1);
+            adwebEnquiry.setUserEffective(0);
+            adwebEnquiry.setWasteEnquiryType("email");
+            adwebEnquiry.setEffectiveReason("系统操作-通过一天内重复邮箱检测到垃圾询盘-" + adwebEnquiry.getEmail());
+            log.info("询盘id是:{}, 站点code是:{}, 通过——一天内—重复邮箱—检测到垃圾询盘",
+                    adwebEnquiry.getId(), adwebEnquiry.getSiteCode());
+            log.info("'--------dealShortSameEmail -----'===>adwebEnquiry.getEmail():{}", adwebEnquiry.getEmail());
+            log.info("'--------dealShortSameEmail -----'===>adwebSite.getId():{}", adwebSite.getId());
+            if (enquirySiteBlackEmailService.count(new QueryWrapper<AdwebSiteBlackEmail>().eq("email", adwebEnquiry.getEmail()).ne("status", 0).eq("site_id", adwebSite.getId()).eq("black_or_white", 0)) == 0) {
+                siteBlackEmailList.add(adwebEnquiry.getEmail());
+                blackEmailList.add(adwebEnquiry.getEmail());
+                log.info("询盘id是:{}, 站点code是:{}, 检测十分钟内重复,已标记邮箱, 邮箱是:{}", adwebEnquiry.getId(), adwebEnquiry.getSiteCode(), adwebEnquiry.getEmail());
+            }
+            // 存储到数据库中
+            EffectiveEnquiryParamDto effectiveEnquiryParamDto = new EffectiveEnquiryParamDto();
+            effectiveEnquiryParamDto.setSiteId(adwebSite.getId());
+            effectiveEnquiryParamDto.setSiteCode(adwebSite.getCode());
+            effectiveEnquiryParamDto.setWasteEnquirySeason(adwebEnquiry.getEmail());
+            enquirySiteBlackEmailService.addBlackEmailByContent(effectiveEnquiryParamDto);
+            // 清除map中的数据
+            adwebRedisUtil.del(oneDayKey);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * 当同步询盘拉取时,处理同个ip的询盘达到一定数量后置为黑名单
+     * 如果是公共黑名单
+     */
+    private boolean dealShortSameIp(AdwebEnquiry adwebEnquiry, List<String> blackIpList, AdwebSite adwebSite, List<String> siteBlackIpList) {
+        Integer tenMin = null;
+        String tenMinKey = SiteIpTenMinKey + adwebSite.getId() + "::" + adwebEnquiry.getFromIp();
+        String oneDayKey = SiteIpOneDayKey + adwebSite.getId() + "::" + adwebEnquiry.getFromIp();
+        if (adwebRedisUtil.hasKey(tenMinKey)) {
+            tenMin = (Integer) adwebRedisUtil.get(tenMinKey) + 1;
+        } else {
+            tenMin = 1;
+        }
+        adwebRedisUtil.set(tenMinKey, tenMin, 10 * 60);
+        if (tenMin > ipTenMinNum) {
+            adwebEnquiry.setWasteEnquiry(1);
+            adwebEnquiry.setUserEffective(0);
+            adwebEnquiry.setWasteEnquiryType("ip");
+            adwebEnquiry.setEffectiveReason("系统操作-通过十分钟内重复IP检测到垃圾询盘-" + adwebEnquiry.getFromIp());
+            log.info("询盘id是:{}, 站点code是:{}, 通过——十分钟内—重复IP—检测到垃圾询盘", adwebEnquiry.getId(), adwebEnquiry.getSiteCode());
+            if (adwebSiteBlackIpService.count(new QueryWrapper<AdwebSiteBlackIp>().eq("ip", adwebEnquiry.getFromIp()).ne("status", 0).eq("site_id", adwebSite.getId()).eq("black_or_white", 0)) == 0) {
+                siteBlackIpList.add(adwebEnquiry.getFromIp());
+                blackIpList.add(adwebEnquiry.getFromIp());
+                log.info("询盘id是:{}, 站点code是:{}, 检测十分钟内重复,已标记ip, ip是:{}", adwebEnquiry.getId(), adwebEnquiry.getSiteCode(), adwebEnquiry.getFromIp());
+            }
+            // 存储到数据库中
+            EffectiveEnquiryParamDto effectiveEnquiryParamDto = new EffectiveEnquiryParamDto();
+            effectiveEnquiryParamDto.setWasteEnquirySeason(adwebEnquiry.getFromIp());
+            effectiveEnquiryParamDto.setSiteId(adwebSite.getId());
+            effectiveEnquiryParamDto.setSiteCode(adwebSite.getCode());
+            adwebSiteBlackIpService.addBlackIpByContent(effectiveEnquiryParamDto);
+            // 清除map中的数据
+            adwebRedisUtil.del(tenMinKey);
+            adwebRedisUtil.del(oneDayKey);
+            return true;
+        }
+
+        Integer oneDay = null;
+        if (adwebRedisUtil.hasKey(oneDayKey)) {
+            oneDay = (Integer) adwebRedisUtil.get(oneDayKey) + 1;
+        } else {
+            oneDay = 1;
+        }
+        adwebRedisUtil.set(oneDayKey, oneDay, 24 * 60 * 60);
+        if (oneDay > ipOneDayNum) {
+            adwebEnquiry.setWasteEnquiry(1);
+            adwebEnquiry.setUserEffective(0);
+            adwebEnquiry.setWasteEnquiryType("ip");
+            adwebEnquiry.setEffectiveReason("系统操作-通过一天内重复IP检测到垃圾询盘-" + adwebEnquiry.getFromIp());
+            log.info("询盘id是:{}, 站点code是:{}, 通过——一天内—重复IP—检测到垃圾询盘", adwebEnquiry.getId(), adwebEnquiry.getSiteCode());
+            if (adwebSiteBlackIpService.count(new QueryWrapper<AdwebSiteBlackIp>().eq("ip", adwebEnquiry.getFromIp()).ne("status", 0).eq("site_id", adwebSite.getId()).eq("black_or_white", 0)) == 0) {
+                siteBlackIpList.add(adwebEnquiry.getFromIp());
+                blackIpList.add(adwebEnquiry.getFromIp());
+                log.info("询盘id是:{}, 站点code是:{}, 检测一天内重复,已标记ip, ip是:{}", adwebEnquiry.getId(), adwebEnquiry.getSiteCode(), adwebEnquiry.getFromIp());
+            }
+            // 存储到数据库中
+            EffectiveEnquiryParamDto effectiveEnquiryParamDto = new EffectiveEnquiryParamDto();
+            effectiveEnquiryParamDto.setWasteEnquirySeason(adwebEnquiry.getFromIp());
+            effectiveEnquiryParamDto.setSiteId(adwebSite.getId());
+            effectiveEnquiryParamDto.setSiteCode(adwebSite.getCode());
+            adwebSiteBlackIpService.addBlackIpByContent(effectiveEnquiryParamDto);
+            // 清除map中的数据
+            adwebRedisUtil.del(oneDayKey);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * 判断是否是在黑名单中
+     *
+     * @param adwebEnquiryList 询盘列表
+     */
+    private void judgeBlacklist(List<AdwebEnquiry> adwebEnquiryList) {
+        for (AdwebEnquiry enquiry : adwebEnquiryList) {
+            boolean isBlackEnquiry = adwebEnquiryBlacklistService.isBlackEnquiry(enquiry);
+            if (isBlackEnquiry) {
+                enquiry.setStatus(0);
+                enquiry.setPushStatus(2);
+            }
+        }
+    }
+
+    @Override
+    public void returnSalesperson(String siteCode,String inquiryId,String sales) {
+        log.info("返回跟进人名称开始");
+        //获取站点
+        QueryWrapper<AdwebSite> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("code",siteCode);
+        AdwebSite adwebSite = adwebSiteService.getOne(queryWrapper);
+
+        RestTemplate restTemplate = new RestTemplate();
+        String url = adwebSite.getDomain() + "/wp-json/inquiry/v1/add-sales";
+        log.info("请求地址{}",url);
+        // 如果需要传递参数
+        HttpHeaders headers = new HttpHeaders();
+        headers.set("Content-Type", "application/json");
+        // 构建请求体,将 recordId 和 name 作为参数传递
+        String requestBody = "{ \"inquiryId\": \"" + inquiryId + "\", \"sales\": \"" + sales + "\" }";
+        log.info("请求参数{}", requestBody);
+        HttpEntity<String> entity = new HttpEntity<>(requestBody, headers);
+
+        // 发送请求
+        restTemplate.exchange(url, HttpMethod.POST, entity, String.class);
+        log.info("返回跟进人名称结束");
+    }
 }

+ 177 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/service/impl/AdwebPublicBlackEmailServiceImpl.java

@@ -0,0 +1,177 @@
+package org.jeecg.modules.adweb.enquiry.service.impl;
+
+import cn.hutool.core.date.DateUtil;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.jeecg.common.util.RedisUtil;
+import org.jeecg.modules.adweb.enquiry.entity.AdwebEnquiry;
+import org.jeecg.modules.adweb.enquiry.entity.AdwebPublicBlackEmail;
+import org.jeecg.modules.adweb.enquiry.entity.AdwebPublicBlackIp;
+import org.jeecg.modules.adweb.enquiry.mapper.AdwebPublicBlackEmailMapper;
+import org.jeecg.modules.adweb.enquiry.service.IAdwebEnquiryService;
+import org.jeecg.modules.adweb.enquiry.service.IAdwebPublicBlackEmailService;
+import org.jeecg.modules.adweb.enquiry.service.IAdwebPublicBlackIpService;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+
+/**
+ * @Description: 询盘公共邮箱黑名单
+ * @Author: jeecg-boot
+ * @Date: 2024-10-18
+ * @Version: V1.0
+ */
+@Slf4j
+@Service
+public class AdwebPublicBlackEmailServiceImpl extends ServiceImpl<AdwebPublicBlackEmailMapper, AdwebPublicBlackEmail> implements IAdwebPublicBlackEmailService {
+
+//    @Resource
+//    private IAdwebEnquiryService adwebEnquiryService;
+//    @Resource
+//    private IAdwebPublicBlackIpService adwebPublicBlackIpService;
+//    @Resource
+//    private RedisUtil redisUtil;
+
+    @Value("${judge_waste_enquiry.ip.delOrdIpDate}")
+    private Integer delOrdIpDate;
+    @Value("${judge_waste_enquiry.email.tenMinNum}")
+    private Integer emailTenMinNum;
+    @Value("${judge_waste_enquiry.email.oneDayNum}")
+    private Integer emailOneDayNum;
+    @Value("${judge_waste_enquiry.ip.tenMinNum}")
+    private Integer ipTenMinNum;
+    @Value("${judge_waste_enquiry.ip.oneDayNum}")
+    private Integer ipOneDayNum;
+    private static final String BlackEmailKey = "BLACK_EMAIL_LIST";
+    private static final String WhiteEmailListKey = "WHITE_EMAIL_LIST";
+    private static final String WhiteIpListKey = "WHITE_IP_LIST";
+    private static final String BlackIpKey = "BLACK_IP_LIST";
+
+    @Resource
+    AdwebPublicBlackEmailMapper adwebPublicBlackEmailMapper;
+
+    @Override
+    public IPage<AdwebPublicBlackEmail> pageList(Page<AdwebPublicBlackEmail> page, String email, Integer blackOrWhite,String column,String order) {
+        return adwebPublicBlackEmailMapper.pageList(page,email,blackOrWhite,column,order);
+    }
+
+    //定时器执行
+//    @Override
+//    public void updateBlackListByEmailAndIp() {
+//
+//        List<AdwebPublicBlackEmail> emailList = this.list(new QueryWrapper<AdwebPublicBlackEmail>().eq("status", 1));
+//
+//        log.info("获取到的email黑名单数量为:{}", emailList.size());
+//
+//        List<String> blackEmailList = emailList.stream().filter(e -> e.getBlackOrWhite() == 0).map(AdwebPublicBlackEmail::getEmail).collect(Collectors.toList());
+//
+//        List<String> whiteEmailList = emailList.stream().filter(e -> e.getBlackOrWhite() == 1).map(AdwebPublicBlackEmail::getEmail).collect(Collectors.toList());
+//
+//        redisUtil.set(BlackEmailKey, blackEmailList, 60 * 60 * 24);
+//        redisUtil.set(WhiteEmailListKey, whiteEmailList, 60 * 60 * 24);
+//
+//        log.info("更新email黑名单成功,黑名单数量为:{},白名单数量为{}", blackEmailList.size(), whiteEmailList.size());
+//
+//        //90天内的ip
+//        List<AdwebPublicBlackIp> ipList = adwebPublicBlackIpService.list(new QueryWrapper<AdwebPublicBlackIp>().eq("status", 1).gt("create_time", DateUtil.offsetDay(DateUtil.beginOfDay(new Date()), -delOrdIpDate)));
+//
+//        log.info("获取到的ip黑名单数量为:{}", ipList.size());
+//
+//        List<String> blackIpList = ipList.stream().filter(e -> e.getBlackOrWhite() == 0).map(AdwebPublicBlackIp::getIp).collect(Collectors.toList());
+//
+//        List<String> whiteIpList = ipList.stream().filter(e -> e.getBlackOrWhite() == 1).map(AdwebPublicBlackIp::getIp).collect(Collectors.toList());
+//
+//        redisUtil.set(BlackIpKey, blackIpList, 60 * 60 * 24);
+//        redisUtil.set(WhiteIpListKey, whiteIpList, 60 * 60 * 24);
+//
+//        log.info("更新ip黑名单成功,黑名单数量为:{},白名单数量为{}", blackIpList.size(), whiteIpList.size());
+//
+//        List<AdwebPublicBlackIp> ordBlackIpList = adwebPublicBlackIpService.list(new QueryWrapper<AdwebPublicBlackIp>().eq("black_or_white", 0).eq("status", 1).lt("create_time", DateUtil.offsetDay(DateUtil.beginOfDay(new Date()), -delOrdIpDate)));
+//
+//        if (ordBlackIpList.size() == 0) {
+//            log.info("没有需要删除的ip黑名单");
+//            return;
+//        }
+//
+//        List<AdwebEnquiry> list = adwebEnquiryService.list(new QueryWrapper<AdwebEnquiry>().eq("status", 1).eq("user_effective", 0).in("from_ip", ordBlackIpList.stream().map(AdwebPublicBlackIp::getIp).collect(Collectors.toList())).select("DISTINCT id,from_ip"));
+//
+//        //删除90天前并且期间没有发过询盘
+//        if (list.size() > 0) {
+//            adwebPublicBlackIpService.update(new UpdateWrapper<AdwebPublicBlackIp>().eq("black_or_white", 0).eq("status", 1).lt("create_time", DateUtil.offsetDay(DateUtil.beginOfDay(new Date()), -delOrdIpDate)).notIn("ip", list.stream().map(AdwebEnquiry::getFromIp).collect(Collectors.toList())).set("status", 0));
+//            return;
+//        }
+//        adwebPublicBlackIpService.update(new UpdateWrapper<AdwebPublicBlackIp>().eq("black_or_white", 0).eq("status", 1).lt("create_time", DateUtil.offsetDay(DateUtil.beginOfDay(new Date()), -delOrdIpDate)).set("status", 0).in("ip", ordBlackIpList.stream().map(AdwebPublicBlackIp::getIp).collect(Collectors.toList())));
+//
+//        log.info("删除90天前的ip黑名单成功");
+//    }
+
+    /**
+    * 定时器执行
+    */
+//    @Override
+//    public void updateEnquiryBlackList() {
+//        List<AdwebEnquiry> enquiryListByTenMin = adwebEnquiryService.list(new QueryWrapper<AdwebEnquiry>().eq("user_effective", 0).eq("status", 1).select("DISTINCT email").groupBy("email,UNIX_TIMESTAMP( record_ctime ) DIV 600 ").having("count(id) > "+emailTenMinNum));
+//
+//        List<AdwebEnquiry> enquiryListByOneDay = adwebEnquiryService.list(new QueryWrapper<AdwebEnquiry>().eq("user_effective", 0).eq("status", 1).select("DISTINCT email").groupBy("email,UNIX_TIMESTAMP( record_ctime ) DIV 3600 ").having("count(id) > "+emailOneDayNum));
+//
+//        List<AdwebEnquiry> enquiryListByIpTenMin = adwebEnquiryService.list(new QueryWrapper<AdwebEnquiry>().eq("user_effective", 0).eq("status", 1).select("DISTINCT from_ip").groupBy("from_ip,UNIX_TIMESTAMP( record_ctime ) DIV 600 ").having("count(id) > "+ipTenMinNum));
+//
+//        List<AdwebEnquiry> enquiryListByIpOneDay = adwebEnquiryService.list(new QueryWrapper<AdwebEnquiry>().eq("user_effective", 0).eq("status", 1).select("DISTINCT from_ip").groupBy("from_ip,UNIX_TIMESTAMP( record_ctime ) DIV 3600 ").having("count(id) > "+ipOneDayNum));
+//
+//        Set<String> emailSet = new HashSet<>();
+//        emailSet.addAll(enquiryListByTenMin.stream().map(AdwebEnquiry::getEmail).collect(Collectors.toList()));
+//        emailSet.addAll(enquiryListByOneDay.stream().map(AdwebEnquiry::getEmail).collect(Collectors.toList()));
+//
+//        Set<String> ipSet = new HashSet<>();
+//        ipSet.addAll(enquiryListByIpTenMin.stream().map(AdwebEnquiry::getFromIp).collect(Collectors.toList()));
+//        ipSet.addAll(enquiryListByIpOneDay.stream().map(AdwebEnquiry::getFromIp).collect(Collectors.toList()));
+//
+//        List<AdwebPublicBlackEmail> emailList = this.list(new QueryWrapper<AdwebPublicBlackEmail>().eq("status", 1));
+//
+//        List<AdwebPublicBlackIp> ipList = adwebPublicBlackIpService.list(new QueryWrapper<AdwebPublicBlackIp>().eq("status", 1));
+//
+//
+//        List<AdwebPublicBlackEmail> blackEmailList = new ArrayList<>();
+//        List<AdwebPublicBlackIp> blackIpList = new ArrayList<>();
+//
+//        //判断是否在存在
+//        for (String email : emailSet) {
+//            if (emailList.stream().noneMatch(e -> e.getEmail().equals(email))) {
+//                AdwebPublicBlackEmail blackEmail = new AdwebPublicBlackEmail();
+//                blackEmail.setEmail(email);
+//                blackEmail.setBlackOrWhite(0);
+//                blackEmail.setStatus(1);
+//                blackEmail.setCreateTime(new Date());
+//                blackEmailList.add(blackEmail);
+//            }
+//        }
+//
+//        //判断是否在存在
+//        for (String ip : ipSet) {
+//            if (ipList.stream().noneMatch(e -> e.getIp().equals(ip))) {
+//                AdwebPublicBlackIp blackIp = new AdwebPublicBlackIp();
+//                blackIp.setIp(ip);
+//                blackIp.setBlackOrWhite(0);
+//                blackIp.setStatus(1);
+//                blackIp.setCreateTime(new Date());
+//                blackIpList.add(blackIp);
+//            }
+//        }
+//
+//        if (blackEmailList.size() > 0) {
+//            this.saveBatch(blackEmailList);
+//        }
+//        if (blackIpList.size() > 0) {
+//            adwebPublicBlackIpService.saveBatch(blackIpList);
+//        }
+//        log.info("从询盘更新Email和IP黑名单成功,新增Email黑名单数量为:" + blackEmailList.size() + ",新增IP黑名单数量为" + blackIpList.size());
+//    }
+}

+ 28 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/service/impl/AdwebPublicBlackIpServiceImpl.java

@@ -0,0 +1,28 @@
+package org.jeecg.modules.adweb.enquiry.service.impl;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import jakarta.annotation.Resource;
+import org.jeecg.modules.adweb.enquiry.entity.AdwebPublicBlackIp;
+import org.jeecg.modules.adweb.enquiry.mapper.AdwebPublicBlackIpMapper;
+import org.jeecg.modules.adweb.enquiry.service.IAdwebPublicBlackIpService;
+import org.springframework.stereotype.Service;
+
+/**
+ * @Description: IP黑名单
+ * @Author: jeecg-boot
+ * @Date:   2023-02-20
+ * @Version: V1.0
+ */
+@Service
+public class AdwebPublicBlackIpServiceImpl extends ServiceImpl<AdwebPublicBlackIpMapper, AdwebPublicBlackIp> implements IAdwebPublicBlackIpService {
+
+    @Resource
+    private AdwebPublicBlackIpMapper adwebPublicBlackIpMapper;
+
+    @Override
+    public IPage<AdwebPublicBlackIp> pageList(Page<AdwebPublicBlackIp> page, String ip, Integer blackOrWhite,String column,String order) {
+        return adwebPublicBlackIpMapper.pageList(page,ip,blackOrWhite,column,order);
+    }
+}

+ 61 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/service/impl/AdwebPublicEnquiryRuleServiceImpl.java

@@ -0,0 +1,61 @@
+package org.jeecg.modules.adweb.enquiry.service.impl;
+
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.jeecg.modules.adweb.common.util.ListUtil;
+import org.jeecg.modules.adweb.enquiry.entity.AdwebPublicEnquiryRule;
+import org.jeecg.modules.adweb.enquiry.mapper.AdwebPublicEnquiryRuleMapper;
+import org.jeecg.modules.adweb.enquiry.service.IAdwebPublicEnquiryRuleService;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.springframework.stereotype.Service;
+
+import jakarta.annotation.Resource;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @Description: 用于询盘规则过滤
+ * @Author: cpq
+ * @Date:   2024-10-17
+ * @Version: V1.0
+ */
+@Service
+public class AdwebPublicEnquiryRuleServiceImpl extends ServiceImpl<AdwebPublicEnquiryRuleMapper, AdwebPublicEnquiryRule> implements IAdwebPublicEnquiryRuleService {
+
+    @Resource
+    private AdwebPublicEnquiryRuleMapper adwebPublicEnquiryRuleMapper;
+
+    @Override
+    public IPage<AdwebPublicEnquiryRule> pageList(Page<AdwebPublicEnquiryRule> page, String word, Integer blackOrWhiteList, Integer isEnable, Integer useStatus,String column,String order) {
+        return adwebPublicEnquiryRuleMapper.pageList(page, word, blackOrWhiteList, isEnable, useStatus,column,order);
+    }
+
+    @Override
+    public List<String> getOpenAiBlackList() {
+        List<AdwebPublicEnquiryRule> list = this.list(new QueryWrapper<AdwebPublicEnquiryRule>()
+                .eq("status", 1)
+                .eq("use_status", 1)
+                .eq("is_enable", 1)
+                .eq("black_or_white_list", 0));
+        if (ListUtil.isEmpty(list)) {
+            return null;
+        }
+        return list.stream().map(AdwebPublicEnquiryRule::getWord).collect(Collectors.toList());
+    }
+
+    @Override
+    public List<String> getEnquiryBlackList() {
+        List<AdwebPublicEnquiryRule> list = this.list(new QueryWrapper<AdwebPublicEnquiryRule>()
+                .eq("status", 1)
+                .eq("use_status", 0)
+                .eq("is_enable", 1)
+                .eq("black_or_white_list", 0));
+        if (ListUtil.isEmpty(list)) {
+            return null;
+        }
+        return list.stream().map(AdwebPublicEnquiryRule::getWord).collect(Collectors.toList());
+    }
+
+}

+ 195 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/service/impl/AdwebSiteBlackEmailServiceImpl.java

@@ -0,0 +1,195 @@
+package org.jeecg.modules.adweb.enquiry.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import jakarta.annotation.Resource;
+import org.jeecg.common.util.RedisUtil;
+import org.jeecg.modules.adweb.common.util.ListUtil;
+import org.jeecg.modules.adweb.enquiry.dto.param.EffectiveEnquiryParamDto;
+import org.jeecg.modules.adweb.enquiry.entity.AdwebSiteBlackEmail;
+import org.jeecg.modules.adweb.enquiry.mapper.AdwebSiteBlackEmailMapper;
+import org.jeecg.modules.adweb.enquiry.service.IAdwebSiteBlackEmailService;
+import org.springframework.stereotype.Service;
+
+import java.util.*;
+
+/**
+ * @Description: enquiry_site_black_email
+ * @Author: jeecg-boot
+ * @Date:   2023-06-28
+ * @Version: V1.0
+ */
+@Service
+public class AdwebSiteBlackEmailServiceImpl extends ServiceImpl<AdwebSiteBlackEmailMapper, AdwebSiteBlackEmail> implements IAdwebSiteBlackEmailService {
+
+    @Resource
+    private RedisUtil redisUtil;
+    @Resource
+    private AdwebSiteBlackEmailMapper enquirySiteBlackEmailMapper;
+
+    private static final String SiteBlackEmailKey = "SITE_BLACK_EMAIL_LIST";
+    private static final String SiteWhiteEmailListKey = "SITE_WHITE_EMAIL_LIST";
+    private static final String SiteEmailTenMinKey = "JUDGE_WASTE_SITE_ENQUIRY_EMAIL_BY_10_MIN::";
+    private static final String SiteEmailOneDayKey = "JUDGE_WASTE_SITE_ENQUIRY_EMAIL_BY_ONE_DAY::";
+    private static final String NotBlackEmailWasteSiteEnquiryKey = "NOT_BLACK_EMAIL_WASTE_SITE_ENQUIRY_MAP::";
+
+    /**
+     * 根据站点id获取并存取黑名单数据到redis
+     */
+    @Override
+    public void saveRedisSiteBlackEmailBySiteId(Integer siteId,Integer blackOrWhite){
+        QueryWrapper<AdwebSiteBlackEmail> siteAllEmailQueryWrapper = new QueryWrapper<>();
+        siteAllEmailQueryWrapper.ne("status", 0);
+        siteAllEmailQueryWrapper.eq("site_id", siteId);
+        siteAllEmailQueryWrapper.eq("black_or_white", blackOrWhite);
+        List<AdwebSiteBlackEmail> allEmailList = list(siteAllEmailQueryWrapper);
+        if(ListUtil.isEmpty(allEmailList)){
+            log.warn("未获取到对应站点的名单数据");
+        }
+
+        List<String> emailList = new ArrayList<>();
+        if(ListUtil.notEmpty(allEmailList)){
+            for (AdwebSiteBlackEmail enquirySiteBlackEmail1 : allEmailList){
+                if(enquirySiteBlackEmail1.getType().equals("0")){
+                    emailList.add("*" + enquirySiteBlackEmail1.getEmail() + "*");
+                }else{
+                    emailList.add(enquirySiteBlackEmail1.getEmail());
+                }
+            }
+        }
+        //处理对应站点的黑名单
+        if(blackOrWhite == 0){
+            if (ListUtil.notEmpty(emailList)) {
+                redisUtil.set(SiteBlackEmailKey + "::" + siteId, emailList, 60 * 60 * 24);
+            }else {
+                redisUtil.del(SiteBlackEmailKey + "::" + siteId);
+            }
+        }else{
+            if (ListUtil.notEmpty(emailList)) {
+                redisUtil.set(SiteWhiteEmailListKey + "::" + siteId, emailList, 60 * 60 * 24);
+            }else {
+                redisUtil.del(SiteWhiteEmailListKey + "::" + siteId);
+            }
+        }
+
+    }
+
+    /**
+     * 根据站点id获取对应所有的黑白名单数据
+     */
+    @Override
+    public Map<String, List<String>> getSiteBlackEmailListBySiteId(Integer siteId){
+        QueryWrapper<AdwebSiteBlackEmail> siteAllEmailQueryWrapper = new QueryWrapper<>();
+        siteAllEmailQueryWrapper.ne("status", 0);
+        siteAllEmailQueryWrapper.eq("site_id", siteId);
+        List<AdwebSiteBlackEmail> allEmailList = list(siteAllEmailQueryWrapper);
+        if(ListUtil.isEmpty(allEmailList)){
+            log.warn("未获取到对应站点的黑白名单数据");
+        }
+
+        List<String> emailList = new ArrayList<>();
+        List<String> whiteEmailList = new ArrayList<>();
+        if(ListUtil.notEmpty(allEmailList)){
+            for (AdwebSiteBlackEmail enquirySiteBlackEmail1 : allEmailList){
+                if(enquirySiteBlackEmail1.getBlackOrWhite() == 0){
+                    if(enquirySiteBlackEmail1.getType().equals("0")){
+                        emailList.add("*" + enquirySiteBlackEmail1.getEmail() + "*");
+                    }else{
+                        emailList.add(enquirySiteBlackEmail1.getEmail());
+                    }
+                }else{
+                    if(enquirySiteBlackEmail1.getType().equals("0")){
+                        whiteEmailList.add("*" + enquirySiteBlackEmail1.getEmail() + "*");
+                    }else{
+                        whiteEmailList.add(enquirySiteBlackEmail1.getEmail());
+                    }
+                }
+            }
+        }
+
+        Map<String, List<String>> enquirySiteBlackEmailMap = new HashMap<>();
+        enquirySiteBlackEmailMap.put("black",emailList);
+        enquirySiteBlackEmailMap.put("white", whiteEmailList);
+        return enquirySiteBlackEmailMap;
+    }
+
+    /**
+     * 获取分页列表数据
+     * @param page
+     * @param enquirySiteBlackEmail
+     * @param codeList
+     * @return
+     */
+    @Override
+    public IPage<AdwebSiteBlackEmail> pageList(Page<AdwebSiteBlackEmail> page, AdwebSiteBlackEmail enquirySiteBlackEmail, List<String> codeList,String column,String order){
+        return enquirySiteBlackEmailMapper.getPageList(page, enquirySiteBlackEmail, codeList, column, order);
+    }
+
+    /**
+     * 更改为垃圾询盘处理邮箱黑名单
+     * @param effectiveEnquiryParamDto
+     */
+    @Override
+    public void addBlackEmailByContent(EffectiveEnquiryParamDto effectiveEnquiryParamDto){
+        //排查添加的邮箱是否已有
+        QueryWrapper<AdwebSiteBlackEmail> enquirySiteBlackEmailQueryWrapper = new QueryWrapper<>();
+        enquirySiteBlackEmailQueryWrapper.eq("email", effectiveEnquiryParamDto.getWasteEnquirySeason());
+        enquirySiteBlackEmailQueryWrapper.eq("site_id", effectiveEnquiryParamDto.getSiteId());
+        enquirySiteBlackEmailQueryWrapper.eq("site_code", effectiveEnquiryParamDto.getSiteCode());
+        enquirySiteBlackEmailQueryWrapper.eq("status", 1);
+        List<AdwebSiteBlackEmail> enquirySiteBlackEmailList = list(enquirySiteBlackEmailQueryWrapper);
+        if(ListUtil.notEmpty(enquirySiteBlackEmailList)){
+            //如果有白名单 先删除原数据,后添加新的黑名单数据
+            for(AdwebSiteBlackEmail enquirySiteBlackEmail : enquirySiteBlackEmailList){
+                if(enquirySiteBlackEmail.getBlackOrWhite() == 1){
+                    if(enquirySiteBlackEmail.getType().equals("1")){
+                        enquirySiteBlackEmail.setStatus(0);
+                        enquirySiteBlackEmail.setUpdateTime(new Date());
+                        updateById(enquirySiteBlackEmail);
+                    }
+
+                    AdwebSiteBlackEmail newEnquirySiteBlackEmail = new AdwebSiteBlackEmail();
+                    newEnquirySiteBlackEmail.setEmail(effectiveEnquiryParamDto.getWasteEnquirySeason());
+                    newEnquirySiteBlackEmail.setBlackOrWhite(0);
+                    newEnquirySiteBlackEmail.setType("1");
+                    newEnquirySiteBlackEmail.setSiteId(effectiveEnquiryParamDto.getSiteId());
+                    newEnquirySiteBlackEmail.setSiteCode(effectiveEnquiryParamDto.getSiteCode());
+                    newEnquirySiteBlackEmail.setStatus(1);
+                    newEnquirySiteBlackEmail.setCreateTime(new Date());
+                    save(newEnquirySiteBlackEmail);
+                }
+            }
+        }else{
+            AdwebSiteBlackEmail enquirySiteBlackEmail = new AdwebSiteBlackEmail();
+            enquirySiteBlackEmail.setEmail(effectiveEnquiryParamDto.getWasteEnquirySeason());
+            enquirySiteBlackEmail.setType("1");
+            enquirySiteBlackEmail.setBlackOrWhite(0);
+            enquirySiteBlackEmail.setSiteId(effectiveEnquiryParamDto.getSiteId());
+            enquirySiteBlackEmail.setSiteCode(effectiveEnquiryParamDto.getSiteCode());
+            enquirySiteBlackEmail.setStatus(1);
+            enquirySiteBlackEmail.setCreateTime(new Date());
+            save(enquirySiteBlackEmail);
+        }
+
+        //重新处理站点的黑名单redis缓存
+        Map<String,List<String>> enquirySiteBlackEmailListMap = getSiteBlackEmailListBySiteId(effectiveEnquiryParamDto.getSiteId());
+        List<String> emailList = enquirySiteBlackEmailListMap.get("black");
+        List<String> whiteEmailList = enquirySiteBlackEmailListMap.get("white");
+
+        //处理对应站点的黑名单
+        if (ListUtil.notEmpty(emailList)) {
+            redisUtil.set(SiteBlackEmailKey + "::" + effectiveEnquiryParamDto.getSiteId(), emailList, 60 * 60 * 24);
+        }else {
+            redisUtil.del(SiteBlackEmailKey + "::" + effectiveEnquiryParamDto.getSiteId());
+        }
+
+        //处理对应站点的白名单
+        if (ListUtil.notEmpty(whiteEmailList)) {
+            redisUtil.set(SiteWhiteEmailListKey + "::" + effectiveEnquiryParamDto.getSiteId(), whiteEmailList, 60 * 60 * 24);
+        }else {
+            redisUtil.del(SiteWhiteEmailListKey + "::" + effectiveEnquiryParamDto.getSiteId());
+        }
+    }
+}

+ 121 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/service/impl/AdwebSiteBlackIpServiceImpl.java

@@ -0,0 +1,121 @@
+package org.jeecg.modules.adweb.enquiry.service.impl;
+
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import jakarta.annotation.Resource;
+import org.jeecg.common.util.RedisUtil;
+import org.jeecg.modules.adweb.common.util.ListUtil;
+import org.jeecg.modules.adweb.enquiry.dto.param.EffectiveEnquiryParamDto;
+import org.jeecg.modules.adweb.enquiry.entity.AdwebSiteBlackIp;
+import org.jeecg.modules.adweb.enquiry.mapper.AdwebSiteBlackIpMapper;
+import org.jeecg.modules.adweb.enquiry.service.IAdwebSiteBlackIpService;
+import org.springframework.stereotype.Service;
+
+import java.util.Date;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @Description: adweb_site_black_ip
+ * @Author: jeecg-boot
+ * @Date:   2023-08-31
+ * @Version: V1.0
+ */
+@Service
+public class AdwebSiteBlackIpServiceImpl extends ServiceImpl<AdwebSiteBlackIpMapper, AdwebSiteBlackIp> implements IAdwebSiteBlackIpService {
+
+    @Resource
+    private AdwebSiteBlackIpMapper adwebSiteBlackIpMapper;
+    @Resource
+    private RedisUtil redisUtil;
+
+    private static final String SiteIpTenMinKey = "JUDGE_WASTE_ENQUIRY_SITE_IP_BY_10_MIN::";
+    private static final String SiteIpOneDayKey = "JUDGE_WASTE_ENQUIRY_SITE_IP_BY_ONE_DAY::";
+    private static final String NotSiteBlackIpWasteEnquiryKey = "NOT_SITE_BLACK_IP_WASTE_ENQUIRY_MAP::";
+    private static final String SiteBlackIpKey = "SITE_BLACK_IP_LIST";
+    private static final String SiteWhiteIpListKey = "SITE_WHITE_IP_LIST";
+
+    /**
+     * 更改为垃圾询盘处理ip黑名单
+     * @param effectiveEnquiryParamDto
+     */
+    @Override
+    public void addBlackIpByContent(EffectiveEnquiryParamDto effectiveEnquiryParamDto){
+        //排查添加的ip是否已有
+        QueryWrapper<AdwebSiteBlackIp> adwebSiteBlackIpQueryWrapper = new QueryWrapper<>();
+        adwebSiteBlackIpQueryWrapper.eq("ip", effectiveEnquiryParamDto.getWasteEnquirySeason());
+        adwebSiteBlackIpQueryWrapper.eq("site_id", effectiveEnquiryParamDto.getSiteId());
+        adwebSiteBlackIpQueryWrapper.eq("site_code", effectiveEnquiryParamDto.getSiteCode());
+        adwebSiteBlackIpQueryWrapper.eq("status", 1);
+        List<AdwebSiteBlackIp> adwebSiteBlackIpList = list(adwebSiteBlackIpQueryWrapper);
+        if(!adwebSiteBlackIpList.isEmpty()){
+            //如果有白名单 先删除原数据,后添加新的黑名单数据
+            AdwebSiteBlackIp adwebSiteBlackIp = adwebSiteBlackIpList.get(0);
+            if(adwebSiteBlackIp.getBlackOrWhite() == 1){
+                adwebSiteBlackIp.setStatus(0);
+                updateById(adwebSiteBlackIp);
+
+                AdwebSiteBlackIp newSiteBlackIp = new AdwebSiteBlackIp();
+                newSiteBlackIp.setIp(effectiveEnquiryParamDto.getWasteEnquirySeason());
+                newSiteBlackIp.setBlackOrWhite(0);
+                newSiteBlackIp.setSiteId(effectiveEnquiryParamDto.getSiteId());
+                newSiteBlackIp.setSiteCode(effectiveEnquiryParamDto.getSiteCode());
+                newSiteBlackIp.setStatus(1);
+                newSiteBlackIp.setCreateTime(new Date());
+                save(newSiteBlackIp);
+            }
+        }else{
+            AdwebSiteBlackIp newSiteBlackIp = new AdwebSiteBlackIp();
+            newSiteBlackIp.setIp(effectiveEnquiryParamDto.getWasteEnquirySeason());
+            newSiteBlackIp.setBlackOrWhite(0);
+            newSiteBlackIp.setSiteId(effectiveEnquiryParamDto.getSiteId());
+            newSiteBlackIp.setSiteCode(effectiveEnquiryParamDto.getSiteCode());
+            newSiteBlackIp.setStatus(1);
+            newSiteBlackIp.setCreateTime(new Date());
+            save(newSiteBlackIp);
+        }
+
+        //重新调整对应站点redis缓存
+        QueryWrapper<AdwebSiteBlackIp> redisWrapper = new QueryWrapper<>();
+        redisWrapper.eq("site_id", effectiveEnquiryParamDto.getSiteId());
+        redisWrapper.eq("site_code", effectiveEnquiryParamDto.getSiteCode());
+        redisWrapper.eq("status", 1);
+        List<AdwebSiteBlackIp> redisList = list(redisWrapper);
+
+        if (!redisList.isEmpty()) {
+            redisUtil.del(SiteBlackIpKey + "::" + effectiveEnquiryParamDto.getSiteId());
+            redisUtil.del(SiteWhiteIpListKey + "::" + effectiveEnquiryParamDto.getSiteId());
+        }
+        if(ListUtil.notEmpty(redisList)){
+            List<String> blackIpList = redisList.stream().filter(siteBlackIp -> siteBlackIp.getBlackOrWhite().equals(0)).map(AdwebSiteBlackIp::getIp).collect(Collectors.toList());
+            if(ListUtil.notEmpty(blackIpList)){
+                redisUtil.set(SiteBlackIpKey + "::" + effectiveEnquiryParamDto.getSiteId(), blackIpList, 60 * 60 * 24);
+            } else{
+                redisUtil.del(SiteBlackIpKey + "::" + effectiveEnquiryParamDto.getSiteId());
+            }
+
+            List<String> whiteIpList = redisList.stream().filter(siteBlackIp -> siteBlackIp.getBlackOrWhite().equals(1)).map(AdwebSiteBlackIp::getIp).collect(Collectors.toList());
+            if(ListUtil.notEmpty(whiteIpList)){
+                redisUtil.set(SiteWhiteIpListKey + "::" + effectiveEnquiryParamDto.getSiteId(), whiteIpList, 60 * 60 * 24);
+            } else{
+                redisUtil.del(SiteWhiteIpListKey + "::" + effectiveEnquiryParamDto.getSiteId());
+            }
+        }
+
+    }
+
+    /**
+     * 获取分页列表数据
+     * @param page
+     * @param adwebSiteBlackIp
+     * @param codeList
+     * @return
+     */
+    @Override
+    public IPage<AdwebSiteBlackIp> pageList(Page<AdwebSiteBlackIp> page, AdwebSiteBlackIp adwebSiteBlackIp, List<String> codeList, String column, String order){
+        return adwebSiteBlackIpMapper.getPageList(page, adwebSiteBlackIp, codeList, column, order);
+    }
+}

+ 63 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/service/impl/AdwebSiteEnquiryRuleServiceImpl.java

@@ -0,0 +1,63 @@
+package org.jeecg.modules.adweb.enquiry.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.jeecg.modules.adweb.enquiry.dto.param.EffectiveEnquiryParamDto;
+import org.jeecg.modules.adweb.enquiry.entity.AdwebSiteEnquiryRule;
+import org.jeecg.modules.adweb.enquiry.mapper.AdwebSiteEnquiryRuleMapper;
+import org.jeecg.modules.adweb.enquiry.service.IAdwebSiteEnquiryRuleService;
+import org.springframework.stereotype.Service;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * @Description: adweb_enquiry_site_rule
+ * @Author: jeecg-boot
+ * @Date:   2023-08-31
+ * @Version: V1.0
+ */
+@Service
+public class AdwebSiteEnquiryRuleServiceImpl extends ServiceImpl<AdwebSiteEnquiryRuleMapper, AdwebSiteEnquiryRule> implements IAdwebSiteEnquiryRuleService {
+
+    /**
+     * 更改为垃圾询盘处理关键词黑名单
+     * @param effectiveEnquiryParamDto
+     */
+    @Override
+    public void addBlackKeywordByContent(EffectiveEnquiryParamDto effectiveEnquiryParamDto){
+        //排查添加的关键词是否已有
+        QueryWrapper<AdwebSiteEnquiryRule> adwebEnquirySiteRuleQueryWrapper = new QueryWrapper<>();
+        adwebEnquirySiteRuleQueryWrapper.eq("word", effectiveEnquiryParamDto.getWasteEnquirySeason());
+        adwebEnquirySiteRuleQueryWrapper.eq("site_id", effectiveEnquiryParamDto.getSiteId());
+        adwebEnquirySiteRuleQueryWrapper.eq("site_code", effectiveEnquiryParamDto.getSiteCode());
+        adwebEnquirySiteRuleQueryWrapper.eq("status", 1);
+        List<AdwebSiteEnquiryRule> adwebEnquirySiteRuleList = list(adwebEnquirySiteRuleQueryWrapper);
+        if(!adwebEnquirySiteRuleList.isEmpty()){
+            //如果有白名单 先删除原数据,后添加新的黑名单数据
+            AdwebSiteEnquiryRule adwebEnquirySiteRule = adwebEnquirySiteRuleList.get(0);
+            if(adwebEnquirySiteRule.getBlackOrWhite() == 1){
+                adwebEnquirySiteRule.setStatus(0);
+                updateById(adwebEnquirySiteRule);
+
+                AdwebSiteEnquiryRule newAdwebSiteEnquiryRule = new AdwebSiteEnquiryRule();
+                newAdwebSiteEnquiryRule.setWord(effectiveEnquiryParamDto.getWasteEnquirySeason());
+                newAdwebSiteEnquiryRule.setBlackOrWhite(0);
+                newAdwebSiteEnquiryRule.setSiteId(effectiveEnquiryParamDto.getSiteId());
+                newAdwebSiteEnquiryRule.setSiteCode(effectiveEnquiryParamDto.getSiteCode());
+                newAdwebSiteEnquiryRule.setStatus(1);
+                newAdwebSiteEnquiryRule.setCreateTime(new Date());
+                save(newAdwebSiteEnquiryRule);
+            }
+        }else{
+            AdwebSiteEnquiryRule newAdwebSiteEnquiryRule = new AdwebSiteEnquiryRule();
+            newAdwebSiteEnquiryRule.setWord(effectiveEnquiryParamDto.getWasteEnquirySeason());
+            newAdwebSiteEnquiryRule.setBlackOrWhite(0);
+            newAdwebSiteEnquiryRule.setSiteId(effectiveEnquiryParamDto.getSiteId());
+            newAdwebSiteEnquiryRule.setSiteCode(effectiveEnquiryParamDto.getSiteCode());
+            newAdwebSiteEnquiryRule.setStatus(1);
+            newAdwebSiteEnquiryRule.setCreateTime(new Date());
+            save(newAdwebSiteEnquiryRule);
+        }
+    }
+}

+ 417 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/service/impl/EnquiryEmailMessageServiceImpl.java

@@ -0,0 +1,417 @@
+package org.jeecg.modules.adweb.enquiry.service.impl;
+
+import cn.hutool.core.collection.CollUtil;
+
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.Data;
+import org.apache.commons.lang3.StringUtils;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.system.vo.DictModel;
+import org.jeecg.common.util.FastJsonUtil;
+
+
+import org.jeecg.modules.adweb.common.service.FeishuService;
+import org.jeecg.modules.adweb.common.util.JedisUtil;
+import org.jeecg.modules.adweb.common.util.ListUtil;
+import org.jeecg.modules.adweb.common.util.AdwebRedisUtil;
+import org.jeecg.modules.adweb.enquiry.constant.EnquiryConstants;
+import org.jeecg.modules.adweb.enquiry.constant.EnquirySendStatus;
+import org.jeecg.modules.adweb.enquiry.entity.AdwebEnquiry;
+import org.jeecg.modules.adweb.enquiry.entity.AdwebEnquiryForm;
+import org.jeecg.modules.adweb.enquiry.entity.EnquiryEmailMessage;
+import org.jeecg.modules.adweb.enquiry.mapper.EnquiryEmailMessageMapper;
+import org.jeecg.modules.adweb.enquiry.service.IAdwebEnquiryFormService;
+import org.jeecg.modules.adweb.enquiry.service.IAdwebEnquiryService;
+import org.jeecg.modules.adweb.enquiry.service.IEnquiryEmailMessageService;
+
+
+import org.jeecg.modules.adweb.site.entity.AdwebSite;
+import org.jeecg.modules.adweb.site.service.IAdwebSiteService;
+import org.jeecg.modules.adweb.system.entity.SysException;
+import org.jeecg.modules.adweb.system.service.IMasterSubAccountRelationService;
+import org.jeecg.modules.adweb.system.service.ISysExceptionService;
+import org.jeecg.modules.message.handle.enums.SendMsgTypeEnum;
+import org.jeecg.modules.message.handle.impl.EmailSendMsgHandle;
+
+import org.jeecg.modules.system.entity.SysUser;
+import org.jeecg.modules.system.service.ISysDictService;
+import org.jeecg.modules.system.service.ISysUserService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.stereotype.Service;
+
+import jakarta.annotation.Resource;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * @Description: adweb_enquiry_email_message
+ * @Author: jeecg-boot
+ * @Date: 2023-02-01
+ * @Version: V1.0
+ */
+@Service
+public class EnquiryEmailMessageServiceImpl extends ServiceImpl<EnquiryEmailMessageMapper, EnquiryEmailMessage> implements IEnquiryEmailMessageService {
+
+    private static byte[] redisKey = EnquiryConstants.ENQUIRY_EMAIL.getBytes();
+
+    @Resource
+    private EnquiryEmailMessageMapper enquiryEmailMessageMapper;
+
+    @Resource
+    private FeishuService feishuService;
+
+    @Resource
+    private AdwebRedisUtil adwebRedisUtil;
+
+    @Resource
+    private ISysDictService sysDictService;
+
+    @Resource
+    private IAdwebEnquiryFormService adwebEnquiryFormService;
+
+    @Resource
+    private ISysExceptionService sysExceptionService;
+
+    @Resource
+    private IAdwebSiteService adwebSiteService;
+
+    @Resource
+    @Lazy
+    private ISysUserService sysUserService;
+
+    @Autowired
+    private IMasterSubAccountRelationService masterSubAccountRelationService;
+
+    @Override
+    public void sendEnquiryEmail(Long enquiryId) {
+        String keyName = "ENQUIRY_SEND_EMAIL_" + enquiryId;
+        if (!adwebRedisUtil.lock(keyName, 10 * 60 * 1000)) {
+            return;
+        }
+
+        QueryWrapper<EnquiryEmailMessage> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("enquiry_id", enquiryId);
+        queryWrapper.eq("send_status", EnquirySendStatus.WAIT_SEND);
+        List<EnquiryEmailMessage> messageList = list(queryWrapper);
+        if (CollUtil.isNotEmpty(messageList)) {
+            UpdateWrapper<EnquiryEmailMessage> updateWrapper = new UpdateWrapper<>();
+            updateWrapper.in("id", messageList.stream().map(EnquiryEmailMessage::getId).collect(Collectors.toList()));
+            updateWrapper.set("send_status", EnquirySendStatus.SENDING);
+            updateWrapper.set("send_start_time", new Date());
+            this.update(updateWrapper);
+            for (EnquiryEmailMessage message : messageList) {
+                sendEmailByMessage(message);
+            }
+        }
+
+        adwebRedisUtil.unlock(keyName);
+    }
+
+    @Override
+    public void sendEmailByMessage(EnquiryEmailMessage message) {
+        try {
+            EmailSendMsgHandle sendMsgHandle = (EmailSendMsgHandle) Class.forName(SendMsgTypeEnum.EMAIL.getImplClass()).newInstance();
+            AdwebSite site = adwebSiteService.getOne(new QueryWrapper<AdwebSite>().eq("code", message.getSiteCode()));
+            String fromName = Objects.toString(site.getCompanyName(), site.getName());
+            sendMsgHandle.sendMsg(message.getEmail(), fromName, getEmailContent(message.getEnquiryId()));
+            dealSendSuccess(message);
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            dealSendFail(message, e.getMessage());
+        }
+    }
+
+    /**
+     * 处理发送时间超过10分钟的邮件消息
+     * 1、清除发送时间
+     *
+     * @return 如果返回true,需要重新发送
+     */
+    // private boolean dealTimeoutMessage(EnquiryEmailMessage message) {
+    //     Date now = new Date();
+    //     Date dealTime = message.getSendStartTime();
+    //     if (DateUtil.between(dealTime, now, DateUnit.MINUTE) >= 10) {
+    //         message.setSendStartTime(new Date());
+    //         updateById(message);
+    //         return true;
+    //     }
+    //     return false;
+    // }
+
+    /**
+     * 邮件发送失败处理
+     * 1、更新发送状态
+     * 2、清除发送时间
+     */
+    private void dealSendSuccess(EnquiryEmailMessage message) {
+        message.setSendStatus(EnquirySendStatus.SEND_SUCCESS);
+        message.setSendStartTime(null);
+        updateById(message);
+    }
+
+    /**
+     * 邮件发送失败处理
+     * 1、增加错误次数
+     * 2、更新发送状态
+     * 3、清除发送时间
+     * 4、如果错误次数到达三次,发送飞书通知
+     */
+    private void dealSendFail(EnquiryEmailMessage message, String errorMsg) {
+        if (StringUtils.isEmpty(errorMsg)) {
+            errorMsg = "发送询盘邮件失败";
+        }
+        message.setSendErrorNum(message.getSendErrorNum() + 1);
+        if (message.getSendErrorNum() >= 3) {
+            message.setSendStatus(EnquirySendStatus.SEND_FAIL);
+        } else {
+            message.setSendStatus(EnquirySendStatus.WAIT_SEND);
+        }
+        message.setSendStartTime(null);
+        String msg = Objects.toString(message.getSendErrorMsg(), "");
+        msg = msg + "," + errorMsg;
+        message.setSendErrorMsg(msg);
+        updateById(message);
+        if (message.getSendErrorNum() >= 3) {
+            feishuService.sendEnquiryEmailFailMsg(message.getEnquiryId(), message.getSiteCode(), message.getEmail(), errorMsg);
+        }
+
+        // 异常入库
+        SysException exception = new SysException();
+        exception.setType(0);
+        exception.setFunctionModule("发送询盘邮件错误");
+        exception.setExceptionDetail(errorMsg);
+        exception.setCreateTime(new Date());
+        exception.setStatus(1);
+        exception.setHandle(0);
+        exception.setPriority(1);
+        sysExceptionService.save(exception);
+    }
+
+    private String getEmailContent(long enquiryId) {
+        List<DictModel> dictModels = sysDictService.queryDictItemsByCode("enquiry_email_template");
+        String head = "", item = "", tail = "";
+        for (DictModel dictModel : dictModels) {
+            if ("head".equals(dictModel.getText())) {
+                head = dictModel.getValue();
+            }
+            if ("item".equals(dictModel.getText())) {
+                item = dictModel.getValue();
+            }
+            if ("tail".equals(dictModel.getText())) {
+                tail = dictModel.getValue();
+            }
+        }
+
+        StringBuilder content = new StringBuilder();
+        content.append(head);
+
+        AdwebEnquiryForm adwebEnquiryForm = adwebEnquiryFormService.getByEnquiryId(enquiryId);
+
+        List<EnquiryFormItem> formItems = new ArrayList<>();
+        //wpforms
+        if("wpforms".equals(adwebEnquiryForm.getPluginName())){
+            formItems = dealWpformEnquiryForm(adwebEnquiryForm);
+        }else{
+            formItems = dealElementerEnquiryForm(adwebEnquiryForm);
+        }
+
+        for (int i = 0; i < formItems.size(); i++) {
+            EnquiryFormItem enquiryFormItem = formItems.get(i);
+            String formItemName = enquiryFormItem.getName();
+            String formItemValue = enquiryFormItem.getValue();
+            String item1 = new String(item);
+            item1 = item1.replace("{{title}}", formItemName);
+            item1 = item1.replace("{{content}}", formItemValue == null || formItemValue == "" ? " " : formItemValue);
+            if (i == 0) {
+                item1 = item1.replace("border-top:1px solid #dddddd;", "");
+            }
+            content.append(item1);
+        }
+        content.append(tail);
+        return content.toString();
+    }
+
+    /**
+     * 获取待发送询盘
+     * 1、首次发送失败的
+     * 2、超过timeout分钟未处理的
+     *
+     * @param timeout 留给首次实时处理的时间,单位分钟,超过这个时间则认为首次邮件发送失败,应该由定时器处理
+     * @param num     获取邮件数量
+     * @return 邮件列表
+     */
+    @Override
+    public List<EnquiryEmailMessage> getWaitSendEmail(int timeout, int num) {
+        return enquiryEmailMessageMapper.getWaitSendEmail(timeout, num);
+    }
+
+    /**
+     * 添加并发送询盘邮件
+     * @param adwebEnquiry
+     */
+    @Override
+    public Result<?> addAndEnquiryEmailMsg(AdwebEnquiry adwebEnquiry, String uid){
+        //处理已有发送的询盘邮件
+        List<String> emailList = new ArrayList<>();
+        if("ALL".equals(uid)){
+            //获取子账户邮箱
+            List<String> subAccountIdList = masterSubAccountRelationService.getSubAccountIdByMaster(String.valueOf(adwebEnquiry.getUid()));
+            if (!subAccountIdList.isEmpty()) {
+                List<SysUser> principalEmailList = sysUserService.list(new QueryWrapper<SysUser>().in("id", subAccountIdList).eq("del_flag", 0).isNotNull("email").ne("email","").select("id", "email"));
+                if (ListUtil.notEmpty(principalEmailList)) {
+                    emailList = principalEmailList.stream().map(SysUser::getEmail).collect(Collectors.toList());
+                }
+            }
+        }else{
+            SysUser sysUser = sysUserService.getById(adwebEnquiry.getPrincipalUid());
+            if(StringUtils.isNotBlank(sysUser.getEmail())){
+                emailList.add(sysUser.getEmail());
+            }
+        }
+
+        if(ListUtil.notEmpty(emailList)){
+            QueryWrapper<EnquiryEmailMessage> enquiryEmailMessageQueryWrapper = new QueryWrapper<>();
+            enquiryEmailMessageQueryWrapper.eq("enquiry_id", adwebEnquiry.getId());
+            enquiryEmailMessageQueryWrapper.eq("site_code", adwebEnquiry.getSiteCode());
+            enquiryEmailMessageQueryWrapper.in("email",emailList);
+            List<EnquiryEmailMessage> enquiryEmailMessageList = list(enquiryEmailMessageQueryWrapper);
+
+            if(ListUtil.notEmpty(enquiryEmailMessageList)){
+                List<String> oldEmailList = enquiryEmailMessageList.stream().map(EnquiryEmailMessage::getEmail).collect(Collectors.toList());
+                List<String> noNeedEmailList = new ArrayList<>();
+                for(String email : emailList){
+                    if(oldEmailList.contains(email)){
+                        noNeedEmailList.add(email);
+                    }
+                }
+                if(ListUtil.notEmpty(noNeedEmailList)){
+                    emailList.removeAll(noNeedEmailList);
+                }
+            }
+
+            if(ListUtil.notEmpty(emailList)){
+                List<EnquiryEmailMessage> enquiryEmailMessageList1 = new ArrayList<>();
+                for (String email : emailList){
+                    EnquiryEmailMessage enquiryEmailMessage = new EnquiryEmailMessage();
+                    enquiryEmailMessage.setEnquiryId(adwebEnquiry.getId());
+                    enquiryEmailMessage.setSiteCode(adwebEnquiry.getSiteCode());
+                    enquiryEmailMessage.setEmail(email);
+                    enquiryEmailMessage.setFromEmail(adwebEnquiry.getFromEmail());
+                    enquiryEmailMessage.setSendStatus(EnquirySendStatus.WAIT_SEND);
+                    enquiryEmailMessage.setSendErrorNum(0);
+                    enquiryEmailMessage.setCreateTime(new Date());
+                    enquiryEmailMessageList1.add(enquiryEmailMessage);
+                }
+
+                boolean result = saveBatch(enquiryEmailMessageList1);
+                if(result){
+                    try {
+                        ObjectMapper objectMapper = new ObjectMapper();
+
+                        JedisUtil.lpush(redisKey, objectMapper.writeValueAsBytes(adwebEnquiry.getId()));
+                        JedisUtil.publishMsg(EnquiryConstants.ENQUIRY_EMAIL_CHANNEL, EnquiryConstants.ENQUIRY_EMAIL);
+                        return Result.OK();
+                    } catch (Exception e) {
+                        log.error("发送失败询盘id:" + adwebEnquiry.getId());
+                        log.error("推送发送询盘邮件的消息失败{}", e);
+                    }
+                }
+            }
+            return Result.OK();
+        }
+        return Result.error("子账户邮箱没有配置,询盘邮件发送失败");
+    }
+
+    /**
+     * 处理询盘发送信息
+     * wpform
+     */
+    private List<EnquiryFormItem> dealWpformEnquiryForm(AdwebEnquiryForm adwebEnquiryForm){
+        String form = adwebEnquiryForm.getForm();
+        Map<String, JSONObject> formObj = FastJsonUtil.parseObject(form, Map.class);
+        List<EnquiryFormItem> formItems = new ArrayList<>();
+        boolean countryFlag = true;
+        for (String key : formObj.keySet()) {
+            JSONObject formItem = formObj.get(key);
+            EnquiryFormItem enquiryFormItem = new EnquiryFormItem();
+            enquiryFormItem.setSort(Integer.parseInt(key));
+            if("Country".equals(formItem.getString("name")) || "country".equals(formItem.getString("name"))){
+                countryFlag = false;
+            }
+            enquiryFormItem.setName(formItem.getString("name"));
+            enquiryFormItem.setValue(formItem.getString("value"));
+            formItems.add(enquiryFormItem);
+        }
+        if(countryFlag) {
+            EnquiryFormItem countryForm = new EnquiryFormItem();
+            countryForm.setSort(99);
+            countryForm.setName("Country");
+            countryForm.setValue(adwebEnquiryForm.getCountry());
+            formItems.add(countryForm);
+        }
+
+        formItems.sort(Comparator.comparingInt(EnquiryFormItem::getSort));
+        return formItems;
+    }
+
+    /**
+     * 处理询盘发送信息
+     * elementer
+     */
+    private List<EnquiryFormItem> dealElementerEnquiryForm(AdwebEnquiryForm adwebEnquiryForm){
+        String form = adwebEnquiryForm.getForm();
+        Map<String, String> formMap = FastJsonUtil.parseObject(form, Map.class);
+        List<EnquiryFormItem> formItems = new ArrayList<>();
+        for (String key : formMap.keySet()) {
+            String value = formMap.get(key);
+            EnquiryFormItem enquiryFormItem = new EnquiryFormItem();
+            if(key.contains("phone") || key.contains("Phone")){
+                enquiryFormItem.setSort(1);
+            }else if (key.contains("email") || key.contains("Email")){
+                enquiryFormItem.setSort(2);
+            }else if (key.contains("ip") || key.contains("Ip")){
+                enquiryFormItem.setSort(3);
+            }else if (key.contains("message") || key.contains("Message")){
+                enquiryFormItem.setSort(4);
+            }else if (key.contains("page") || key.contains("Page")){
+                enquiryFormItem.setSort(5);
+            }else if (key.contains("name") || key.contains("Name")){
+                enquiryFormItem.setSort(6);
+            }else if (key.contains("company") || key.contains("Company")){
+                enquiryFormItem.setSort(7);
+            }else {
+                enquiryFormItem.setSort(9);
+            }
+            enquiryFormItem.setName(key);
+            enquiryFormItem.setValue(value);
+            formItems.add(enquiryFormItem);
+        }
+
+        //国家信息
+        EnquiryFormItem countryForm = new EnquiryFormItem();
+        countryForm.setSort(8);
+        countryForm.setName("Country");
+        countryForm.setValue(adwebEnquiryForm.getCountry());
+        formItems.add(countryForm);
+
+        formItems.sort(Comparator.comparingInt(EnquiryFormItem::getSort));
+        return formItems;
+    }
+}
+
+
+@Data
+class EnquiryFormItem {
+
+    private int sort;
+
+    private String name;
+
+    private String value;
+
+}

+ 1 - 1
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/seo/entity/SeoKeywordsSerp.java

@@ -61,7 +61,7 @@ public class SeoKeywordsSerp implements Serializable {
 	/**结果类型分组排名*/
 	@Excel(name = "结果类型分组排名", width = 15)
     @Schema(description = "结果类型分组排名")
-    private Integer rankType;
+    private Integer rankGroup;
 	/**自然全局排名*/
 	@Excel(name = "自然全局排名", width = 15)
     @Schema(description = "自然全局排名")

+ 2 - 2
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/seo/mapper/SeoKeywordsMapper.java

@@ -60,10 +60,10 @@ public interface SeoKeywordsMapper extends BaseMapper<SeoKeywords> {
                                       String buttonSort);
 
     /**
-     * 获取当日需要DateForSEO serp查询的关键词列表
+     * 获取当日需要DateForSEO Serp查询的关键词列表
      *
      * @return 关键词列表
      */
-    List<SeoKeywords> getKeywordsToSerp(int keywordType);
+    List<SeoKeywords> getKeywordsToSerp(List<String> sideCodes, int keywordType, int limit);
 
 }

+ 5 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/seo/mapper/SeoKeywordsSerpMapper.java

@@ -13,4 +13,9 @@ import org.jeecg.modules.adweb.seo.entity.SeoKeywordsSerp;
  */
 public interface SeoKeywordsSerpMapper extends BaseMapper<SeoKeywordsSerp> {
 
+    /**
+     * 返回指定关键词的最后一次Serp记录
+     */
+    SeoKeywordsSerp getLatestSeoKeywordSerp(int keywordId);
+
 }

+ 9 - 10
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/seo/mapper/xml/SeoKeywordsMapper.xml

@@ -167,18 +167,17 @@
         FROM
         seo_keywords
         WHERE
-        `status` = 1
-        AND site_code IN (
-        SELECT
-        `code`
-        FROM
-        adweb_site
-        WHERE
-        run_status = 1
-        AND `status` = 1
-        )
+        status = 1
+        AND
+        search_status != 1
+        AND site_code IN
+        <foreach collection="sideCodes" item="sideCode" open="(" separator="," close=")">
+            #{sideCode}
+        </foreach>
         <if test = "keywordType != null">
             AND keyword_type = #{keywordType}
         </if>
+        AND last_search_time <![CDATA[ <]]> CURDATE()
+        LIMIT #{limit}
     </select>
 </mapper>

+ 12 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/seo/mapper/xml/SeoKeywordsSerpMapper.xml

@@ -2,4 +2,16 @@
 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="org.jeecg.modules.adweb.seo.mapper.SeoKeywordsSerpMapper">
 
+    <select id="getLatestSeoKeywordSerp" resultType="org.jeecg.modules.adweb.seo.entity.SeoKeywordsSerp">
+        SELECT
+        *
+        FROM
+        seo_keywords_serp
+        WHERE
+        keywords_id = #{keywordId}
+        ORDER BY
+        se_date DESC
+        LIMIT 1
+    </select>
+
 </mapper>

+ 2 - 1
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/seo/service/ISeoKeywordsSerpService.java

@@ -2,6 +2,7 @@ package org.jeecg.modules.adweb.seo.service;
 
 import org.jeecg.modules.adweb.seo.entity.SeoKeywordsSerp;
 import com.baomidou.mybatisplus.extension.service.IService;
+import java.util.Date;
 
 /**
  * @Description: SEO关键词搜索排名
@@ -10,5 +11,5 @@ import com.baomidou.mybatisplus.extension.service.IService;
  * @Version: V1.0
  */
 public interface ISeoKeywordsSerpService extends IService<SeoKeywordsSerp> {
-
+    boolean fillKeywordsSerpHistory(int keywordId, Date seDatetime);
 }

+ 278 - 20
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/seo/service/dataforseo/DataForSEOService.java

@@ -1,20 +1,60 @@
 package org.jeecg.modules.adweb.seo.service.dataforseo;
 
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.json.JSONUtil;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
+import com.google.common.collect.Lists;
+
 import io.github.dataforseo.client.ApiClient;
+import io.github.dataforseo.client.ApiException;
 import io.github.dataforseo.client.api.SerpApi;
 import io.github.dataforseo.client.auth.HttpBasicAuth;
+import io.github.dataforseo.client.model.*;
 
 import jakarta.annotation.PostConstruct;
 
+import lombok.extern.slf4j.Slf4j;
+
+import org.apache.commons.lang3.StringUtils;
+import org.jeecg.modules.adweb.common.util.AdwebRedisUtil;
+import org.jeecg.modules.adweb.common.util.CommonUtil;
+import org.jeecg.modules.adweb.common.util.DateUtil;
+import org.jeecg.modules.adweb.common.util.ListUtil;
+import org.jeecg.modules.adweb.seo.entity.SeoKeywords;
 import org.jeecg.modules.adweb.seo.entity.SeoKeywordsSerp;
+import org.jeecg.modules.adweb.seo.mapper.SeoKeywordsMapper;
+import org.jeecg.modules.adweb.seo.service.ISeoKeywordsSerpService;
+import org.jeecg.modules.adweb.seo.service.ISeoKeywordsService;
+import org.jeecg.modules.adweb.site.entity.AdwebSite;
+import org.jeecg.modules.adweb.site.service.IAdwebSiteService;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 
+import java.util.*;
+
 /**
+ * DataForSEO Serp查询 - 基于Redis定时同步
+ *
+ * <p>1. 暂不使用DataForSEO callback实时更新方式,考虑AdWeb API稳定性
+ *
+ * <p>2. 暂不使用DataForSEO serp/google/organic/tasks_ready API - 每次仅返回一个task,与文档不符
+ *
  * @author wfansh
  */
+@Slf4j
 @Service
 public class DataForSEOService {
+    private static final int MAX_TASKS_PER_SERP_REQUEST = 100;
+    private static final int SERP_STATUS_CODE_SUCCESS = 20000;
+    private static final int SERP_STATUS_CODE_TASK_CREATED = 20100;
+    private static final int SERP_STATUS_CODE_TASK_HANDED = 40601;
+    private static final int SERP_STATUS_CODE_TASK_IN_QUEUE = 40602;
+
+    // Google一页显示搜索结果数量
+    private static final int GOOGLE_SEARCH_PAGE_SIZE = 10;
 
     @Value("${dataforseo.username}")
     private String username;
@@ -25,14 +65,24 @@ public class DataForSEOService {
     @Value("${dataforseo.api-path}")
     private String apiPath;
 
+    @Autowired private IAdwebSiteService adwebSiteService;
+
+    @Autowired private SeoKeywordsMapper seoKeywordsMapper;
+
+    @Autowired private ISeoKeywordsService seoKeywordsService;
+
+    @Autowired private ISeoKeywordsSerpService seoKeywordsSerpService;
+
+    @Autowired private AdwebRedisUtil redisUtil;
+
     private SerpApi serpApi;
 
     @PostConstruct
     private void init() {
         ApiClient defaultClient = io.github.dataforseo.client.Configuration.getDefaultApiClient();
         defaultClient.setBasePath(apiPath);
-        // HTTP超时 - 30秒
-        defaultClient.setConnectTimeout(30 * 1000);
+        // API超时 - 60秒
+        defaultClient.setConnectTimeout(60 * 1000);
 
         // API认证方式 - basicAuth
         HttpBasicAuth basicAuth = (HttpBasicAuth) defaultClient.getAuthentication("basicAuth");
@@ -43,26 +93,234 @@ public class DataForSEOService {
     }
 
     /**
-     * 从DataForSEO拉取keywords serp数据,同步到{@link SeoKeywordsSerp}表
+     * 全局查询更新DataForSEO keywords Serp数据 - 启动Serp任务并保存到Redis
      *
      * @param keywordType 1 - 指定词; 2 - 长尾词
+     * @param limit 最大查询条数
+     */
+    public void runKeywordsSerpTasks(List<String> siteCodes, int keywordType, int limit) {
+        if (ListUtil.isEmpty(siteCodes)) {
+            siteCodes =
+                    adwebSiteService
+                            .list(
+                                    new LambdaQueryWrapper<AdwebSite>()
+                                            .eq(AdwebSite::getStatus, 1)
+                                            .eq(AdwebSite::getRunStatus, 1))
+                            .stream()
+                            .map(AdwebSite::getCode)
+                            .toList();
+        }
+
+        List<SeoKeywords> seoKeywords =
+                seoKeywordsMapper.getKeywordsToSerp(siteCodes, keywordType, limit);
+
+        if (ListUtil.isEmpty(seoKeywords)) {
+            log.info("暂无需要Serp查询的关键词");
+        } else {
+            // DataForSEO - each POST call containing no more than 100 tasks
+            // https://docs.dataforseo.com/v3/serp/google/organic/task_post
+            Lists.partition(seoKeywords, MAX_TASKS_PER_SERP_REQUEST).forEach(this::sendSerpRequest);
+        }
+    }
+
+    /** 同步DataForSEO Serp结果 - 从Redis中获取正在运行的任务 */
+    public void syncKeywordsSerpResults() {
+        Set<String> serpTaskRedisKeys = redisUtil.keys(this.getSerpTaskRedisKey("*"));
+
+        if (CollectionUtil.isEmpty(serpTaskRedisKeys)) {
+            log.info("Redis中暂无需要同步的Serp关键词");
+        } else {
+            for (String serpTaskRedisKey : serpTaskRedisKeys) {
+                this.onSerpResult(serpTaskRedisKey);
+            }
+        }
+    }
+
+    /**
+     * 向DataForSEO发送Serp请求
+     *
+     * <p>1. 将taskId保存到Redis
+     *
+     * <p>2. 更新{@link SeoKeywords}表
      */
-    public void syncKeywordsSerp(int keywordType) {
-        // 1. 查询待更新keywords
-
-
-//        // TODO: 判断网站状态
-//        List<GoogleGTM> googleGTMS = googleGTMService.list();
-//
-//        for (GoogleGTM googleGTM : googleGTMS) {
-//            // 每个帐号同步更新三张报表
-//            try {
-//                this.syncGACountryReport(googleGTM);
-//                this.syncGASourceMediumReport(googleGTM);
-//                this.syncGAPagePathReport(googleGTM);
-//            } catch (RuntimeException e) {
-//                log.warn("同步GA报表异常, siteId = {], error = {}", googleGTM.getSiteId(), e);
-//            }
-//        }
+    private void sendSerpRequest(List<SeoKeywords> seoKeywords) {
+        try {
+            Date now = new Date();
+
+            // 1. 创建DataForSEO Serp查询请求,每个请求最多包含100个任务
+            List<SerpTaskRequestInfo> serpTaskRequestInfoList = Lists.newArrayList();
+            for (SeoKeywords seoKeyword :
+                    seoKeywords.subList(
+                            0, Math.min(seoKeywords.size(), MAX_TASKS_PER_SERP_REQUEST))) {
+                SerpTaskRequestInfo serpTaskRequestInfo = new SerpTaskRequestInfo();
+                serpTaskRequestInfo.setKeyword(seoKeyword.getKeywords());
+                serpTaskRequestInfo.setSeDomain("google.com");
+                serpTaskRequestInfo.setLanguageCode(
+                        StringUtils.defaultIfEmpty(seoKeyword.getLang(), "en"));
+                serpTaskRequestInfo.setLocationCode(2840); // 美国
+                serpTaskRequestInfo.setTag(Integer.toString(seoKeyword.getId())); // tag = keywordId
+                serpTaskRequestInfoList.add(serpTaskRequestInfo);
+            }
+
+            // 2. 发送DataForSEO Serp查询请求,验证并记录响应结果
+            SerpGoogleOrganicTaskPostResponseInfo serpTaskPostResponseInfo =
+                    serpApi.googleOrganicTaskPost(serpTaskRequestInfoList);
+            log.info(
+                    "创建DataForSEO Serp任务,response = {}",
+                    JSONUtil.toJsonStr(serpTaskPostResponseInfo));
+            if (serpTaskPostResponseInfo.getStatusCode() != SERP_STATUS_CODE_SUCCESS) {
+                throw new ApiException(serpTaskPostResponseInfo.getStatusMessage());
+            }
+
+            // 3. 过滤创建成功的Serp tasks,保存到Redis
+            List<SerpGoogleOrganicTaskPostTaskInfo> serpingTasks =
+                    serpTaskPostResponseInfo.getTasks().stream()
+                            .filter(task -> task.getStatusCode() == SERP_STATUS_CODE_TASK_CREATED)
+                            .toList();
+            List<Integer> serpingKeywordIds = Lists.newArrayList();
+
+            for (SerpGoogleOrganicTaskPostTaskInfo serpingTask : serpingTasks) {
+                Map<String, String> data = (Map<String, String>) serpingTask.getData();
+                String keywordId = data.get("tag");
+                redisUtil.set(this.getSerpTaskRedisKey(keywordId), serpingTask.getId());
+
+                serpingKeywordIds.add(Integer.parseInt(keywordId));
+            }
+
+            // 4. 更新seo_keywords表
+            List<SeoKeywords> serpingKeywords =
+                    seoKeywords.stream()
+                            .filter(keyword -> serpingKeywordIds.contains(keyword.getId()))
+                            .toList();
+            serpingKeywords.forEach(
+                    seoKeyword -> {
+                        seoKeyword.setTimerLastSearchTime(now); // 定时器执行时间
+                        seoKeyword.setSearchStatus(1); // 状态 -> 正在查询
+                    });
+            seoKeywordsService.updateBatchById(serpingKeywords);
+
+            log.info(
+                    "{}个关键词Serp查询任务创建完成 - {}",
+                    serpingKeywords.size(),
+                    serpingKeywords.stream().map(SeoKeywords::getId).toList());
+        } catch (ApiException e) {
+            log.error("创建DataForSEO Serp任务失败", e);
+        }
+    }
+
+    /**
+     * 处理DataForSEO Serp查询结果
+     *
+     * <p>1. 更新{@link SeoKeywords}表
+     *
+     * <p>2. 更新{@link SeoKeywordsSerp}表
+     *
+     * <p>3. 从Redis删除taskId
+     */
+    private boolean onSerpResult(String serpTaskRedisKey) {
+        try {
+            // 1. 查询Serp task
+            String taskId = redisUtil.getString(serpTaskRedisKey);
+            SerpGoogleOrganicTaskGetRegularTaskInfo serpTask =
+                    serpApi.googleOrganicTaskGetRegular(taskId).getTasks().get(0);
+            log.info("获取DataForSEO Serp任务,response = {}", JSONUtil.toJsonStr(serpTask));
+            if (serpTask.getStatusCode() != SERP_STATUS_CODE_SUCCESS) {
+                log.info(
+                        "DataForSEO Serp任务 {} 状态为 {} {}",
+                        taskId,
+                        serpTask.getStatusCode(),
+                        serpTask.getStatusMessage());
+                // Serp task正在处理中...
+                if (Arrays.asList(SERP_STATUS_CODE_TASK_HANDED, SERP_STATUS_CODE_TASK_IN_QUEUE)
+                        .contains(serpTask.getStatusCode())) {
+                    return true;
+                }
+                throw new ApiException(serpTask.getStatusMessage());
+            }
+            SerpGoogleOrganicTaskGetRegularResultInfo serpResult = serpTask.getResult().get(0);
+
+            // 2. 查询seo_keywords表,根据域名过滤Serp result items
+            int keywordId = Integer.parseInt(this.getKeywordIdFromRedisKey(serpTaskRedisKey));
+            SeoKeywords seoKeyword = seoKeywordsService.getById(keywordId);
+            if (Objects.isNull(seoKeyword)) {
+                log.info("无法获取关键词 ID = {}", keywordId);
+
+                redisUtil.del(serpTaskRedisKey);
+                return false;
+            }
+
+            String topPrivateDomain =
+                    CommonUtil.getTopPrivateDomain(seoKeyword.getDomain()); // 顶级域名
+            OrganicSerpElementItem serpItem =
+                    serpResult.getItems().stream()
+                            .filter(OrganicSerpElementItem.class::isInstance)
+                            .map(OrganicSerpElementItem.class::cast)
+                            .filter(item -> item.getDomain().contains(topPrivateDomain)) // 根据域名匹配
+                            .findAny()
+                            .orElse(null);
+
+            // 读取Serp相关数据
+            Date seDatetime =
+                    DateUtil.parseDate(serpResult.getDatetime(), DateUtil.ZONED_DATE_TIME_PATTERN);
+            String positionUrl =
+                    Objects.nonNull(serpItem)
+                            ? StringUtils.removeEnd(serpItem.getUrl(), "/")
+                            : null;
+            int rankGroup = Objects.nonNull(serpItem) ? serpItem.getRankGroup() : 0;
+            int rankAbsolute = Objects.nonNull(serpItem) ? serpItem.getRankAbsolute() : 0;
+
+            // 3.更新seo_keywords表
+            UpdateWrapper<SeoKeywords> seoKeywordsUpdateWrapper = new UpdateWrapper<>();
+            seoKeywordsUpdateWrapper.eq("id", keywordId);
+            seoKeywordsUpdateWrapper.set("last_search_time", seDatetime);
+            seoKeywordsUpdateWrapper.set("position_url", positionUrl);
+            seoKeywordsUpdateWrapper.set("last_rank", rankGroup);
+            seoKeywordsUpdateWrapper.set("search_status", 0); // 状态 -> 查询结束
+            seoKeywordsService.update(seoKeywordsUpdateWrapper);
+
+            // 4. 更新seo_keywords_serp表
+            // 4.1 填充与上次更新时间之间的数据, 截止到seDatetime的前一天
+            seoKeywordsSerpService.fillKeywordsSerpHistory(keywordId, seDatetime);
+            // 4.2 更新Serp表
+            SeoKeywordsSerp keywordSerp =
+                    seoKeywordsSerpService
+                            // 如果seDatetime当天有数据,则覆盖
+                            .list(
+                                    new LambdaQueryWrapper<SeoKeywordsSerp>()
+                                            .eq(SeoKeywordsSerp::getKeywordsId, keywordId)
+                                            .eq(
+                                                    SeoKeywordsSerp::getSeDate,
+                                                    DateUtil.formatDate(
+                                                            seDatetime, DateUtil.DATE_PATTERN)))
+                            .stream()
+                            .findFirst()
+                            .orElse(new SeoKeywordsSerp());
+
+            keywordSerp.setKeywordsId(keywordId);
+            keywordSerp.setSearchUrl(serpResult.getCheckUrl());
+            keywordSerp.setSeDomain(serpResult.getSeDomain());
+            keywordSerp.setLanguageCode(serpResult.getLanguageCode());
+            keywordSerp.setType("organic_results");
+            keywordSerp.setPageNumber(rankGroup > 0 ? rankGroup / GOOGLE_SEARCH_PAGE_SIZE + 1 : 0);
+            keywordSerp.setRankGroup(rankGroup);
+            keywordSerp.setRankAbsolute(rankAbsolute);
+            keywordSerp.setSeDate(DateUtil.formatDateStr(seDatetime, DateUtil.DATE_PATTERN));
+            keywordSerp.setSeDatetime(seDatetime);
+            seoKeywordsSerpService.save(keywordSerp);
+
+            redisUtil.del(serpTaskRedisKey);
+            return true;
+        } catch (ApiException e) {
+            log.error("同步DataForSEO Serp任务失败", e);
+            return false;
+        }
+    }
+
+    private String getSerpTaskRedisKey(String keywordId) {
+        return String.format("serp_task:%s", keywordId);
+    }
+
+    private String getKeywordIdFromRedisKey(String serpTaskRedisKey) {
+        return serpTaskRedisKey.split(":")[1];
     }
 }

+ 66 - 6
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/seo/service/impl/SeoKeywordsSerpServiceImpl.java

@@ -1,19 +1,79 @@
 package org.jeecg.modules.adweb.seo.service.impl;
 
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+
+import lombok.extern.slf4j.Slf4j;
+
+import org.apache.commons.lang3.StringUtils;
+import org.jeecg.modules.adweb.common.util.DateUtil;
+import org.jeecg.modules.adweb.common.util.ListUtil;
 import org.jeecg.modules.adweb.seo.entity.SeoKeywordsSerp;
 import org.jeecg.modules.adweb.seo.mapper.SeoKeywordsSerpMapper;
 import org.jeecg.modules.adweb.seo.service.ISeoKeywordsSerpService;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Objects;
 
 /**
- * @Description: SEO关键词搜索排名
- * @Author: jeecg-boot
- * @Date:   2024-10-15
- * @Version: V1.0
+ * @Description: SEO关键词搜索排名 @Author: jeecg-boot @Date: 2024-10-15 @Version: V1.0
  */
+@Slf4j
 @Service
-public class SeoKeywordsSerpServiceImpl extends ServiceImpl<SeoKeywordsSerpMapper, SeoKeywordsSerp> implements ISeoKeywordsSerpService {
+public class SeoKeywordsSerpServiceImpl extends ServiceImpl<SeoKeywordsSerpMapper, SeoKeywordsSerp>
+        implements ISeoKeywordsSerpService {
+
+    @Autowired private SeoKeywordsSerpMapper seoKeywordsSerpMapper;
+
+    /**
+     * 向seo_keywords_serp表中补充数据,截止到seDatetime的前一天
+     *
+     * @param keywordId 关键词ID
+     * @param seDatetime serp返回时间,此日期不需要填充
+     */
+    @Override
+    public boolean fillKeywordsSerpHistory(int keywordId, Date seDatetime) {
+        SeoKeywordsSerp latestSerp = seoKeywordsSerpMapper.getLatestSeoKeywordSerp(keywordId);
+        if (Objects.isNull(latestSerp)) {
+            return false;
+        }
+
+        // Serp最后更新时间 + 一天
+        Date startDate =
+                DateUtil.getTmrZeroTime(
+                        DateUtil.parseDate(latestSerp.getSeDate(), DateUtil.DATE_PATTERN));
+        // DateForSEO返回的SearchEngine时间
+        Date endDate = DateUtil.getTodayZeroTime(seDatetime);
+
+        List<SeoKeywordsSerp> serpsToFill = new ArrayList<>();
+        for (Date currentDate = startDate;
+                currentDate.compareTo(endDate) < 0;
+                currentDate = DateUtil.addDays(currentDate, 1)) {
+            // 设置成跟latestSerp相同的值
+            SeoKeywordsSerp serp = new SeoKeywordsSerp();
+            serp.setKeywordsId(keywordId);
+            serp.setSearchUrl(latestSerp.getSearchUrl());
+            serp.setSeDomain(latestSerp.getSeDomain());
+            serp.setLanguageCode(latestSerp.getLanguageCode());
+            serp.setType(
+                    StringUtils.appendIfMissing(latestSerp.getType(), "_copy")); // 标识出是复制的Serp值
+            serp.setPageNumber(latestSerp.getPageNumber());
+            serp.setRankGroup(latestSerp.getRankGroup());
+            serp.setRankAbsolute(latestSerp.getRankAbsolute());
+            serp.setSeDate(
+                    DateUtil.formatDateStr(currentDate, DateUtil.DATE_PATTERN)); // 复制Serp值的目标日期
+            serp.setSeDatetime(latestSerp.getSeDatetime()); // 真实Serp返回的SearchingEngine时间
+            serpsToFill.add(serp);
+        }
+
+        if (ListUtil.notEmpty(serpsToFill)) {
+            log.info("复制Serp记录,keyword ID = {}, 时间范围 = {} to {}", keywordId, startDate, endDate);
+            return this.saveBatch(serpsToFill);
+        }
 
+        return true;
+    }
 }

+ 6 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/site/entity/AdwebSite.java

@@ -1,5 +1,8 @@
 package org.jeecg.modules.adweb.site.entity;
 
+import java.io.Serializable;
+import java.util.Date;
+
 import com.baomidou.mybatisplus.annotation.IdType;
 import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableId;
@@ -379,6 +382,9 @@ public class AdwebSite implements Serializable {
     private java.lang.String enquirySendEmailType;
 
     @TableField(exist = false)
+    private Date enquiryMessageTime;
+
+    @TableField(exist = false)
     private String planId;
 
     @TableField(exist = false)

+ 20 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/site/service/IAdwebSiteService.java

@@ -4,6 +4,8 @@ import org.jeecg.modules.adweb.site.entity.AdwebSite;
 import com.baomidou.mybatisplus.extension.service.IService;
 import org.jeecg.modules.adweb.site.dto.WordPressConfig;
 
+import java.util.List;
+
 /**
  * @Description: adweb站点配置表单
  * @Author: jeecg-boot
@@ -26,4 +28,22 @@ public interface IAdwebSiteService extends IService<AdwebSite> {
      * @return 站点code
      */
     String getSiteCodeById(Integer id);
+
+    /**
+     * 根据父站点id获取站群所有id
+     *
+     * @param parentId 父站点id
+     * @return 父站点id和子站点id
+     */
+    List<Integer> getAllSiteIdByParentId(Integer parentId);
+
+    /**
+     * 根据站点id获取站群id
+     *
+     * @param siteId 站点id
+     * @return 站群id列表
+     */
+    List<Integer> getAllSiteIdBySiteId(Integer siteId);
+
+    public String getSiteNameByCode(String siteCode);
 }

+ 61 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/site/service/impl/AdwebSiteServiceImpl.java

@@ -1,7 +1,9 @@
 package org.jeecg.modules.adweb.site.service.impl;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.xkcoding.http.util.StringUtil;
 import org.apache.commons.lang.StringUtils;
 import org.apache.shiro.SecurityUtils;
 import org.jeecg.common.system.vo.LoginUser;
@@ -21,6 +23,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import jakarta.annotation.Resource;
 
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 
@@ -134,4 +137,62 @@ public class AdwebSiteServiceImpl extends ServiceImpl<AdwebSiteMapper, AdwebSite
         }
         return adwebSite.getCode();
     }
+
+    /**
+     * 根据站点id获取主站点的siteCode,如果站点本身就是主站点,则返回自身的code
+     *
+     * @param siteId 站点id
+     * @return 父站点code
+     */
+    @Override
+    public List<Integer> getAllSiteIdBySiteId(Integer siteId) {
+        AdwebSite adwebSite = this.getById(siteId);
+        if (StringUtil.isEmpty(adwebSite.getParentGroupCode())) {
+            return this.getAllSiteIdByParentId(siteId);
+        }
+
+        String code = adwebSite.getParentGroupCode();
+        QueryWrapper<AdwebSite> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("code", code).or().eq("parent_code", code);
+        List<AdwebSite> siteList = this.list(queryWrapper);
+        List<Integer> siteIds = new ArrayList<>();
+        for (AdwebSite site : siteList) {
+            siteIds.add(site.getId());
+        }
+        return siteIds;
+    }
+
+    /**
+     * 根据父站点id获取站群所有id
+     *
+     * @param parentId 父站点id
+     * @return 父站点id和子站点id
+     */
+    @Override
+    public List<Integer> getAllSiteIdByParentId(Integer parentId) {
+        String siteCode = this.getSiteCodeById(parentId);
+        QueryWrapper<AdwebSite> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("code", siteCode).or().eq("parent_code", siteCode);
+        List<AdwebSite> siteList = this.list(queryWrapper);
+        List<Integer> siteIds = new ArrayList<>();
+        for (AdwebSite site : siteList) {
+            siteIds.add(site.getId());
+        }
+        return siteIds;
+    }
+
+    @Override
+    public String getSiteNameByCode(String siteCode) {
+        try {
+            List<AdwebSite> adwebSites = this.list(new LambdaQueryWrapper<AdwebSite>()
+                    .eq(AdwebSite::getCode, siteCode)
+                    .ne(AdwebSite::getStatus, 0));
+            if (!adwebSites.isEmpty()) {
+                return adwebSites.get(0).getName();
+            }
+        } catch (Exception e) {
+            log.error("获取站点名称失败");
+        }
+        return "";
+    }
 }

+ 58 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/system/entity/MasterSubAccountRelation.java

@@ -0,0 +1,58 @@
+package org.jeecg.modules.adweb.system.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * “Adweb会员”主账户和子账户对应关系
+ */
+@Data
+@TableName("master_sub_account_relation")
+@EqualsAndHashCode(callSuper = false)
+@Schema(description="MasterSubAccountRelation")
+public class MasterSubAccountRelation implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 子账户ID
+     */
+    @TableId(type = IdType.ASSIGN_ID)
+    @Schema(description = "子账户ID")
+    private String subId;
+    /**
+     * 主账户ID
+     */
+    @Schema(description = "主账户ID")
+    private String masterId;
+
+    /**
+     * 子账户名
+     */
+    @Schema(description = "子账户名")
+    private String subName;
+    /**
+     * 主账户名
+     */
+    @Schema(description = "主账户名")
+    private String masterName;
+
+    /**
+     * 状态, 1:有效, 0:无效
+     */
+    @Schema(description = "状态")
+    private Integer status;
+
+    @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern="yyyy-MM-dd")
+    @Schema(description = "createTime")
+    private Date createTime;
+}

+ 81 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/system/entity/SysException.java

@@ -0,0 +1,81 @@
+package org.jeecg.modules.adweb.system.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.jeecgframework.poi.excel.annotation.Excel;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * @Description: sys_exception
+ * @Author: jeecg-boot
+ * @Date:   2023-01-13
+ * @Version: V1.0
+ */
+@Data
+@TableName("sys_exception")
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = false)
+@Schema(description="sys_exception")
+public class SysException implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+	/**id*/
+	@TableId(type = IdType.AUTO)
+    @Schema(description = "id")
+    private Integer id;
+	/**类型,0功能错误,1业务错误*/
+	@Excel(name = "类型,0功能错误,1业务错误", width = 15)
+    @Schema(description = "类型,0功能错误,1业务错误")
+    private Integer type;
+	/**功能模块*/
+	@Excel(name = "功能模块", width = 15)
+    @Schema(description = "功能模块")
+    private String functionModule;
+	/**异常详情*/
+	@Excel(name = "异常详情", width = 15)
+    @Schema(description = "异常详情")
+    private String exceptionDetail;
+	/**异常描述*/
+	@Excel(name = "异常描述", width = 15)
+    @Schema(description = "异常描述")
+    private String exceptionDescription;
+	/**参数*/
+	@Excel(name = "参数", width = 15)
+    @Schema(description = "参数")
+    private String param;
+	/**路径*/
+	@Excel(name = "路径", width = 15)
+    @Schema(description = "路径")
+    private String url;
+	/**返回结果*/
+	@Excel(name = "返回结果", width = 15)
+    @Schema(description = "返回结果")
+    private String result;
+	/**创建时间*/
+	@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+    @Schema(description = "创建时间")
+    private Date createTime;
+	/**1有效,0删除*/
+	@Excel(name = "1有效,0删除", width = 15)
+    @Schema(description = "1有效,0删除")
+    private Integer status;
+	/**1已解决,0未解决*/
+	@Excel(name = "1已解决,0未解决", width = 15)
+    @Schema(description = "1已解决,0未解决")
+    private Integer handle;
+    /**1最高,3最低*/
+    @Excel(name = "1最高,3最低", width = 15)
+    @Schema(description = "1最高,3最低")
+    private Integer priority;
+
+}

+ 11 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/system/mapper/MasterSubAccountRelationMapper.java

@@ -0,0 +1,11 @@
+package org.jeecg.modules.adweb.system.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.jeecg.modules.adweb.system.entity.MasterSubAccountRelation;
+
+/**
+ * “Adweb会员”主账户和子账户对应关系
+ */
+public interface MasterSubAccountRelationMapper extends BaseMapper<MasterSubAccountRelation> {
+
+}

+ 14 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/system/mapper/SysExceptionMapper.java

@@ -0,0 +1,14 @@
+package org.jeecg.modules.adweb.system.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.jeecg.modules.adweb.system.entity.SysException;
+
+/**
+ * @Description: sys_exception
+ * @Author: jeecg-boot
+ * @Date:   2023-01-13
+ * @Version: V1.0
+ */
+public interface SysExceptionMapper extends BaseMapper<SysException> {
+
+}

+ 46 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/system/service/IMasterSubAccountRelationService.java

@@ -0,0 +1,46 @@
+package org.jeecg.modules.adweb.system.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.jeecg.modules.adweb.system.entity.MasterSubAccountRelation;
+
+import java.util.List;
+
+/**
+ * “Adweb会员”主账户和子账户对应关系
+ */
+public interface IMasterSubAccountRelationService extends IService<MasterSubAccountRelation> {
+    /**
+     * 通过子账户ID获取主账户ID
+     * @param subId
+     * @return
+     */
+    String getMasterAccountIdBySub(String subId);
+
+    /**
+     * 通过子账户ID获取主账户名
+     * @param subId
+     * @return
+     */
+    String getMasterAccountNameBySub(String subId);
+
+    /**
+     * 通过主账户ID获取子账户ID
+     * @param masterId
+     * @return
+     */
+    List<String> getSubAccountIdByMaster(String masterId);
+
+    /**
+     * 保存主账户和子账户ID
+     * @param relation
+     */
+    void insertAccountRelation(MasterSubAccountRelation relation);
+
+    /**
+     * 根据uid获取一组uid,包括父账户和子账户
+     *
+     * @param uid 可以是父账户的uid,也可以是某一个子账户的uid
+     * @return 根据uid获取一组uid
+     */
+    List<String> getUidList(String uid);
+}

+ 14 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/system/service/ISysExceptionService.java

@@ -0,0 +1,14 @@
+package org.jeecg.modules.adweb.system.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.jeecg.modules.adweb.system.entity.SysException;
+
+/**
+ * @Description: sys_exception
+ * @Author: jeecg-boot
+ * @Date:   2023-01-13
+ * @Version: V1.0
+ */
+public interface ISysExceptionService extends IService<SysException> {
+
+}

+ 12 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/system/service/SysAdwebApi.java

@@ -1,5 +1,8 @@
 package org.jeecg.modules.adweb.system.service;
 
+import org.jeecg.common.system.vo.DictPropertyModel;
+import org.jeecg.modules.system.entity.SysDictItem;
+
 import java.util.List;
 
 public interface SysAdwebApi {
@@ -28,4 +31,13 @@ public interface SysAdwebApi {
      * 判断一个用户是否是adweb子会员
      */
     boolean isAdwebSubVip();
+
+    /**
+     * 38根据字典code获取字典信息
+     *
+     * @return
+     */
+    public List<DictPropertyModel> queryDictInfoByDictCode(String dictCode);
+
+    List<SysDictItem> selectItemsByDictCode(String mainId);
 }

+ 129 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/system/service/impl/MasterSubAccountRelationServiceImpl.java

@@ -0,0 +1,129 @@
+package org.jeecg.modules.adweb.system.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.jeecg.common.system.api.ISysBaseAPI;
+import org.jeecg.modules.adweb.common.util.ListUtil;
+import org.jeecg.modules.adweb.system.entity.MasterSubAccountRelation;
+import org.jeecg.modules.adweb.system.mapper.MasterSubAccountRelationMapper;
+import org.jeecg.modules.adweb.system.service.IMasterSubAccountRelationService;
+import org.jeecg.modules.adweb.system.service.SysAdwebApi;
+import org.springframework.stereotype.Service;
+
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Service
+@Slf4j
+public class MasterSubAccountRelationServiceImpl extends ServiceImpl<MasterSubAccountRelationMapper, MasterSubAccountRelation> implements IMasterSubAccountRelationService {
+
+    @Resource
+    private ISysBaseAPI sysBaseAPI;
+
+    @Resource
+    private SysAdwebApi sysAdwebApi;
+
+    @Override
+    public String getMasterAccountIdBySub(String subId){
+        String masterId = "";
+        LambdaQueryWrapper<MasterSubAccountRelation> query = new LambdaQueryWrapper<>();
+        query.eq(MasterSubAccountRelation::getSubId,subId);
+        query.eq(MasterSubAccountRelation::getStatus,1);
+        MasterSubAccountRelation relation = null;
+        try {
+            relation = this.getBaseMapper().selectOne(query);
+            if(relation != null){
+                masterId = relation.getMasterId();
+            }
+        } catch (Exception e){
+            log.error("通过子账户ID获取主账户ID失败");
+        }
+        return masterId;
+    }
+
+    @Override
+    public String getMasterAccountNameBySub(String subId){
+        String masterName = "";
+        LambdaQueryWrapper<MasterSubAccountRelation> query = new LambdaQueryWrapper<>();
+        query.eq(MasterSubAccountRelation::getSubId,subId);
+        query.eq(MasterSubAccountRelation::getStatus,1);
+        MasterSubAccountRelation relation = null;
+        try {
+            relation = this.getBaseMapper().selectOne(query);
+            if(relation != null){
+                masterName = relation.getMasterName();
+            }
+        } catch (Exception e){
+            log.error("通过子账户ID获取主账户ID失败");
+        }
+        return masterName;
+    }
+
+    @Override
+    public List<String> getSubAccountIdByMaster(String masterId){
+        List<String> subIdList = null;
+        LambdaQueryWrapper<MasterSubAccountRelation> query = new LambdaQueryWrapper<>();
+        query.eq(MasterSubAccountRelation::getMasterId,masterId);
+        query.eq(MasterSubAccountRelation::getStatus,1);
+        List<MasterSubAccountRelation> relationList = null;
+        try {
+            relationList = this.getBaseMapper().selectList(query);
+        } catch (Exception e){
+            log.error("通过主账户ID获取子账户ID失败");
+        }
+        subIdList = relationList.stream().map(MasterSubAccountRelation::getSubId).collect(Collectors.toList());
+        return subIdList;
+    }
+
+    @Override
+    public void insertAccountRelation(MasterSubAccountRelation relation){
+        relation.setCreateTime(new Date());
+        try {
+            if(relation != null){
+                this.getBaseMapper().insert(relation);
+            }
+        }catch (Exception e){
+            log.error("保存主账户和子账户ID失败");
+        }
+    }
+
+    /**
+     * 根据uid获取一组uid,包括父账户和子账户
+     *
+     * @param uid 可以是父账户的uid,也可以是某一个子账户的uid
+     * @return 根据uid获取一组uid
+     */
+    @Override
+    public List<String> getUidList(String uid) {
+        List<String> defaultList = Arrays.asList(uid);
+
+        String masterId = uid;
+        if (sysAdwebApi.isAdwebSubVip()) {
+            QueryWrapper<MasterSubAccountRelation> queryWrapper = new QueryWrapper<>();
+            queryWrapper.eq("sub_id", uid);
+            queryWrapper.eq("status", 1);
+            List<MasterSubAccountRelation> relations = this.list(queryWrapper);
+            if (ListUtil.isEmpty(relations)) {
+                return defaultList;
+            }
+            masterId = relations.get(0).getMasterId();
+        }
+
+        QueryWrapper<MasterSubAccountRelation> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("master_id", masterId);
+        queryWrapper.eq("status", 1);
+        List<MasterSubAccountRelation> relations = this.list(queryWrapper);
+        if (ListUtil.isEmpty(relations)) {
+            return defaultList;
+        }
+        List<String> uidList = relations.stream().map(MasterSubAccountRelation::getSubId).collect(Collectors.toList());
+        uidList.add(masterId);
+        return uidList;
+    }
+
+}

+ 30 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/system/service/impl/SysAdwebApiImpl.java

@@ -7,6 +7,8 @@ import jakarta.annotation.Resource;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.shiro.SecurityUtils;
 import org.jeecg.common.system.api.ISysBaseAPI;
+import org.jeecg.common.system.vo.DictModel;
+import org.jeecg.common.system.vo.DictPropertyModel;
 import org.jeecg.common.system.vo.LoginUser;
 import org.jeecg.modules.adweb.common.constant.AdwebConstant;
 import org.jeecg.modules.adweb.common.constant.NumConstant;
@@ -15,9 +17,12 @@ import org.jeecg.modules.adweb.site.entity.AdwebSite;
 import org.jeecg.modules.adweb.site.service.IAdwebSiteService;
 import org.jeecg.modules.adweb.site.service.ISiteUserPermissionService;
 import org.jeecg.modules.adweb.system.service.SysAdwebApi;
+import org.jeecg.modules.system.entity.SysDictItem;
 import org.jeecg.modules.system.entity.SysUser;
+import org.jeecg.modules.system.mapper.SysDictItemMapper;
 import org.jeecg.modules.system.mapper.SysUserMapper;
 import org.jeecg.modules.system.mapper.SysUserRoleMapper;
+import org.jeecg.modules.system.service.ISysDictService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
@@ -34,6 +39,9 @@ public class SysAdwebApiImpl implements SysAdwebApi {
     @Resource
     private SysUserMapper userMapper;
 
+    @Resource
+    private SysDictItemMapper sysDictItemMapper;
+
     @Autowired
     private ISiteUserPermissionService siteUserPermissionService;
 
@@ -43,6 +51,9 @@ public class SysAdwebApiImpl implements SysAdwebApi {
     @Autowired
     private ISysBaseAPI sysBaseAPI;
 
+    @Autowired
+    private ISysDictService sysDictService;
+
     @Override
     public boolean isAdmin() {
         LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
@@ -174,4 +185,23 @@ public class SysAdwebApiImpl implements SysAdwebApi {
         }
         return false;
     }
+
+    @Override
+    public List<DictPropertyModel> queryDictInfoByDictCode(String dictCode) {
+        List<DictModel> dictModels = sysDictService.queryDictItemsByCode(dictCode);
+        List<DictPropertyModel> propertyModels = new ArrayList<>();
+        for (DictModel data : dictModels) {
+            DictPropertyModel propertyModel = new DictPropertyModel();
+            propertyModel.setCatalogCode(dictCode);
+            propertyModel.setLabel(data.getText());
+            propertyModel.setValue(data.getValue());
+            propertyModels.add(propertyModel);
+        }
+        return propertyModels;
+    }
+
+    @Override
+    public List<SysDictItem> selectItemsByDictCode(String dictCode) {
+        return sysDictItemMapper.selectItemsByDictCode(dictCode);
+    }
 }

+ 18 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/system/service/impl/SysExceptionServiceImpl.java

@@ -0,0 +1,18 @@
+package org.jeecg.modules.adweb.system.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.jeecg.modules.adweb.system.entity.SysException;
+import org.jeecg.modules.adweb.system.mapper.SysExceptionMapper;
+import org.jeecg.modules.adweb.system.service.ISysExceptionService;
+import org.springframework.stereotype.Service;
+
+/**
+ * @Description: sys_exception
+ * @Author: jeecg-boot
+ * @Date:   2023-01-13
+ * @Version: V1.0
+ */
+@Service
+public class SysExceptionServiceImpl extends ServiceImpl<SysExceptionMapper, SysException> implements ISysExceptionService {
+
+}

+ 33 - 2
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/mq/EnquiryReceiver.java

@@ -1,5 +1,6 @@
 package org.jeecg.modules.mq;
 
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.rabbitmq.client.Channel;
 
 import lombok.extern.slf4j.Slf4j;
@@ -8,11 +9,19 @@ import org.jeecg.boot.starter.rabbitmq.core.BaseRabbiMqHandler;
 import org.jeecg.boot.starter.rabbitmq.listenter.MqListener;
 import org.jeecg.common.annotation.RabbitComponent;
 import org.jeecg.modules.adweb.enquiry.dto.EnquiryDTO;
+import org.jeecg.modules.adweb.enquiry.service.IAdwebEnquiryService;
+import org.jeecg.modules.adweb.site.entity.AdwebSite;
+import org.jeecg.modules.adweb.site.service.IAdwebSiteService;
 import org.springframework.amqp.rabbit.annotation.RabbitHandler;
 import org.springframework.amqp.rabbit.annotation.RabbitListener;
 import org.springframework.amqp.support.AmqpHeaders;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.messaging.handler.annotation.Header;
 
+import java.io.IOException;
+import java.util.List;
+import java.util.concurrent.TimeoutException;
+
 /**
  * Rabbit MQ - 询盘消息接收
  *
@@ -22,13 +31,19 @@ import org.springframework.messaging.handler.annotation.Header;
 @RabbitComponent(value = "enquiryReceiver")
 public class EnquiryReceiver extends BaseRabbiMqHandler<EnquiryDTO> {
 
+    @Autowired
+    private IAdwebSiteService adwebSiteService;
+
+    @Autowired
+    private IAdwebEnquiryService adwebEnquiryService;
+
     @RabbitHandler
     // ackMode需要设置为MANUAL - BaseRabbiMqHandler.onMessage()有channel.basicAck()操作
-    @RabbitListener(queues = "enquiry", ackMode = "MANUAL")
+    @RabbitListener(queues = "site_enquiry", ackMode = "MANUAL")
     public void onMessage(
             EnquiryDTO enquiryDTO,
             Channel channel,
-            @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag) {
+            @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag) throws IOException, TimeoutException {
         super.onMessage(
                 enquiryDTO,
                 deliveryTag,
@@ -38,6 +53,22 @@ public class EnquiryReceiver extends BaseRabbiMqHandler<EnquiryDTO> {
                     public void handler(EnquiryDTO enquiry, Channel channel) {
                         // 业务处理
                         log.info("收到MQ消息 {}", enquiry);
+
+                        // 查看发布当前消息的站点是否是 adweb3 平台中绑定的是否是有效站点, 如果不是则直接确认消息,不做业务处理
+                        List<AdwebSite> adwebSites = adwebSiteService.list(new LambdaQueryWrapper<AdwebSite>()
+                                .like(AdwebSite::getDomain, enquiry.getSiteHost())
+                                .ne(AdwebSite::getStatus, 0));
+
+                        if (adwebSites.isEmpty()) {
+                            try {
+                                channel.basicAck(deliveryTag, false);
+                            } catch (IOException e) {
+                                log.error(String.format("站点:%s 不是adweb3的有效绑定站点,MQ消息确认失败: %s", enquiry.getSiteHost(), e.getMessage()), e);
+                            }
+                        }
+                        // 询盘入库
+                        adwebEnquiryService.addEnquiry(enquiry, enquiry.getPluginName(), adwebSites);
+
                     }
                 });
     }

+ 10 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysDictItemMapper.java

@@ -23,4 +23,14 @@ public interface SysDictItemMapper extends BaseMapper<SysDictItem> {
      */
     @Select("SELECT * FROM sys_dict_item WHERE DICT_ID = #{mainId} order by sort_order asc, item_value asc")
     public List<SysDictItem> selectItemsByMainId(String mainId);
+
+    @Select("SELECT\n" +
+            "\t * \n" +
+            "FROM\n" +
+            "\tsys_dict_item t1\n" +
+            "\tJOIN sys_dict t2 ON t1.dict_id = t2.id\n" +
+            "WHERE\n" +
+            "\tt2.dict_code = #{dictCode} AND\n" +
+            "\tt1.`status` = 1")
+    List<SysDictItem> selectItemsByDictCode(String dictCode);
 }

+ 10 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/SysDictMapper.java

@@ -11,6 +11,7 @@ import org.jeecg.common.system.vo.DictModel;
 import org.jeecg.common.system.vo.DictModelMany;
 import org.jeecg.common.system.vo.DictQuery;
 import org.jeecg.modules.system.entity.SysDict;
+import org.jeecg.modules.system.entity.SysDictItem;
 import org.jeecg.modules.system.model.DuplicateCheckVo;
 import org.jeecg.modules.system.model.TreeSelectModel;
 
@@ -200,4 +201,13 @@ public interface SysDictMapper extends BaseMapper<SysDict> {
 	 */
 	@Select("select * from sys_dict where del_flag = 1 and tenant_id = #{tenantId}")
 	List<SysDict> queryDeleteListBtTenantId(@Param("tenantId") Integer tenantId);
+
+	/**
+	 * 根据字典code和text获取字典条目
+	 *
+	 * @param dictCode 字典code
+	 * @param itemText 字典text
+	 * @return 字典中的一个条目
+	 */
+	SysDictItem getDictItemByCodeAndText(String dictCode, String itemText);
 }

+ 15 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/mapper/xml/SysDictMapper.xml

@@ -218,4 +218,19 @@
 	</select>
 
 
+	<select id="getDictItemByCodeAndText" resultType="org.jeecg.modules.system.entity.SysDictItem">
+		SELECT
+			t2.*
+		FROM
+			sys_dict t1,
+			sys_dict_item t2
+		WHERE
+			t1.id = t2.dict_id
+		  AND t1.dict_code = #{dictCode}
+		  AND t1.del_flag = 0
+		  AND t2.`status` = 1
+		  AND t2.item_text = #{itemText}
+			LIMIT 1
+	</select>
+
 </mapper>

+ 10 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/ISysDictService.java

@@ -287,4 +287,14 @@ public interface ISysDictService extends IService<SysDict> {
 	 * @param sysDictVo
 	 */
 	void editDictByLowAppId(SysDictVo sysDictVo);
+
+
+	/**
+	 * 根据字典code和text获取字典条目
+	 *
+	 * @param dictCode 字典code
+	 * @param itemText 字典text
+	 * @return 字典中的一个条目
+	 */
+	SysDictItem getDictItemByCodeAndText(String dictCode, String itemText);
 }

+ 12 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysDictServiceImpl.java

@@ -881,4 +881,16 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl
 		//新增子项
 		this.addDictItem(id,dictItemList);
 	}
+
+	/**
+	 * 根据字典code和text获取字典条目
+	 *
+	 * @param dictCode 字典code
+	 * @param itemText 字典text
+	 * @return 字典中的一个条目
+	 */
+	@Override
+	public SysDictItem getDictItemByCodeAndText(String dictCode, String itemText) {
+		return sysDictMapper.getDictItemByCodeAndText(dictCode, itemText);
+	}
 }

+ 65 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/xxl/DataForSEOJob.java

@@ -0,0 +1,65 @@
+package org.jeecg.modules.xxl;
+
+import com.xxl.job.core.biz.model.ReturnT;
+import com.xxl.job.core.handler.annotation.XxlJob;
+
+import lombok.extern.slf4j.Slf4j;
+
+import org.jeecg.modules.adweb.common.constant.AdwebConstant;
+import org.jeecg.modules.adweb.seo.service.dataforseo.DataForSEOService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * DataForSEO Serp查询及同步任务,{@link DataForSEOService}
+ *
+ * @author wfansh
+ */
+@Slf4j
+@Component
+public class DataForSEOJob {
+
+    @Autowired private DataForSEOService dataForSEOService;
+
+    @XxlJob("runLongTailKeywordsSerpTasksHandler")
+    public ReturnT<String> runLongTailKeywordsSerpTasksHandler(String param) {
+        log.info("执行长尾词Serp查询..., param = {}", param);
+        dataForSEOService.runKeywordsSerpTasks(
+                this.parseSiteCodes(param),
+                AdwebConstant.KEYWORD_TYPE_LONG_TAIL,
+                Integer.MAX_VALUE);
+        log.info("执行长尾词Serp查询结束");
+
+        return ReturnT.SUCCESS;
+    }
+
+    @XxlJob("runAppointKeywordsSerpTasksHandler")
+    public ReturnT<String> runAppointKeywordsSerpTasksHandler(String param) {
+        log.info("执行指定词Serp查询..., param = {}", param);
+        dataForSEOService.runKeywordsSerpTasks(
+                this.parseSiteCodes(param), AdwebConstant.KEYWORD_TYPE_APPOINT, Integer.MAX_VALUE);
+        log.info("执行指定词Serp查询结束");
+
+        return ReturnT.SUCCESS;
+    }
+
+    @XxlJob("syncKeywordsSerpResultsHandler")
+    public ReturnT<String> syncKeywordsSerpResultsHandler(String param) {
+        log.info("同步关键词Serp查询结果...");
+        dataForSEOService.syncKeywordsSerpResults();
+        log.info("同步关键词Serp查询结果结束");
+
+        return ReturnT.SUCCESS;
+    }
+
+    private List<String> parseSiteCodes(String param) {
+        return Objects.nonNull(param)
+                ? Arrays.stream(param.split(",")).map(siteCode -> siteCode.trim()).toList()
+                : Collections.EMPTY_LIST;
+    }
+}

+ 4 - 1
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/xxl/GAReportJob.java

@@ -1,5 +1,6 @@
 package org.jeecg.modules.xxl;
 
+import com.xxl.job.core.biz.model.ReturnT;
 import com.xxl.job.core.handler.annotation.XxlJob;
 
 import lombok.extern.slf4j.Slf4j;
@@ -20,9 +21,11 @@ public class GAReportJob {
     @Autowired private GAReportService gaReportService;
 
     @XxlJob("syncGAReportHandler")
-    public void syncGAReportHandler() {
+    public ReturnT<String> syncGAReportHandler(String param) {
         log.info("同步GA报表数据...");
         gaReportService.syncGAReport();
         log.info("同步GA报表数据结束");
+
+        return ReturnT.SUCCESS;
     }
 }

+ 31 - 1
jeecg-module-system/jeecg-system-start/src/main/resources/application-dev.yml

@@ -356,8 +356,38 @@ data-bridge:
     host: http://data-bridge.v3.adwebcloud.com:9002
     token: lgoXX9APqgPLGMPECiNoxaPx
 
+##GEOIP MMDB 静态数据库文件
+geoip:
+  static:
+    city:
+      mmdb: D:\Advich\GeoLite2-City.mmdb
+
+# 机器人预警url
+robot:
+  enquiry-url: https://open.feishu.cn/open-apis/bot/v2/hook/042cf8d0-0072-435c-bf5c-656b9368a5ac  #询盘拉取失败通知
+  market-plan-missing-url: https://open.feishu.cn/open-apis/bot/v2/hook/4a7110ff-9121-49fc-b0b6-0d809b548ad4  #缺少营销方案导致的拉取站点失败
+  flow-abnormal-url: https://open.feishu.cn/open-apis/bot/v2/hook/81ec5829-ba64-43d7-9662-2054e80a4ebe  #流量异常通知
+  keyword-preOrSuffix-url: https://open.feishu.cn/open-apis/bot/v2/hook/325b4b0a-df54-4c7f-adaf-c5da61bb12b3  #关键词前后缀通知
+  localize-product-fail-url: https://open.feishu.cn/open-apis/bot/v2/hook/46e780fc-6ed9-45ec-b39f-1e332a236386 #产品图片本地化失败通知
+  gtm-url: https://open.feishu.cn/open-apis/bot/v2/hook/e29a515d-7331-428e-b890-5b5549ffcab5 #跟踪gtm通知
+
+#垃圾询盘判断规则
+judge_waste_enquiry:
+  email:
+    tenMinNum: 3 # 10分钟内最多发送3次
+    oneDayNum: 5 # 一天最多发送5封邮件
+    notBlackListNum: 3 #不在黑名单中的邮箱发送次数
+    notBlackListDate: 7 #不在邮箱黑名单中的垃圾询盘计数的天数
+  ip:
+    tenMinNum: 3 # 10分钟内最多发送次数 >
+    oneDayNum: 5 # 一天内最多发送次数 >
+    notBlackListNum: 3 #不在Ip黑名单中垃圾询盘计数次数 >
+    notBlackListDate: 7 #不在Ip黑名单中垃圾询盘计数的天数
+    delOrdIpDate: 90 #删除时效性低的Ip时间
+
 ### dataforseo
 dataforseo:
   username: advichdev@gmail.com
   password: 0845d3de83295cca
-  api-path: https://api.dataforseo.com
+  api-path: https://api.dataforseo.com
+

+ 31 - 1
jeecg-module-system/jeecg-system-start/src/main/resources/application-prod.yml

@@ -344,8 +344,38 @@ data-bridge:
     host: http://data-bridge.v3.adwebcloud.com:9002
     token: lgoXX9APqgPLGMPECiNoxaPx
 
+##GEOIP MMDB 静态数据库文件
+geoip:
+  static:
+    city:
+      mmdb: /home/adweb/adweb3/sharing/GeoLite2-City.mmdb
+
+# 机器人预警url
+robot:
+  enquiry-url: https://open.feishu.cn/open-apis/bot/v2/hook/042cf8d0-0072-435c-bf5c-656b9368a5ac  #询盘拉取失败通知
+  market-plan-missing-url: https://open.feishu.cn/open-apis/bot/v2/hook/4a7110ff-9121-49fc-b0b6-0d809b548ad4  #缺少营销方案导致的拉取站点失败
+  flow-abnormal-url: https://open.feishu.cn/open-apis/bot/v2/hook/81ec5829-ba64-43d7-9662-2054e80a4ebe  #流量异常通知
+  keyword-preOrSuffix-url: https://open.feishu.cn/open-apis/bot/v2/hook/325b4b0a-df54-4c7f-adaf-c5da61bb12b3
+  localize-product-fail-url: https://open.feishu.cn/open-apis/bot/v2/hook/46e780fc-6ed9-45ec-b39f-1e332a236386
+  gtm-url: https://open.feishu.cn/open-apis/bot/v2/hook/e29a515d-7331-428e-b890-5b5549ffcab5
+
+#垃圾询盘判断规则
+judge_waste_enquiry:
+  email:
+    tenMinNum: 3 # 10分钟内最多发送3次
+    oneDayNum: 5 # 一天最多发送5封邮件
+    notBlackListNum: 3 #不在黑名单中的邮箱发送次数
+    notBlackListDate: 7 #不在邮箱黑名单中的垃圾询盘计数的天数
+  ip:
+    tenMinNum: 3 # 10分钟内最多发送次数 >
+    oneDayNum: 5 # 一天内最多发送次数 >
+    notBlackListNum: 3 #不在Ip黑名单中垃圾询盘计数次数 >
+    notBlackListDate: 7 #不在Ip黑名单中垃圾询盘计数的天数
+    delOrdIpDate: 90 #删除时效性低的Ip时间
+
 ### dataforseo
 dataforseo:
   username: advichdev@gmail.com
   password: 0845d3de83295cca
-  api-path: https://api.dataforseo.com
+  api-path: https://api.dataforseo.com
+

Some files were not shown because too many files changed in this diff