Ver Fonte

框架改动

1811872455@163.com há 1 mês atrás
pai
commit
2a9a5118ea
100 ficheiros alterados com 3570 adições e 89 exclusões
  1. 0 28
      java/storlead-crm/storlead-email/README.md
  2. 0 4
      java/storlead-crm/storlead-email/src/main/java/com/storlead/crm/email/package-info.java
  3. 0 28
      java/storlead-crm/storlead-order/README.md
  4. 0 4
      java/storlead-crm/storlead-order/src/main/java/com/storlead/crm/order/package-info.java
  5. 348 0
      java/storlead-dependencies/pom.xml
  6. 34 0
      java/storlead-es/pom.xml
  7. 44 0
      java/storlead-es/src/main/java/com/storlead/es/config/ElasticSearchConfig.java
  8. 46 0
      java/storlead-es/src/main/java/com/storlead/es/pojo/vo/EsGenericVO.java
  9. 67 0
      java/storlead-es/src/main/java/com/storlead/es/pojo/vo/EsQuerySimilarityVO.java
  10. 16 0
      java/storlead-es/src/main/java/com/storlead/es/pojo/vo/EsQueryVO.java
  11. 15 0
      java/storlead-es/src/main/java/com/storlead/es/pojo/vo/FieldConfig.java
  12. 19 0
      java/storlead-es/src/main/java/com/storlead/es/pojo/vo/IndexFieldConfig.java
  13. 52 0
      java/storlead-es/src/main/java/com/storlead/es/server/BaseSearchService.java
  14. 17 0
      java/storlead-es/src/main/java/com/storlead/es/server/EsSearchCustomerService.java
  15. 319 0
      java/storlead-es/src/main/java/com/storlead/es/server/impl/BaseSearchServiceImpl.java
  16. 269 0
      java/storlead-es/src/main/java/com/storlead/es/server/impl/EsSearchCustomerServiceImpl.java
  17. 7 9
      java/storlead-message/pom.xml
  18. 20 0
      java/storlead-message/src/main/java/com/storlead/message/controller/UserMessageNoticeConfigController.java
  19. 58 0
      java/storlead-message/src/main/java/com/storlead/message/entity/UserMessageNoticeConfigEntity.java
  20. 96 0
      java/storlead-message/src/main/java/com/storlead/message/enums/MessageTypeEnum.java
  21. 77 0
      java/storlead-message/src/main/java/com/storlead/message/enums/OperationEventEnum.java
  22. 21 0
      java/storlead-message/src/main/java/com/storlead/message/mapper/InsideMessageRecordMapper.java
  23. 32 0
      java/storlead-message/src/main/java/com/storlead/message/mapper/InsideMessageSendLogMapper.java
  24. 17 0
      java/storlead-message/src/main/java/com/storlead/message/mapper/MessageTemplateEventDetailMapper.java
  25. 29 0
      java/storlead-message/src/main/java/com/storlead/message/mapper/MessageTemplateEventGroupMapper.java
  26. 16 0
      java/storlead-message/src/main/java/com/storlead/message/mapper/UserMessageNoticeConfigMapper.java
  27. 34 0
      java/storlead-message/src/main/java/com/storlead/message/mapper/xml/InsideMessageRecordMapper.xml
  28. 26 0
      java/storlead-message/src/main/java/com/storlead/message/mapper/xml/InsideMessageSendLogMapper.xml
  29. 35 0
      java/storlead-message/src/main/java/com/storlead/message/mapper/xml/UserMessageNoticeConfigMapper.xml
  30. 27 0
      java/storlead-message/src/main/java/com/storlead/message/pojo/dto/MessageDTO.java
  31. 12 0
      java/storlead-message/src/main/java/com/storlead/message/pojo/dto/MessageTemplateDetailDTO.java
  32. 15 0
      java/storlead-message/src/main/java/com/storlead/message/pojo/dto/MessageTemplateEventDTO.java
  33. 31 0
      java/storlead-message/src/main/java/com/storlead/message/pojo/dto/MessageTestDTO.java
  34. 98 0
      java/storlead-message/src/main/java/com/storlead/message/pojo/entity/InsideMessageRecordEntity.java
  35. 70 0
      java/storlead-message/src/main/java/com/storlead/message/pojo/entity/InsideMessageSendLogEntity.java
  36. 63 0
      java/storlead-message/src/main/java/com/storlead/message/pojo/entity/MessageTemplateEventDetailEntity.java
  37. 64 0
      java/storlead-message/src/main/java/com/storlead/message/pojo/entity/MessageTemplateEventGroupEntity.java
  38. 20 0
      java/storlead-message/src/main/java/com/storlead/message/pojo/vo/MessageArgTemplateVO.java
  39. 46 0
      java/storlead-message/src/main/java/com/storlead/message/pojo/vo/MessageDetailVO.java
  40. 25 0
      java/storlead-message/src/main/java/com/storlead/message/pojo/vo/MessageNoReadTotalVO.java
  41. 29 0
      java/storlead-message/src/main/java/com/storlead/message/pojo/vo/MessageTemplateVO.java
  42. 20 0
      java/storlead-message/src/main/java/com/storlead/message/pojo/vo/MessageTypeReadStateVO.java
  43. 46 0
      java/storlead-message/src/main/java/com/storlead/message/service/InsideMessageRecordService.java
  44. 31 0
      java/storlead-message/src/main/java/com/storlead/message/service/InsideMessageSendLogService.java
  45. 26 0
      java/storlead-message/src/main/java/com/storlead/message/service/MessageTemplateEventDetailService.java
  46. 21 0
      java/storlead-message/src/main/java/com/storlead/message/service/MessageTemplateEventGroupService.java
  47. 19 0
      java/storlead-message/src/main/java/com/storlead/message/service/UserMessageNoticeConfigService.java
  48. 23 0
      java/storlead-message/src/main/java/com/storlead/message/service/WechatMessageService.java
  49. 130 0
      java/storlead-message/src/main/java/com/storlead/message/service/impl/InsideMessageRecordServiceImpl.java
  50. 43 0
      java/storlead-message/src/main/java/com/storlead/message/service/impl/InsideMessageSendLogServiceImpl.java
  51. 165 0
      java/storlead-message/src/main/java/com/storlead/message/service/impl/MessageService.java
  52. 255 0
      java/storlead-message/src/main/java/com/storlead/message/service/impl/MessageTemplateEventDetailServiceImpl.java
  53. 30 0
      java/storlead-message/src/main/java/com/storlead/message/service/impl/MessageTemplateEventGroupServiceImpl.java
  54. 56 0
      java/storlead-message/src/main/java/com/storlead/message/service/impl/UserMessageNoticeConfigServiceImpl.java
  55. 167 0
      java/storlead-message/src/main/java/com/storlead/message/service/impl/WechatMessageServiceImpl.java
  56. 38 0
      java/storlead-message/src/main/resources/mapper/InsideMessageRecordMapper.xml
  57. 59 0
      java/storlead-message/src/main/resources/mapper/InsideMessageSendLogMapper.xml
  58. 23 0
      java/storlead-message/src/main/resources/mapper/MessageTemplateEventDetailMapper.xml
  59. 26 0
      java/storlead-message/src/main/resources/mapper/MessageTemplateEventGroupMapper.xml
  60. 35 0
      java/storlead-message/src/main/resources/mapper/UserMessageNoticeConfigMapper.xml
  61. 13 0
      java/storlead-message/src/test/java/com/storlead/tems/message/MessageApplicationTests.java
  62. 23 0
      java/storlead-sasa/pom.xml
  63. 9 10
      java/storlead-sasa/storlead-okr/pom.xml
  64. 7 0
      java/storlead-sasa/storlead-okr/src/main/java/org/example/Main.java
  65. 22 0
      java/storlead-sasa/storlead-project/pom.xml
  66. 7 0
      java/storlead-sasa/storlead-project/src/main/java/org/example/Main.java
  67. 22 0
      java/storlead-sasa/storlead-salary/pom.xml
  68. 7 0
      java/storlead-sasa/storlead-salary/src/main/java/org/example/Main.java
  69. 22 0
      java/storlead-sasa/storlead-sales/pom.xml
  70. 7 0
      java/storlead-sasa/storlead-sales/src/main/java/org/example/Main.java
  71. 4 6
      java/storlead-sasa/storlead-trade/pom.xml
  72. 0 0
      java/storlead-sasa/storlead-trade/storlead-acquisition/README.md
  73. 0 0
      java/storlead-sasa/storlead-trade/storlead-acquisition/pom.xml
  74. 0 0
      java/storlead-sasa/storlead-trade/storlead-acquisition/src/main/java/com/storlead/crm/acquisition/package-info.java
  75. 0 0
      java/storlead-sasa/storlead-trade/storlead-customer/README.md
  76. 0 0
      java/storlead-sasa/storlead-trade/storlead-customer/pom.xml
  77. 0 0
      java/storlead-sasa/storlead-trade/storlead-customer/src/main/java/com/storlead/crm/customer/controller/CustomerAiAnalysisController.java
  78. 0 0
      java/storlead-sasa/storlead-trade/storlead-customer/src/main/java/com/storlead/crm/customer/dto/CustomerSingleAnalysisRequestDTO.java
  79. 0 0
      java/storlead-sasa/storlead-trade/storlead-customer/src/main/java/com/storlead/crm/customer/entity/CustomerAnalysisResultEntity.java
  80. 0 0
      java/storlead-sasa/storlead-trade/storlead-customer/src/main/java/com/storlead/crm/customer/entity/CustomerCompanyEntity.java
  81. 0 0
      java/storlead-sasa/storlead-trade/storlead-customer/src/main/java/com/storlead/crm/customer/entity/CustomerEntity.java
  82. 0 0
      java/storlead-sasa/storlead-trade/storlead-customer/src/main/java/com/storlead/crm/customer/entity/LiaisonEntity.java
  83. 0 0
      java/storlead-sasa/storlead-trade/storlead-customer/src/main/java/com/storlead/crm/customer/mapper/CustomerAnalysisResultEntityMapper.java
  84. 0 0
      java/storlead-sasa/storlead-trade/storlead-customer/src/main/java/com/storlead/crm/customer/mapper/CustomerCompanyEntityMapper.java
  85. 0 0
      java/storlead-sasa/storlead-trade/storlead-customer/src/main/java/com/storlead/crm/customer/mapper/CustomerEntityMapper.java
  86. 0 0
      java/storlead-sasa/storlead-trade/storlead-customer/src/main/java/com/storlead/crm/customer/mapper/LiaisonEntityMapper.java
  87. 0 0
      java/storlead-sasa/storlead-trade/storlead-customer/src/main/java/com/storlead/crm/customer/package-info.java
  88. 0 0
      java/storlead-sasa/storlead-trade/storlead-customer/src/main/java/com/storlead/crm/customer/service/CustomerAiAnalysisService.java
  89. 0 0
      java/storlead-sasa/storlead-trade/storlead-customer/src/main/java/com/storlead/crm/customer/service/CustomerAnalysisResultEntityService.java
  90. 0 0
      java/storlead-sasa/storlead-trade/storlead-customer/src/main/java/com/storlead/crm/customer/service/CustomerCompanyEntityService.java
  91. 0 0
      java/storlead-sasa/storlead-trade/storlead-customer/src/main/java/com/storlead/crm/customer/service/CustomerEntityService.java
  92. 0 0
      java/storlead-sasa/storlead-trade/storlead-customer/src/main/java/com/storlead/crm/customer/service/LiaisonEntityService.java
  93. 0 0
      java/storlead-sasa/storlead-trade/storlead-customer/src/main/java/com/storlead/crm/customer/service/impl/CustomerAiAnalysisServiceImpl.java
  94. 0 0
      java/storlead-sasa/storlead-trade/storlead-customer/src/main/java/com/storlead/crm/customer/service/impl/CustomerAnalysisResultEntityServiceImpl.java
  95. 0 0
      java/storlead-sasa/storlead-trade/storlead-customer/src/main/java/com/storlead/crm/customer/service/impl/CustomerCompanyEntityServiceImpl.java
  96. 0 0
      java/storlead-sasa/storlead-trade/storlead-customer/src/main/java/com/storlead/crm/customer/service/impl/CustomerEntityServiceImpl.java
  97. 0 0
      java/storlead-sasa/storlead-trade/storlead-customer/src/main/java/com/storlead/crm/customer/service/impl/LiaisonEntityServiceImpl.java
  98. 0 0
      java/storlead-sasa/storlead-trade/storlead-customer/src/main/resources/mapper/CustomerAnalysisResultEntityMapper.xml
  99. 0 0
      java/storlead-sasa/storlead-trade/storlead-customer/src/main/resources/mapper/CustomerCompanyEntityMapper.xml
  100. 0 0
      java/storlead-sasa/storlead-trade/storlead-customer/src/main/resources/mapper/CustomerEntityMapper.xml

+ 0 - 28
java/storlead-crm/storlead-email/README.md

@@ -1,28 +0,0 @@
-# 邮件(storlead-email)
-
-对应目录:`storlead-email` · Maven `artifactId`:`storlead-email` · Java 包根:`com.storlead.crm.email`
-
-## 模块定位
-
-记录与查询「对客户/线索的邮件触达」事实数据,支撑沟通历史、合规留痕与效果复盘。
-
-## 建议实现的业务功能
-
-1. **发送记录**  
-   收件人、抄送、主题、发送时间、发送结果(成功/失败/退信)、关联客户或线索 ID。
-
-2. **内容与模板关联(按合规设计)**  
-   可仅存摘要或模板 ID + 变量快照;若需全文,按公司合规策略存储与脱敏。
-
-3. **接收与线程(可选)**  
-   若对接邮箱同步:入站邮件、会话线程 ID,便于在系统内查看往来记录。
-
-4. **检索与统计**  
-   按客户、时间、主题、结果筛选;发送量、失败率等基础统计。
-
-5. **多租户**  
-   记录按租户隔离。
-
-## 非本模块职责
-
-SMTP/API 底层投递一般由基础设施或独立消息服务承担;本模块以业务侧记录与查询为主。客户公海、订单、营销活动编排见 `storlead-customer`、`storlead-order`、`storlead-marketing` 等模块。

+ 0 - 4
java/storlead-crm/storlead-email/src/main/java/com/storlead/crm/email/package-info.java

@@ -1,4 +0,0 @@
-/**
- * 邮件记录。
- */
-package com.storlead.crm.email;

+ 0 - 28
java/storlead-crm/storlead-order/README.md

@@ -1,28 +0,0 @@
-# 订单(storlead-order)
-
-对应目录:`storlead-order` · Maven `artifactId`:`storlead-order` · Java 包根:`com.storlead.crm.order`
-
-## 模块定位
-
-管理与客户/商机相关的交易订单全生命周期,为营收统计、履约与客户价值分析提供数据基础。
-
-## 建议实现的业务功能
-
-1. **订单主数据**  
-   订单编号、客户关联、商品/服务行、金额、币种、状态(待支付、已支付、履约中、完成、关闭等)。
-
-2. **状态与流转**  
-   创建、改价、取消、退款申请与结果;状态机或明确规则,保证可追溯。
-
-3. **与客户/营销的关联**  
-   订单关联 `storlead-customer` 中的主体;可选记录营销活动或优惠券来源,便于归因。
-
-4. **查询与导出**  
-   多条件列表、详情、运营或财务维度导出(权限控制下)。
-
-5. **多租户**  
-   订单数据按租户隔离;金额与敏感字段访问受角色控制。
-
-## 非本模块职责
-
-客户公海分配、邮件单封记录、营销批次执行明细、获客渠道与表单等,由 `storlead-customer`、`storlead-email`、`storlead-marketing`、`storlead-acquisition` 等子模块实现。

+ 0 - 4
java/storlead-crm/storlead-order/src/main/java/com/storlead/crm/order/package-info.java

@@ -1,4 +0,0 @@
-/**
- * 订单。
- */
-package com.storlead.crm.order;

+ 348 - 0
java/storlead-dependencies/pom.xml

@@ -0,0 +1,348 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>com.storlead.boot</groupId>
+    <artifactId>storlead-dependencies</artifactId>
+    <version>${revision}</version>
+
+    <packaging>pom</packaging>
+    <name>${project.artifactId}</name>
+    <description>整个项目的依赖版本</description>
+
+    <properties>
+        <!-- 与根工程保持一致的统一版本号 -->
+        <revision>1.0.1</revision>
+        <flatten-maven-plugin.version>1.6.0</flatten-maven-plugin.version>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <spring.boot.starter.parent>2.7.0</spring.boot.starter.parent>
+        <spring.boot.version>2.7.0</spring.boot.version>
+        <knife4j.version>4.5.0</knife4j.version>
+        <spring-web.version>5.3.32</spring-web.version>
+        <jsoup.version>1.18.3</jsoup.version>
+        <mockito-inline.version>4.11.0</mockito-inline.version>
+        <lombok.version>1.18.36</lombok.version>
+        <spring.framework.version>5.3.20</spring.framework.version>
+        <spring.security.version>5.8.14</spring.security.version>
+        <fastjson.version>2.0.23</fastjson.version>
+        <!--    5.8.35-->
+        <hutool.version>5.4.3</hutool.version>
+        <springdoc.version>1.7.0</springdoc.version>
+        <swagger.ui.version>3.0.0</swagger.ui.version>
+        <swagger.version>3.0.0</swagger.version>
+        <swagger.annotations.version>1.5.22</swagger.annotations.version>
+        <spring.web.socket.version>1.5.3</spring.web.socket.version>
+
+        <!-- DB 相关 -->
+        <druid.version>1.1.24</druid.version>
+        <mybatis.version>3.5.17</mybatis.version>
+        <mybatis-plus.version>3.1.2</mybatis-plus.version>
+        <datasource.spring.boot.starter>2.5.4</datasource.spring.boot.starter>
+        <dynamic-datasource.version>4.3.1</dynamic-datasource.version>
+        <mybatis-plus-join.version>1.4.13</mybatis-plus-join.version>
+        <mysql.connector.version>5.1.47</mysql.connector.version>
+        <guava.version>33.4.0-jre</guava.version>
+        <aviator.version>5.2.7</aviator.version>
+        <transmittable.thread.version>2.14.0</transmittable.thread.version>
+        <google.code.gson.version>2.10.1</google.code.gson.version>
+        <squareup.okhttp.version>4.12.0</squareup.okhttp.version>
+        <okhttp.sse.version>4.10.0</okhttp.sse.version>
+        <spring.validation.version>2.6.3</spring.validation.version>
+        <apache.httpcore5.client5.version>5.2.1</apache.httpcore5.client5.version>
+        <apache.httpcore5.version>5.2.1</apache.httpcore5.version>
+        <apache.httpcore5-h2.version>5.2.1</apache.httpcore5-h2.version>
+        <apache.httpasyncclient.version>4.1.5</apache.httpasyncclient.version>
+        <io.jsonwebtoken.version>0.9.1</io.jsonwebtoken.version>
+        <io.jsonwebtoken.java.jwt.version>3.7.0</io.jsonwebtoken.java.jwt.version>
+    </properties>
+
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>org.springframework</groupId>
+                <artifactId>spring-web</artifactId>
+                <version>${spring-web.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>com.baomidou</groupId>
+                <artifactId>mybatis-plus-generator</artifactId>
+                <version>${mybatis-plus.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>com.daydayup.boot</groupId>
+                <artifactId>daydayup-mybatis</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>com.daydayup.boot</groupId>
+                <artifactId>daydayup-common</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>com.daydayup.boot</groupId>
+                <artifactId>daydayup-system</artifactId>
+                <version>${revision}</version>
+            </dependency>
+
+<!--            &lt;!&ndash;swagger&ndash;&gt;-->
+            <dependency>
+                <groupId>io.springfox</groupId>
+                <artifactId>springfox-swagger2</artifactId>
+                <version>${swagger.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>io.springfox</groupId>
+                <artifactId>springfox-swagger-ui</artifactId>
+                <version>${swagger.ui.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>io.swagger</groupId>
+                <artifactId>swagger-annotations</artifactId>
+                <version>${swagger.annotations.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>com.google.code.gson</groupId>
+                <artifactId>gson</artifactId>
+                <version>${google.code.gson.version}</version> <!-- 建议使用最新版本 -->
+            </dependency>
+
+            <dependency>
+                <groupId>com.alibaba</groupId>
+                <artifactId>fastjson</artifactId>
+                <version>${fastjson.version}</version>
+            </dependency>
+
+
+            <dependency>
+                <groupId>org.apache.httpcomponents.client5</groupId>
+                <artifactId>httpclient5</artifactId>
+                <version>${apache.httpcore5.client5.version}</version>
+            </dependency>
+
+            <!-- https://mvnrepository.com/artifact/org.apache.httpcomponents.core5/httpcore5 -->
+            <dependency>
+                <groupId>org.apache.httpcomponents.core5</groupId>
+                <artifactId>httpcore5</artifactId>
+                <version>${apache.httpcore5.version}</version>
+            </dependency>
+
+            <!--JWT-->
+            <dependency>
+                <groupId>com.auth0</groupId>
+                <artifactId>java-jwt</artifactId>
+                <version>${io.jsonwebtoken.java.jwt.version}</version>
+            </dependency>
+
+            <!--  jwt 需要,移除会报错  -->
+            <dependency>
+                <groupId>io.jsonwebtoken</groupId>
+                <artifactId>jjwt</artifactId>
+                <version>${io.jsonwebtoken.version}</version>
+            </dependency>
+            <!-- https://mvnrepository.com/artifact/org.apache.httpcomponents.core5/httpcore5-h2 -->
+            <dependency>
+                <groupId>org.apache.httpcomponents.core5</groupId>
+                <artifactId>httpcore5-h2</artifactId>
+                <version>${apache.httpcore5-h2.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>org.apache.httpcomponents</groupId>
+                <artifactId>httpasyncclient</artifactId>
+                <version>${apache.httpasyncclient.version}</version>
+            </dependency>
+<!--            <dependency>-->
+<!--                <groupId>com.github.xiaoymin</groupId>-->
+<!--                <artifactId>swagger-bootstrap-ui</artifactId>-->
+<!--                <version>1.8.7</version>-->
+<!--            </dependency>-->
+
+
+<!--            <dependency>-->
+<!--                <groupId>com.squareup.okhttp3</groupId>-->
+<!--                <artifactId>okhttp</artifactId>-->
+<!--                <version>${squareup.okhttp.version}</version> &lt;!&ndash; 2023年最新稳定版 &ndash;&gt;-->
+<!--            </dependency>-->
+
+            <dependency>
+                <groupId>com.squareup.okhttp3</groupId>
+                <artifactId>okhttp-sse</artifactId>
+                <version>${okhttp.sse.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>org.projectlombok</groupId>
+                <artifactId>lombok</artifactId>
+                <version>${lombok.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>cn.hutool</groupId>
+                <artifactId>hutool-all</artifactId>
+                <version>${hutool.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-dependencies</artifactId>
+                <version>${spring.boot.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>com.github.xiaoymin</groupId>
+                <artifactId>knife4j-openapi3-spring-boot-starter</artifactId>
+                <version>${knife4j.version}</version>
+            </dependency>
+<!--            <dependency>-->
+<!--                <groupId>cn.hutool</groupId>-->
+<!--                <artifactId>hutool-all</artifactId>-->
+<!--                <version>4.5.11</version>-->
+<!--            </dependency>-->
+
+            <dependency>
+                <groupId>com.googlecode.aviator</groupId>
+                <artifactId>aviator</artifactId>
+                <version>${aviator.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>com.alibaba</groupId>
+                <artifactId>transmittable-thread-local</artifactId>
+                <version>${transmittable.thread.version}</version> <!-- 建议使用最新版本 -->
+            </dependency>
+
+            <!-- mybatis-plus -->
+            <dependency>
+                <groupId>com.baomidou</groupId>
+                <artifactId>mybatis-plus-boot-starter</artifactId>
+                <version>${mybatis-plus.version}</version>
+            </dependency>
+
+            <!--mysql-->
+            <dependency>
+                <groupId>mysql</groupId>
+                <artifactId>mysql-connector-java</artifactId>
+                <version>${mysql.connector.version}</version>
+            </dependency>
+
+            <!-- 动态数据源 -->
+            <dependency>
+                <groupId>com.baomidou</groupId>
+                <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
+                <version>${datasource.spring.boot.starter}</version>
+            </dependency>
+
+            <!-- druid -->
+            <dependency>
+                <groupId>com.alibaba</groupId>
+                <artifactId>druid-spring-boot-starter</artifactId>
+                <version>${druid.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>com.github.yulichang</groupId>
+                <artifactId>mybatis-plus-join-boot-starter</artifactId> <!-- MyBatis 联表查询 -->
+                <version>${mybatis-plus-join.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>org.java-websocket</groupId>
+                <artifactId>Java-WebSocket</artifactId>
+                <version>${spring.web.socket.version}</version>
+            </dependency>
+
+            <!-- Web 相关 -->
+            <dependency>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-starter-web</artifactId>
+                <version>2.7.0</version>
+                <exclusions>
+                    <exclusion>
+                        <groupId>org.springframework</groupId>
+                        <artifactId>spring-web</artifactId>
+                    </exclusion>
+                </exclusions>
+            </dependency>
+
+            <dependency>
+                <groupId>org.jsoup</groupId>
+                <artifactId>jsoup</artifactId>
+                <version>${jsoup.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>com.google.guava</groupId>
+                <artifactId>guava</artifactId>
+                <version>${guava.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>org.mockito</groupId>
+                <artifactId>mockito-inline</artifactId>
+                <version>${mockito-inline.version}</version> <!-- 支持 Mockito 的 final 类与 static 方法的 mock -->
+            </dependency>
+
+            <dependency>
+                <groupId>org.springdoc</groupId>
+                <artifactId>springdoc-openapi-ui</artifactId>
+                <version>${springdoc.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-starter-test</artifactId>
+                <version>${spring.boot.version}</version>
+                <exclusions>
+                    <exclusion>
+                        <artifactId>asm</artifactId>
+                        <groupId>org.ow2.asm</groupId>
+                    </exclusion>
+                    <exclusion>
+                        <groupId>org.mockito</groupId>
+                        <artifactId>mockito-core</artifactId>
+                    </exclusion>
+                </exclusions>
+            </dependency>
+
+        </dependencies>
+
+    </dependencyManagement>
+
+<!--    <build>-->
+<!--        <plugins>-->
+<!--            &lt;!&ndash; 统一 revision 版本 &ndash;&gt;-->
+<!--            <plugin>-->
+<!--                <groupId>org.codehaus.mojo</groupId>-->
+<!--                <artifactId>flatten-maven-plugin</artifactId>-->
+<!--                <version>${flatten-maven-plugin.version}</version>-->
+<!--                <configuration>-->
+<!--                    <flattenMode>bom</flattenMode>-->
+<!--                    <updatePomFile>true</updatePomFile>-->
+<!--                </configuration>-->
+<!--                <executions>-->
+<!--                    <execution>-->
+<!--                        <goals>-->
+<!--                            <goal>flatten</goal>-->
+<!--                        </goals>-->
+<!--                        <id>flatten</id>-->
+<!--                        <phase>process-resources</phase>-->
+<!--                    </execution>-->
+<!--                    <execution>-->
+<!--                        <goals>-->
+<!--                            <goal>clean</goal>-->
+<!--                        </goals>-->
+<!--                        <id>flatten.clean</id>-->
+<!--                        <phase>clean</phase>-->
+<!--                    </execution>-->
+<!--                </executions>-->
+<!--            </plugin>-->
+<!--        </plugins>-->
+<!--    </build>-->
+</project>

+ 34 - 0
java/storlead-es/pom.xml

@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <artifactId>storlead-smarttrade-platform</artifactId>
+        <groupId>com.storlead.boot</groupId>
+        <version>1.0</version>
+        <relativePath>../../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>storlead-es</artifactId>
+    <packaging>jar</packaging>
+    <name>storlead-es</name>
+    <version>1.0</version>
+    <description>common project for Spring Boot</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.storlead.boot</groupId>
+            <artifactId>storlead-common</artifactId>
+            <version>1.0</version>
+            <scope>compile</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>
+

+ 44 - 0
java/storlead-es/src/main/java/com/storlead/es/config/ElasticSearchConfig.java

@@ -0,0 +1,44 @@
+package com.storlead.es.config;
+
+import org.apache.http.HttpHost;
+import org.apache.http.auth.AuthScope;
+import org.apache.http.auth.UsernamePasswordCredentials;
+import org.apache.http.impl.client.BasicCredentialsProvider;
+import org.elasticsearch.client.RestClient;
+import org.elasticsearch.client.RestHighLevelClient;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @program: sp-tems-gotr
+ * @description:
+ * @author: chenkq
+ * @create: 2023-06-16 17:03
+ */
+@Configuration
+public class ElasticSearchConfig {
+
+    @Bean
+    public RestHighLevelClient restHighLevelClient() {
+
+        String hostname = "39.108.252.62";
+        int port = 9200;
+        // 定义 Elasticsearch 集群的用户名和密码
+        String username = "elastic";
+        String password = "storlead123456";
+        // 配置 RestClient
+        RestHighLevelClient client = new RestHighLevelClient(
+                RestClient.builder(
+                                new HttpHost(hostname, port, "http"))
+                        .setHttpClientConfigCallback(httpClientBuilder ->
+                                httpClientBuilder.setDefaultCredentialsProvider(
+                                        new BasicCredentialsProvider() {{
+                                            setCredentials(AuthScope.ANY,
+                                                    new UsernamePasswordCredentials(username, password));
+                                        }}
+                                )
+                        )
+        );
+        return client;
+    }
+}

+ 46 - 0
java/storlead-es/src/main/java/com/storlead/es/pojo/vo/EsGenericVO.java

@@ -0,0 +1,46 @@
+package com.storlead.es.pojo.vo;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * @program: sp-tems-gotr
+ * @description:
+ * @author: chenkq
+ * @create: 2023-07-04 16:29
+ */
+@Data
+public class EsGenericVO implements Serializable {
+
+    private String queryText;
+
+    private String minScore;
+
+    private String indexName;
+
+    private String fieldName;
+
+    private String fieldKey;
+    @ApiModelProperty(value = "客户种类(10客户、11线索)")
+    private Integer customerForm;
+
+    @ApiModelProperty(value = "匹配索引和字段")
+    public List<IndexFieldConfig> indexFields;
+}
+//{
+//        "queryText": "ta@aselsan.com.tr",
+//        "topN": 100,
+//        "fieldKey": "keyword",
+//        "minScore": 60.0,
+//        "indexFields": [
+//        {
+//        "indexName" : "liaison_data_index","resourceType":10,"fields":[{"fieldName":"email.keyword","fieldDescribe":"联系人邮箱"},{"fieldName":"email1.keyword","fieldDescribe":"联系人备用邮箱1"},{"fieldName":"email2.keyword","fieldDescribe":"联系人备用邮箱2"},{"fieldName":"email3.keyword","fieldDescribe":"联系人备用邮箱3"}]
+//        },{
+//        "indexName" : "customer_company_data_index","resourceType":30,"fields":[{"fieldName":"email.keyword","fieldDescribe":"企业邮箱"},{"fieldName":"email1.keyword","fieldDescribe":"企业备用邮箱1"},{"fieldName":"email2.keyword","fieldDescribe":"企业备用邮箱2"},{"fieldName":"email3.keyword","fieldDescribe":"企业备用邮箱3"}]
+//        }
+//        ]
+//}

+ 67 - 0
java/storlead-es/src/main/java/com/storlead/es/pojo/vo/EsQuerySimilarityVO.java

@@ -0,0 +1,67 @@
+package com.storlead.es.pojo.vo;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+import java.util.Date;
+
+/**
+ * @program: sp-sales-platform
+ * @description:
+ * @author: chenkq
+ * @create: 2025-04-16 10:16
+ */
+@Data
+public class EsQuerySimilarityVO {
+    @ApiModelProperty(value = "业务Id")
+    private Long id;
+    @ApiModelProperty(value = "业务Id")
+    private Long customerId;
+    @ApiModelProperty(value = "客户名称")
+    private String customerName;
+    @ApiModelProperty(value = "联系人姓名")
+    private String name;
+    @ApiModelProperty(value = "错误提示")
+    private String errorMsg;
+    @ApiModelProperty(value = "原有对象")
+    private Object object;
+
+    @ApiModelProperty(value = "被查重复字段")
+    private String duplicateFieldNow;
+    @ApiModelProperty(value = "被查重复值")
+    private String duplicateValueNow;
+
+    @ApiModelProperty(value = "重复字段")
+    private String duplicateField;
+    @ApiModelProperty(value = "重复值")
+    private String duplicateValue;
+    @ApiModelProperty(value = "相似度")
+    private String similarityScore;
+    @ApiModelProperty(value = "所属索引")
+    private String indexName;
+    @ApiModelProperty(value = "匹配的字段名")
+    private String matchedField;
+    @ApiModelProperty(value = "错误类型")
+    private String resourceType;
+    @ApiModelProperty(value = "最后跟进时间")
+    @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+    @JSONField(format ="yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime lastFollowUpTime;
+
+    @ApiModelProperty(value = "未跟进天数")
+    private Integer noFollowUpDate;
+    private Long ownerBy;
+
+    @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+    @JSONField(format ="yyyy-MM-dd HH:mm:ss")
+    @TableField(fill = FieldFill.INSERT)
+    private Date createTime;
+}

+ 16 - 0
java/storlead-es/src/main/java/com/storlead/es/pojo/vo/EsQueryVO.java

@@ -0,0 +1,16 @@
+package com.storlead.es.pojo.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * @program: sp-tems
+ * @description:
+ * @author: chenkq
+ * @create: 2023-12-13 17:12
+ */
+@Data
+public class EsQueryVO implements Serializable {
+
+}

+ 15 - 0
java/storlead-es/src/main/java/com/storlead/es/pojo/vo/FieldConfig.java

@@ -0,0 +1,15 @@
+package com.storlead.es.pojo.vo;
+
+import lombok.Data;
+
+/**
+ * @program: sp-sales-platform
+ * @description:
+ * @author: chenkq
+ * @create: 2025-04-16 10:56
+ */
+@Data
+public class FieldConfig {
+    private String fieldName;
+    private String fieldDescribe;
+}

+ 19 - 0
java/storlead-es/src/main/java/com/storlead/es/pojo/vo/IndexFieldConfig.java

@@ -0,0 +1,19 @@
+package com.storlead.es.pojo.vo;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * @program: sp-sales-platform
+ * @description:
+ * @author: chenkq
+ * @create: 2025-04-16 10:26
+ */
+@Data
+public class IndexFieldConfig {
+    private String indexName;
+    private Integer resourceType;
+    private List<FieldConfig> fields;
+
+}

+ 52 - 0
java/storlead-es/src/main/java/com/storlead/es/server/BaseSearchService.java

@@ -0,0 +1,52 @@
+package com.storlead.es.server;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.storlead.common.object.Page;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+public interface BaseSearchService<T> {
+
+    /**
+     * 搜 索
+     *
+     * @param keyword
+     * @param clazz
+     * @return
+     */
+    List<T> query(Class<T> clazz, String keyword, String indexName);
+
+    /**
+     * 分页搜索
+     *
+     * @param keyword
+     * @param clazz
+     * @return
+     */
+    IPage<T> queryPage(Class<T> clazz, String keyword, Page page, String indexName);
+
+
+    IPage<T> queryHitPage(Class<T> clazz, String keyword, Page page, String... hightFields);
+
+    /**
+     * 搜索高亮显示
+     *
+     * @param keyword    关键字
+     * @param indexName  索引库
+     * @param fieldNames 搜索的字段
+     * @return
+     */
+    List<T> queryHit(Class<T> clazz, String keyword, String indexName, String... fieldNames);
+
+    List<T> queryHitByPage(Class<T> clazz, Page page, String keyword, String indexName, String... fieldNames);
+
+    List<T> queryHit(Class<T> clazz, String keyword, String fieldName, String indexName);
+
+    List<T> queryHitByPage(Class<T> clazz, Page page, String keyword, String fieldName, String indexName);
+
+    List<T> querySimilarityPage(Class<T> clazz, Page page, String keyword, String indexName, String... fieldNames);
+
+    List<Map<String, Object>> searchByNameSimilarity(String inputName);
+}

+ 17 - 0
java/storlead-es/src/main/java/com/storlead/es/server/EsSearchCustomerService.java

@@ -0,0 +1,17 @@
+package com.storlead.es.server;
+
+import com.storlead.es.pojo.vo.EsGenericVO;
+import com.storlead.es.pojo.vo.EsQuerySimilarityVO;
+
+import java.util.List;
+
+/**
+ * @program: sp-sales-platform
+ * @description:
+ * @author: chenkq
+ * @create: 2025-04-16 09:56
+ */
+public interface EsSearchCustomerService {
+
+    List<EsQuerySimilarityVO> listComparisonSimilarity(EsGenericVO dto);
+}

+ 319 - 0
java/storlead-es/src/main/java/com/storlead/es/server/impl/BaseSearchServiceImpl.java

@@ -0,0 +1,319 @@
+package com.storlead.es.server.impl;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.storlead.es.server.BaseSearchService;
+import com.storlead.common.object.Page;
+import org.elasticsearch.action.search.SearchRequest;
+import org.elasticsearch.common.unit.Fuzziness;
+import org.elasticsearch.index.query.QueryBuilder;
+import org.elasticsearch.index.query.QueryBuilders;
+import org.elasticsearch.index.query.QueryStringQueryBuilder;
+import org.elasticsearch.script.Script;
+import org.elasticsearch.script.ScriptType;
+import org.springframework.data.elasticsearch.core.SearchHit;
+import org.springframework.data.elasticsearch.core.SearchHits;
+import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
+import org.elasticsearch.search.sort.SortBuilders;
+import org.elasticsearch.search.sort.SortOrder;
+import org.slf4j.LoggerFactory;
+import org.slf4j.Logger;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
+import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
+import org.springframework.data.elasticsearch.core.query.*;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+
+import javax.annotation.Resource;
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * @program: sp-tems-gotr
+ * @description:
+ * @author: chenkq
+ * @create: 2023-06-16 16:42
+ */
+@Service
+public class BaseSearchServiceImpl<T> implements BaseSearchService<T> {
+
+    private Logger logger = LoggerFactory.getLogger(getClass());
+
+    @Resource
+    private ElasticsearchRestTemplate elasticsearchTemplate;
+
+
+    public void save(Class<T> clazz) {
+        try {
+            elasticsearchTemplate.save(clazz);
+        }catch (Exception e) {
+            logger.error("");
+        }
+    }
+
+    public void save(Class<T> clazz,String indexId) {
+        try {
+            T info = elasticsearchTemplate.get(indexId, clazz);
+            if (Objects.nonNull(info)) {
+                elasticsearchTemplate.delete(indexId,clazz);
+                elasticsearchTemplate.save(clazz);
+            }
+        }catch (Exception e) {
+            logger.error("");
+        }
+    }
+
+    @Override
+    public List<T> query(Class<T> clazz,String keyword, String indexName) {
+        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
+                .withQuery(new QueryStringQueryBuilder(keyword))
+                .withSort(SortBuilders.scoreSort().order(SortOrder.DESC))
+                // .withSort(new FieldSortBuilder("createTime").order(SortOrder.DESC))
+                .build();
+        // 使用 IndexCoordinates 指定索引
+        IndexCoordinates indexCoordinates = IndexCoordinates.of(indexName);
+        List<T> infos = elasticsearchTemplate.search(searchQuery,clazz,indexCoordinates)
+                .stream()
+                .map(SearchHit::getContent)
+                .collect(Collectors.toList());
+         return infos;
+    }
+
+    @Override
+    public IPage<T> queryPage(Class<T> clazz, String keyword, Page page, String indexName) {
+        Pageable pageable = PageRequest.of(page.getPageIndex(), page.getPageSize());
+        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
+                .withQuery(new QueryStringQueryBuilder(keyword))
+                .withSort(SortBuilders.scoreSort().order(SortOrder.DESC))
+                .withPageable(pageable)
+                .build();
+        SearchHits<T> searchHits = elasticsearchTemplate.search(searchQuery,clazz);
+        long totalHits = searchHits.getTotalHits();
+        List<T> infos = searchHits
+                .stream()
+                .map(org.springframework.data.elasticsearch.core.SearchHit::getContent)
+                .collect(Collectors.toList());
+
+        IPage<T> res = new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(page.getPageIndex(),page.getPageSize());
+        res.setTotal(totalHits);
+        res.setRecords(infos);
+        return res;
+    }
+
+    @Override
+    public IPage<T> queryHitPage(Class<T> clazz, String keyword, Page page,String ... hightFields) {
+        Pageable pageable = PageRequest.of(page.getPageIndex(), page.getPageSize());
+
+        HighlightBuilder highlightBuilder = builderHighlightField(hightFields);
+        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
+                .withQuery(new QueryStringQueryBuilder(keyword))
+                .withSort(SortBuilders.scoreSort().order(SortOrder.DESC))
+                .withPageable(pageable)
+                .withHighlightBuilder(highlightBuilder)
+                .build();
+        SearchHits<T> searchHit = elasticsearchTemplate.search(searchQuery,clazz);
+        List<SearchHit<T>> searchHits = searchHit.getSearchHits();
+        List<T> infos = new ArrayList<>();
+        for(SearchHit<T> hit :searchHits) {
+            T info = hit.getContent();
+            Map<String, List<String>> maps =  hit.getHighlightFields();
+            for (String key : maps.keySet()) {
+                 List<String> vals = maps.get(key);
+                 if (!CollectionUtils.isEmpty(vals)) {
+                     String fieldValue = vals.get(0);
+                     try {
+                         Field field = info.getClass().getDeclaredField(key);
+                         field.setAccessible(true);
+                         field.set(info,fieldValue);
+                     }catch (Exception e) {
+                         logger.error("---",e);
+                     }
+                 }
+            }
+            infos.add(hit.getContent());
+        }
+        long totalHits = searchHit.getTotalHits();
+        IPage<T> res = new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(page.getPageIndex(),page.getPageSize());
+        res.setTotal(totalHits);
+        res.setRecords(infos);
+        return res;
+    }
+
+    private HighlightBuilder builderHighlightField(String ... hightFields) {
+        HighlightBuilder highlightBuilder = new HighlightBuilder();
+        highlightBuilder.preTags("<em>").postTags("</em>");
+        //设置高亮的方法
+        highlightBuilder.highlighterType("plain");
+        //设置分段的数量不做限制
+        highlightBuilder.numOfFragments(0);
+        if (Objects.isNull(hightFields) || hightFields.length == 0) {
+            return highlightBuilder;
+        }
+        for(String hightField : hightFields) {
+            highlightBuilder.field(hightField);
+        }
+        return highlightBuilder;
+    }
+
+    @Override
+    public  List<T> queryHit(Class<T> clazz,String keyword,String fieldName,String indexName) {
+
+        HighlightBuilder highlightBuilder = new HighlightBuilder()
+                .field("title")
+                .preTags("<em>")
+                .postTags("</em>");
+        // 构建查询条件
+        QueryBuilder queryBuilder = QueryBuilders.matchQuery(fieldName,keyword);
+
+        // 构建搜索查询
+        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
+                .withQuery(queryBuilder)
+                .withHighlightBuilder(highlightBuilder)
+                .build();
+
+        // 使用 IndexCoordinates 指定索引
+        IndexCoordinates indexCoordinates = IndexCoordinates.of(indexName);
+        // 执行搜索查询
+        SearchHits<T> searchHits = elasticsearchTemplate.search(searchQuery,clazz,indexCoordinates);
+//      for (HighlightField highlightField : highlightFields) {
+//          String fieldName = highlightField.getName();
+//          String highlightedText = highlightField.getSnippets().get(0);
+//          System.out.println("Highlighted field: " + fieldName + ", Text: " + highlightedText);
+//      }
+        List<T> infos = searchHits
+                .stream()
+                .map(SearchHit::getContent)
+                .collect(Collectors.toList());
+        return infos;
+    }
+
+    @Override
+    public  List<T> queryHitByPage(Class<T> clazz,Page page,String keyword,String fieldName,String indexName) {
+
+        // 构建查询条件
+        Pageable pageable = PageRequest.of(page.getPageIndex(), page.getPageSize());
+        QueryBuilder queryBuilder = QueryBuilders.matchQuery(fieldName,keyword);
+
+        // 构建搜索查询
+        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
+                .withQuery(queryBuilder)
+                .withPageable(pageable)
+                .build();
+
+        // 执行搜索查询
+        SearchHits<T> searchHits = elasticsearchTemplate.search(searchQuery, clazz);
+        List<T> infos = searchHits
+                .stream()
+                .map(org.springframework.data.elasticsearch.core.SearchHit::getContent)
+                .collect(Collectors.toList());
+
+        return infos;
+    }
+
+    /**
+     * 高亮显示
+     * @auther:
+     * @date:
+     */
+    @Override
+    public  List<T> queryHit(Class<T> clazz,String keyword,String indexName,String ... fieldNames) {
+
+        // 构建查询条件
+        QueryBuilder queryBuilder = QueryBuilders.multiMatchQuery(keyword, fieldNames);
+
+        // 构建搜索查询
+        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
+                .withQuery(queryBuilder)
+                .build();
+
+        // 执行搜索查询
+        SearchHits<T> searchHits = elasticsearchTemplate.search(searchQuery,clazz);
+        List<T> infos = searchHits
+                .stream()
+                .map(SearchHit::getContent)
+                .collect(Collectors.toList());
+
+        return infos;
+    }
+
+    @Override
+    public  List<T> queryHitByPage(Class<T> clazz,Page page,String keyword,String indexName,String ... fieldNames) {
+
+        // 构建查询条件
+        Pageable pageable = PageRequest.of(page.getPageIndex(), page.getPageSize());
+        QueryBuilder queryBuilder = QueryBuilders.multiMatchQuery(keyword, fieldNames);
+
+        // 构建搜索查询
+        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
+                .withQuery(queryBuilder)
+                .withPageable(pageable)
+                .build();
+
+        // 执行搜索查询
+        SearchHits<T> searchHits = elasticsearchTemplate.search(searchQuery, clazz);
+        List<T> infos = searchHits
+                .stream()
+                .map(SearchHit::getContent)
+                .collect(Collectors.toList());
+
+        return infos;
+    }
+
+    @Override
+    public  List<T> querySimilarityPage(Class<T> clazz,Page page,String keyword,String indexName,String ... fieldNames) {
+
+        // 构建查询条件
+        Pageable pageable = PageRequest.of(page.getPageIndex(), page.getPageSize());
+        QueryBuilder queryBuilder = QueryBuilders.multiMatchQuery(keyword, fieldNames);
+
+        // 构建搜索查询
+        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
+                .withQuery(queryBuilder)
+                .withPageable(pageable)
+                .build();
+
+        // 执行搜索查询
+        SearchHits<T> searchHits = elasticsearchTemplate.search(searchQuery, clazz);
+        List<T> infos = searchHits
+                .stream()
+                .map(SearchHit::getContent)
+                .collect(Collectors.toList());
+
+        return infos;
+    }
+
+    @Override
+    public List<Map<String, Object>> searchByNameSimilarity(String inputName) {
+
+        SearchRequest searchRequest = new SearchRequest("customer_data");
+        searchRequest.source().query(QueryBuilders.termQuery("customer_name", "sear"));
+
+
+        NativeSearchQuery query = new NativeSearchQueryBuilder()
+                .withQuery(QueryBuilders.fuzzyQuery("customer_name", inputName).fuzziness(Fuzziness.AUTO))
+                .withPageable(PageRequest.of(0, 10)) // 设置分页,最大返回 10 个结果
+                .build();
+
+//        Query query = new NativeSearchQueryBuilder()
+//                .withQuery(QueryBuilders.fuzzyQuery("customer_name", inputName)
+//                        .fuzziness("AUTO"))  // 使用 fuzziness 设置模糊度
+//                .withPageable(PageRequest.of(0, 10)) // 设置分页,最多返回 10 个结果
+//                .build();
+
+        // 执行查询并返回结果
+        SearchHits<Map> searchHits = elasticsearchTemplate.search(query, Map.class, IndexCoordinates.of("customer_data"));
+
+        // 处理查询结果并返回包含 id、customer_name 和 score 的列表
+        return searchHits.getSearchHits().stream().map(hit -> {
+            Map<String, Object> result = new HashMap<>();
+            result.put("id", hit.getId());
+            result.put("customer_name", ((Map<String, Object>) hit.getContent()).get("customer_name"));
+            result.put("similarity_score", hit.getScore());
+            return result;
+        }).collect(Collectors.toList());
+    }
+
+}

+ 269 - 0
java/storlead-es/src/main/java/com/storlead/es/server/impl/EsSearchCustomerServiceImpl.java

@@ -0,0 +1,269 @@
+package com.storlead.es.server.impl;
+
+import cn.hutool.core.util.StrUtil;
+import com.storlead.es.pojo.vo.EsGenericVO;
+import com.storlead.es.pojo.vo.EsQuerySimilarityVO;
+import com.storlead.es.pojo.vo.FieldConfig;
+import com.storlead.es.pojo.vo.IndexFieldConfig;
+import com.storlead.es.server.EsSearchCustomerService;
+import com.storlead.frame.core.assemble.Result;
+import org.apache.commons.lang3.tuple.Pair;
+import org.elasticsearch.index.query.BoolQueryBuilder;
+import org.elasticsearch.index.query.QueryBuilders;
+import org.elasticsearch.index.query.functionscore.ScriptScoreQueryBuilder;
+import org.elasticsearch.script.Script;
+import org.elasticsearch.script.ScriptType;
+import org.elasticsearch.search.sort.SortBuilders;
+import org.elasticsearch.search.sort.SortOrder;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
+import org.springframework.data.elasticsearch.core.SearchHits;
+import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
+import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
+import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+
+import javax.annotation.Resource;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * @program: sp-sales-platform
+ * @description:
+ * @author: chenkq
+ * @create: 2025-04-16 09:57
+ */
+@Service
+public class EsSearchCustomerServiceImpl implements EsSearchCustomerService {
+
+    @Resource
+    private ElasticsearchRestTemplate elasticsearchTemplate;
+
+    private static String similarityScript = "\n" +
+            "def field = params.field;\n" +  // 使用参数传入字段名
+            "if (!doc.containsKey(field) || doc[field].size() == 0 || doc[field].value == null) {\n" +
+            "    return 0;\n" +
+            "}\n" +
+            "if (params.query == null) return 0;\n" +
+            "def docValue = doc[field].value;\n" +
+            "\n" +
+            "String s1 = docValue.toString().toLowerCase();\n" +
+            "String s2 = params.query?.toString().toLowerCase();\n" +
+            "\n" +
+            "// 空值检查\n" +
+            "if (s1 == null || s2 == null) return 0;\n" +
+            "\n" +
+            "// 完全匹配直接返回100\n" +
+            "if (s1.equals(s2)) return 100;\n" +
+            "\n" +
+            "// 计算编辑距离(内联实现)\n" +
+            "int s1_len = s1.length();\n" +
+            "int s2_len = s2.length();\n" +
+            "\n" +
+            "// 快速检查\n" +
+            "if (s1_len == 0 || s2_len == 0) return 0;\n" +
+            "if (s1_len == 0) return (int)(100 * (1 - (s2_len / Math.max(1, s2_len))));\n" +
+            "if (s2_len == 0) return (int)(100 * (1 - (s1_len / Math.max(1, s1_len))));\n" +
+            "\n" +
+            "// 使用单数组优化空间复杂度\n" +
+            "int[] costs = new int[s2_len + 1];\n" +
+            "for (int j = 0; j <= s2_len; j++) {\n" +
+            "    costs[j] = j;\n" +
+            "}\n" +
+            "\n" +
+            "for (int i = 1; i <= s1_len; i++) {\n" +
+            "    costs[0] = i;\n" +
+            "    int prev = i - 1;\n" +
+            "    for (int j = 1; j <= s2_len; j++) {\n" +
+            "        int cost = (s1.charAt(i - 1) == s2.charAt(j - 1)) ? 0 : 1;\n" +
+            "        int insertion = costs[j] + 1;\n" +
+            "        int deletion = costs[j - 1] + 1;\n" +
+            "        int substitution = prev + cost;\n" +
+            "        int current = insertion;\n" +
+            "        if (deletion < current) {\n" +
+            "           current = deletion;\n" +
+            "        } \n" +
+            "        if (substitution < current) {\n" +
+            "           current = substitution;\n" +
+            "        } \n" +
+            "        prev = costs[j];\n" +
+            "        costs[j] = current;\n" +
+            "    }\n" +
+            "}\n" +
+            "\n" +
+            "int distance = costs[s2_len];\n" +
+            "int maxLen = s1_len > s2_len ? s1_len : s2_len;\n" +
+            "if (maxLen == 0) return 100;\n"+
+            "\n" +
+            "// 计算相似度百分比(0-100)\n" +
+            "double similarity = 100 * (1 - ((double)distance / maxLen));\n" +
+            "return (int) Math.round(similarity);";
+
+    @Override
+    public List<EsQuerySimilarityVO> listComparisonSimilarity(EsGenericVO dto) {
+
+//        Map<String, List<String>> indexFieldsMap = Map.of(
+//                "liaison_data_index", Arrays.asList("email.keyword","email1.keyword","email2.keyword","email3.keyword"),
+//                "customer_company_data_index", Arrays.asList("email.keyword","email1.keyword","email2.keyword","email3.keyword")
+//        );
+
+
+        // 保存索引名称和查询的列表
+        List<IndexFieldConfig>  indexFields=  dto.getIndexFields();
+//        Map<String, List<FieldConfig>> indexFieldsMap = indexFields.stream()
+//                .collect(Collectors.toMap(
+//                        IndexFieldConfig::getIndexName,
+//                        IndexFieldConfig::getFields
+//                ));
+
+        Map<String, IndexFieldConfig> indexFieldsMap = indexFields.stream().collect(Collectors.toMap(IndexFieldConfig::getIndexName, IndexFieldConfig -> IndexFieldConfig));
+
+        List<Map> combinedResults = new ArrayList<>();
+
+        float minScore = Float.parseFloat(dto.getMinScore());
+        List<Pair<String, NativeSearchQuery>> indexQueries = new ArrayList<>();
+        indexFieldsMap.forEach((indexName, indexField) -> {
+            List<FieldConfig> fields = indexField.getFields();
+            for (int i = 0; i < fields.size(); i++) {
+                BoolQueryBuilder indexQuery = QueryBuilders.boolQuery();
+                FieldConfig field = fields.get(i);
+                Map<String, Object> scriptParams = new HashMap<>();
+                scriptParams.put("field", field.getFieldName());
+                scriptParams.put("query", dto.getQueryText());
+                scriptParams.put("targetIndex", indexName);
+                indexQuery.mustNot(QueryBuilders.termQuery("is_delete", 1)); // Exclude deleted records
+                if(!Objects.isNull(dto.getCustomerForm())){
+                    indexQuery.must(QueryBuilders.termQuery("customer_form", dto.getCustomerForm())); // Exclude deleted records
+                }
+
+//                indexQuery.should(
+//                        QueryBuilders.scriptScoreQuery(
+//                                QueryBuilders.matchAllQuery(),
+//                                new Script(
+//                                        ScriptType.INLINE,
+//                                        "painless",
+//                                        similarityScript,
+//                                        scriptParams
+//                                )
+//                        ).setMinScore(minScore)
+//                );
+                ScriptScoreQueryBuilder scriptScoreQuery = QueryBuilders.scriptScoreQuery(
+                        indexQuery,  // 先应用 mustNot 过滤
+                        new Script(
+                                ScriptType.INLINE,
+                                "painless",
+                                similarityScript,
+                                scriptParams
+                        )
+                ).setMinScore(minScore);  // 只返回 _score >= minScore 的数据
+                NativeSearchQuery indexSearchQuery = new NativeSearchQueryBuilder()
+                        .withQuery(scriptScoreQuery)
+                        .withSort(SortBuilders.scoreSort().order(SortOrder.DESC))
+                        .withPageable(PageRequest.of(0, 1000))
+                        .build();
+                indexQueries.add(Pair.of(indexName, indexSearchQuery));
+
+                SearchHits<Map> hits = elasticsearchTemplate.search(
+                        indexSearchQuery,
+                        Map.class,
+                        IndexCoordinates.of(indexName));
+
+                hits.getSearchHits().stream()
+                        .map(hit -> {
+                            Map<String, Object> content = new HashMap<>(hit.getContent());
+                            content.put("similarityScore", hit.getScore());
+                            content.put("matchedIndex", hit.getIndex());
+                            content.put("matchedField", field.getFieldName());
+                            return content;
+                        })
+                        .forEach(combinedResults::add);
+            }
+        });
+
+// 执行查询并合并结果
+
+//        for (Pair<String, NativeSearchQuery> pair : indexQueries) {
+//            String indexName = pair.getLeft();
+//            NativeSearchQuery query = pair.getRight();
+//
+//        }
+
+
+
+        // 按相似度分数排序
+        combinedResults.sort((a, b) -> {
+            float scoreA = (float) a.getOrDefault("similarityScore", 0f);
+            float scoreB = (float) b.getOrDefault("similarityScore", 0f);
+            return Float.compare(scoreB, scoreA); // 降序排序
+        });
+
+        List<EsQuerySimilarityVO> vos = convertToVoList(combinedResults,indexFieldsMap);
+        return vos;
+    }
+
+
+    public  List<EsQuerySimilarityVO> convertToVoList(List<Map> combinedResults,Map<String, IndexFieldConfig> indexFieldsMap) {
+        if (CollectionUtils.isEmpty(combinedResults)) {
+            return new ArrayList<>();
+        }
+        return combinedResults.stream()
+                .map(result -> {
+                    EsQuerySimilarityVO vo = new EsQuerySimilarityVO();
+
+                    // 1. 设置基础字段
+                    vo.setId(Long.valueOf(result.get("id").toString())); // 假设id字段存在
+                    if (result.containsKey("customer_id") && Objects.nonNull(result.get("customer_id"))) {
+                        vo.setCustomerId(Long.valueOf(result.get("customer_id").toString())); // 假设customer_id字段存在
+                    }
+                    if (result.containsKey("owner_by") && Objects.nonNull(result.get("owner_by"))) {
+                        vo.setOwnerBy(Long.valueOf(result.get("owner_by").toString())); // 假设customer_id字段存在
+                    }
+
+                    vo.setObject(result); // 保留原始数据
+
+                    // 2. 设置相似度分数(转换为百分比字符串)
+                    Float score = (Float) result.get("similarityScore");
+                    vo.setSimilarityScore(score.toString());
+                    // 3. 设置索引名称
+                    vo.setIndexName((String) result.get("matchedIndex"));
+                    IndexFieldConfig indexField = indexFieldsMap.get(vo.getIndexName());
+                    vo.setResourceType(indexField.getResourceType().toString());
+//
+//                    vo.setMatchedField(matchedField);
+                    // 4. 找出匹配的字段名
+                    findMatchedField(vo,result, vo.getIndexName(),indexFieldsMap);
+//                    vo.setMatchedField(matchedField);
+                    if (StrUtil.isNotBlank(vo.getMatchedField())) {
+                        vo.setDuplicateValue(result.get(vo.getMatchedField()).toString());
+                    }
+                    return vo;
+                })
+                .collect(Collectors.toList());
+    }
+
+    // 辅助方法:找出实际匹配的字段
+    private void findMatchedField(EsQuerySimilarityVO vo,Map<String, Object> result, String indexName,Map<String, IndexFieldConfig> indexConfigMap) {
+        // 获取该索引对应的字段列表
+        IndexFieldConfig indexConfig = indexConfigMap.get(indexName);
+        List<FieldConfig> fields = indexConfig.getFields();
+        // 遍历字段,找出有值的字段
+        for (FieldConfig field : fields) {
+            // 移除.keyword后缀(如果需要)
+            String cpField =  result.get("matchedField").toString();
+            if (cpField.equals(field.getFieldName())) {
+                String baseField = cpField.replace(".keyword", "");
+                if (result.containsKey(baseField) && result.get(baseField) != null) {
+                    vo.setMatchedField(baseField);
+                    vo.setDuplicateField(baseField);
+//                    vo.setErrorMsg(field.getFieldDescribe()+"重复");
+                    vo.setErrorMsg(field.getFieldDescribe());
+                }
+            }
+
+        }
+    }
+}
+
+
+

+ 7 - 9
java/storlead-crm/storlead-order/pom.xml → java/storlead-message/pom.xml

@@ -3,22 +3,20 @@
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
     <modelVersion>4.0.0</modelVersion>
+
     <parent>
     <parent>
         <groupId>com.storlead.boot</groupId>
         <groupId>com.storlead.boot</groupId>
-        <artifactId>storlead-crm</artifactId>
+        <artifactId>storlead-smarttrade-platform</artifactId>
         <version>1.0</version>
         <version>1.0</version>
-        <relativePath>../pom.xml</relativePath>
+        <relativePath>../../pom.xml</relativePath>
     </parent>
     </parent>
 
 
-    <artifactId>storlead-order</artifactId>
+    <artifactId>storlead-message</artifactId>
     <packaging>jar</packaging>
     <packaging>jar</packaging>
-    <name>${project.artifactId}</name>
-    <description>订单</description>
+    <name>storlead-message</name>
+    <version>1.0</version>
 
 
     <dependencies>
     <dependencies>
-        <dependency>
-            <groupId>com.storlead.boot</groupId>
-            <artifactId>storlead-web</artifactId>
-        </dependency>
+
     </dependencies>
     </dependencies>
 </project>
 </project>

+ 20 - 0
java/storlead-message/src/main/java/com/storlead/message/controller/UserMessageNoticeConfigController.java

@@ -0,0 +1,20 @@
+package com.storlead.message.controller;
+
+
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * <p>
+ * 消息开关配置 前端控制器
+ * </p>
+ *
+ * @author chenkq
+ * @since 2025-04-25
+ */
+@RestController
+@RequestMapping("/user-message-notice-config-entity")
+public class UserMessageNoticeConfigController {
+
+}

+ 58 - 0
java/storlead-message/src/main/java/com/storlead/message/entity/UserMessageNoticeConfigEntity.java

@@ -0,0 +1,58 @@
+package com.storlead.message.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.storlead.frame.mybatis.entity.SysBaseField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableField;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 消息开关配置
+ * </p>
+ *
+ * @author chenkq
+ * @since 2025-04-25
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@Accessors(chain = true)
+@TableName("user_message_notice_config")
+@ApiModel(value="UserMessageNoticeConfigEntity对象", description="消息开关配置")
+public class UserMessageNoticeConfigEntity extends SysBaseField {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "主键id")
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    @ApiModelProperty(value = "模板名称")
+    @TableField("template_event_id")
+    private Long templateEventId;
+
+    @ApiModelProperty(value = "模板code")
+    @TableField("template_event_code")
+    private String templateEventCode;
+
+    @ApiModelProperty(value = "site:站内,sms:短信,wecom:企业微信,mail:邮件")
+    @TableField("template_detail_type")
+    private String templateDetailType;
+
+    @ApiModelProperty(value = "数组: site:站内,sms:短信,wecom:企业微信,mail:邮件,需要同时控制的消息类型")
+    @TableField(exist = false)
+    private List<String> templateDetailTypels;
+
+    @ApiModelProperty(value = "备注")
+    @TableField("remark")
+    private Long remark;
+
+
+}

+ 96 - 0
java/storlead-message/src/main/java/com/storlead/message/enums/MessageTypeEnum.java

@@ -0,0 +1,96 @@
+package com.storlead.message.enums;
+
+import com.storlead.common.constant.CodeGenerateInterface;
+import com.storlead.message.pojo.vo.MessageTypeReadStateVO;
+import lombok.Getter;
+import org.springframework.util.CollectionUtils;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @program: sp-sales-platform
+ * @description:
+ * @author: chenkq
+ * @create: 2024-09-06 09:26
+ */
+@Getter
+public enum MessageTypeEnum {
+    /**
+     * 为了查询分类而产生
+     * 消息类型细分 0:普通消息,1:@我相关,2:审批消息,微信小程序用( 3:目标完成贡献值分配提醒,4:简报待审消息,5:赞扬,6:提升,7:报告,99:其他)
+     */
+    CUSTOMER("10", "客户"),
+    CLUS("11", "线索"),
+    LIAISON("20", "联系人"),
+    BUSINESS("30", "商机"),
+    ORDER_FORM("40", "订单"),
+    //    TASK_CANCELED("50", "回款"),
+//    TASK_CANCELED("60", "退款"),
+//    TASK_CANCELED("70", "费用"),
+    TASK_CANCELED("80", "任务"),
+    FOLLOW_UP("90", "跟进"),
+    WORK_ORDER("100", "工单"),
+    BULLETIN("120", "公告"),
+    PERFORMANCE_GOAL("130", "目标"),
+    BROADCAST("200", "统计"),
+    OTHER_EXTEND("999", "其他"),
+    /**
+     *  首页的消息需要查
+     *  首页包含:目标和简报
+     */
+    ;
+    public static MessageTypeEnum [] messageSubTypes = MessageTypeEnum.values();
+
+    public static Map getMessageTypeMap(List<String> types) {
+        Map<String,Integer> map = new HashMap<>();
+        for(MessageTypeEnum subTypeEnum: messageSubTypes) {
+            if (CollectionUtils.isEmpty(types)) {
+                map.put(subTypeEnum.getCode(),Integer.valueOf(0));
+            } else {
+                if (types.contains(subTypeEnum.getCode())) {
+                    map.put(subTypeEnum.getCode(),Integer.valueOf(0));
+                }
+            }
+        }
+        return map;
+    }
+
+    public static List<MessageTypeReadStateVO> getMessageTypeReadStatels(List<String> types) {
+        List<MessageTypeReadStateVO> arr = new ArrayList<>();
+        for(MessageTypeEnum subTypeEnum: messageSubTypes) {
+            MessageTypeReadStateVO vo = new MessageTypeReadStateVO();
+            vo.setMessageType(Integer.valueOf(subTypeEnum.getCode()));
+            vo.setMessageTypeName(subTypeEnum.getDesc());
+            if (CollectionUtils.isEmpty(types)) {
+                vo.setStateNumber(Integer.valueOf(0));
+                arr.add(vo);
+            } else {
+                if (types.contains(subTypeEnum.getCode())) {
+                    vo.setStateNumber(Integer.valueOf(0));
+                    arr.add(vo);
+                }
+            }
+        }
+        return arr;
+    }
+
+    private String code;
+    private String desc;
+
+    MessageTypeEnum(String code, String desc) {
+        this.code = code;
+        this.desc = desc;
+    }
+
+    public static MessageTypeEnum getByCode(Integer code) {
+        for (MessageTypeEnum tag : MessageTypeEnum.values()) {
+            if (tag.code.equals(code)) {
+                return tag;
+            }
+        }
+        return null; // 如果找不到对应的枚举值,可以返回null或者抛出异常
+    }
+}

+ 77 - 0
java/storlead-message/src/main/java/com/storlead/message/enums/OperationEventEnum.java

@@ -0,0 +1,77 @@
+package com.storlead.message.enums;
+
+/**
+ * @program: sp-sales-platform
+ * @description:
+ * @author: chenkq
+ * @create: 2024-08-19 14:44
+ */
+public enum OperationEventEnum {
+    MEMBER_ADD_CLUE("MEMBER_ADD_CLUE", "成员新增线索"),
+    MEMBER_RECEIVE_CLUE("MEMBER_RECEIVE_CLUE", "成员领取线索"),
+    DISTRIBUTE_CLUE("DISTRIBUTE_CLUE", "分配线索"),
+    TRANSFER_CLUE("TRANSFER_CLUE", "转移线索"),
+    CONVERT_TO_CUSTOMER("CONVERT_TO_CUSTOMER", "转为客户"),
+    PUBLIC_WARNING("PUBLIC_WARNING", "置公预警"),
+    CLEAR_WARNING("CLEAR_WARNING", "清除预警"),
+    DATA_CHANGE("DATA_CHANGE", "数据变更"),
+    COMMENT_FOLLOW_UP("COMMENT_FOLLOW_UP", "评论跟进"),
+    NEW_EMAIL("NEW_EMAIL", "新邮件"),
+    NEW_TASK("NEW_TASK", "新建任务"),
+    FOLLOW_UP_REMINDER("FOLLOW_UP_REMINDER", "跟进提醒"),
+    FOLLOW_UP_OVERDUE("FOLLOW_UP_OVERDUE", "跟进逾期"),
+    DUPLICATE_WARNING("DUPLICATE_WARNING", "查重预警"),
+    ADD_CUSTOMER("ADD_CUSTOMER", "新增客户"),
+    TRANSFER_CUSTOMER("TRANSFER_CUSTOMER", "转移客户"),
+    MOVE_TO_PUBLIC("MOVE_TO_PUBLIC", "移入公海"),
+    DUPLICATE_WARNING_AGAIN("DUPLICATE_WARNING", "查重预警"),
+    DELETE_CUSTOMER("DELETE_CUSTOMER", "删除客户"),
+    PUBLIC_WARNING_AGAIN("PUBLIC_WARNING", "置公预警"),
+    GARBAGE_CUSTOMER_WARNING("GARBAGE_CUSTOMER_WARNING", "置垃圾客户预警"),
+    CLEAR_WARNING_AGAIN("CLEAR_WARNING", "清除预警"),
+    DATA_CHANGE_AGAIN("DATA_CHANGE", "数据变更"),
+    ADD_SAMPLE("ADD_SAMPLE", "新增寄样"),
+    CUSTOMER_COLLABORATION("CUSTOMER_COLLABORATION", "客户协作"),
+    CUSTOMER_MERGE("CUSTOMER_MERGE", "客户合并"),
+    COMMENT_FOLLOW_UP_AGAIN("COMMENT_FOLLOW_UP", "评论跟进"),
+    NEW_EMAIL_AGAIN("NEW_EMAIL", "新邮件"),
+    NEW_TASK_AGAIN("NEW_TASK", "新建任务"),
+    FOLLOW_UP_REMINDER_AGAIN("FOLLOW_UP_REMINDER", "跟进提醒"),
+    FOLLOW_UP_OVERDUE_AGAIN("FOLLOW_UP_OVERDUE", "跟进逾期"),
+    ADD_OPPORTUNITY("ADD_OPPORTUNITY", "新增商机"),
+    TRANSFER_OPPORTUNITY("TRANSFER_OPPORTUNITY", "转移商机"),
+    OPPORTUNITY_COLLABORATION("OPPORTUNITY_COLLABORATION", "商机协作"),
+    ADD_QUOTE("ADD_QUOTE", "新增报价"),
+    NEW_TASK_THIRD("NEW_TASK", "新建任务"),
+    FOLLOW_UP_REMINDER_THIRD("FOLLOW_UP_REMINDER", "跟进提醒"),
+    FOLLOW_UP_OVERDUE_THIRD("FOLLOW_UP_OVERDUE", "跟进逾期"),
+    DATA_CHANGE_THIRD("DATA_CHANGE", "数据变更"),
+    COMMENT_FOLLOW_UP_THIRD("COMMENT_FOLLOW_UP", "评论跟进"),
+    CONVERT_TO_ORDER("CONVERT_TO_ORDER", "转为订单"),
+    DELETE_OPPORTUNITY("DELETE_OPPORTUNITY", "删除商机"),
+    ADD_ORDER("ADD_ORDER", "新增订单"),
+    TRANSFER_ORDER("TRANSFER_ORDER", "转移订单"),
+    ADD_COLLABORATION("ADD_COLLABORATION", "添加协作"),
+    NEW_TASK_FOURTH("NEW_TASK", "新建任务"),
+    FOLLOW_UP_REMINDER_FOURTH("FOLLOW_UP_REMINDER", "跟进提醒"),
+    FOLLOW_UP_OVERDUE_FOURTH("FOLLOW_UP_OVERDUE", "跟进逾期"),
+    DATA_CHANGE_FOURTH("DATA_CHANGE", "数据变更"),
+    ADD_BULLETIN("ADD_BULLETIN", "发布公告"),
+    DELETE_ORDER("DELETE_ORDER", "删除订单");
+
+    private final String code;
+    private final String desc;
+
+    OperationEventEnum(String code, String desc) {
+        this.code = code;
+        this.desc = desc;
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public String getDesc() {
+        return desc;
+    }
+}

+ 21 - 0
java/storlead-message/src/main/java/com/storlead/message/mapper/InsideMessageRecordMapper.java

@@ -0,0 +1,21 @@
+package com.storlead.message.mapper;
+
+import com.storlead.frame.mybatis.mapper.MyBaseMapper;
+import com.storlead.message.pojo.entity.InsideMessageRecordEntity;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+
+import java.util.Map;
+
+/**
+ * <p>
+ * 系统内部消息 Mapper 接口
+ * </p>
+ *
+ * @author chenkq
+ * @since 2024-04-19
+ */
+public interface InsideMessageRecordMapper extends MyBaseMapper<InsideMessageRecordEntity> {
+
+    Map selectOldById(@Param("tableName") String tableName,@Param("fieldColumn") String fieldColumn,@Param("id") Long id);
+}

+ 32 - 0
java/storlead-message/src/main/java/com/storlead/message/mapper/InsideMessageSendLogMapper.java

@@ -0,0 +1,32 @@
+package com.storlead.message.mapper;
+
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.Constants;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.storlead.frame.mybatis.mapper.MyBaseMapper;
+import com.storlead.message.pojo.entity.InsideMessageSendLogEntity;
+import com.storlead.message.pojo.vo.MessageDetailVO;
+import com.storlead.message.pojo.vo.MessageNoReadTotalVO;
+import com.storlead.message.pojo.vo.MessageTypeReadStateVO;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 内部消息人员接收记录表 Mapper 接口
+ * </p>
+ *
+ * @author chenkq
+ * @since 2024-04-19
+ */
+public interface InsideMessageSendLogMapper extends MyBaseMapper<InsideMessageSendLogEntity> {
+
+    IPage<MessageDetailVO> pageListMessageLog(Page<InsideMessageSendLogEntity> page, @Param(Constants.WRAPPER) Wrapper<InsideMessageSendLogEntity> wrapper);
+
+    MessageNoReadTotalVO countNoReadNumber(@Param(Constants.WRAPPER) Wrapper<InsideMessageSendLogEntity> wrapper);
+
+    List<MessageTypeReadStateVO> countNoReadCount(@Param(Constants.WRAPPER) Wrapper<InsideMessageSendLogEntity> wrapper);
+
+}

+ 17 - 0
java/storlead-message/src/main/java/com/storlead/message/mapper/MessageTemplateEventDetailMapper.java

@@ -0,0 +1,17 @@
+package com.storlead.message.mapper;
+
+import com.storlead.frame.mybatis.mapper.MyBaseMapper;
+import com.storlead.message.pojo.entity.MessageTemplateEventDetailEntity;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * <p>
+ * 消息模板 Mapper 接口
+ * </p>
+ *
+ * @author chenkq
+ * @since 2024-04-19
+ */
+public interface MessageTemplateEventDetailMapper extends MyBaseMapper<MessageTemplateEventDetailEntity> {
+
+}

+ 29 - 0
java/storlead-message/src/main/java/com/storlead/message/mapper/MessageTemplateEventGroupMapper.java

@@ -0,0 +1,29 @@
+package com.storlead.message.mapper;
+
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.Constants;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.storlead.frame.mybatis.mapper.MyBaseMapper;
+import com.storlead.message.pojo.entity.InsideMessageSendLogEntity;
+import com.storlead.message.pojo.entity.MessageTemplateEventGroupEntity;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.storlead.message.pojo.vo.MessageDetailVO;
+import com.storlead.message.pojo.vo.MessageNoReadTotalVO;
+import com.storlead.message.pojo.vo.MessageTemplateVO;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 实践规则模板 Mapper 接口
+ * </p>
+ *
+ * @author chenkq
+ * @since 2024-04-19
+ */
+public interface MessageTemplateEventGroupMapper extends MyBaseMapper<MessageTemplateEventGroupEntity> {
+
+    IPage<MessageTemplateVO> selectMessageTemplateList(Page<MessageTemplateEventGroupEntity> page, @Param(Constants.WRAPPER) Wrapper<MessageTemplateEventGroupEntity> wrapper);
+}

+ 16 - 0
java/storlead-message/src/main/java/com/storlead/message/mapper/UserMessageNoticeConfigMapper.java

@@ -0,0 +1,16 @@
+package com.storlead.message.mapper;
+
+import com.storlead.message.entity.UserMessageNoticeConfigEntity;
+import com.storlead.frame.mybatis.mapper.MyBaseMapper;
+
+/**
+ * <p>
+ * 消息开关配置 Mapper 接口
+ * </p>
+ *
+ * @author chenkq
+ * @since 2025-04-25
+ */
+public interface UserMessageNoticeConfigMapper extends MyBaseMapper<UserMessageNoticeConfigEntity> {
+
+}

+ 34 - 0
java/storlead-message/src/main/java/com/storlead/message/mapper/xml/InsideMessageRecordMapper.xml

@@ -0,0 +1,34 @@
+<?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="com.storlead.message.mapper.InsideMessageRecordMapper">
+
+        <!-- 通用查询映射结果 -->
+        <resultMap id="BaseResultMap" type="com.storlead.model.message.entity.InsideMessageRecordEntity">
+                    <id column="id" property="id" />
+                    <result column="title" property="title" />
+                    <result column="content" property="content" />
+                    <result column="message_icon" property="messageIcon" />
+                    <result column="message_tag" property="messageTag" />
+                    <result column="callback_url" property="callbackUrl" />
+                    <result column="wx_callback_url" property="wxCallbackUrl" />
+                    <result column="send_user_id" property="sendUserId" />
+                    <result column="status" property="status" />
+                    <result column="message_type" property="messageType" />
+                    <result column="message_sub_type" property="messageSubType" />
+                    <result column="timer_send_time" property="timerSendTime" />
+                    <result column="actually_send_time" property="actuallySendTime" />
+                    <result column="create_by" property="createBy" />
+                    <result column="create_time" property="createTime" />
+                    <result column="update_by" property="updateBy" />
+                    <result column="update_time" property="updateTime" />
+                    <result column="enabled" property="enabled" />
+                    <result column="is_delete" property="isDelete" />
+                    <result column="sort" property="sort" />
+        </resultMap>
+
+        <!-- 通用查询结果列 -->
+        <sql id="Base_Column_List">
+            id, title, content, message_icon, message_tag, callback_url, wx_callback_url, send_user_id, status, message_type, message_sub_type, timer_send_time, actually_send_time, create_by, create_time, update_by, update_time, enabled, is_delete, sort
+        </sql>
+
+</mapper>

+ 26 - 0
java/storlead-message/src/main/java/com/storlead/message/mapper/xml/InsideMessageSendLogMapper.xml

@@ -0,0 +1,26 @@
+<?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="com.storlead.message.mapper.InsideMessageSendLogMapper">
+
+        <!-- 通用查询映射结果 -->
+        <resultMap id="BaseResultMap" type="com.storlead.model.message.entity.InsideMessageSendLogEntity">
+                    <id column="id" property="id" />
+                    <result column="message_id" property="messageId" />
+                    <result column="receiver_user_id" property="receiverUserId" />
+                    <result column="is_read" property="isRead" />
+                    <result column="status" property="status" />
+                    <result column="create_by" property="createBy" />
+                    <result column="create_time" property="createTime" />
+                    <result column="update_by" property="updateBy" />
+                    <result column="update_time" property="updateTime" />
+                    <result column="enabled" property="enabled" />
+                    <result column="is_delete" property="isDelete" />
+                    <result column="sort" property="sort" />
+        </resultMap>
+
+        <!-- 通用查询结果列 -->
+        <sql id="Base_Column_List">
+            id, message_id, receiver_user_id, is_read, status, create_by, create_time, update_by, update_time, enabled, is_delete, sort
+        </sql>
+
+</mapper>

+ 35 - 0
java/storlead-message/src/main/java/com/storlead/message/mapper/xml/UserMessageNoticeConfigMapper.xml

@@ -0,0 +1,35 @@
+<?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="com.storlead.message.mapper.UserMessageNoticeConfigMapper">
+
+        <!-- 通用查询映射结果 -->
+        <resultMap id="BaseResultMap" type="com.storlead.message.entity.UserMessageNoticeConfigEntity">
+                    <id column="id" property="id" />
+                <result column="create_by" property="createBy" />
+                <result column="owner_by" property="ownerBy" />
+                <result column="create_time" property="createTime" />
+                <result column="update_by" property="updateBy" />
+                <result column="update_time" property="updateTime" />
+                <result column="enabled" property="enabled" />
+                <result column="is_delete" property="isDelete" />
+                <result column="sort" property="sort" />
+                    <result column="template_event_id" property="templateEventId" />
+                    <result column="template_event_code" property="templateEventCode" />
+                    <result column="template_detail_type" property="templateDetailType" />
+                    <result column="remark" property="remark" />
+        </resultMap>
+
+        <!-- 通用查询结果列 -->
+        <sql id="Base_Column_List">
+                create_by,
+                owner_by,
+                create_time,
+                update_by,
+                update_time,
+                enabled,
+                is_delete,
+                sort,
+            id, template_event_id, template_event_code, template_detail_type, remark
+        </sql>
+
+</mapper>

+ 27 - 0
java/storlead-message/src/main/java/com/storlead/message/pojo/dto/MessageDTO.java

@@ -0,0 +1,27 @@
+package com.storlead.message.pojo.dto;
+
+import com.storlead.common.object.Page;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * @program: sp-sales-platform
+ * @description:
+ * @author: chenkq
+ * @create: 2024-04-19 16:39
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@ApiModel(value="站内消息", description="站内消息")
+public class MessageDTO extends Page {
+
+    @ApiModelProperty(value = "字典")
+    private String messageType;
+
+    @ApiModelProperty(value = "0:未读,1:已读")
+    private Integer isRead;
+}

+ 12 - 0
java/storlead-message/src/main/java/com/storlead/message/pojo/dto/MessageTemplateDetailDTO.java

@@ -0,0 +1,12 @@
+package com.storlead.message.pojo.dto;
+
+import com.storlead.message.pojo.entity.MessageTemplateEventDetailEntity;
+
+/**
+ * @program: sp-sales-platform
+ * @description:
+ * @author: chenkq
+ * @create: 2024-05-09 18:06
+ */
+public class MessageTemplateDetailDTO extends MessageTemplateEventDetailEntity {
+}

+ 15 - 0
java/storlead-message/src/main/java/com/storlead/message/pojo/dto/MessageTemplateEventDTO.java

@@ -0,0 +1,15 @@
+package com.storlead.message.pojo.dto;
+
+import com.storlead.common.object.QueryBaseEntity;
+import lombok.Data;
+
+/**
+ * @program: sp-sales-platform
+ * @description:
+ * @author: chenkq
+ * @create: 2024-04-26 17:20
+ */
+@Data
+public class MessageTemplateEventDTO extends QueryBaseEntity {
+    private Integer templateServiceType;
+}

+ 31 - 0
java/storlead-message/src/main/java/com/storlead/message/pojo/dto/MessageTestDTO.java

@@ -0,0 +1,31 @@
+package com.storlead.message.pojo.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.util.Set;
+
+/**
+ * @program: sp-sales-platform
+ * @description:
+ * @author: chenkq
+ * @create: 2024-08-15 10:24
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@ApiModel(value="站内消息", description="站内消息")
+public class MessageTestDTO {
+
+    @ApiModelProperty(value = "数据Id")
+    private Long dataId;
+
+    @ApiModelProperty(value = "触发事件")
+    private String eventCode;
+
+    @ApiModelProperty(value = "接收人")
+    private Set<Long> toUserIds;
+}

+ 98 - 0
java/storlead-message/src/main/java/com/storlead/message/pojo/entity/InsideMessageRecordEntity.java

@@ -0,0 +1,98 @@
+package com.storlead.message.pojo.entity;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import com.baomidou.mybatisplus.annotation.TableId;
+import java.time.LocalDateTime;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.storlead.frame.mybatis.entity.SysBaseField;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.springframework.format.annotation.DateTimeFormat;
+
+/**
+ * <p>
+ * 系统内部消息
+ * </p>
+ *
+ * @author chenkq
+ * @since 2024-04-19
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@Accessors(chain = true)
+@TableName("inside_message_record")
+@ApiModel(value="InsideMessageRecordEntity对象", description="系统内部消息")
+public class InsideMessageRecordEntity extends SysBaseField {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "主键id")
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    @ApiModelProperty(value = "消息标题")
+    private String title;
+
+    @ApiModelProperty(value = "内容")
+    private String content;
+
+    @ApiModelProperty(value = "模板图标")
+    private String messageIcon;
+
+    @ApiModelProperty(value = "模板标签")
+    private String messageTag;
+
+    @ApiModelProperty(value = "回调地址")
+    private String callbackUrl;
+
+    @ApiModelProperty(value = "微信小程序回调地址")
+    private String wxCallbackUrl;
+
+    @ApiModelProperty(value = "发送人")
+    private Long sendUserId;
+
+    @ApiModelProperty(value = "归属人员")
+    private Long ownerBy;
+
+    @ApiModelProperty(value = "是否已读 0:未发送,1:已发送,2:撤回")
+    private Integer status;
+
+    @ApiModelProperty(value = "所属业务组")
+    private Integer messageType;
+
+    @ApiModelProperty(value = "细分消息类型(对应事件)")
+    private Integer messageSubType;
+
+    @ApiModelProperty(value = "定时发送时间")
+    @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+    @JSONField(format ="yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime timerSendTime;
+
+    @ApiModelProperty(value = "实际发送时间")
+    @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+    @JSONField(format ="yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime actuallySendTime;
+
+
+    public InsideMessageRecordEntity() {}
+
+    public InsideMessageRecordEntity(String title, String content,String messageIcon,String messageTag,String callbackUrl, Long sendUserId, Integer status, Integer messageType) {
+        this.title = title;
+        this.content = content;
+        this.messageTag = messageTag;
+        this.messageIcon = messageIcon;
+        this.callbackUrl = callbackUrl;
+        this.sendUserId = sendUserId;
+        this.status = status;
+        this.messageType = messageType;
+    }
+}

+ 70 - 0
java/storlead-message/src/main/java/com/storlead/message/pojo/entity/InsideMessageSendLogEntity.java

@@ -0,0 +1,70 @@
+package com.storlead.message.pojo.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import com.baomidou.mybatisplus.annotation.TableId;
+import java.time.LocalDateTime;
+
+import com.storlead.frame.mybatis.entity.SysBaseField;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * <p>
+ * 内部消息人员接收记录表
+ * </p>
+ *
+ * @author chenkq
+ * @since 2024-04-19
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@Accessors(chain = true)
+@TableName("inside_message_send_log")
+@ApiModel(value="InsideMessageSendLogEntity对象", description="内部消息人员接收记录表")
+public class InsideMessageSendLogEntity extends SysBaseField {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "主键id")
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    @ApiModelProperty(value = "消息id")
+    private Long messageId;
+
+    @ApiModelProperty(value = "接收人")
+    private Long receiverUserId;
+
+    @ApiModelProperty(value = "所属业务组")
+    private Integer messageType;
+
+    @ApiModelProperty(value = "细分消息类型(对应事件)")
+    private Integer messageSubType;
+
+    @ApiModelProperty(value = "未读:0 ,已读:1")
+    private Integer isRead;
+
+    @ApiModelProperty(value = "是否已读 0:未接收,1:已接收")
+    private Integer status;
+
+    @ApiModelProperty(value = "归属人员")
+    private Long ownerBy;
+
+    public InsideMessageSendLogEntity() {
+
+    }
+
+    public InsideMessageSendLogEntity(Long messageId,Long receiverUserId, Integer isRead, Integer status,Integer messageType) {
+        this.messageId = messageId;
+        this.receiverUserId =receiverUserId;
+        this.isRead = isRead;
+        this.status = status;
+        this.messageType = messageType;
+
+    }
+}

+ 63 - 0
java/storlead-message/src/main/java/com/storlead/message/pojo/entity/MessageTemplateEventDetailEntity.java

@@ -0,0 +1,63 @@
+package com.storlead.message.pojo.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import com.baomidou.mybatisplus.annotation.TableId;
+import java.time.LocalDateTime;
+
+import com.storlead.frame.mybatis.entity.SysBaseField;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * <p>
+ * 消息模板
+ * </p>
+ *
+ * @author chenkq
+ * @since 2024-04-19
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@Accessors(chain = true)
+@TableName("message_template_event_detail")
+@ApiModel(value="MessageTemplateEventDetailEntity对象", description="消息模板")
+public class MessageTemplateEventDetailEntity extends SysBaseField {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "主键id")
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    @ApiModelProperty(value = "模板id")
+    private Long templateEventId;
+
+    @ApiModelProperty(value = "模板图标")
+    private String templateIcon;
+
+    @ApiModelProperty(value = "模板标签")
+    private String templateTag;
+
+    @ApiModelProperty(value = "模板code")
+    private String templateEventName;
+
+    @ApiModelProperty(value = "site:站内,sms:短信,wecom:企业微信,mail:邮件")
+    private String templateDetailType;
+
+    @ApiModelProperty(value = "msg:消息,card:卡片 :默认:card")
+    private String templateMessageView;
+
+    @ApiModelProperty(value = "消息标题")
+    private String messageTitle;
+
+    @ApiModelProperty(value = "模板标题")
+    private String messageCentent;
+
+    @ApiModelProperty(value = "回调地址")
+    private String callbackUrl;
+}

+ 64 - 0
java/storlead-message/src/main/java/com/storlead/message/pojo/entity/MessageTemplateEventGroupEntity.java

@@ -0,0 +1,64 @@
+package com.storlead.message.pojo.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import com.baomidou.mybatisplus.annotation.TableId;
+import java.time.LocalDateTime;
+
+import com.storlead.frame.annotate.Dict;
+import com.storlead.frame.mybatis.entity.SysBaseField;
+import io.opentracing.tag.IntTag;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * <p>
+ * 实践规则模板
+ * </p>
+ *
+ * @author chenkq
+ * @since 2024-04-19
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@Accessors(chain = true)
+@TableName("message_template_event_group")
+@ApiModel(value="MessageTemplateEventGroupEntity对象", description="实践规则模板")
+public class MessageTemplateEventGroupEntity extends SysBaseField {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "主键id")
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    @ApiModelProperty(value = "模块名称")
+    private String templateServiceName;
+
+    @ApiModelProperty(value = "业务模块,对应消息类型")
+    @Dict(dictCode = "work_data_group",valueField = "templateServiceName")
+    private Integer templateServiceType;
+
+    @ApiModelProperty(value = " 对应server 业务模块,匹配表名")
+    private String templateServiceCode;
+
+    @ApiModelProperty(value = "事件")
+    private String eventName;
+
+    @ApiModelProperty(value = "事件 code")
+    private String eventCode;
+
+    @ApiModelProperty(value = "事件规则")
+    private String eventRuleScript;
+
+    @ApiModelProperty(value = "接收人key")
+    private String receiverKey;
+
+    @ApiModelProperty(value = "通知的APPCODE")
+    private String noticeAppCode;
+
+}

+ 20 - 0
java/storlead-message/src/main/java/com/storlead/message/pojo/vo/MessageArgTemplateVO.java

@@ -0,0 +1,20 @@
+package com.storlead.message.pojo.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * @program: sp-sales-platform
+ * @description:
+ * @author: chenkq
+ * @create: 2024-08-19 11:58
+ */
+@Data
+public class MessageArgTemplateVO {
+
+    @ApiModelProperty(value = "属性名")
+    private String  propertyName;
+
+    @ApiModelProperty(value = "属性key")
+    private String  propertyKey;
+}

+ 46 - 0
java/storlead-message/src/main/java/com/storlead/message/pojo/vo/MessageDetailVO.java

@@ -0,0 +1,46 @@
+package com.storlead.message.pojo.vo;
+
+import com.storlead.message.pojo.entity.InsideMessageSendLogEntity;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * @program: sp-sales-platform
+ * @description:
+ * @author: chenkq
+ * @create: 2024-04-19 16:40
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@ApiModel(value="站内消息", description="站内消息")
+public class MessageDetailVO extends InsideMessageSendLogEntity {
+
+    @ApiModelProperty(value = "消息标题")
+    private String title;
+
+    @ApiModelProperty(value = "消息内容")
+    private String content;
+
+    @ApiModelProperty(value = "图标")
+    private String messageIcon;
+
+    @ApiModelProperty(value = "标签")
+    private String messageTag;
+
+    @ApiModelProperty(value = "回调地址")
+    private String callbackUrl;
+
+    @ApiModelProperty(value = "发送人id")
+    private Long sendUserId;
+
+    @ApiModelProperty(value = "发送人")
+    private String sendUserName;
+
+    @ApiModelProperty(value = "发送头像图片")
+    private String photo;
+}
+

+ 25 - 0
java/storlead-message/src/main/java/com/storlead/message/pojo/vo/MessageNoReadTotalVO.java

@@ -0,0 +1,25 @@
+package com.storlead.message.pojo.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * @program: sp-sales-platform
+ * @description:
+ * @author: chenkq
+ * @create: 2024-04-19 16:43
+ */
+@Data
+public class MessageNoReadTotalVO implements Serializable {
+
+    @ApiModelProperty(value = "所有未读数")
+    private Integer noReadNum = 0;
+
+    @ApiModelProperty(value = "@我未读数")
+    private Integer atNoReadNum = 0;
+
+    @ApiModelProperty(value = "审批未读数")
+    private Integer approveNoReadNum = 0;
+}

+ 29 - 0
java/storlead-message/src/main/java/com/storlead/message/pojo/vo/MessageTemplateVO.java

@@ -0,0 +1,29 @@
+package com.storlead.message.pojo.vo;
+
+import com.storlead.message.entity.UserMessageNoticeConfigEntity;
+import com.storlead.message.pojo.entity.MessageTemplateEventDetailEntity;
+import com.storlead.message.pojo.entity.MessageTemplateEventGroupEntity;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * @program: sp-sales-platform
+ * @description:
+ * @author: chenkq
+ * @create: 2024-05-09 16:32
+ */
+@Data
+public class MessageTemplateVO extends MessageTemplateEventGroupEntity {
+
+    @ApiModelProperty(value = "模块名称")
+    private List<MessageTemplateEventDetailEntity> detailEntities;
+
+    @ApiModelProperty(value = "配置参数")
+    private List<MessageArgTemplateVO> argls;
+
+    @ApiModelProperty(value = "个人设置")
+    private List<UserMessageNoticeConfigEntity> userDetails;
+
+}

+ 20 - 0
java/storlead-message/src/main/java/com/storlead/message/pojo/vo/MessageTypeReadStateVO.java

@@ -0,0 +1,20 @@
+package com.storlead.message.pojo.vo;
+
+import lombok.Data;
+
+/**
+ * @program: sp-sales-platform
+ * @description:
+ * @author: chenkq
+ * @create: 2024-09-06 09:17
+ */
+@Data
+public class MessageTypeReadStateVO {
+
+    private Integer messageType;
+
+    private String messageTypeName;
+
+    private Integer stateNumber;
+
+}

+ 46 - 0
java/storlead-message/src/main/java/com/storlead/message/service/InsideMessageRecordService.java

@@ -0,0 +1,46 @@
+package com.storlead.message.service;
+
+import com.storlead.frame.core.assemble.Result;
+import com.storlead.frame.mybatis.service.MyBaseService;
+import com.storlead.message.pojo.entity.InsideMessageRecordEntity;
+import com.storlead.message.pojo.entity.MessageTemplateEventDetailEntity;
+import com.storlead.message.pojo.entity.MessageTemplateEventGroupEntity;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * <p>
+ * 系统内部消息 服务类
+ * </p>
+ *
+ * @author chenkq
+ * @since 2024-04-19
+ */
+public interface InsideMessageRecordService extends MyBaseService<InsideMessageRecordEntity> {
+
+    Map getOldMapDataById(String table,String fieldColumn,String id);
+
+
+    /**
+     * @param templateEventId  站内消息模板
+     * @param map 参数
+     * @param receiverUserId 接收人
+     * @param callbackParam 回调参数
+     * @return
+     */
+    Result sendInsideMessage(MessageTemplateEventGroupEntity eventGroup,MessageTemplateEventDetailEntity templateEventDetail, Map map, Long receiverUserId, String callbackParam, Long sendUserId);
+    /**
+     * @param templateEventId  消息事件模板
+     * @param map 参数
+     * @param receiverUserIds 接收人
+     * @param callbackParam 回调参数
+     * @return
+     */
+    Result sendInsideMessage(MessageTemplateEventGroupEntity eventGroup,MessageTemplateEventDetailEntity templateEventDetail, Map map, Collection<Long> receiverUserIds, String callbackParam, Long sendUserId);
+
+    void asynSendInsideMessage(MessageTemplateEventGroupEntity eventGroup,MessageTemplateEventDetailEntity templateEventDetail, Map map, Long receiverUserId, String callbackParam,Long sendUserId);
+    void asynSendInsideMessage(MessageTemplateEventGroupEntity eventGroup,MessageTemplateEventDetailEntity templateEventDetail, Map map, Collection<Long> receiverUserIds, String callbackParam,Long sendUserId);
+
+}

+ 31 - 0
java/storlead-message/src/main/java/com/storlead/message/service/InsideMessageSendLogService.java

@@ -0,0 +1,31 @@
+package com.storlead.message.service;
+
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.storlead.frame.mybatis.service.MyBaseService;
+import com.storlead.message.pojo.entity.InsideMessageSendLogEntity;
+import com.storlead.message.pojo.vo.MessageDetailVO;
+import com.storlead.message.pojo.vo.MessageNoReadTotalVO;
+import com.storlead.message.pojo.vo.MessageTypeReadStateVO;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 内部消息人员接收记录表 服务类
+ * </p>
+ *
+ * @author chenkq
+ * @since 2024-04-19
+ */
+public interface InsideMessageSendLogService extends MyBaseService<InsideMessageSendLogEntity> {
+
+    IPage<MessageDetailVO> queryListMessageLog(Page<InsideMessageSendLogEntity> page, Wrapper<InsideMessageSendLogEntity> wrapper);
+
+    MessageNoReadTotalVO countNoReadtotal(Wrapper<InsideMessageSendLogEntity> wrapper);
+
+    List<MessageTypeReadStateVO> getCountNoReadCount(Wrapper<InsideMessageSendLogEntity> wrapper);
+
+
+}

+ 26 - 0
java/storlead-message/src/main/java/com/storlead/message/service/MessageTemplateEventDetailService.java

@@ -0,0 +1,26 @@
+package com.storlead.message.service;
+
+import com.storlead.frame.mybatis.service.MyBaseService;
+import com.storlead.message.pojo.entity.MessageTemplateEventDetailEntity;
+import com.storlead.message.pojo.entity.MessageTemplateEventGroupEntity;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * <p>
+ * 消息模板 服务类
+ * </p>
+ *
+ * @author chenkq
+ * @since 2024-04-19
+ */
+public interface MessageTemplateEventDetailService extends MyBaseService<MessageTemplateEventDetailEntity> {
+
+    void asynSendMessage(MessageTemplateEventGroupEntity eventGroup, Map messageMap);
+
+    void asynSendMessage(MessageTemplateEventGroupEntity eventGroup, Map messageMap, String... args);
+
+    void asynSendMessage(MessageTemplateEventGroupEntity eventGroup, Map messageMap, Set<Long> toUserIds, String... args);
+}

+ 21 - 0
java/storlead-message/src/main/java/com/storlead/message/service/MessageTemplateEventGroupService.java

@@ -0,0 +1,21 @@
+package com.storlead.message.service;
+
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.storlead.frame.mybatis.service.MyBaseService;
+import com.storlead.message.pojo.entity.MessageTemplateEventGroupEntity;
+import com.storlead.message.pojo.vo.MessageTemplateVO;
+
+/**
+ * <p>
+ * 实践规则模板 服务类
+ * </p>
+ *
+ * @author chenkq
+ * @since 2024-04-19
+ */
+public interface MessageTemplateEventGroupService extends MyBaseService<MessageTemplateEventGroupEntity> {
+
+    IPage<MessageTemplateVO> listPage(Page<MessageTemplateEventGroupEntity> page, Wrapper<MessageTemplateEventGroupEntity> wrapper);
+}

+ 19 - 0
java/storlead-message/src/main/java/com/storlead/message/service/UserMessageNoticeConfigService.java

@@ -0,0 +1,19 @@
+package com.storlead.message.service;
+
+import com.storlead.message.entity.UserMessageNoticeConfigEntity;
+import com.storlead.frame.mybatis.service.MyBaseService;
+
+import java.util.Set;
+
+/**
+ * <p>
+ * 消息开关配置 服务类
+ * </p>
+ *
+ * @author chenkq
+ * @since 2025-04-25
+ */
+public interface UserMessageNoticeConfigService extends MyBaseService<UserMessageNoticeConfigEntity> {
+
+    Set<Long> checkUserNoticeConfig(Set<Long> ids,Long templateId,String messageType);
+}

+ 23 - 0
java/storlead-message/src/main/java/com/storlead/message/service/WechatMessageService.java

@@ -0,0 +1,23 @@
+package com.storlead.message.service;
+
+import com.storlead.frame.core.assemble.Result;
+import com.storlead.message.pojo.entity.MessageTemplateEventDetailEntity;
+import org.springframework.stereotype.Component;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+public interface WechatMessageService {
+
+    /**
+     * @param eventDetail  短信模板
+     * @param map 参数
+     * @param receiverUserIds 接收人
+     * @param callbackParam 回调参数
+     * @return
+     */
+    Result sendWechatMessage(MessageTemplateEventDetailEntity eventDetail, Map map, Collection<Long> receiverUserIds, String callbackParam);
+
+    Result sendWechatMessage(MessageTemplateEventDetailEntity eventDetail, Map map, Collection<Long> receiverUserIds, String callbackParam,String appCode);
+}

+ 130 - 0
java/storlead-message/src/main/java/com/storlead/message/service/impl/InsideMessageRecordServiceImpl.java

@@ -0,0 +1,130 @@
+package com.storlead.message.service.impl;
+
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.storlead.common.util.HtmlUtils;
+import com.storlead.frame.core.assemble.Result;
+import com.storlead.frame.enums.ErrorMsgCode;
+import com.storlead.frame.mybatis.service.impl.MyBaseServiceImpl;
+import com.storlead.message.pojo.entity.InsideMessageRecordEntity;
+import com.storlead.message.mapper.InsideMessageRecordMapper;
+import com.storlead.message.pojo.entity.InsideMessageSendLogEntity;
+import com.storlead.message.pojo.entity.MessageTemplateEventDetailEntity;
+import com.storlead.message.pojo.entity.MessageTemplateEventGroupEntity;
+import com.storlead.message.service.InsideMessageRecordService;
+import com.storlead.message.service.InsideMessageSendLogService;
+import com.storlead.message.service.MessageTemplateEventGroupService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * <p>
+ * 系统内部消息 服务实现类
+ * </p>
+ *
+ * @author chenkq
+ * @since 2024-04-19
+ */
+@Service
+public class InsideMessageRecordServiceImpl extends MyBaseServiceImpl<InsideMessageRecordMapper, InsideMessageRecordEntity> implements InsideMessageRecordService {
+
+    @Override
+    public Map getOldMapDataById(String table,String fieldColumn,String id ) {
+        return this.baseMapper.selectOldById(table,fieldColumn,Long.valueOf(id));
+    }
+
+    @Value("${domainname}")
+    private  String domainname;
+
+    @Autowired
+    private MessageTemplateEventGroupService templateService;
+
+    @Autowired
+    private InsideMessageSendLogService insideMessageSendLogService;
+
+    @Override
+    public Result sendInsideMessage(MessageTemplateEventGroupEntity eventGroup,MessageTemplateEventDetailEntity templateEventDetail, Map map, Long receiverUserId, String callbackParam, Long sendUserId) {
+        return sendInsideMessage(eventGroup,templateEventDetail,map, Arrays.asList(receiverUserId),callbackParam,sendUserId);
+    }
+
+    @Override
+    public Result sendInsideMessage(MessageTemplateEventGroupEntity eventGroup,MessageTemplateEventDetailEntity templateEventDetail, Map map, Collection<Long> receiverUserIds, String callbackParam, Long sendUserId) {
+
+        String domain = this.domainname;
+
+        MessageTemplateEventDetailEntity templateEntity = templateEventDetail;
+        if (Objects.isNull(templateEntity)) {
+            return Result.error(ErrorMsgCode.WECHAT_SMS_100006);
+        }
+        if (CollectionUtils.isEmpty(receiverUserIds)) {
+            return Result.error(ErrorMsgCode.WECHAT_SMS_100008);
+        }
+        String title = templateEntity.getMessageTitle();
+        title = title.replace("<br>","\n");
+        String content = templateEntity.getMessageCentent();
+        if (Objects.isNull(content)) {
+            content = templateEntity.getMessageTitle();
+        }
+        Iterator<Map.Entry< Integer, String >> iterator = map.entrySet().iterator();
+        while (iterator.hasNext()) {
+            Map.Entry< Integer, String > entry = iterator.next();
+            if (Objects.nonNull(entry)) {
+                String value =  HtmlUtils.userContent(entry.getValue());
+                content = content.replace("${"+entry.getKey()+"}$",value);
+                title = title.replace("${"+entry.getKey()+"}$",value);
+            }
+        }
+        content = content.replace("<br>","\n");
+        String router = domain +""+ (StrUtil.isNotBlank(templateEntity.getCallbackUrl()) ? templateEntity.getCallbackUrl() : map.get("callbackUrl"));
+        if (Objects.nonNull(router)) {
+            Object jump = Objects.nonNull(map) ? map.get("jump") : null;
+            Object id = Objects.nonNull(map) ? map.get("id") : null;
+            if (Objects.nonNull(id)) {
+                router = router.replace("${id}$",id.toString());
+            } else {
+                router = router.replace("${id}$","");
+            }
+            if (Objects.nonNull(jump)) {
+                router = router.replace("${jump}$",jump.toString());
+            } else {
+                router = router.replace("${jump}$","");
+            }
+        }
+
+        log.error("asynSendWechatMessage - senderUserId3------------"+sendUserId);
+        if (Objects.isNull(sendUserId)) {
+            sendUserId = 0L;
+        }
+
+        InsideMessageRecordEntity entity = new InsideMessageRecordEntity(title,content,templateEntity.getTemplateIcon(),templateEntity.getTemplateTag(),router,sendUserId,1,eventGroup.getTemplateServiceType());
+        entity.setCreateBy(sendUserId);
+        entity.setUpdateBy(sendUserId);
+        saveOrUpdate(entity);
+
+        List<InsideMessageSendLogEntity> messageSendLogs = new ArrayList<>();
+        for (Long receiverUserId : receiverUserIds) {
+            InsideMessageSendLogEntity messageSendLog = new InsideMessageSendLogEntity(entity.getId(),receiverUserId,0,1,entity.getMessageType());
+            messageSendLog.setCreateBy(sendUserId);
+            messageSendLog.setUpdateBy(sendUserId);
+            messageSendLogs.add(messageSendLog);
+        }
+        insideMessageSendLogService.saveOrUpdateBatch(messageSendLogs);
+        return Result.ok();
+    }
+
+    @Override
+    public void asynSendInsideMessage(MessageTemplateEventGroupEntity eventGroup,MessageTemplateEventDetailEntity templateEventDetail, Map map, Long receiverUserId, String callbackParam,Long sendUserId) {
+        sendInsideMessage(eventGroup,templateEventDetail,map,Arrays.asList(receiverUserId),callbackParam,sendUserId);
+    }
+
+    @Override
+    public void asynSendInsideMessage(MessageTemplateEventGroupEntity eventGroup,MessageTemplateEventDetailEntity templateEventDetail, Map map, Collection<Long> receiverUserIds, String callbackParam,Long sendUserId) {
+        sendInsideMessage(eventGroup,templateEventDetail,map,receiverUserIds,callbackParam,sendUserId);
+    }
+}

+ 43 - 0
java/storlead-message/src/main/java/com/storlead/message/service/impl/InsideMessageSendLogServiceImpl.java

@@ -0,0 +1,43 @@
+package com.storlead.message.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.storlead.frame.mybatis.service.impl.MyBaseServiceImpl;
+import com.storlead.message.pojo.entity.InsideMessageSendLogEntity;
+import com.storlead.message.pojo.vo.MessageDetailVO;
+import com.storlead.message.pojo.vo.MessageNoReadTotalVO;
+import com.storlead.message.mapper.InsideMessageSendLogMapper;
+import com.storlead.message.pojo.vo.MessageTypeReadStateVO;
+import com.storlead.message.service.InsideMessageSendLogService;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 内部消息人员接收记录表 服务实现类
+ * </p>
+ *
+ * @author chenkq
+ * @since 2024-04-19
+ */
+@Service
+public class InsideMessageSendLogServiceImpl extends MyBaseServiceImpl<InsideMessageSendLogMapper, InsideMessageSendLogEntity> implements InsideMessageSendLogService {
+
+    @Override
+    public IPage<MessageDetailVO> queryListMessageLog(Page<InsideMessageSendLogEntity> page, Wrapper<InsideMessageSendLogEntity> wrapper) {
+        return this.baseMapper.pageListMessageLog(page,wrapper);
+    }
+
+    @Override
+    public MessageNoReadTotalVO countNoReadtotal(Wrapper<InsideMessageSendLogEntity> wrapper) {
+        return this.baseMapper.countNoReadNumber(wrapper);
+    }
+
+    @Override
+    public List<MessageTypeReadStateVO> getCountNoReadCount(Wrapper<InsideMessageSendLogEntity> wrapper) {
+        return this.baseMapper.countNoReadCount(wrapper);
+    }
+
+}

+ 165 - 0
java/storlead-message/src/main/java/com/storlead/message/service/impl/MessageService.java

@@ -0,0 +1,165 @@
+package com.storlead.message.service.impl;
+
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.googlecode.aviator.AviatorEvaluator;
+import com.googlecode.aviator.Expression;
+import com.googlecode.aviator.runtime.function.AbstractFunction;
+import com.googlecode.aviator.runtime.type.AviatorBoolean;
+import com.googlecode.aviator.runtime.type.AviatorObject;
+import com.storlead.common.aviator.MapKeyExistsFunction;
+import com.storlead.frame.auth.util.LoginUserUtil;
+import com.storlead.message.pojo.entity.MessageTemplateEventGroupEntity;
+import com.storlead.message.service.InsideMessageRecordService;
+import com.storlead.message.service.MessageTemplateEventDetailService;
+import com.storlead.message.service.MessageTemplateEventGroupService;
+import lombok.extern.log4j.Log4j2;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+import com.googlecode.aviator.utils.Reflector;
+import javax.annotation.Resource;
+import java.util.*;
+
+import com.storlead.common.aviator.EqualsFunction;
+/**
+ * @program: sp-sales-platform
+ * @description:
+ * @author: chenkq
+ * @create: 2024-04-23 11:34
+ */
+
+@Log4j2
+@Service
+public class MessageService {
+
+    @Resource
+    private InsideMessageRecordService messageRecordService;
+
+    @Resource
+    private MessageTemplateEventGroupService eventGroupService;
+
+    @Resource
+    private MessageTemplateEventDetailService eventDetailService;
+
+
+    // 客户
+    // 商机
+//    public void autoMatchEventSendMessage(Map beforeMap,Map afterMap,String templateService,String... sendType) {
+//
+//    }
+
+
+
+    public Map getOldMapData(Map sqlmap,String fieldColumn,String table){
+        try {
+            Map<String,Object> var1 = messageRecordService.getOldMapDataById(table,fieldColumn,sqlmap.get("id").toString());
+            Map<String,Object> vargs = new HashMap<>();
+            if (!CollectionUtils.isEmpty(var1)) {
+                for (Map.Entry<String, Object> entry : var1.entrySet()) {
+                    String camelCaseKey= StrUtil.toCamelCase("before"+entry.getKey());
+                    vargs.put(camelCaseKey,entry.getValue());
+                }
+            }
+            return vargs;
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+//    public void autoMatchEventSendMessage(Map beforeMap,Map afterMap,String templateService) {
+//        autoMatchEventSendMessage(beforeMap,afterMap,templateService,"site","wecom","sms","mail");
+//    }
+    public void autoMatchEventSendMessage(Map beforeMap,Map afterMap,String templateService) {
+
+        autoMatchEventSendMessage(beforeMap ,afterMap,templateService,"site","wecom","sms","mail");
+    }
+
+    public void autoMatchEventSendMessage(Map<String,Object> messageMap, String templateServiceType, String eventCode, Set<Long> toUserIds, String... args) {
+        try {
+            LambdaQueryWrapper<MessageTemplateEventGroupEntity> templateEventWrapper = new LambdaQueryWrapper<>();
+            templateEventWrapper.eq(MessageTemplateEventGroupEntity::getTemplateServiceType,templateServiceType);
+            templateEventWrapper.eq(MessageTemplateEventGroupEntity::getEventCode,eventCode);
+            templateEventWrapper.last(" limit 1");
+            MessageTemplateEventGroupEntity  eventGroup = eventGroupService.getOne(templateEventWrapper);
+            if (Objects.isNull(eventGroup)) {
+                return;
+            }
+            asynSendMessage(eventGroup,messageMap,toUserIds,args);
+        }catch (Exception e) {
+            log.error("autoMatchEventSendMessage --- error",e);
+        }
+    }
+
+    /**
+     * 自动匹配消息事件规则
+     * @param updateDataMap
+     * @param oldDataMap
+     * @param templateService
+     */
+    public void autoMatchEventSendMessage(Map beforeMap,Map afterMap,String templateService,String... args) {
+        HashMap<String,Object> vargs = new HashMap();
+        if (!CollectionUtils.isEmpty(beforeMap)) {
+            vargs.putAll(beforeMap);
+        }
+        vargs.put("beforeMap",beforeMap);
+        if (!CollectionUtils.isEmpty(afterMap)) {
+            vargs.putAll(afterMap);
+        }
+        vargs.put("afterMap",afterMap);
+        Map<String, Object> env = new HashMap<>();
+        env.put("map", vargs);
+        LambdaQueryWrapper<MessageTemplateEventGroupEntity> templateEventWrapper = new LambdaQueryWrapper<>();
+        templateEventWrapper.eq(MessageTemplateEventGroupEntity::getTemplateServiceCode,templateService);
+        List<MessageTemplateEventGroupEntity>  eventGroups = eventGroupService.list(templateEventWrapper);
+        if (CollectionUtils.isEmpty(eventGroups)) {
+            return;
+        }
+        for(MessageTemplateEventGroupEntity eventGroup : eventGroups) {
+            if (StrUtil.isNotBlank(eventGroup.getEventRuleScript())) {
+                AviatorEvaluator.addFunction(new MapKeyExistsFunction());
+                String expression = eventGroup.getEventRuleScript();
+                Expression exp = AviatorEvaluator.compile(expression);
+                Boolean rst = (Boolean)exp.execute(env);
+                if (rst) {
+                    log.info("-------------匹配到消息事件规则:"+eventGroup.getEventRuleScript());
+                    asynSendMessage(eventGroup,vargs,null,args);
+                }
+            }
+        }
+    }
+
+    public void sendMessage(MessageTemplateEventGroupEntity eventGroup, Map messageMap){
+        eventDetailService.asynSendMessage(eventGroup,messageMap);
+    }
+
+    public void asynSendMessage(MessageTemplateEventGroupEntity eventGroup, Map messageMap, Set<Long> toUserIds,String... args){
+        eventDetailService.asynSendMessage(eventGroup,messageMap,toUserIds,args);
+    }
+
+
+
+    public static void main(String[] args) {
+        // 注册自定义函数
+        AviatorEvaluator.addFunction(new MapKeyExistsFunction());
+        // 创建一个Map对象并添加一些键值对
+        Map<String, Object> map = new HashMap<>();
+        map.put("age", 25);
+        map.put("city", "New York");
+
+        // 编写表达式判断Map中是否不包含"userName"键
+        String expression = "!containsKey(map,'id')";
+
+        // 编译表达式
+        Expression compiledExp = AviatorEvaluator.compile(expression);
+
+        // 创建环境变量,将map传入
+        Map<String, Object> env = new HashMap<>();
+        env.put("map", map);
+
+        // 计算表达式
+        Boolean result = (Boolean) compiledExp.execute(env);
+
+        // 输出结果
+        System.out.println("Map中是否不包含'userName'键: " + result);
+    }
+}

+ 255 - 0
java/storlead-message/src/main/java/com/storlead/message/service/impl/MessageTemplateEventDetailServiceImpl.java

@@ -0,0 +1,255 @@
+package com.storlead.message.service.impl;
+
+import cn.hutool.core.util.StrUtil;
+import com.alibaba.ttl.TtlRunnable;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.storlead.common.util.HtmlUtils;
+import com.storlead.common.util.encryptor.AccessKeyEncryptor;
+import com.storlead.frame.auth.util.LoginUserUtil;
+import com.storlead.frame.core.assemble.Result;
+import com.storlead.frame.enums.ErrorMsgCode;
+import com.storlead.frame.mybatis.service.impl.MyBaseServiceImpl;
+import com.storlead.frame.thread.ThreadPoolUtil;
+import com.storlead.message.pojo.entity.MessageTemplateEventDetailEntity;
+import com.storlead.message.mapper.MessageTemplateEventDetailMapper;
+import com.storlead.message.pojo.entity.MessageTemplateEventGroupEntity;
+import com.storlead.message.service.InsideMessageRecordService;
+import com.storlead.message.service.MessageTemplateEventDetailService;
+import com.storlead.message.service.UserMessageNoticeConfigService;
+import com.storlead.message.service.WechatMessageService;
+import com.storlead.sales.mail.entity.SmtpPopSettingsEntity;
+import com.storlead.sales.mail.pojo.SendMailDTO;
+import com.storlead.sales.mail.service.EmailsService;
+import com.storlead.sales.mail.service.SmtpPopSettingsService;
+import com.storlead.user.pojo.entity.DeptEntity;
+import com.storlead.user.pojo.entity.UserEntity;
+import com.storlead.user.service.IDepartService;
+import com.storlead.user.service.IUserService;
+import org.apache.catalina.User;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+
+import javax.annotation.Resource;
+import java.lang.reflect.Array;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * <p>
+ * 消息模板 服务实现类
+ * </p>
+ *
+ * @author chenkq
+ * @since 2024-04-19
+ */
+@Service
+public class MessageTemplateEventDetailServiceImpl extends MyBaseServiceImpl<MessageTemplateEventDetailMapper, MessageTemplateEventDetailEntity> implements MessageTemplateEventDetailService {
+
+    @Value("${domainname}")
+    private  String domainname;
+
+    @Resource
+    private InsideMessageRecordService insideMessageRecordService;
+
+    @Resource
+    private SmtpPopSettingsService smtpPopSettingsService;
+
+    @Resource
+    private EmailsService emailsService;
+
+    @Resource
+    private WechatMessageService  wechatMessageService;
+
+    @Resource
+    private IUserService userService;
+
+    @Resource
+    private IDepartService departService;
+
+    @Resource
+    private UserMessageNoticeConfigService userMessageNoticeConfigService;
+
+
+    @Override
+    public void asynSendMessage(MessageTemplateEventGroupEntity eventGroup, Map messageMap) {
+        asynSendMessage(eventGroup,messageMap,"site","wecom","sms","mail");
+    }
+    @Override
+    public void asynSendMessage(MessageTemplateEventGroupEntity eventGroup, Map messageMap, String... args) {
+        asynSendMessage(eventGroup,messageMap,null,args);
+    }
+
+    @Override
+    public void asynSendMessage(MessageTemplateEventGroupEntity eventGroup, Map messageMap,Set<Long> toUserIds,String... rmindArgs) {
+
+        String domain = this.domainname;
+        Long senderUserId = LoginUserUtil.getCurrentUserId();
+        if (Objects.isNull(senderUserId)) {
+            senderUserId = 1L;
+        }
+        Set<Long> receiverUserIds = new HashSet<>();
+        if (!CollectionUtils.isEmpty(toUserIds)) {
+            receiverUserIds.addAll(toUserIds);
+        }
+       log.error("asynSendWechatMessage - senderUserId1 ----------- " +LoginUserUtil.getCurrentUserId());
+
+
+
+        // 当前用户
+        // 创建人 createBy
+        // 归属人 ownerBy
+        // 部门负责人 deptManagerId
+        // 部门负责人 deptManagerId
+        String noticeAppCode = eventGroup.getNoticeAppCode();
+        log.error("asynSendWechatMessage - getNoticeAppCode ----------- " +noticeAppCode);
+
+        String receiverKey =  eventGroup.getReceiverKey();
+        if (StrUtil.isNotBlank(receiverKey)) {
+            List<String> receiverls = Arrays.asList(receiverKey.split(","));
+            //  deptManagerId,ownerBy,createBy
+            // 创建人、归属人、部门负责人
+            if (receiverls.contains("deptManagerId")) {
+                if (messageMap.containsKey("ownerBy")) {
+                    Long ownerBy = (Long) messageMap.get("ownerBy");
+                    Long deptManagerId =  getDeptManagerIdByUser(ownerBy);
+                    if (Objects.nonNull(deptManagerId) && !deptManagerId.equals(ownerBy)) {
+                        receiverUserIds.add(deptManagerId);
+                    }
+                }
+            }
+            else if (!CollectionUtils.isEmpty(receiverls)) {
+                for (String receiverkey : receiverls) {
+                    if (messageMap.containsKey(receiverkey)) {
+                        Object receiver = messageMap.get(receiverkey);
+                        if (Objects.nonNull(receiver)) {
+                            if (receiver instanceof String) {
+                                receiverUserIds.addAll(Arrays.asList(receiver.toString().split(",")).stream().map(Long::parseLong).collect(Collectors.toSet()));
+                            } else if (receiver instanceof Long) {
+                                receiverUserIds.add((Long) receiver);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        if (Objects.nonNull(senderUserId) && !CollectionUtils.isEmpty(receiverUserIds) && !receiverUserIds.equals(Set.of(1L))) {
+            receiverUserIds.remove(senderUserId);
+        }
+        if (CollectionUtils.isEmpty(receiverUserIds)) {
+            return;
+        }
+        Long finalSenderUserId = senderUserId;
+        MessageTemplateEventGroupEntity newEventGroup = new MessageTemplateEventGroupEntity();
+        BeanUtils.copyProperties(eventGroup,newEventGroup);
+        Runnable ttlRunnable = TtlRunnable.get(new Runnable() {
+            @Override
+            public void run() {
+
+                List<String> rmindTypes =  Arrays.asList(rmindArgs);
+                List<MessageTemplateEventDetailEntity> eventDetaills = list(new LambdaQueryWrapper<MessageTemplateEventDetailEntity>().eq(MessageTemplateEventDetailEntity::getTemplateEventId,eventGroup.getId()));
+
+                if (CollectionUtils.isEmpty(receiverUserIds)) {
+                    return;
+                }
+                for (MessageTemplateEventDetailEntity eventDetail : eventDetaills) {
+                    /**
+                     * 站内
+                     */
+                    if (eventDetail.getTemplateDetailType().equals("site")  && eventDetail.getEnabled() && rmindTypes.contains("site")) {
+                        Set<Long> toUserIds =  userMessageNoticeConfigService.checkUserNoticeConfig(receiverUserIds,newEventGroup.getId(),"site");
+                        insideMessageRecordService.sendInsideMessage(newEventGroup,eventDetail,messageMap,toUserIds, eventDetail.getCallbackUrl(), finalSenderUserId);
+                    }
+                    /**
+                     * 企业微信
+                     */
+                    if (eventDetail.getTemplateDetailType().equals("wecom") && eventDetail.getEnabled() && rmindTypes.contains("wecom")) {
+                        Set<Long> toUserIds =  userMessageNoticeConfigService.checkUserNoticeConfig(receiverUserIds,newEventGroup.getId(),"wecom");
+                        if (StrUtil.isNotBlank(noticeAppCode)) {
+                            wechatMessageService.sendWechatMessage(eventDetail,messageMap,toUserIds,eventDetail.getCallbackUrl(),noticeAppCode);
+                        } else {
+                            wechatMessageService.sendWechatMessage(eventDetail,messageMap,toUserIds,eventDetail.getCallbackUrl());
+                        }
+                    }
+                    /**
+                     * 短信
+                     */
+                    if (eventDetail.getTemplateDetailType().equals("sms")  && eventDetail.getEnabled() && rmindTypes.contains("sms")) {
+
+                    }
+                    /**
+                     * 邮件
+                     */
+                    if (eventDetail.getTemplateDetailType().equals("mail")  && eventDetail.getEnabled() && rmindTypes.contains("mail")) {
+                        Set<Long> toUserIds =  userMessageNoticeConfigService.checkUserNoticeConfig(receiverUserIds,newEventGroup.getId(),"mail");
+                        if (CollectionUtils.isEmpty(toUserIds)) {
+                            continue;
+                        }
+                        SmtpPopSettingsEntity sendSmtpPops = smtpPopSettingsService.getSystemSmtpPop(1L);
+                        if (Objects.isNull(sendSmtpPops)) {
+                            continue;
+                        }
+                        List<SmtpPopSettingsEntity> receiverSmtpPops = smtpPopSettingsService.getDefaultSmtpPopls(receiverUserIds);
+                        if (CollectionUtils.isEmpty(receiverSmtpPops)) {
+                            continue;
+                        }
+                        AccessKeyEncryptor accessKeyEncryptor = AccessKeyEncryptor.getAccessKeyEncryptor("");
+                        String pass = accessKeyEncryptor.decrypt(sendSmtpPops.getEmailPassword());
+                        sendSmtpPops.setEmailPassword(pass);
+
+                        MessageTemplateEventDetailEntity templateEntity = eventDetail;
+                        String title = templateEntity.getMessageTitle();
+                        title = title.replace("<br>","\n");
+                        String content = templateEntity.getMessageCentent();
+
+                        Iterator <Map.Entry< Integer, String >> iterator = messageMap.entrySet().iterator();
+                        while (iterator.hasNext()) {
+                            Map.Entry< Integer, String > entry = iterator.next();
+                            String value =  HtmlUtils.userContent(entry.getValue());
+                            content = content.replace("${"+entry.getKey()+"}$",value);
+                        }
+                        content = content.replace("<br>","\n");
+                        String router = domain +""+ (StrUtil.isNotBlank(templateEntity.getCallbackUrl()) ? templateEntity.getCallbackUrl() : messageMap.get("callbackUrl"));
+                        Object id = Objects.nonNull(messageMap) ? messageMap.get("id") : null;
+                        Object jump = Objects.nonNull(messageMap) ? messageMap.get("jump") : null;
+                        if (StrUtil.isNotBlank(router)) {
+                            if (Objects.nonNull(id)) {
+                                router = router.replace("${id}$",id.toString());
+                            } else {
+                                router = router.replace("${id}$","");
+                            }
+                            if (Objects.nonNull(jump)) {
+                                router = router.replace("${jump}$",jump.toString());
+                            } else {
+                                router = router.replace("${jump}$","");
+                            }
+                        }
+                        List<String> recipientls = receiverSmtpPops.stream().map(SmtpPopSettingsEntity::getEmailAddress).collect(Collectors.toList());
+                        SendMailDTO dto = new SendMailDTO();
+                        dto.setSubject(title);
+                        String routers = "</p><p><a href='"+router+"'>查看</a></p>";
+                        dto.setContent(content+""+routers);
+                        dto.setRecipientls(recipientls);
+                        emailsService.sendEmail(dto,sendSmtpPops);
+                    }
+                }
+            }
+        });
+        ThreadPoolUtil.execute(ttlRunnable);
+    }
+
+    /**
+     * 根据用户id 获取用户部门负责人
+     */
+    public Long getDeptManagerIdByUser(Long userId) {
+        UserEntity user =  userService.getById(userId);
+        if (Objects.nonNull(user) && user.getDeptId() != null) {
+           DeptEntity dept = departService.getById(user.getDeptId());
+           if (Objects.nonNull(dept)) {
+               return dept.getManagerId();
+           }
+        }
+        return null;
+    }
+}

+ 30 - 0
java/storlead-message/src/main/java/com/storlead/message/service/impl/MessageTemplateEventGroupServiceImpl.java

@@ -0,0 +1,30 @@
+package com.storlead.message.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+
+import com.storlead.frame.mybatis.service.impl.MyBaseServiceImpl;
+import com.storlead.message.pojo.entity.InsideMessageSendLogEntity;
+import com.storlead.message.pojo.entity.MessageTemplateEventGroupEntity;
+import com.storlead.message.mapper.MessageTemplateEventGroupMapper;
+import com.storlead.message.pojo.vo.MessageDetailVO;
+import com.storlead.message.pojo.vo.MessageTemplateVO;
+import com.storlead.message.service.MessageTemplateEventGroupService;
+import org.springframework.stereotype.Service;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+/**
+ * <p>
+ * 实践规则模板 服务实现类
+ * </p>
+ *
+ * @author chenkq
+ * @since 2024-04-19
+ */
+@Service
+public class MessageTemplateEventGroupServiceImpl extends MyBaseServiceImpl<MessageTemplateEventGroupMapper, MessageTemplateEventGroupEntity> implements MessageTemplateEventGroupService {
+
+    @Override
+    public IPage<MessageTemplateVO> listPage(Page<MessageTemplateEventGroupEntity> page, Wrapper<MessageTemplateEventGroupEntity> wrapper) {
+        return this.baseMapper.selectMessageTemplateList(page,wrapper);
+    }
+}

+ 56 - 0
java/storlead-message/src/main/java/com/storlead/message/service/impl/UserMessageNoticeConfigServiceImpl.java

@@ -0,0 +1,56 @@
+package com.storlead.message.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.storlead.common.constant.CommonConstant;
+import com.storlead.message.entity.UserMessageNoticeConfigEntity;
+import com.storlead.message.mapper.UserMessageNoticeConfigMapper;
+import com.storlead.message.service.UserMessageNoticeConfigService;
+import com.storlead.frame.mybatis.service.impl.MyBaseServiceImpl;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * <p>
+ * 消息开关配置 服务实现类
+ * </p>
+ *
+ * @author chenkq
+ * @since 2025-04-25
+ */
+@Service
+public class UserMessageNoticeConfigServiceImpl extends MyBaseServiceImpl<UserMessageNoticeConfigMapper, UserMessageNoticeConfigEntity> implements UserMessageNoticeConfigService {
+
+    @Override
+    public Set<Long> checkUserNoticeConfig(Set<Long> userIds,Long templateId,String messageType) {
+        Set<Long> newToUser = new HashSet<>(userIds);
+        try {
+            if (CollectionUtils.isEmpty(newToUser)) {
+                return newToUser;
+            }
+            LambdaQueryWrapper<UserMessageNoticeConfigEntity> userMessageConfigW = new LambdaQueryWrapper<>();
+            userMessageConfigW.eq(UserMessageNoticeConfigEntity::getTemplateEventId,templateId);
+            userMessageConfigW.eq(UserMessageNoticeConfigEntity::getTemplateDetailType,messageType);
+            userMessageConfigW.in(UserMessageNoticeConfigEntity::getOwnerBy,userIds);
+            userMessageConfigW.in(UserMessageNoticeConfigEntity::getIsDelete, CommonConstant.DEL_FLAG_0);
+            userMessageConfigW.in(UserMessageNoticeConfigEntity::getEnabled, Integer.valueOf(0));
+            List<UserMessageNoticeConfigEntity> ls = this.list(userMessageConfigW);
+
+            if (!CollectionUtils.isEmpty(ls)) {
+                Set<Long> rmUserIds = ls.stream().map(UserMessageNoticeConfigEntity::getOwnerBy).collect(Collectors.toSet());
+                if (!CollectionUtils.isEmpty(rmUserIds)) {
+                    newToUser.removeAll(rmUserIds);
+                }
+            }
+            return newToUser;
+        } catch (Exception e) {
+            log.error("checkUserNoticeConfig --- error -- ",e);
+            return newToUser;
+        }
+
+    }
+}

+ 167 - 0
java/storlead-message/src/main/java/com/storlead/message/service/impl/WechatMessageServiceImpl.java

@@ -0,0 +1,167 @@
+package com.storlead.message.service.impl;
+
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.storlead.common.util.HtmlUtils;
+import com.storlead.frame.core.assemble.Result;
+import com.storlead.frame.enums.ErrorMsgCode;
+import com.storlead.message.pojo.entity.MessageTemplateEventDetailEntity;
+import com.storlead.message.service.WechatMessageService;
+import com.storlead.user.pojo.entity.UserEntity;
+import com.storlead.user.service.IUserService;
+import com.storlead.user.service.impl.UserServiceImpl;
+import com.storlead.wx.service.CorpWeChatService;
+import lombok.extern.log4j.Log4j2;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+
+import javax.annotation.Resource;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * @program: sp-sales-platform
+ * @description:
+ * @author: chenkq
+ * @create: 2024-04-26 10:14
+ */
+@Log4j2
+@Service
+public class WechatMessageServiceImpl implements WechatMessageService {
+
+
+    @Resource
+    private IUserService userService;
+
+    @Autowired
+    private CorpWeChatService corpWeChatService;
+
+    /**
+     * @param eventDetail  短信模板
+     * @param map 参数
+     * @param receiverUserIds 接收人
+     * @param callbackParam 回调参数
+     * @return
+     */
+    @Override
+    public Result sendWechatMessage(MessageTemplateEventDetailEntity eventDetail, Map map, Collection<Long> receiverUserIds,String callbackParam){
+        //发送企业微信
+        try {
+            MessageTemplateEventDetailEntity templateEntity = eventDetail;
+            if (Objects.isNull(templateEntity)) {
+                return Result.error(ErrorMsgCode.WECHAT_SMS_100006);
+            }
+            if (CollectionUtils.isEmpty(receiverUserIds)) {
+                return Result.error(ErrorMsgCode.WECHAT_SMS_100008);
+            }
+            String title = templateEntity.getMessageTitle();
+            title = title.replace("<br>","\n");
+            Object titleRemark = Objects.nonNull(map) ? map.get("titleRemark") : null;
+            if (Objects.nonNull(titleRemark)) {
+                title = title.replace("${titleRemark}$",titleRemark.toString());
+            }
+
+            String content = templateEntity.getMessageCentent();
+
+            Iterator <Map.Entry< Integer, String >> iterator = map.entrySet().iterator();
+            while (iterator.hasNext()) {
+                Map.Entry< Integer, String > entry = iterator.next();
+                String value =  HtmlUtils.userContent(entry.getValue());
+                content = content.replace("${"+entry.getKey()+"}$",value);
+            }
+            content = content.replace("<br>","\n");
+            String router =""+ (StrUtil.isNotBlank(templateEntity.getCallbackUrl()) ? templateEntity.getCallbackUrl() : map.get("callbackUrl"));
+            if (StrUtil.isNotBlank(router)) {
+                Object id = Objects.nonNull(map) ? map.get("id") : null;
+                Object jump = Objects.nonNull(map) ? map.get("jump") : null;
+                if (StrUtil.isNotBlank(router)) {
+                    if (Objects.nonNull(id)) {
+                        router = router.replace("${id}$",id.toString());
+                    } else {
+                        router = router.replace("${id}$","");
+                    }
+                    if (Objects.nonNull(jump)) {
+                        router = router.replace("${jump}$",jump.toString());
+                    } else {
+                        router = router.replace("${jump}$","");
+                    }
+                }
+            }
+            List<UserEntity> userEntityList = userService.getUserListByStaffIds(receiverUserIds);
+            if (CollectionUtils.isEmpty(userEntityList)) {
+                return Result.error(ErrorMsgCode.WECHAT_SMS_100009);
+            }
+            List<String> wxUseridList = userEntityList.stream().map(e->e.getXworkUserId()).collect(Collectors.toList());
+            Set<String> userids = new HashSet<>(wxUseridList);
+
+            if ("card".equals(eventDetail.getTemplateMessageView())) {
+                corpWeChatService.sendTextCardMsgByUserId(title,content,userids,router);
+            } else {
+                corpWeChatService.sendTextMsg(content,userids,null,null);
+            }
+        } catch (Exception e) {
+            log.error("目标提醒发送企业微信失败 错误为 " + e);
+            return Result.error(ErrorMsgCode.WECHAT_SMS_100007.getCode(),e.getMessage());
+        }
+        return Result.ok();
+    }
+
+    @Override
+    public Result sendWechatMessage(MessageTemplateEventDetailEntity eventDetail, Map map, Collection<Long> receiverUserIds, String callbackParam, String appCode) {
+        //发送企业微信
+        try {
+            MessageTemplateEventDetailEntity templateEntity = eventDetail;
+            if (Objects.isNull(templateEntity)) {
+                return Result.error(ErrorMsgCode.WECHAT_SMS_100006);
+            }
+            if (CollectionUtils.isEmpty(receiverUserIds)) {
+                return Result.error(ErrorMsgCode.WECHAT_SMS_100008);
+            }
+            String title = templateEntity.getMessageTitle();
+            title = title.replace("<br>","\n");
+            Object titleRemark = Objects.nonNull(map) ? map.get("titleRemark") : null;
+            if (Objects.nonNull(titleRemark)) {
+                title = title.replace("${titleRemark}$",titleRemark.toString());
+            }
+            String content = templateEntity.getMessageCentent();
+            Iterator <Map.Entry< Integer, String >> iterator = map.entrySet().iterator();
+            while (iterator.hasNext()) {
+                Map.Entry< Integer, String > entry = iterator.next();
+                String value =  HtmlUtils.userContent(entry.getValue());
+                content = content.replace("${"+entry.getKey()+"}$",value);
+            }
+            content = content.replace("<br>","\n");
+            String router =""+ (StrUtil.isNotBlank(templateEntity.getCallbackUrl()) ? templateEntity.getCallbackUrl() : map.get("callbackUrl"));
+            if (StrUtil.isNotBlank(router)) {
+                Object id = Objects.nonNull(map) ? map.get("id") : null;
+                Object jump = Objects.nonNull(map) ? map.get("jump") : null;
+                if (StrUtil.isNotBlank(router)) {
+                    if (Objects.nonNull(id)) {
+                        router = router.replace("${id}$",id.toString());
+                    } else {
+                        router = router.replace("${id}$","");
+                    }
+                    if (Objects.nonNull(jump)) {
+                        router = router.replace("${jump}$",jump.toString());
+                    } else {
+                        router = router.replace("${jump}$","");
+                    }
+                }
+            }
+            List<UserEntity> userEntityList = userService.getUserListByStaffIds(receiverUserIds);
+            if (CollectionUtils.isEmpty(userEntityList)) {
+                return Result.error(ErrorMsgCode.WECHAT_SMS_100009);
+            }
+            List<String> wxUseridList = userEntityList.stream().map(e->e.getXworkUserId()).collect(Collectors.toList());
+            Set<String> userids = new HashSet<>(wxUseridList);
+
+                 corpWeChatService.sendTextCardMsgByUserIdByAppCode(title,content,router,userids,null,appCode);
+
+        } catch (Exception e) {
+            log.error("目标提醒发送企业微信失败 错误为 " + e);
+            return Result.error(ErrorMsgCode.WECHAT_SMS_100007.getCode(),e.getMessage());
+        }
+        return Result.ok();
+    }
+}

+ 38 - 0
java/storlead-message/src/main/resources/mapper/InsideMessageRecordMapper.xml

@@ -0,0 +1,38 @@
+<?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="com.storlead.message.mapper.InsideMessageRecordMapper">
+
+        <!-- 通用查询映射结果 -->
+        <resultMap id="BaseResultMap" type="com.storlead.message.pojo.entity.InsideMessageRecordEntity">
+                    <id column="id" property="id" />
+                    <result column="title" property="title" />
+                    <result column="content" property="content" />
+                    <result column="message_icon" property="messageIcon" />
+                    <result column="message_tag" property="messageTag" />
+                    <result column="callback_url" property="callbackUrl" />
+                    <result column="wx_callback_url" property="wxCallbackUrl" />
+                    <result column="send_user_id" property="sendUserId" />
+                    <result column="status" property="status" />
+                    <result column="message_type" property="messageType" />
+                    <result column="message_sub_type" property="messageSubType" />
+                    <result column="timer_send_time" property="timerSendTime" />
+                    <result column="actually_send_time" property="actuallySendTime" />
+                    <result column="create_by" property="createBy" />
+                    <result column="create_time" property="createTime" />
+                    <result column="update_by" property="updateBy" />
+                    <result column="update_time" property="updateTime" />
+                    <result column="enabled" property="enabled" />
+                    <result column="is_delete" property="isDelete" />
+                    <result column="sort" property="sort" />
+        </resultMap>
+
+        <!-- 通用查询结果列 -->
+        <sql id="Base_Column_List">
+            id, title, content, message_icon, message_tag, callback_url, wx_callback_url, send_user_id, status, message_type, message_sub_type, timer_send_time, actually_send_time, create_by, create_time, update_by, update_time, enabled, is_delete, sort
+        </sql>
+
+    <select id="selectOldById" resultType="map">
+        select ${fieldColumn} from ${tableName} where id = #{id}
+    </select>
+
+</mapper>

+ 59 - 0
java/storlead-message/src/main/resources/mapper/InsideMessageSendLogMapper.xml

@@ -0,0 +1,59 @@
+<?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="com.storlead.message.mapper.InsideMessageSendLogMapper">
+
+        <!-- 通用查询映射结果 -->
+        <resultMap id="BaseResultMap" type="com.storlead.message.pojo.entity.InsideMessageSendLogEntity">
+                    <id column="id" property="id" />
+                    <result column="message_id" property="messageId" />
+                    <result column="receiver_user_id" property="receiverUserId" />
+                    <result column="is_read" property="isRead" />
+                    <result column="status" property="status" />
+                    <result column="create_by" property="createBy" />
+                    <result column="create_time" property="createTime" />
+                    <result column="update_by" property="updateBy" />
+                    <result column="update_time" property="updateTime" />
+                    <result column="enabled" property="enabled" />
+                    <result column="is_delete" property="isDelete" />
+                    <result column="sort" property="sort" />
+        </resultMap>
+
+        <!-- 通用查询结果列 -->
+        <sql id="Base_Column_List">
+            id, message_id, receiver_user_id, is_read, status, create_by, create_time, update_by, update_time, enabled, is_delete, sort
+        </sql>
+
+
+    <select id="pageListMessageLog" resultType="com.storlead.message.pojo.vo.MessageDetailVO">
+        SELECT
+            mlog.* ,mr.title,mr.content,mr.message_icon,mr.message_tag,mr.callback_url,send_user_id,us.avatar as photo,us.real_name as send_user_name
+        FROM
+            inside_message_send_log AS mlog
+                LEFT JOIN inside_message_record AS mr ON mlog.message_id = mr.id
+                LEFT JOIN `user` as us on us.id = mr.send_user_id
+            ${ew.customSqlSegment}
+    </select>
+
+    <select id="countNoReadNumber" resultType="com.storlead.message.pojo.vo.MessageNoReadTotalVO">
+        SELECT
+            ifnull(sum(case when mlog.is_read = 0 then 1 else 0 end),0) as no_read_num,
+            ifnull(sum(case when mlog.is_read = 0 and  mlog.message_type = 1 then 1 else 0 end),0) as at_no_read_num,
+            ifnull(sum(case when mlog.is_read = 0 and  mlog.message_type = 2 then 1 else 0 end),0) as approve_no_read_num
+        FROM
+            inside_message_send_log AS mlog
+                LEFT JOIN inside_message_record AS mr ON mlog.message_id = mr.id
+                LEFT JOIN `user` as us on us.id = mr.send_user_id
+            ${ew.customSqlSegment}
+    </select>
+
+    <select id="countNoReadCount" resultType="com.storlead.message.pojo.vo.MessageTypeReadStateVO">
+        SELECT
+            mr.message_type as messageType,ifnull(sum(case when mlog.is_read = 0 then 1 else 0 end),0) as stateNumber
+        FROM
+            inside_message_send_log AS mlog
+                LEFT JOIN inside_message_record AS mr ON mlog.message_id = mr.id
+                LEFT JOIN `user` as us on us.id = mr.send_user_id
+            ${ew.customSqlSegment}
+        group by mr.message_type
+    </select>
+</mapper>

+ 23 - 0
java/storlead-message/src/main/resources/mapper/MessageTemplateEventDetailMapper.xml

@@ -0,0 +1,23 @@
+<?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="com.storlead.message.mapper.MessageTemplateEventDetailMapper">
+
+        <!-- 通用查询映射结果 -->
+        <resultMap id="BaseResultMap" extends="com.storlead.frame.mapper.SysBaseFieldMapper.BaseResultMap" type="com.storlead.message.pojo.entity.MessageTemplateEventDetailEntity">
+            <id column="id" property="id" />
+            <result column="template_event_id" property="templateEventId" />
+            <result column="template_event_name" property="templateEventName" />
+            <result column="template_detail_type" property="templateDetailType" />
+            <result column="message_title" property="messageTitle" />
+            <result column="message_centent" property="messageCentent" />
+            <result column="callback_url" property="callbackUrl" />
+            <result column="template_icon" property="templateIcon" />
+            <result column="template_tag" property="templateTag" />
+        </resultMap>
+
+        <!-- 通用查询结果列 -->
+        <sql id="Base_Column_List">
+            id, template_event_id, template_event_name, template_icon,template_tag,template_detail_type, message_title, message_centent, callback_url, remark,<include refid="com.storlead.frame.mapper.SysBaseFieldMapper.Base_Column_List"></include>
+        </sql>
+
+</mapper>

+ 26 - 0
java/storlead-message/src/main/resources/mapper/MessageTemplateEventGroupMapper.xml

@@ -0,0 +1,26 @@
+<?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="com.storlead.message.mapper.MessageTemplateEventGroupMapper">
+
+        <!-- 通用查询映射结果 -->
+        <resultMap id="BaseResultMap" extends="com.storlead.frame.mapper.SysBaseFieldMapper.BaseResultMap" type="com.storlead.message.pojo.entity.MessageTemplateEventGroupEntity">
+             <id column="id" property="id" />
+             <result column="template_service_name" property="templateServiceName" />
+            <result column="template_service_type" property="templateServiceType" />
+             <result column="template_service_code" property="templateServiceCode" />
+             <result column="event_name" property="eventName" />
+             <result column="event_code" property="eventCode" />
+             <result column="event_rule_script" property="eventRuleScript" />
+            <result column="receiver_key" property="receiverKey" />
+        </resultMap>
+
+        <!-- 通用查询结果列 -->
+        <sql id="Base_Column_List">
+            id, template_service_name, template_service_code, event_name, event_code, event_rule_script,receiver_key,
+            <include refid="com.storlead.frame.mapper.SysBaseFieldMapper.Base_Column_List"></include>
+        </sql>
+
+        <select id="selectMessageTemplateList" resultType="com.storlead.message.pojo.vo.MessageTemplateVO">
+            select * from message_template_event_group ${ew.customSqlSegment}
+        </select>
+</mapper>

+ 35 - 0
java/storlead-message/src/main/resources/mapper/UserMessageNoticeConfigMapper.xml

@@ -0,0 +1,35 @@
+<?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="com.storlead.message.mapper.UserMessageNoticeConfigMapper">
+
+        <!-- 通用查询映射结果 -->
+        <resultMap id="BaseResultMap" type="com.storlead.message.entity.UserMessageNoticeConfigEntity">
+                    <id column="id" property="id" />
+                <result column="create_by" property="createBy" />
+                <result column="owner_by" property="ownerBy" />
+                <result column="create_time" property="createTime" />
+                <result column="update_by" property="updateBy" />
+                <result column="update_time" property="updateTime" />
+                <result column="enabled" property="enabled" />
+                <result column="is_delete" property="isDelete" />
+                <result column="sort" property="sort" />
+                    <result column="template_event_id" property="templateEventId" />
+                    <result column="template_event_code" property="templateEventCode" />
+                    <result column="template_detail_type" property="templateDetailType" />
+                    <result column="remark" property="remark" />
+        </resultMap>
+
+        <!-- 通用查询结果列 -->
+        <sql id="Base_Column_List">
+                create_by,
+                owner_by,
+                create_time,
+                update_by,
+                update_time,
+                enabled,
+                is_delete,
+                sort,
+            id, template_event_id, template_event_code, template_detail_type, remark
+        </sql>
+
+</mapper>

+ 13 - 0
java/storlead-message/src/test/java/com/storlead/tems/message/MessageApplicationTests.java

@@ -0,0 +1,13 @@
+package com.storlead.sales.message;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+class MessageApplicationTests {
+
+    @Test
+    void contextLoads() {
+    }
+
+}

+ 23 - 0
java/storlead-sasa/pom.xml

@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.storlead.boot</groupId>
+        <artifactId>storlead-saas-platform</artifactId>
+        <version>1.0</version>
+        <relativePath>../../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>storlead-sasa</artifactId>
+    <packaging>pom</packaging>
+
+    <modules>
+        <module>storlead-trade</module>
+        <module>storlead-salary</module>
+        <module>storlead-sales</module>
+        <module>storlead-okr</module>
+        <module>storlead-project</module>
+    </modules>
+</project>

+ 9 - 10
java/storlead-crm/storlead-email/pom.xml → java/storlead-sasa/storlead-okr/pom.xml

@@ -3,22 +3,21 @@
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
     <modelVersion>4.0.0</modelVersion>
+
     <parent>
     <parent>
         <groupId>com.storlead.boot</groupId>
         <groupId>com.storlead.boot</groupId>
-        <artifactId>storlead-crm</artifactId>
+        <artifactId>storlead-saas</artifactId>
         <version>1.0</version>
         <version>1.0</version>
-        <relativePath>../pom.xml</relativePath>
     </parent>
     </parent>
 
 
-    <artifactId>storlead-email</artifactId>
+    <artifactId>storlead-okr</artifactId>
     <packaging>jar</packaging>
     <packaging>jar</packaging>
     <name>${project.artifactId}</name>
     <name>${project.artifactId}</name>
-    <description>邮件记录</description>
 
 
-    <dependencies>
-        <dependency>
-            <groupId>com.storlead.boot</groupId>
-            <artifactId>storlead-web</artifactId>
-        </dependency>
-    </dependencies>
+    <properties>
+        <maven.compiler.source>17</maven.compiler.source>
+        <maven.compiler.target>17</maven.compiler.target>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
 </project>
 </project>

+ 7 - 0
java/storlead-sasa/storlead-okr/src/main/java/org/example/Main.java

@@ -0,0 +1,7 @@
+package org.example;
+
+public class Main {
+    public static void main(String[] args) {
+        System.out.println("Hello world!");
+    }
+}

+ 22 - 0
java/storlead-sasa/storlead-project/pom.xml

@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.storlead.boot</groupId>
+        <artifactId>storlead-saas</artifactId>
+        <version>1.0</version>
+    </parent>
+
+    <artifactId>storlead-project</artifactId>
+    <packaging>jar</packaging>
+    <name>${project.artifactId}</name>
+
+    <properties>
+        <maven.compiler.source>17</maven.compiler.source>
+        <maven.compiler.target>17</maven.compiler.target>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+</project>

+ 7 - 0
java/storlead-sasa/storlead-project/src/main/java/org/example/Main.java

@@ -0,0 +1,7 @@
+package org.example;
+
+public class Main {
+    public static void main(String[] args) {
+        System.out.println("Hello world!");
+    }
+}

+ 22 - 0
java/storlead-sasa/storlead-salary/pom.xml

@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.storlead.boot</groupId>
+        <artifactId>storlead-saas</artifactId>
+        <version>1.0</version>
+    </parent>
+
+    <artifactId>storlead-salary</artifactId>
+    <packaging>jar</packaging>
+    <name>${project.artifactId}</name>
+
+    <properties>
+        <maven.compiler.source>17</maven.compiler.source>
+        <maven.compiler.target>17</maven.compiler.target>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+</project>

+ 7 - 0
java/storlead-sasa/storlead-salary/src/main/java/org/example/Main.java

@@ -0,0 +1,7 @@
+package org.example;
+
+public class Main {
+    public static void main(String[] args) {
+        System.out.println("Hello world!");
+    }
+}

+ 22 - 0
java/storlead-sasa/storlead-sales/pom.xml

@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.storlead.boot</groupId>
+        <artifactId>storlead-saas</artifactId>
+        <version>1.0</version>
+    </parent>
+
+    <artifactId>storlead-sales</artifactId>
+    <packaging>jar</packaging>
+    <name>${project.artifactId}</name>
+
+    <properties>
+        <maven.compiler.source>17</maven.compiler.source>
+        <maven.compiler.target>17</maven.compiler.target>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+</project>

+ 7 - 0
java/storlead-sasa/storlead-sales/src/main/java/org/example/Main.java

@@ -0,0 +1,7 @@
+package org.example;
+
+public class Main {
+    public static void main(String[] args) {
+        System.out.println("Hello world!");
+    }
+}

+ 4 - 6
java/storlead-crm/pom.xml → java/storlead-sasa/storlead-trade/pom.xml

@@ -5,20 +5,18 @@
     <modelVersion>4.0.0</modelVersion>
     <modelVersion>4.0.0</modelVersion>
     <parent>
     <parent>
         <groupId>com.storlead.boot</groupId>
         <groupId>com.storlead.boot</groupId>
-        <artifactId>storlead-smarttrade-platform</artifactId>
+        <artifactId>storlead-saas-platform</artifactId>
         <version>1.0</version>
         <version>1.0</version>
-        <relativePath>../../pom.xml</relativePath>
+        <relativePath>../../../pom.xml</relativePath>
     </parent>
     </parent>
 
 
-    <artifactId>storlead-crm</artifactId>
+    <artifactId>storlead-trade</artifactId>
     <packaging>pom</packaging>
     <packaging>pom</packaging>
-    <name>storlead-crm</name>
+    <name>storlead-trade</name>
     <description>客户经营域聚合模块;具体业务在下方子模块中实现。</description>
     <description>客户经营域聚合模块;具体业务在下方子模块中实现。</description>
 
 
     <modules>
     <modules>
         <module>storlead-customer</module>
         <module>storlead-customer</module>
-        <module>storlead-order</module>
-        <module>storlead-email</module>
         <module>storlead-marketing</module>
         <module>storlead-marketing</module>
         <module>storlead-acquisition</module>
         <module>storlead-acquisition</module>
     </modules>
     </modules>

+ 0 - 0
java/storlead-crm/storlead-acquisition/README.md → java/storlead-sasa/storlead-trade/storlead-acquisition/README.md


+ 0 - 0
java/storlead-crm/storlead-acquisition/pom.xml → java/storlead-sasa/storlead-trade/storlead-acquisition/pom.xml


+ 0 - 0
java/storlead-crm/storlead-acquisition/src/main/java/com/storlead/crm/acquisition/package-info.java → java/storlead-sasa/storlead-trade/storlead-acquisition/src/main/java/com/storlead/crm/acquisition/package-info.java


+ 0 - 0
java/storlead-crm/storlead-customer/README.md → java/storlead-sasa/storlead-trade/storlead-customer/README.md


+ 0 - 0
java/storlead-crm/storlead-customer/pom.xml → java/storlead-sasa/storlead-trade/storlead-customer/pom.xml


+ 0 - 0
java/storlead-crm/storlead-customer/src/main/java/com/storlead/crm/customer/controller/CustomerAiAnalysisController.java → java/storlead-sasa/storlead-trade/storlead-customer/src/main/java/com/storlead/crm/customer/controller/CustomerAiAnalysisController.java


+ 0 - 0
java/storlead-crm/storlead-customer/src/main/java/com/storlead/crm/customer/dto/CustomerSingleAnalysisRequestDTO.java → java/storlead-sasa/storlead-trade/storlead-customer/src/main/java/com/storlead/crm/customer/dto/CustomerSingleAnalysisRequestDTO.java


+ 0 - 0
java/storlead-crm/storlead-customer/src/main/java/com/storlead/crm/customer/entity/CustomerAnalysisResultEntity.java → java/storlead-sasa/storlead-trade/storlead-customer/src/main/java/com/storlead/crm/customer/entity/CustomerAnalysisResultEntity.java


+ 0 - 0
java/storlead-crm/storlead-customer/src/main/java/com/storlead/crm/customer/entity/CustomerCompanyEntity.java → java/storlead-sasa/storlead-trade/storlead-customer/src/main/java/com/storlead/crm/customer/entity/CustomerCompanyEntity.java


+ 0 - 0
java/storlead-crm/storlead-customer/src/main/java/com/storlead/crm/customer/entity/CustomerEntity.java → java/storlead-sasa/storlead-trade/storlead-customer/src/main/java/com/storlead/crm/customer/entity/CustomerEntity.java


+ 0 - 0
java/storlead-crm/storlead-customer/src/main/java/com/storlead/crm/customer/entity/LiaisonEntity.java → java/storlead-sasa/storlead-trade/storlead-customer/src/main/java/com/storlead/crm/customer/entity/LiaisonEntity.java


+ 0 - 0
java/storlead-crm/storlead-customer/src/main/java/com/storlead/crm/customer/mapper/CustomerAnalysisResultEntityMapper.java → java/storlead-sasa/storlead-trade/storlead-customer/src/main/java/com/storlead/crm/customer/mapper/CustomerAnalysisResultEntityMapper.java


+ 0 - 0
java/storlead-crm/storlead-customer/src/main/java/com/storlead/crm/customer/mapper/CustomerCompanyEntityMapper.java → java/storlead-sasa/storlead-trade/storlead-customer/src/main/java/com/storlead/crm/customer/mapper/CustomerCompanyEntityMapper.java


+ 0 - 0
java/storlead-crm/storlead-customer/src/main/java/com/storlead/crm/customer/mapper/CustomerEntityMapper.java → java/storlead-sasa/storlead-trade/storlead-customer/src/main/java/com/storlead/crm/customer/mapper/CustomerEntityMapper.java


+ 0 - 0
java/storlead-crm/storlead-customer/src/main/java/com/storlead/crm/customer/mapper/LiaisonEntityMapper.java → java/storlead-sasa/storlead-trade/storlead-customer/src/main/java/com/storlead/crm/customer/mapper/LiaisonEntityMapper.java


+ 0 - 0
java/storlead-crm/storlead-customer/src/main/java/com/storlead/crm/customer/package-info.java → java/storlead-sasa/storlead-trade/storlead-customer/src/main/java/com/storlead/crm/customer/package-info.java


+ 0 - 0
java/storlead-crm/storlead-customer/src/main/java/com/storlead/crm/customer/service/CustomerAiAnalysisService.java → java/storlead-sasa/storlead-trade/storlead-customer/src/main/java/com/storlead/crm/customer/service/CustomerAiAnalysisService.java


+ 0 - 0
java/storlead-crm/storlead-customer/src/main/java/com/storlead/crm/customer/service/CustomerAnalysisResultEntityService.java → java/storlead-sasa/storlead-trade/storlead-customer/src/main/java/com/storlead/crm/customer/service/CustomerAnalysisResultEntityService.java


+ 0 - 0
java/storlead-crm/storlead-customer/src/main/java/com/storlead/crm/customer/service/CustomerCompanyEntityService.java → java/storlead-sasa/storlead-trade/storlead-customer/src/main/java/com/storlead/crm/customer/service/CustomerCompanyEntityService.java


+ 0 - 0
java/storlead-crm/storlead-customer/src/main/java/com/storlead/crm/customer/service/CustomerEntityService.java → java/storlead-sasa/storlead-trade/storlead-customer/src/main/java/com/storlead/crm/customer/service/CustomerEntityService.java


+ 0 - 0
java/storlead-crm/storlead-customer/src/main/java/com/storlead/crm/customer/service/LiaisonEntityService.java → java/storlead-sasa/storlead-trade/storlead-customer/src/main/java/com/storlead/crm/customer/service/LiaisonEntityService.java


+ 0 - 0
java/storlead-crm/storlead-customer/src/main/java/com/storlead/crm/customer/service/impl/CustomerAiAnalysisServiceImpl.java → java/storlead-sasa/storlead-trade/storlead-customer/src/main/java/com/storlead/crm/customer/service/impl/CustomerAiAnalysisServiceImpl.java


+ 0 - 0
java/storlead-crm/storlead-customer/src/main/java/com/storlead/crm/customer/service/impl/CustomerAnalysisResultEntityServiceImpl.java → java/storlead-sasa/storlead-trade/storlead-customer/src/main/java/com/storlead/crm/customer/service/impl/CustomerAnalysisResultEntityServiceImpl.java


+ 0 - 0
java/storlead-crm/storlead-customer/src/main/java/com/storlead/crm/customer/service/impl/CustomerCompanyEntityServiceImpl.java → java/storlead-sasa/storlead-trade/storlead-customer/src/main/java/com/storlead/crm/customer/service/impl/CustomerCompanyEntityServiceImpl.java


+ 0 - 0
java/storlead-crm/storlead-customer/src/main/java/com/storlead/crm/customer/service/impl/CustomerEntityServiceImpl.java → java/storlead-sasa/storlead-trade/storlead-customer/src/main/java/com/storlead/crm/customer/service/impl/CustomerEntityServiceImpl.java


+ 0 - 0
java/storlead-crm/storlead-customer/src/main/java/com/storlead/crm/customer/service/impl/LiaisonEntityServiceImpl.java → java/storlead-sasa/storlead-trade/storlead-customer/src/main/java/com/storlead/crm/customer/service/impl/LiaisonEntityServiceImpl.java


+ 0 - 0
java/storlead-crm/storlead-customer/src/main/resources/mapper/CustomerAnalysisResultEntityMapper.xml → java/storlead-sasa/storlead-trade/storlead-customer/src/main/resources/mapper/CustomerAnalysisResultEntityMapper.xml


+ 0 - 0
java/storlead-crm/storlead-customer/src/main/resources/mapper/CustomerCompanyEntityMapper.xml → java/storlead-sasa/storlead-trade/storlead-customer/src/main/resources/mapper/CustomerCompanyEntityMapper.xml


+ 0 - 0
java/storlead-crm/storlead-customer/src/main/resources/mapper/CustomerEntityMapper.xml → java/storlead-sasa/storlead-trade/storlead-customer/src/main/resources/mapper/CustomerEntityMapper.xml


Alguns ficheiros não foram mostrados porque muitos ficheiros mudaram neste diff