2
0

2 Коммитууд c61b71eaef ... 03d9ba21a0

Эзэн SHA1 Мессеж Огноо
  x 03d9ba21a0 sync 10 сар өмнө
  x ce98637d70 240410更新 10 сар өмнө
100 өөрчлөгдсөн 3539 нэмэгдсэн , 956 устгасан
  1. 1 0
      README.md
  2. BIN
      config/lib/libWeWorkFinanceSdk_Java.so
  3. 17 0
      config/lib/会话存档sdk存档说明
  4. BIN
      config/lw_nacos_config.zip
  5. 51 0
      config/lw_nacos_config/.metadata.yml
  6. 114 0
      config/lw_nacos_config/DEFAULT_GROUP/gateway-router
  7. 22 0
      config/lw_nacos_config/DEFAULT_GROUP/linkwe-api.yml
  8. 33 0
      config/lw_nacos_config/DEFAULT_GROUP/linkwe-auth.yml
  9. 145 0
      config/lw_nacos_config/DEFAULT_GROUP/linkwe-common.yml
  10. 2 0
      config/lw_nacos_config/DEFAULT_GROUP/linkwe-event-task.yml
  11. 25 0
      config/lw_nacos_config/DEFAULT_GROUP/linkwe-file.yml
  12. 55 0
      config/lw_nacos_config/DEFAULT_GROUP/linkwe-gateway.yml
  13. 37 0
      config/lw_nacos_config/DEFAULT_GROUP/linkwe-scheduler.yml
  14. 37 0
      config/lw_nacos_config/DEFAULT_GROUP/linkwe-wecom.yml
  15. 16 0
      config/lw_nacos_config/DEFAULT_GROUP/linkwe-wx-api.yml
  16. 12 8
      config/run/bootstrap.yml
  17. 116 0
      linkwe-ai/pom.xml
  18. 28 0
      linkwe-ai/src/main/java/com/linkwechat/LinkweAiApplication.java
  19. 9 0
      linkwe-ai/src/main/java/com/linkwechat/annotation/AiMsgAop.java
  20. 41 0
      linkwe-ai/src/main/java/com/linkwechat/aspecj/WeAiMsgTokenAspect.java
  21. 141 0
      linkwe-ai/src/main/java/com/linkwechat/config/SwaggerConfig.java
  22. 21 0
      linkwe-ai/src/main/java/com/linkwechat/config/WebConfig.java
  23. 90 0
      linkwe-ai/src/main/java/com/linkwechat/controller/WeAiAssistantController.java
  24. 19 0
      linkwe-ai/src/main/java/com/linkwechat/domain/AiMessage.java
  25. 37 0
      linkwe-ai/src/main/java/com/linkwechat/domain/PostBaseQuery.java
  26. 16 0
      linkwe-ai/src/main/java/com/linkwechat/domain/WeAiCollectionMsgQuery.java
  27. 23 0
      linkwe-ai/src/main/java/com/linkwechat/domain/WeAiCollectionMsgVo.java
  28. 18 0
      linkwe-ai/src/main/java/com/linkwechat/domain/WeAiMsgListQuery.java
  29. 23 0
      linkwe-ai/src/main/java/com/linkwechat/domain/WeAiMsgQuery.java
  30. 80 0
      linkwe-ai/src/main/java/com/linkwechat/domain/WeAiMsgVo.java
  31. 50 0
      linkwe-ai/src/main/java/com/linkwechat/interceptor/RequestContextInterceptor.java
  32. 38 0
      linkwe-ai/src/main/java/com/linkwechat/listener/AiMessageListener.java
  33. 50 0
      linkwe-ai/src/main/java/com/linkwechat/service/IWeAiSessionService.java
  34. 291 0
      linkwe-ai/src/main/java/com/linkwechat/service/impl/WeAiSessionServiceImpl.java
  35. 64 0
      linkwe-ai/src/main/java/com/linkwechat/utils/WeAiSessionUtil.java
  36. 10 0
      linkwe-ai/src/main/resources/banner.txt
  37. 206 0
      linkwe-ai/src/main/resources/logback-spring.xml
  38. 24 0
      linkwe-ai/src/main/resources/spy.properties
  39. 13 0
      linkwe-ai/src/test/java/com/linkwechat/LinkweAiApplicationTests.java
  40. 19 21
      linkwe-api/pom.xml
  41. 2 1
      linkwe-api/src/main/java/com/linkwechat/LinkWeApiApplication.java
  42. 2 3
      linkwe-api/src/main/java/com/linkwechat/config/SwaggerConfig.java
  43. 264 41
      linkwe-api/src/main/java/com/linkwechat/controller/WeCommunityKeywordGroupController.java
  44. 100 37
      linkwe-api/src/main/java/com/linkwechat/controller/WeCommunityNewGroupController.java
  45. 142 60
      linkwe-api/src/main/java/com/linkwechat/controller/WeCommunityPresTagGroupController.java
  46. 0 2
      linkwe-api/src/main/java/com/linkwechat/controller/WeContentTalkController.java
  47. 33 50
      linkwe-api/src/main/java/com/linkwechat/controller/WeCorpAccountController.java
  48. 7 13
      linkwe-api/src/main/java/com/linkwechat/controller/WeCustomerController.java
  49. 2 1
      linkwe-api/src/main/java/com/linkwechat/controller/WeCustomerLinkController.java
  50. 0 1
      linkwe-api/src/main/java/com/linkwechat/controller/WeFissionController.java
  51. 1 1
      linkwe-api/src/main/java/com/linkwechat/controller/WeFormSurveyCatalogueController.java
  52. 63 360
      linkwe-api/src/main/java/com/linkwechat/controller/WeFormSurveyStatisticsController.java
  53. 57 0
      linkwe-api/src/main/java/com/linkwechat/controller/WeGroupChatController.java
  54. 71 1
      linkwe-api/src/main/java/com/linkwechat/controller/WeGroupCodeController.java
  55. 15 15
      linkwe-api/src/main/java/com/linkwechat/controller/WeGroupMessageTemplateController.java
  56. 96 0
      linkwe-api/src/main/java/com/linkwechat/controller/WeIndexController.java
  57. 8 4
      linkwe-api/src/main/java/com/linkwechat/controller/WeLeadsController.java
  58. 4 1
      linkwe-api/src/main/java/com/linkwechat/controller/WeLeadsSeaController.java
  59. 0 8
      linkwe-api/src/main/java/com/linkwechat/controller/WeLiveController.java
  60. 8 7
      linkwe-api/src/main/java/com/linkwechat/controller/WeLxQrCodeController.java
  61. 47 12
      linkwe-api/src/main/java/com/linkwechat/controller/WeMaterialController.java
  62. 7 4
      linkwe-api/src/main/java/com/linkwechat/controller/WeMomentsTaskController.java
  63. 6 4
      linkwe-api/src/main/java/com/linkwechat/controller/WeOperationCenterController.java
  64. 6 1
      linkwe-api/src/main/java/com/linkwechat/controller/WeProductOrderController.java
  65. 77 5
      linkwe-api/src/main/java/com/linkwechat/controller/WeQrCodeController.java
  66. 3 2
      linkwe-api/src/main/java/com/linkwechat/controller/WeSopController.java
  67. 91 32
      linkwe-api/src/main/java/com/linkwechat/controller/WeStoreCodeController.java
  68. 7 2
      linkwe-api/src/main/java/com/linkwechat/interceptor/RequestContextInterceptor.java
  69. 1 1
      linkwe-api/src/main/resources/logback-spring.xml
  70. 1 1
      linkwe-api/src/main/resources/templates/jump.html
  71. 24 2
      linkwe-auth/pom.xml
  72. 2 1
      linkwe-auth/src/main/java/com/linkwechat/LinkWeAuthApplication.java
  73. 1 1
      linkwe-auth/src/main/java/com/linkwechat/web/controller/system/SysConfigController.java
  74. 12 0
      linkwe-auth/src/main/java/com/linkwechat/web/domain/vo/RouterVo.java
  75. 8 5
      linkwe-auth/src/main/java/com/linkwechat/web/interceptor/RequestContextInterceptor.java
  76. 12 2
      linkwe-auth/src/main/java/com/linkwechat/web/service/impl/SysMenuServiceImpl.java
  77. 1 1
      linkwe-auth/src/main/resources/logback-spring.xml
  78. 1 1
      linkwe-auth/src/main/resources/mapper/system/SysUserMapper.xml
  79. 17 4
      linkwe-common/pom.xml
  80. 1 1
      linkwe-common/src/main/java/com/linkwechat/common/annotation/DataScope.java
  81. 10 145
      linkwe-common/src/main/java/com/linkwechat/common/aop/DataScopeAspect.java
  82. 32 0
      linkwe-common/src/main/java/com/linkwechat/common/config/LinkWeChatConfig.java
  83. 19 0
      linkwe-common/src/main/java/com/linkwechat/common/config/mybatis/BatchSqlInjector.java
  84. 6 22
      linkwe-common/src/main/java/com/linkwechat/common/config/mybatis/DataScopeHandler.java
  85. 9 53
      linkwe-common/src/main/java/com/linkwechat/common/config/mybatis/DataScopeInterceptor.java
  86. 17 0
      linkwe-common/src/main/java/com/linkwechat/common/config/mybatis/LwBaseMapper.java
  87. 6 1
      linkwe-common/src/main/java/com/linkwechat/common/config/mybatis/MybatisPlusConfig.java
  88. 4 10
      linkwe-common/src/main/java/com/linkwechat/common/config/mybatis/PearlDataScopeHandler.java
  89. 16 0
      linkwe-common/src/main/java/com/linkwechat/common/config/mybatis/WeBaseMapper.java
  90. 2 1
      linkwe-common/src/main/java/com/linkwechat/common/constant/SecurityConstants.java
  91. 6 0
      linkwe-common/src/main/java/com/linkwechat/common/constant/SynchRecordConstants.java
  92. 29 0
      linkwe-common/src/main/java/com/linkwechat/common/constant/WeComeStateContants.java
  93. 3 0
      linkwe-common/src/main/java/com/linkwechat/common/constant/WeConstans.java
  94. 58 0
      linkwe-common/src/main/java/com/linkwechat/common/constant/WeServerNameConstants.java
  95. 54 0
      linkwe-common/src/main/java/com/linkwechat/common/core/controller/BaseController.java
  96. 3 0
      linkwe-common/src/main/java/com/linkwechat/common/core/domain/model/LoginUser.java
  97. 2 1
      linkwe-common/src/main/java/com/linkwechat/common/core/page/TableSupport.java
  98. 11 5
      linkwe-common/src/main/java/com/linkwechat/common/core/redis/RedisService.java
  99. 56 0
      linkwe-common/src/main/java/com/linkwechat/common/enums/CategoryMediaGroupType.java
  100. 2 1
      linkwe-common/src/main/java/com/linkwechat/common/enums/FileCosType.java

+ 1 - 0
README.md

@@ -1,5 +1,6 @@
 <p></p>
 <p></p>
+<p></p>
 
 ![输入图片说明](readme-pic/logo.png)
 

BIN
config/lib/libWeWorkFinanceSdk_Java.so


+ 17 - 0
config/lib/会话存档sdk存档说明

@@ -0,0 +1,17 @@
+当前os文件是企业微信官方提供用于解析会话存档内容,切记勿修改名称等。
+
+sdk官方下载地址:https://developer.work.weixin.qq.com/document/path/91774
+
+会话存档公钥私钥生成器 http://web.chacuo.net/netrsakeypair/
+生成密钥位数:2048位(bit) 密钥格式:PKCS#1  输出格式:PEM/Base64
+
+1:系统如果原生jar部署,将该文件复制到linux服务器的 /app/lib下,目录如果不存在新建,然后将libWeWorkFinanceSdk_Java.so放进去
+    Finance文件下   System.load("/app/lib/libWeWorkFinanceSdk_Java.so");
+2:如果是dokcer部署,系统打包成docker镜像,会自动将libWeWorkFinanceSdk_Java.so 复制到/app/lib下,无需做处理。
+    Finance文件下   System.load(System.getProperty("java.library.path")+"/libWeWorkFinanceSdk_Java.so");
+
+3:如果是windows欢迎部署运行自行处理,将sdk中的以下.dll文件直接放入C:\Windows\System32目录下,然后在环境变量的Path中添加该目录。
+         libcrypto-1_1-x64
+         libcurl-x64
+         libssl-1_1-x64
+         WeWorkFinanceSdk

BIN
config/lw_nacos_config.zip


+ 51 - 0
config/lw_nacos_config/.metadata.yml

@@ -0,0 +1,51 @@
+metadata:
+- appName: ''
+  dataId: linkwe-common.yml
+  desc: ''
+  group: DEFAULT_GROUP
+  type: yaml
+- appName: ''
+  dataId: linkwe-api.yml
+  desc: ''
+  group: DEFAULT_GROUP
+  type: yaml
+- appName: ''
+  dataId: linkwe-auth.yml
+  desc: ''
+  group: DEFAULT_GROUP
+  type: yaml
+- appName: ''
+  dataId: linkwe-event-task.yml
+  desc: ''
+  group: DEFAULT_GROUP
+  type: yaml
+- appName: ''
+  dataId: linkwe-file.yml
+  desc: ''
+  group: DEFAULT_GROUP
+  type: yaml
+- appName: ''
+  dataId: linkwe-gateway.yml
+  desc: ''
+  group: DEFAULT_GROUP
+  type: yaml
+- appName: ''
+  dataId: linkwe-scheduler.yml
+  desc: ''
+  group: DEFAULT_GROUP
+  type: yaml
+- appName: ''
+  dataId: linkwe-wecom.yml
+  desc: ''
+  group: DEFAULT_GROUP
+  type: yaml
+- appName: ''
+  dataId: linkwe-wx-api.yml
+  desc: ''
+  group: DEFAULT_GROUP
+  type: yaml
+- appName: ''
+  dataId: gateway-router
+  desc: ''
+  group: DEFAULT_GROUP
+  type: json

+ 114 - 0
config/lw_nacos_config/DEFAULT_GROUP/gateway-router

@@ -0,0 +1,114 @@
+[{
+    "id": "linkwe-auth",
+    "order": 0,
+    "predicates": [{
+        "args": {
+            "pattern": "/auth/**"
+        },
+        "name": "Path"
+    }],
+    "filters":[{
+        "name":"ValidateCodeFilter"
+    },{
+        "name":"CacheRequestFilter"
+    }
+    ],
+    "uri": "lb://linkwe-auth"
+},{
+    "id": "linkwe-auth-system",
+    "order": 0,
+    "predicates": [{
+        "args": {
+            "pattern": "/system/**"
+        },
+        "name": "Path"
+    }],
+    "uri": "lb://linkwe-auth"
+},{
+    "id": "linkwe-wecom",
+    "order": 2,
+    "predicates": [{
+        "args": {
+            "pattern": "/wecom/**"
+        },
+        "name": "Path"
+    }],
+    "filters":[{
+        "args": {
+            "_genkey_0":"1"
+        },
+        "name":"StripPrefix"
+    }],
+    "uri": "lb://linkwe-wecom"
+},{
+    "id": "linkwe-api",
+    "order": 3,
+    "predicates": [{
+        "args": {
+            "pattern": "/open/**"
+        },
+        "name": "Path"
+    }],
+    "uri": "lb://linkwe-api"
+},{
+    "id": "linkwe-file",
+    "order": 4,
+    "predicates": [{
+        "args": {
+            "pattern": "/file/**"
+        },
+        "name": "Path"
+    }],
+    "uri": "lb://linkwe-file"
+},{
+  "id": "linkwe-auth-common",
+  "order": 0,
+  "predicates": [{
+    "args": {
+      "pattern": "/common/**"
+    },
+    "name": "Path"
+  }],
+  "uri": "lb://linkwe-auth"
+},{
+    "id": "linkwe-wx-api",
+    "order": 3,
+    "predicates": [{
+        "args": {
+            "pattern": "/wx-api/**"
+        },
+        "name": "Path"
+    }],
+    "uri": "lb://linkwe-wx-api"
+}
+,{
+    "id": "yshop-mall",
+    "order": 0,
+    "predicates": [{
+        "args": {
+            "pattern": "/mall/**"
+        },
+        "name": "Path"
+    }],
+    "uri": "lb://yshop-mall"
+},{
+    "id": "yshop-weixin",
+    "order": 0,
+    "predicates": [{
+        "args": {
+            "pattern": "/wx/**"
+        },
+        "name": "Path"
+    }],
+    "uri": "lb://yshop-weixin"
+},{
+    "id": "yshop-auth",
+    "order": 0,
+    "predicates": [{
+        "args": {
+            "pattern": "/ident/**"
+        },
+        "name": "Path"
+    }],
+    "uri": "lb://yshop-auth"
+}]

+ 22 - 0
config/lw_nacos_config/DEFAULT_GROUP/linkwe-api.yml

@@ -0,0 +1,22 @@
+server:
+  port: 6091
+  servlet:
+    # 应用的访问路径
+    context-path: /open
+  tomcat:
+    # tomcat的URI编码
+    uri-encoding: UTF-8
+
+logging:
+  path: /usr/local/app/linwechat-api/logs/linkwe-api
+
+swagger:
+  enabled: true
+  pathMapping: /
+  title: LinkWeChat业务接口
+  description: LinkWeChat业务相关接口
+  version: 3.0
+
+weixin:
+  short:
+    env-version: release

+ 33 - 0
config/lw_nacos_config/DEFAULT_GROUP/linkwe-auth.yml

@@ -0,0 +1,33 @@
+# 项目相关配置
+linkwechat:
+  # 名称
+  name: linkwe-auth
+  # 版本
+  version: 3.1.0
+  # 版权年份
+  copyrightYear: 2021
+# 开发环境配置
+server:
+  port: 6880
+  servlet:
+    # 应用的访问路径
+    context-path: /
+  tomcat:
+    # tomcat的URI编码
+    uri-encoding: UTF-8
+
+# PageHelper分页插件
+pagehelper:
+  helperDialect: mysql
+  reasonable: true
+  supportMethodsArguments: true
+  params: count=countSql
+
+mybatis-plus:
+  mapper-locations: classpath*:mapper/**/*Mapper.xml
+  type-aliases-package: com.linkwechat.**.domain
+  type-handlers-package: com.linkwechat.common.handler.GenericTypeHandler
+
+rsa:
+  privateKey: MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAqhHyZfSsYourNxaY7Nt+PrgrxkiA50efORdI5U5lsW79MmFnusUA355oaSXcLhu5xxB38SMSyP2KvuKNPuH3owIDAQABAkAfoiLyL+Z4lf4Myxk6xUDgLaWGximj20CUf+5BKKnlrK+Ed8gAkM0HqoTt2UZwA5E2MzS4EI2gjfQhz5X28uqxAiEA3wNFxfrCZlSZHb0gn2zDpWowcSxQAgiCstxGUoOqlW8CIQDDOerGKH5OmCJ4Z21v+F25WaHYPxCFMvwxpcw99EcvDQIgIdhDTIqD2jfYjPTY8Jj3EDGPbH2HHuffvflECt3Ek60CIQCFRlCkHpi7hthhYhovyloRYsM+IS9h/0BzlEAuO0ktMQIgSPT3aFAgJYwKpqRYKlLDVcflZFCKY7u3UP8iWi1Qw0Y=
+  publicKey: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ==

+ 145 - 0
config/lw_nacos_config/DEFAULT_GROUP/linkwe-common.yml

@@ -0,0 +1,145 @@
+linkwechat:
+  # 获取ip地址开关
+  addressEnabled: false
+  #扫码登陆url
+  wecomeLoginUrl: https://open.work.weixin.qq.com/wwopen/sso/qrConnect?appid=ww622fc852f79c3f13&agentid=1000080&redirect_uri=http%3A%2F%2Fdemo.linkwechat.net%2FauthRedirect&state=web_login
+  customerServiceQrUrl: https://link-wechat-1251309172.cos.ap-nanjing.myqcloud.com/2022/10/21/957501f7-8517-4186-b6f4-3272ad1b8e33.png
+  demoEnviron: false
+  editPwd: true
+  enableFilePreview: true
+  baiduMapsAk: edGc5mIugVxx7lwUx9YpraKeWmExG64o #百度地图开发者ak
+  authorizeUrl: https://open.weixin.qq.com/connect/oauth2/authorize #js sdk身份认证url,不变
+  h5Domain: https://demo.linkwechat.net/mobile #移动端访问地址
+  fissionUrl: ${linkwechat.h5Domain}/#/taskTreasure?id={0} #任务宝链接配置
+  guideCodeUrl:  ${linkwechat.h5Domain}/#/guideCode #导购码
+  guideGroupUrl: ${linkwechat.h5Domain}/#/storeCode #导购群码
+  lostCustomerRedirectUrl: ${linkwechat.h5Domain}/#/lostCustomers #客户流失
+  seasRedirectUrl: ${linkwechat.h5Domain}/#/highSeas #客户公海链接
+  communityNewGroupUrl: ${linkwechat.h5Domain}/#/groupCode?type=newCustomerGroup&id={0}
+  tagRedirectUrl: ${linkwechat.h5Domain}/#/task #老客标签建群H5链接
+  customerSopRedirectUrl: ${linkwechat.h5Domain}/#/personalSOPDetails #客户SOP的H5跳转链接
+  groupSopRedirectUrl: ${linkwechat.h5Domain}/#/customerBaseDetails #客群SOP的H5跳转链接
+  liveUrl: ${linkwechat.h5Domain}/index-wx.html#/reminder?id={0} #直播页面
+  shortLinkDomainName: "sl.linkwechat.net/t/"
+  customerShortLinkDomainName: sl.linkwechat.net/l/
+  shortAppletUrl: "pages/index/index"
+  knowCustomerUrl: ${linkwechat.h5Domain}/index-wx.html#/identity?id={0} #识客码
+  lxQrCodeUrl: ${linkwechat.h5Domain}/#/pullNews?id={}&type={} #红包/卡券拉新地址
+  appMsgUrl: ${linkwechat.h5Domain}/#/shortLinkPush?id={} #短链推广-应用消息详情
+  materialDetailUrl: ${linkwechat.h5Domain}/#/metrialDetail?materiaId={}&otherModle=true #素材详情
+  momentsUrl: ${linkwechat.h5Domain}/#/friendsDetail?id={} #朋友圈移动端详情页
+  leadsDetailUrl: /clueHighseas/detail?id={} #线索中心移动端-待办任务-线索长时间未跟进-详情页
+  leadsCovenantWaitFollowUpUrl: /clueHighseas/followDetail?recordId={} #线索中心移动端-待办任务-线索约定事项待跟进-详情页
+  fincaceProxyConfig:
+    proxy: "" #使用代理的请求,需要传入代理的链接。如:socks5://10.0.0.1:8081 或者 http://10.0.0.1:8081
+    paswd: "" #代理账号密码,需要传入代理的账号密码。如 user_name:passwd_123
+# Spring配置
+spring:
+  jackson:
+    time-zone: GMT+8
+  mvc:
+    pathmatch:
+      matching-strategy: ant_path_matcher
+  devtools:
+    restart:
+      enabled: true
+  main:
+    allow-bean-definition-overriding: true
+    allow-circular-references: true
+  datasource:
+    type: com.alibaba.druid.pool.DruidDataSource
+    driver-class-name: com.p6spy.engine.spy.P6SpyDriver
+    druid:
+      url: jdbc:p6spy:mysql://127.0.0.1:3306/lw-cloud?spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true
+      username: root
+      password: root
+      # 初始连接数
+      initialSize: 5
+      # 最小连接池数量
+      minIdle: 10
+      # 最大连接池数量
+      maxActive: 20
+      # 配置获取连接等待超时的时间
+      maxWait: 60000
+      # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
+      timeBetweenEvictionRunsMillis: 60000
+      # 配置一个连接在池中最小生存的时间,单位是毫秒
+      minEvictableIdleTimeMillis: 300000
+      # 配置一个连接在池中最大生存的时间,单位是毫秒
+      maxEvictableIdleTimeMillis: 900000
+      # 配置检测连接是否有效
+      validationQuery: SELECT 1 FROM DUAL
+      testWhileIdle: true
+      testOnBorrow: false
+      testOnReturn: false
+      filter:
+        stat:
+          enabled: true
+          # 慢SQL记录
+          log-slow-sql: true
+          slow-sql-millis: 1000
+          merge-sql: false
+        wall:
+          config:
+            multi-statement-allow: true
+  # redis 配置
+  redis:
+    # 地址
+    host: 127.0.0.1
+    # 端口,默认为6379
+    port: 6379
+    database: 5
+    # 密码
+    password:
+    # 连接超时时间
+    timeout: 10s
+    lettuce:
+      pool:
+        # 连接池中的最小空闲连接
+        min-idle: 0
+        # 连接池中的最大空闲连接
+        max-idle: 8
+        # 连接池的最大数据库连接数
+        max-active: 8
+        # #连接池最大阻塞等待时间(使用负值表示没有限制)
+        max-wait: -1ms
+      cluster:
+        refresh:
+          adaptive: true
+  rabbitmq:
+    host: 127.0.0.1
+    port: 5672
+    username: lw
+    password: lw
+    virtual-host: lwProdVhost
+    #publisher-confirm-type: correlated #消息确认机制
+    listener:
+      simple:
+        acknowledge-mode: manual  #手动 ack
+        default-requeue-rejected: true
+        retry:
+          enabled: true
+          max-attempts: 3
+      direct:
+        acknowledge-mode: manual
+        retry:
+          enabled: true
+feign:
+  okhttp:
+    enabled: false
+  httpclient:
+    enabled: true
+  client:
+    refresh-enabled: true
+
+wecom:
+  error-code-retry: -1,42001,42009,40082,40014
+  serve:
+    linkwe-wecom: linkwe-wecom
+    linkwe-auth: linkwe-auth
+    linkwe-file: linkwe-file
+    linkwe-api: linkwe-api
+  kf: 
+    end: 
+      msgmenu: 
+        content: "{\"head_content\":\"您好,本次会话服务已结束,请对我的服务质量进行评价? \",\"list\":[{\"type\":\"click\",\"click\":{\"id\":\"101\",\"content\":\"好评\"}},{\"type\":\"click\",\"click\":{\"id\":\"102\",\"content\":\"一般\"}},{\"type\":\"click\",\"click\":{\"id\":\"103\",\"content\":\"差评\"}},{\"type\":\"view\",\"view\":{\"url\":\"https://demo.linkwechat.net/mobile/#/evaluate?poolId={}\",\"content\":\"去写评价语\"}}]}"

+ 2 - 0
config/lw_nacos_config/DEFAULT_GROUP/linkwe-event-task.yml

@@ -0,0 +1,2 @@
+server:
+  port: 6092

+ 25 - 0
config/lw_nacos_config/DEFAULT_GROUP/linkwe-file.yml

@@ -0,0 +1,25 @@
+# Tomcat
+server:
+  port: 9101
+  servlet:
+    # 应用的访问路径
+    context-path: /file
+
+# 项目相关配置
+linkwechat:
+  # 腾讯云存储
+  file:
+    #单个数据大小,单位MB
+    maxFileSize: 50
+    #总上传数据大小,单位MB
+    maxRequestSize: 100
+    #腾讯云对象存储
+    object: tencentOss
+    #AES加解密的Key, Key length 128/192/256 bits
+    aesKey: qykj@20221101_te
+    cos:
+      secretId: AKIDQRCizIeUGl13vakkDQMH0VkjhPr1r
+      secretKey: e3D8oFetseC0f8OX9XeV7UcTDiyyQ8
+      region: ap-nanjing
+      bucketName: link-wechat-1251309172
+      cosImgUrlPrefix: https://link-wechat-1251309172.cos.ap-nanjing.myqcloud.com/

+ 55 - 0
config/lw_nacos_config/DEFAULT_GROUP/linkwe-gateway.yml

@@ -0,0 +1,55 @@
+# Tomcat
+server:
+  port: 6180
+
+security:
+  ignore:
+    whites:
+      - /auth/**
+      - /open/wecom/**
+      - /open/groupCode/getActualCode/**
+      - /open/form/survey/getInfo/**
+      - /open/form/answer/add
+      - /system/area/list
+      - /open/form/statistic/add
+      - /open/form/answer/isCompleteSurvey
+      - /open/form/statistic/insertPieValue
+      - /open/form/statistic/siteStas
+      - /wx-api/material/get/**
+      - /wx-api/material/action/addView
+      - /wx-api/track/material/auth/**
+      - /wx-api/groupCode/getActualCode/**
+      - /open/t/**
+      - /open/l/**
+      - /open/short/link/getByShort/**
+      - /mall/**
+      - /wx/**
+      - /ident/**
+  captcha:
+    enabled: true
+    type: math
+
+spring:
+  application:
+    name: linkwechat-gateway
+  cloud:
+    gateway:
+      globalcors:
+        corsConfigurations:
+          '[/**]':
+            allowedOrigins: "*"
+            allowedMethods: "*"
+            allowedHeaders: "*"
+      discovery:
+        locator:
+          enabled: true
+          lower-case-service-id: true
+          filters:
+            - StripPrefix=1
+
+nacos:
+  gateway:
+    route:
+      config:
+        data-id: gateway-router
+        group: DEFAULT_GROUP

+ 37 - 0
config/lw_nacos_config/DEFAULT_GROUP/linkwe-scheduler.yml

@@ -0,0 +1,37 @@
+server:
+  port: 6400
+
+xxl:
+  job:
+    admin:
+      addresses: http://127.0.0.1:18080/xxl-job-admin
+    accessToken: default_token
+    executor:
+      appname: linkwechat-ky-scheduler
+      address:
+      ip: 127.0.0.1
+      port: 18081
+      logpath: /data/applogs/xxl-job/jobhandler
+      logretentiondays: 30
+
+spring:
+  application:
+    name: linkwechat-scheduler
+
+welcome-msg:
+  lxqr:
+    red-packet-img: ${linkwechat.h5Domain}/static/redPullNews.png
+    red-packet-link: ${linkwechat.h5Domain}/#/redOrCardPullNews?id={}&type={}&orderId={}
+    coupon-img: ${linkwechat.h5Domain}/static/cardPullNews.png
+    coupon-link: ${linkwechat.h5Domain}/#/cardPullNews?id={}&type={}
+    description: 点击领取
+
+task-msg:
+  qi-rule:
+    title: 会话质检
+    desc: 你有一条【{}】的{}回话已超时未回复,请及时处理
+    manage-desc: 有一条处于你督导规则下成员【{}】的{}会话已超时未回复
+    url: ${linkwechat.h5Domain}/#/quality?id={}&type={}
+    btnTxt: 去处理
+    manage-btnTxt: 去查看
+    weeklyUrl: ${linkwechat.h5Domain}/#/weekly?id={}

+ 37 - 0
config/lw_nacos_config/DEFAULT_GROUP/linkwe-wecom.yml

@@ -0,0 +1,37 @@
+server:
+  # 服务器的HTTP端口,默认为8090
+  port: 6093
+  servlet:
+    # 应用的访问路径
+    context-path: /
+  tomcat:
+    # tomcat的URI编码
+    uri-encoding: UTF-8
+linkwechat:
+  weComeProxyConfig:
+    startProxy: false #是否开启代理 true开启 false不开启,如果为false,则proxyIp,proxyPort,proxyUserName,proxyPassword需要配置。
+    proxyIp: "" #代理服务器的ip
+    #代理服务器端口
+    proxyPort: 0  
+    proxyUserName: "" #代理服务器账号
+    proxyPassword: "" #代理服务器密码
+# forest配置
+forest:
+  backend: okhttp3
+  max-retry-count:  3 # 请求失败后重试次数,默认为0次不重试
+  max-retry-interval: 5000 #重试间隔时间
+  connect-timeout: 5000 #链接超时时间
+  timeout: 5000  # 请求超时时间
+  ## 日志总开关,打开/关闭Forest请求/响应日志(默认为 true)
+  log-enabled: true
+  ## 打开/关闭Forest请求日志(默认为 true)
+  log-request: true
+  ## 打开/关闭Forest响应状态日志(默认为 true)
+  log-response-status: true
+  ## 打开/关闭Forest响应内容日志(默认为 false)
+  log-response-content: true
+  variables:
+    weComServerUrl: https://qyapi.weixin.qq.com/cgi-bin
+    wxServerUrl: https://api.weixin.qq.com/sns
+    wxCommonServerUrl: https://api.weixin.qq.com/cgi-bin
+    wxAppletServerUrl: https://api.weixin.qq.com/wxa

+ 16 - 0
config/lw_nacos_config/DEFAULT_GROUP/linkwe-wx-api.yml

@@ -0,0 +1,16 @@
+server:
+  # 服务器的HTTP端口,默认为8090
+  port: 6094
+  servlet:
+    # 应用的访问路径
+    context-path: /wx-api
+  tomcat:
+    # tomcat的URI编码
+    uri-encoding: UTF-8
+
+swagger:
+  enabled: true
+  pathMapping: /
+  title: LinkWeChat微信业务接口
+  description: LinkWeChat微信业务相关接口
+  version: 3.0

+ 12 - 8
config/run/bootstrap.yml

@@ -1,5 +1,9 @@
 spring:
-  profiles: local
+  profiles:
+    active: '@spring.profiles.active@'
+---
+spring:
+  profiles: dev
   main:
     allow-bean-definition-overriding: true
     allow-circular-references: true
@@ -8,7 +12,7 @@ spring:
       # 配置中心
       config:
         # 命名空间id(此处不用public,因public初始化的空间, id为空)  4e237601-cea8-414d-b7b9-d7adc8cbcf95
-        namespace: 0c644b7e-505b-4c39-bee2-297e828abc17
+        namespace: ewscrm
         # nacos的ip地址和端口 120.79.64.17:10848
         server-addr: 127.0.0.1:8848
         # 这个就表示 在我们nacos命名空间id为 dev中 有一个data-id 为 demo-service.yml 的配置文件 读取这个里面的配置
@@ -26,7 +30,7 @@ spring:
         server-addr: ${spring.cloud.nacos.config.server-addr}
 ---
 spring:
-  profiles: dev
+  profiles: test
   main:
     allow-bean-definition-overriding: true
     allow-circular-references: true
@@ -35,9 +39,9 @@ spring:
       # 配置中心
       config:
         # 命名空间id(此处不用public,因public初始化的空间, id为空)
-        namespace: 5633d616-30dc-40e4-8816-f82e88f329ab
+        namespace: ewscrm
         # nacos的ip地址和端口
-        server-addr: 127.0.0.1:8848
+        server-addr: 172.30.0.47:8848
         # 这个就表示 在我们nacos命名空间id为 dev中 有一个data-id 为 demo-service.yml 的配置文件 读取这个里面的配置
         file-extension: yml
         config-retry-time: 300000
@@ -62,9 +66,9 @@ spring:
       # 配置中心
       config:
         # 命名空间id(此处不用public,因public初始化的空间, id为空)
-        namespace: 4e237601-cea8-414d-b7b9-d7adc8cbcf95
-        # nacos的ip地址和端口 
-        server-addr:  127.0.0.1:8848
+        namespace: ewscrm
+        # nacos的ip地址和端口
+        server-addr: 172.30.0.47:8848
         # 这个就表示 在我们nacos命名空间id为 dev中 有一个data-id 为 demo-service.yml 的配置文件 读取这个里面的配置
         file-extension: yml
         config-retry-time: 300000

+ 116 - 0
linkwe-ai/pom.xml

@@ -0,0 +1,116 @@
+<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <artifactId>linkwechat-cloud</artifactId>
+        <groupId>com.linkwechat</groupId>
+        <version>2023-release</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>linkwe-ai</artifactId>
+    <name>linkwe-ai</name>
+    <description>linkwe-ai</description>
+
+    <properties>
+        <java.version>1.8</java.version>
+        <maven.compiler.source>1.8</maven.compiler.source>
+        <maven.compiler.target>1.8</maven.compiler.target>
+        <maven.build.timestamp.format>yyyyMMddHHmmss</maven.build.timestamp.format>
+    </properties>
+
+    <dependencies>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>com.linkwechat</groupId>
+            <artifactId>linkwe-service</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.alibaba.cloud</groupId>
+            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
+            <version>2021.1</version>
+        </dependency>
+
+        <!-- SpringCloud Alibaba Nacos Config -->
+        <dependency>
+            <groupId>com.alibaba.cloud</groupId>
+            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+        </dependency>
+
+        <!-- 阿里数据库连接池 -->
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>druid-spring-boot-starter</artifactId>
+        </dependency>
+
+        <!-- swagger2-->
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-swagger2</artifactId>
+        </dependency>
+    </dependencies>
+
+
+    <build>
+        <finalName>lw-ai</finalName>
+        <plugins>
+            <!-- 引用Spring Boot Maven插件 -->
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>${springboot.maven.version}</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <!-- 引用jib-maven-plugin插件 -->
+            <plugin>
+                <groupId>com.google.cloud.tools</groupId>
+                <artifactId>jib-maven-plugin</artifactId>
+                <version>${jib.maven.plugin.version}</version>
+                <configuration>
+                    <to>
+                        <image>${docker.harbor.addr}/${docker.harbor.project}/${project.artifactId}:${docker.harbor.tag.version}</image>
+                        <auth>
+                            <username>${docker.harbor.username}</username>
+                            <password>${docker.harbor.password}</password>
+                        </auth>
+                    </to>
+                    <container>
+                        <jvmFlags>
+                            <jvmFlag>-Duser.timezone=Asia/Shanghai</jvmFlag>
+                        </jvmFlags>
+                    </container>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

+ 28 - 0
linkwe-ai/src/main/java/com/linkwechat/LinkweAiApplication.java

@@ -0,0 +1,28 @@
+package com.linkwechat;
+
+import com.github.pagehelper.autoconfigure.PageHelperAutoConfiguration;
+import com.linkwechat.common.config.fegin.FeginConfig;
+import com.linkwechat.common.constant.WeServerNameConstants;
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.cloud.openfeign.EnableFeignClients;
+import org.springframework.scheduling.annotation.EnableAsync;
+
+
+@MapperScan("com.linkwechat.**.mapper")
+@SpringBootApplication(exclude = {PageHelperAutoConfiguration.class})
+@EnableAsync
+@EnableFeignClients(defaultConfiguration = FeginConfig.class)
+public class LinkweAiApplication {
+
+    public static void main(String[] args) {
+        new SpringApplicationBuilder(LinkweAiApplication.class)
+                .properties("spring.config.name:bootstrap", "config/run/bootstrap.yml")
+                .properties("spring.application.name="+ WeServerNameConstants.linkweAi)
+                .build().run(args);
+        System.out.println("(♥◠‿◠)ノ゙  LinkWe-ai启动成功   ლ(´ڡ`ლ)゙ ");
+    }
+
+}

+ 9 - 0
linkwe-ai/src/main/java/com/linkwechat/annotation/AiMsgAop.java

@@ -0,0 +1,9 @@
+package com.linkwechat.annotation;
+
+import java.lang.annotation.*;
+
+@Target({ElementType.PARAMETER, ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface AiMsgAop {
+}

+ 41 - 0
linkwe-ai/src/main/java/com/linkwechat/aspecj/WeAiMsgTokenAspect.java

@@ -0,0 +1,41 @@
+//package com.linkwechat.aspecj;
+//
+//import com.linkwechat.common.exception.wecom.WeComException;
+//import com.linkwechat.service.IWeAiMsgService;
+//import lombok.extern.slf4j.Slf4j;
+//import org.aspectj.lang.JoinPoint;
+//import org.aspectj.lang.annotation.Aspect;
+//import org.aspectj.lang.annotation.Before;
+//import org.aspectj.lang.annotation.Pointcut;
+//import org.springframework.beans.factory.annotation.Autowired;
+//import org.springframework.beans.factory.annotation.Value;
+//import org.springframework.stereotype.Component;
+//
+//@Slf4j
+//@Aspect
+//@Component
+//public class WeAiMsgTokenAspect {
+//
+//    @Autowired
+//    private IWeAiMsgService weAiMsgService;
+//
+//    @Value("${ai.token.num:10000}")
+//    private int tokenTotalNum;
+//
+//
+//    @Pointcut("@annotation(com.linkwechat.annotation.AiMsgAop)")
+//    public void annotationPointCut() {
+//    }
+//
+//    @Before(value = "annotationPointCut()")
+//    public void tokenComputeHandle(JoinPoint joinPoint) throws Throwable {
+//        Object[] args = joinPoint.getArgs();
+//        if (args == null || args.length <= 0) {
+//            return;
+//        }
+//        Integer todayToken = weAiMsgService.computeTodayToken();
+//        if(todayToken != null && todayToken >= tokenTotalNum){
+//            throw new WeComException("今天已超过配额限制");
+//        }
+//    }
+//}

+ 141 - 0
linkwe-ai/src/main/java/com/linkwechat/config/SwaggerConfig.java

@@ -0,0 +1,141 @@
+package com.linkwechat.config;
+
+import com.linkwechat.common.config.LinkWeChatConfig;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.service.*;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spi.service.contexts.SecurityContext;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Swagger2的接口配置
+ *
+ * @author ruoyi
+ */
+@Configuration
+@EnableSwagger2
+public class SwaggerConfig {
+
+
+    /**
+     * 系统基础配置
+     */
+    @Autowired
+    private LinkWeChatConfig linkWeChatConfig;
+
+    /**
+     * 是否开启swagger
+     */
+    @Value("${swagger.enabled}")
+    private boolean enabled;
+
+    /**
+     * 设置请求的统一前缀
+     */
+    @Value("${swagger.pathMapping}")
+    private String pathMapping;
+    /**
+     * 标题
+     */
+    @Value("${swagger.title}")
+    private String title;
+    /**
+     * 描述
+     */
+    @Value("${swagger.description}")
+    private String description;
+    /**
+     * 版本
+     */
+    @Value("${swagger.version}")
+    private String version;
+
+    /**
+     * 创建API
+     */
+    @Bean
+    public Docket createRestApi() {
+        return new Docket(DocumentationType.SWAGGER_2)
+                // 是否启用Swagger
+                .enable(enabled)
+                // 用来创建该API的基本信息,展示在文档的页面中(自定义展示的信息)
+                .apiInfo(apiInfo())
+                // 设置哪些接口暴露给Swagger展示
+                .select()
+                // 扫描所有有注解的api,用这种方式更灵活
+                .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
+                // 扫描指定包中的swagger注解
+                // .apis(RequestHandlerSelectors.basePackage("com.ruoyi.project.tool.swagger"))
+                // 扫描所有 .apis(RequestHandlerSelectors.any())
+                .paths(PathSelectors.any())
+                .build()
+                /* 设置安全模式,swagger可以设置访问token */
+                .securitySchemes(securitySchemes())
+                .securityContexts(securityContexts())
+                .pathMapping(pathMapping);
+    }
+
+    /**
+     * 安全模式,这里指定token通过Authorization头请求头传递
+     */
+    private List<ApiKey> securitySchemes() {
+        List<ApiKey> apiKeyList = new ArrayList<ApiKey>();
+        apiKeyList.add(new ApiKey("Authorization", "Authorization", "header"));
+        return apiKeyList;
+    }
+
+    /**
+     * 安全上下文
+     */
+    private List<SecurityContext> securityContexts() {
+        List<SecurityContext> securityContexts = new ArrayList<>();
+        securityContexts.add(
+                SecurityContext.builder()
+                        .securityReferences(defaultAuth())
+                        .forPaths(PathSelectors.regex("^(?!auth).*$"))
+                        .build());
+        return securityContexts;
+    }
+
+    /**
+     * 默认的安全上引用
+     */
+    private List<SecurityReference> defaultAuth() {
+        AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
+        AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
+        authorizationScopes[0] = authorizationScope;
+        List<SecurityReference> securityReferences = new ArrayList<>();
+        securityReferences.add(new SecurityReference("Authorization", authorizationScopes));
+        return securityReferences;
+    }
+
+    /**
+     * 添加摘要信息
+     */
+    private ApiInfo apiInfo() {
+        // 用ApiInfoBuilder进行定制
+        return new ApiInfoBuilder()
+                // 设置标题
+                .title(title)
+                // 描述
+                .description(description)
+                // 作者信息
+                .contact(new Contact(linkWeChatConfig.getName(), null, null))
+                // 版本
+                .version("版本号:" + version)
+                .build();
+    }
+
+
+}

+ 21 - 0
linkwe-ai/src/main/java/com/linkwechat/config/WebConfig.java

@@ -0,0 +1,21 @@
+package com.linkwechat.config;
+
+import com.linkwechat.interceptor.RequestContextInterceptor;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.CorsRegistry;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+/**
+ * @author danmo
+ * @description 拦截器配置
+ * @date 2022/4/9 22:58
+ **/
+@Configuration
+public class WebConfig implements WebMvcConfigurer {
+
+    @Override
+    public void addInterceptors(InterceptorRegistry registry) {
+        registry.addInterceptor(new RequestContextInterceptor());
+    }
+}

+ 90 - 0
linkwe-ai/src/main/java/com/linkwechat/controller/WeAiAssistantController.java

@@ -0,0 +1,90 @@
+package com.linkwechat.controller;
+
+import com.github.pagehelper.PageInfo;
+import com.linkwechat.common.core.controller.BaseController;
+import com.linkwechat.common.core.domain.AjaxResult;
+import com.linkwechat.common.core.page.TableDataInfo;
+import com.linkwechat.domain.*;
+import com.linkwechat.service.IWeAiSessionService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
+
+import java.util.List;
+
+@RestController
+@RequestMapping(value = "/assistant")
+@Api(tags = "AI助手管理")
+public class WeAiAssistantController extends BaseController {
+
+    @Autowired
+    private IWeAiSessionService iWeAiSessionService;
+
+
+    @ApiOperation(value = "创建连接", httpMethod = "GET")
+    @GetMapping(value = "/create/connect", produces = {MediaType.TEXT_EVENT_STREAM_VALUE})
+    public SseEmitter createSseConnect(@RequestParam("sessionId") String sessionId) {
+        return iWeAiSessionService.createSseConnect(sessionId);
+    }
+
+    @ApiOperation(value = "关闭连接", httpMethod = "GET")
+    @GetMapping("/close/connect/{sessionId}")
+    public AjaxResult closeSseConnect(@PathVariable("sessionId") String sessionId) {
+        iWeAiSessionService.closeSseConnect(sessionId);
+        return AjaxResult.success();
+    }
+
+    /* @ApiOperation(value = "发送消息",httpMethod = "POST")
+     @PostMapping("/send/msg")
+     public AjaxResult sendMsg(@RequestBody @Validated WeAiMsgQuery query){
+         iWeAiSessionService.sendMsg(query);
+         return AjaxResult.success();
+     }
+ */
+    @ApiOperation(value = "发送消息", httpMethod = "POST")
+    @PostMapping(value = "/send/msg", produces = {MediaType.TEXT_EVENT_STREAM_VALUE})
+    public SseEmitter sendMsg(@RequestBody @Validated WeAiMsgQuery query) {
+        return iWeAiSessionService.createAndSendMsg(query);
+    }
+
+    @ApiOperation(value = "消息列表", httpMethod = "POST")
+    @PostMapping("/msg/list")
+    public TableDataInfo<List<WeAiMsgVo>> list(@RequestBody WeAiMsgListQuery query) {
+        startPage(query.getPageIndex(), query.getPageSize());
+        PageInfo<WeAiMsgVo> reslut = iWeAiSessionService.list(query);
+        return getDataTable(reslut);
+    }
+
+    @ApiOperation(value = "消息详情", httpMethod = "GET")
+    @GetMapping("/msg/get/{sessionId}")
+    public AjaxResult<WeAiMsgVo> getDetail(@PathVariable("sessionId") String sessionId) {
+        List<WeAiMsgVo> reslut = iWeAiSessionService.getDetail(sessionId);
+        return AjaxResult.success(reslut);
+    }
+
+    @ApiOperation(value = "删除会话", httpMethod = "POST")
+    @PostMapping("/msg/del")
+    public AjaxResult<WeAiMsgVo> delMsg(@RequestBody WeAiMsgQuery query) {
+        iWeAiSessionService.delMsg(query);
+        return AjaxResult.success();
+    }
+
+    @ApiOperation(value = "收藏对话", httpMethod = "POST")
+    @PostMapping("/msg/collection")
+    public AjaxResult<WeAiMsgVo> collectionMsg(@RequestBody WeAiCollectionMsgQuery query) {
+        iWeAiSessionService.collectionMsg(query);
+        return AjaxResult.success();
+    }
+
+    @ApiOperation(value = "收藏列表", httpMethod = "POST")
+    @PostMapping("/msg/collection/list")
+    public TableDataInfo<List<WeAiCollectionMsgVo>>collectionList(@RequestBody WeAiMsgListQuery query) {
+        startPage(query.getPageIndex(), query.getPageSize());
+        PageInfo<WeAiCollectionMsgVo> reslut = iWeAiSessionService.collectionList(query);
+        return getDataTable(reslut);
+    }
+}

+ 19 - 0
linkwe-ai/src/main/java/com/linkwechat/domain/AiMessage.java

@@ -0,0 +1,19 @@
+package com.linkwechat.domain;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+@ApiModel
+@Data
+public class AiMessage {
+
+    @ApiModelProperty("角色")
+    private String role;
+
+    @ApiModelProperty("内容")
+    private String content;
+}

+ 37 - 0
linkwe-ai/src/main/java/com/linkwechat/domain/PostBaseQuery.java

@@ -0,0 +1,37 @@
+package com.linkwechat.domain;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * @author danmo
+ * @date 2023年07月06日 22:58
+ */
+@ApiModel
+@Data
+public class PostBaseQuery {
+
+    @ApiModelProperty(value = "页码", hidden = true)
+    private Integer pageIndex = 1;
+
+    @ApiModelProperty(value = "条数", hidden = true)
+    private Integer pageSize = 10;
+
+    @ApiModelProperty(value = "排序字段", hidden = true)
+    private String sortField;
+
+    @ApiModelProperty(value = "排序方式 asc、desc", hidden = true)
+    private String sort;
+
+    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
+    @ApiModelProperty(value = "开始时间", example = "yyyy-MM-dd", hidden = true)
+    private Date beginTime;
+
+    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
+    @ApiModelProperty(value = "结束时间", example = "yyyy-MM-dd", hidden = true)
+    private Date endTime;
+}

+ 16 - 0
linkwe-ai/src/main/java/com/linkwechat/domain/WeAiCollectionMsgQuery.java

@@ -0,0 +1,16 @@
+package com.linkwechat.domain;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@ApiModel
+@Data
+public class WeAiCollectionMsgQuery {
+
+    @ApiModelProperty("消息ID")
+    private String msgId;
+
+    @ApiModelProperty("收藏状态 0-未收藏 1-已收藏")
+    private Integer status;
+}

+ 23 - 0
linkwe-ai/src/main/java/com/linkwechat/domain/WeAiCollectionMsgVo.java

@@ -0,0 +1,23 @@
+package com.linkwechat.domain;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+import java.util.List;
+
+@ApiModel
+@Data
+public class WeAiCollectionMsgVo {
+
+    @ApiModelProperty("会话ID")
+    private String sessionId;
+
+    @ApiModelProperty("AI对话消息ID")
+    private String msgId;
+
+    @ApiModelProperty("对话内容")
+    private List<WeAiMsgVo> contentList;
+}

+ 18 - 0
linkwe-ai/src/main/java/com/linkwechat/domain/WeAiMsgListQuery.java

@@ -0,0 +1,18 @@
+package com.linkwechat.domain;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+@ApiModel
+@Data
+public class WeAiMsgListQuery extends WeAiMsgQuery {
+
+    @ApiModelProperty("内容")
+    private String content;
+
+    @ApiModelProperty(value = "员工ID",hidden = true)
+    private Long userId;
+}

+ 23 - 0
linkwe-ai/src/main/java/com/linkwechat/domain/WeAiMsgQuery.java

@@ -0,0 +1,23 @@
+package com.linkwechat.domain;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+
+@ApiModel
+@Data
+public class WeAiMsgQuery extends PostBaseQuery {
+
+    @ApiModelProperty(value = "会话ID", required = true)
+    private String sessionId;
+
+    @NotNull(message = "消息不能为空")
+    @ApiModelProperty(value = "消息", required = true)
+    private AiMessage msg;
+
+    @ApiModelProperty(hidden = true)
+    private Long userId;
+}

+ 80 - 0
linkwe-ai/src/main/java/com/linkwechat/domain/WeAiMsgVo.java

@@ -0,0 +1,80 @@
+package com.linkwechat.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.tencentcloudapi.hunyuan.v20230901.models.Message;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+@ApiModel
+@Data
+public class WeAiMsgVo {
+
+    /**
+     * 主键id
+     */
+    @ApiModelProperty(value = "主键id")
+    private Long id;
+
+
+    /**
+     * 会话ID
+     */
+    @ApiModelProperty(value = "会话ID")
+    private String sessionId;
+
+
+    /**
+     * AI对话ID
+     */
+    @ApiModelProperty(value = "AI对话ID")
+    private String msgId;
+
+
+    /**
+     * 员工ID
+     */
+    @ApiModelProperty(value = "员工ID")
+    private Long userId;
+
+
+    /**
+     * 角色
+     */
+    @ApiModelProperty(value = "角色")
+    private String role;
+
+
+    /**
+     * 内容
+     */
+    @ApiModelProperty(value = "内容")
+    private String content;
+
+
+    /**
+     * 结果ID
+     */
+    @ApiModelProperty(value = "结果ID")
+    private String requestId;
+
+
+    /**
+     * 发送时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    @ApiModelProperty(value = "发送时间")
+    private Date sendTime;
+
+
+    /**
+     * 收藏 0-未收藏 1-收藏
+     */
+    @ApiModelProperty(value = "收藏 0-未收藏 1-收藏")
+    private Integer collection;
+}

+ 50 - 0
linkwe-ai/src/main/java/com/linkwechat/interceptor/RequestContextInterceptor.java

@@ -0,0 +1,50 @@
+package com.linkwechat.interceptor;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.alibaba.fastjson.JSONObject;
+import com.linkwechat.common.constant.SecurityConstants;
+import com.linkwechat.common.context.SecurityContextHolder;
+import com.linkwechat.common.core.domain.model.LoginUser;
+import com.linkwechat.common.exception.wecom.WeComException;
+import com.linkwechat.common.utils.ServletUtils;
+import com.linkwechat.common.utils.StringUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+import org.springframework.web.method.HandlerMethod;
+import org.springframework.web.servlet.HandlerInterceptor;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * 自定义请求头拦截器,将Header数据封装到线程变量中方便获取
+ *
+ * @author danmo
+ */
+@Slf4j
+@Component
+public class RequestContextInterceptor implements HandlerInterceptor {
+    @Override
+    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
+        if (!(handler instanceof HandlerMethod)) {
+            return true;
+        }
+        SecurityContextHolder.setCorpId(ServletUtils.getHeader(request, SecurityConstants.CORP_ID));
+        SecurityContextHolder.setCorpName(ServletUtils.getHeader(request, SecurityConstants.CORP_NAME));
+        SecurityContextHolder.setUserId(ServletUtils.getHeader(request, SecurityConstants.USER_ID));
+        SecurityContextHolder.setUserName(ServletUtils.getHeader(request, SecurityConstants.USER_NAME));
+        SecurityContextHolder.setUserType(ServletUtils.getHeader(request, SecurityConstants.USER_TYPE));
+        SecurityContextHolder.setUserKey(ServletUtils.getHeader(request, SecurityConstants.USER_KEY));
+        String loginUserStr = ServletUtils.getHeader(request, SecurityConstants.LOGIN_USER);
+        if(StringUtils.isNotEmpty(loginUserStr)){
+            SecurityContextHolder.set(SecurityConstants.Details.LOGIN_USER.getCode(), JSONObject.parseObject(loginUserStr, LoginUser.class));
+        }
+        return true;
+    }
+
+    @Override
+    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
+            throws Exception {
+        SecurityContextHolder.remove();
+    }
+}

+ 38 - 0
linkwe-ai/src/main/java/com/linkwechat/listener/AiMessageListener.java

@@ -0,0 +1,38 @@
+package com.linkwechat.listener;
+
+import com.alibaba.fastjson.JSONObject;
+import com.linkwechat.domain.WeAiMsgQuery;
+import com.linkwechat.service.IWeAiSessionService;
+import com.rabbitmq.client.Channel;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.amqp.core.Message;
+import org.springframework.amqp.rabbit.annotation.RabbitHandler;
+import org.springframework.amqp.rabbit.annotation.RabbitListener;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.io.IOException;
+
+@Component
+@Slf4j
+public class AiMessageListener {
+
+    @Autowired
+    private IWeAiSessionService iWeAiSessionService;
+
+    @RabbitHandler
+    @RabbitListener(queues = "${wecom.mq.queue.ai-msg:Qu_AiMsg}")
+    public void subscribe(String msg, Channel channel, Message message) throws IOException {
+        try {
+            log.info("发送AI消息:msg:{}", msg);
+            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
+            iWeAiSessionService.sendAiMsg(JSONObject.parseObject(msg, WeAiMsgQuery.class));
+        } catch (Exception e) {
+            log.error("发送AI消息监听-消息处理失败 msg:{},error:{}", msg, e.getMessage(), e);
+            channel.basicNack(message.getMessageProperties().getDeliveryTag(), true, true);
+        }
+
+    }
+
+
+}

+ 50 - 0
linkwe-ai/src/main/java/com/linkwechat/service/IWeAiSessionService.java

@@ -0,0 +1,50 @@
+package com.linkwechat.service;
+
+import com.github.pagehelper.PageInfo;
+import com.linkwechat.domain.*;
+import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
+
+import java.util.List;
+
+public interface IWeAiSessionService {
+    SseEmitter createSseConnect(String sessionId);
+
+
+    void closeSseConnect(String sessionId);
+
+    void sendMsg(WeAiMsgQuery query);
+
+    void sendAiMsg(WeAiMsgQuery query);
+
+    PageInfo<WeAiMsgVo> list(WeAiMsgListQuery query);
+
+    List<WeAiMsgVo> getDetail(String sessionId);
+
+    /**
+     * 创建连接并发送消息
+     * @param query
+     * @return
+     */
+    SseEmitter createAndSendMsg(WeAiMsgQuery query);
+
+    /**
+     * 删除会话
+     * @param query
+     */
+    void delMsg(WeAiMsgQuery query);
+
+    /**
+     * 收藏/取消消息
+     * @param query
+     * @return
+     */
+    void collectionMsg(WeAiCollectionMsgQuery query);
+
+
+    /**
+     * 收藏列表
+     * @param query
+     * @return
+     */
+    PageInfo<WeAiCollectionMsgVo> collectionList(WeAiMsgListQuery query);
+}

+ 291 - 0
linkwe-ai/src/main/java/com/linkwechat/service/impl/WeAiSessionServiceImpl.java

@@ -0,0 +1,291 @@
+package com.linkwechat.service.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.thread.ThreadUtil;
+import cn.hutool.core.util.IdUtil;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.github.pagehelper.PageInfo;
+import com.linkwechat.annotation.AiMsgAop;
+import com.linkwechat.common.context.SecurityContextHolder;
+import com.linkwechat.common.exception.wecom.WeComException;
+import com.linkwechat.common.utils.SecurityUtils;
+import com.linkwechat.common.utils.StringUtils;
+import com.linkwechat.config.rabbitmq.RabbitMQSettingConfig;
+import com.linkwechat.domain.*;
+import com.linkwechat.service.HunYuanService;
+import com.linkwechat.service.IWeAiMsgService;
+import com.linkwechat.service.IWeAiSessionService;
+import com.linkwechat.utils.WeAiSessionUtil;
+import com.tencentcloudapi.hunyuan.v20230901.models.ChatStdResponse;
+import com.tencentcloudapi.hunyuan.v20230901.models.Choice;
+import com.tencentcloudapi.hunyuan.v20230901.models.Delta;
+import com.tencentcloudapi.hunyuan.v20230901.models.Message;
+import io.netty.util.concurrent.DefaultThreadFactory;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.amqp.rabbit.core.RabbitTemplate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
+
+import java.io.IOException;
+import java.util.*;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Service
+public class WeAiSessionServiceImpl implements IWeAiSessionService {
+
+    @Autowired
+    private IWeAiMsgService iWeAiMsgService;
+
+    @Autowired
+    private HunYuanService hunYuanService;
+
+    @Autowired
+    private RabbitTemplate rabbitTemplate;
+
+    @Autowired
+    private RabbitMQSettingConfig rabbitMQSettingConfig;
+
+    @Value("${ai.token.num:10000}")
+    private int tokenTotalNum;
+
+    private static ExecutorService sseThread = new ScheduledThreadPoolExecutor(1, new DefaultThreadFactory("we-sse-pool-%d"));
+
+    @Override
+    public SseEmitter createSseConnect(String sessionId) {
+        if (StringUtils.isEmpty(sessionId)) {
+            sessionId = IdUtil.simpleUUID();
+        }
+        // 设置超时时间,0表示不过期。默认30秒,超过时间未完成会抛出异常:AsyncRequestTimeoutException
+        SseEmitter sseEmitter = new SseEmitter(0L);
+        // 注册回调
+        sseEmitter.onCompletion(completionCallBack(sessionId));
+
+        WeAiSessionUtil.add(sessionId, sseEmitter);
+        log.info("创建新的sse连接,当前session:{}", sessionId);
+
+        try {
+            sseEmitter.send(SseEmitter.event().id("sessionId").data(sessionId));
+        } catch (IOException e) {
+            log.error("SseEmitterServiceImpl[createSseConnect]: 创建长链接异常,客户端ID:{}", sessionId, e);
+            throw new WeComException("创建连接异常!");
+        }
+        return sseEmitter;
+    }
+
+    @Override
+    public void closeSseConnect(String sessionId) {
+        WeAiSessionUtil.removeAndClose(sessionId);
+    }
+
+    @Override
+    public void sendMsg(WeAiMsgQuery query) {
+        SseEmitter sseEmitter = WeAiSessionUtil.get(query.getSessionId());
+        if (Objects.nonNull(sseEmitter)) {
+            sendAiMsg(query);
+        } else {
+            rabbitTemplate.convertAndSend(rabbitMQSettingConfig.getAiMsgEx(), "", JSONObject.toJSONString(query));
+        }
+    }
+
+
+    private Runnable completionCallBack(String sessionId) {
+        return () -> {
+            log.info("结束连接:{}", sessionId);
+            WeAiSessionUtil.removeAndClose(sessionId);
+        };
+    }
+
+
+    public void sendAiMsg(WeAiMsgQuery query) {
+        log.info("sendAiMsg---{}",JSONObject.toJSONString(query));
+        if (Objects.isNull(query.getMsg())) {
+            return;
+        }
+        List<AiMessage> aiMessageList = new ArrayList<>();
+
+        List<WeAiMsg> aiLastMsgList = iWeAiMsgService.list(new LambdaQueryWrapper<WeAiMsg>()
+                .eq(WeAiMsg::getSessionId, query.getSessionId())
+                .orderByAsc(WeAiMsg::getId)
+                .last(" limit 40"));
+
+        if (CollectionUtil.isNotEmpty(aiLastMsgList)) {
+            for (WeAiMsg aiMsg : aiLastMsgList) {
+                AiMessage aiMessage = new AiMessage();
+                aiMessage.setRole(aiMsg.getRole());
+                aiMessage.setContent(aiMsg.getContent());
+                aiMessageList.add(aiMessage);
+            }
+        }
+        aiMessageList.add(query.getMsg());
+
+
+        Message[] msgArray = aiMessageList.stream().map(item -> {
+            Message message = new Message();
+            message.setRole(item.getRole());
+            message.setContent(item.getContent());
+            return message;
+        }).toArray(Message[]::new);
+
+
+        WeAiMsg replyMsg = new WeAiMsg();
+        replyMsg.setSessionId(query.getSessionId());
+        StringBuilder replyContent = new StringBuilder();
+        ThreadPoolExecutor threadPoolExecutor = ThreadUtil.newExecutor(5, 10);
+        SseEmitter sseEmitter = WeAiSessionUtil.get(query.getSessionId());
+        hunYuanService.sendMsg(msgArray, (data) -> {
+            if (Objects.nonNull(sseEmitter)) {
+                ChatStdResponse response = JSONObject.parseObject(data, ChatStdResponse.class);
+                replyMsg.setMsgId(response.getId());
+                replyMsg.setNote(response.getNote());
+                replyMsg.setRequestId(response.getRequestId());
+                replyMsg.setSendTime(new Date(response.getCreated() * 1000));
+                try {
+                    sseEmitter.send(SseEmitter.event().name("msg").data(response));
+                } catch (IOException e) {
+                    log.error("发送客户端异常 query:{}", JSONObject.toJSONString(query), e);
+                }
+                replyMsg.setPromptTokens(response.getUsage().getPromptTokens().intValue());
+                replyMsg.setCompletionTokens(response.getUsage().getCompletionTokens().intValue());
+                replyMsg.setTotalTokens(response.getUsage().getTotalTokens().intValue());
+                replyContent.append(Arrays.stream(response.getChoices()).map(Choice::getDelta).map(Delta::getContent).findFirst().orElse(""));
+                String role = Arrays.stream(response.getChoices()).map(Choice::getDelta).map(Delta::getRole).findFirst().orElse("assistant");
+                replyMsg.setRole(role);
+            }
+        });
+        if (Objects.nonNull(sseEmitter)) {
+            sseEmitter.complete();
+        }
+        replyMsg.setContent(replyContent.toString());
+        replyMsg.setUserId(query.getUserId());
+
+        WeAiMsg sendMsg = new WeAiMsg();
+        sendMsg.setSessionId(query.getSessionId());
+        sendMsg.setMsgId(replyMsg.getMsgId());
+        sendMsg.setSendTime(new Date());
+        sendMsg.setRole(query.getMsg().getRole());
+        sendMsg.setContent(query.getMsg().getContent());
+        sendMsg.setUserId(query.getUserId());
+
+        List<WeAiMsg> addMsgList = new ArrayList<>();
+        addMsgList.add(sendMsg);
+        addMsgList.add(replyMsg);
+        iWeAiMsgService.saveBatch(addMsgList);
+    }
+
+    @Override
+    public PageInfo<WeAiMsgVo> list(WeAiMsgListQuery query) {
+        PageInfo<WeAiMsgVo> pageInfo = new PageInfo<>();
+        List<WeAiMsg> weAiMsgList = iWeAiMsgService.getSessionList(SecurityUtils.getUserId(),query.getContent());
+        if (CollectionUtil.isNotEmpty(weAiMsgList)) {
+            List<WeAiMsgVo> weAiMsgVos = weAiMsgList.stream().map(item -> {
+                WeAiMsgVo weAiMsgVo = new WeAiMsgVo();
+                BeanUtil.copyProperties(item, weAiMsgVo);
+                return weAiMsgVo;
+            }).collect(Collectors.toList());
+            pageInfo.setList(weAiMsgVos);
+        }
+        PageInfo<WeAiMsg> msgPageInfo = new PageInfo<>(weAiMsgList);
+        pageInfo.setTotal(msgPageInfo.getTotal());
+        return pageInfo;
+    }
+
+    @Override
+    public List<WeAiMsgVo> getDetail(String sessionId) {
+        List<WeAiMsg> list = iWeAiMsgService.list(new LambdaQueryWrapper<WeAiMsg>().eq(WeAiMsg::getSessionId, sessionId).eq(WeAiMsg::getUserId, SecurityUtils.getUserId())
+                .orderByAsc(WeAiMsg::getId));
+        if (CollectionUtil.isNotEmpty(list)) {
+            return list.stream().map(item -> {
+                WeAiMsgVo weAiMsgVo = new WeAiMsgVo();
+                BeanUtil.copyProperties(item, weAiMsgVo);
+                return weAiMsgVo;
+            }).collect(Collectors.toList());
+        }
+        return null;
+    }
+
+    //@AiMsgAop
+    @Override
+    public SseEmitter createAndSendMsg(WeAiMsgQuery query) {
+        query.setUserId(SecurityUtils.getUserId());
+        log.info("createAndSendMsg---{}",JSONObject.toJSONString(query));
+        if (StringUtils.isEmpty(query.getSessionId())) {
+            query.setSessionId(IdUtil.simpleUUID());
+        }
+        // 设置超时时间,0表示不过期。默认30秒,超过时间未完成会抛出异常:AsyncRequestTimeoutException
+        SseEmitter sseEmitter = new SseEmitter(30 * 1000L);
+        // 注册回调
+        sseEmitter.onCompletion(completionCallBack(query.getSessionId()));
+        WeAiSessionUtil.add(query.getSessionId(), sseEmitter);
+        log.info("创建新的sse连接,当前session:{}", query.getSessionId());
+        sseEmitter.onTimeout(() -> {
+            log.info("连接超时 sessionId:{}", query.getSessionId());
+            WeAiSessionUtil.removeAndClose(query.getSessionId());
+        });
+        try {
+            Integer todayToken = iWeAiMsgService.computeTodayToken();
+            if(todayToken != null && todayToken >= tokenTotalNum){
+                sseEmitter.send(SseEmitter.event().name("error").data("今天已超过配额限制"));
+            }else {
+                sseEmitter.send(SseEmitter.event().id("sessionId").data(query.getSessionId()));
+                if (StringUtils.isEmpty(query.getMsg().getContent())) {
+                    throw new WeComException("消息内容不能为空!");
+                }
+                sseThread.execute(() -> {
+                    sendAiMsg(query);
+                });
+            }
+        } catch (IOException e) {
+            log.error("链接异常,sessionId:{}", query.getSessionId(), e);
+            throw new WeComException("连接异常!");
+        }
+        return sseEmitter;
+    }
+
+    @Override
+    public void delMsg(WeAiMsgQuery query) {
+        iWeAiMsgService.delMsg(query.getSessionId());
+    }
+
+    @Override
+    public void collectionMsg(WeAiCollectionMsgQuery query) {
+        if(StringUtils.isEmpty(query.getMsgId())){
+            return;
+        }
+        iWeAiMsgService.collectionMsg(query.getMsgId(),query.getStatus());
+    }
+
+    @Override
+    public PageInfo<WeAiCollectionMsgVo> collectionList(WeAiMsgListQuery query) {
+        PageInfo<WeAiCollectionMsgVo> pageInfo = new PageInfo<>();
+        List<String> msgIds = iWeAiMsgService.collectionMsgIdByQuery(SecurityUtils.getUserId(),query.getContent());
+        if (CollectionUtil.isNotEmpty(msgIds)) {
+            List<WeAiMsg> weAiMsgList = iWeAiMsgService.collectionList(msgIds);
+            Map<String, List<WeAiMsg>> msgMap = weAiMsgList.stream().collect(Collectors.groupingBy(WeAiMsg::getMsgId));
+            List<WeAiCollectionMsgVo> reustList = new ArrayList<>();
+            for (String msgId : msgIds) {
+                WeAiCollectionMsgVo weAiCollectionMsg = new WeAiCollectionMsgVo();
+                weAiCollectionMsg.setMsgId(msgId);
+                List<WeAiMsgVo> weAiMsgVoList = msgMap.get(msgId).stream().map(item -> {
+                    weAiCollectionMsg.setSessionId(item.getSessionId());
+                    WeAiMsgVo weAiMsgVo = new WeAiMsgVo();
+                    BeanUtil.copyProperties(item, weAiMsgVo);
+                    return weAiMsgVo;
+                }).sorted(Comparator.comparing(WeAiMsgVo::getId)).collect(Collectors.toList());
+                weAiCollectionMsg.setContentList(weAiMsgVoList);
+                reustList.add(weAiCollectionMsg);
+            }
+            pageInfo.setList(reustList);
+        }
+        PageInfo<String> msgPageInfo = new PageInfo<>(msgIds);
+        pageInfo.setTotal(msgPageInfo.getTotal());
+        return pageInfo;
+    }
+}

+ 64 - 0
linkwe-ai/src/main/java/com/linkwechat/utils/WeAiSessionUtil.java

@@ -0,0 +1,64 @@
+package com.linkwechat.utils;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
+
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * @author danmo
+ * @date 2023年09月22日 10:53
+ */
+@Slf4j
+public class WeAiSessionUtil {
+
+    public static Map<String, SseEmitter> sessionPool = new ConcurrentHashMap<>(16);
+
+
+
+    /**
+     * 添加session
+     *
+     * @param key     sessionId
+     * @param session session
+     */
+    public static void add(String key, SseEmitter session) {
+        sessionPool.put(key, session);
+    }
+
+    /**
+     * 移除session
+     *
+     * @param key sessionId
+     */
+    public static void remove(String key) {
+        sessionPool.remove(key);
+    }
+
+    /**
+     * 移除session并关闭连接
+     *
+     * @param key sessionId
+     */
+    public static void removeAndClose(String key) {
+        if (sessionPool.containsKey(key)) {
+            SseEmitter sseEmitter = sessionPool.remove(key);
+            if(Objects.nonNull(sseEmitter)){
+                sseEmitter.complete();
+            }
+        }
+
+    }
+
+    /**
+     * 获取session
+     *
+     * @param key sessionId
+     * @return
+     */
+    public static SseEmitter get(String key) {
+        return sessionPool.get(key);
+    }
+}

+ 10 - 0
linkwe-ai/src/main/resources/banner.txt

@@ -0,0 +1,10 @@
+${AnsiColor.GREEN}
+  _     _       _   __        __    ____ _           _      _    _
+ | |   (_)_ __ | | _\ \      / /__ / ___| |__   __ _| |_   / \  (_)
+ | |   | | '_ \| |/ /\ \ /\ / / _ \ |   | '_ \ / _` | __| / _ \ | |
+ | |___| | | | |   <  \ V  V /  __/ |___| | | | (_| | |_ / ___ \| |
+ |_____|_|_| |_|_|\_\  \_/\_/ \___|\____|_| |_|\__,_|\__/_/   \_\ |
+
+ ${AnsiColor.BRIGHT_WHITE}
+
+ Spring Boot Version: ${spring-boot.version}

+ 206 - 0
linkwe-ai/src/main/resources/logback-spring.xml

@@ -0,0 +1,206 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration scan="true" scanPeriod="60 seconds" debug="false">
+    <!-- 日志存放路径 -->
+
+    <property name="app_name" value="linkwe-ai"/>
+
+    <!-- 日志输出格式 -->
+    <property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} | %-5level | %thread | %logger{36}:%L | %M | %msg%n" />
+
+    <!--  邮件 -->
+    <!-- SMTP server的地址,必需指定。如网易的SMTP服务器地址是: smtp.163.com -->
+    <property name="smtpHost" value="smtp.163.com"/><!--填入要发送邮件的smtp服务器地址-->
+    <!-- SMTP server的端口地址。默认值:25 -->
+    <property name="smtpPort" value="25"/>
+    <!-- 发送邮件账号,默认为null -->
+    <property name="username" value="*"/><!--发件人账号-->
+    <!-- 发送邮件密码,默认为null -->
+    <property name="password" value="*"/><!--发件人密码-->
+    <!-- 如果设置为true,appender将会使用SSL连接到日志服务器。默认值:false -->
+    <property name="SSL" value="true"/>
+    <!-- 指定发送到那个邮箱,可设置多个<to>属性,指定多个目的邮箱 -->
+    <property name="email_to" value="*"/>
+    <!--收件人账号多个可以逗号隔开-->
+    <!-- 指定发件人名称。如果设置成“&lt;ADMIN&gt; ”,则邮件发件人将会是“<ADMIN> ” -->
+    <property name="email_from" value="1" />
+    <!-- 指定emial的标题,它需要满足PatternLayout中的格式要求。如果设置成“Log: %logger - %msg ”,就案例来讲,则发送邮件时,标题为“【Error】: com.foo.Bar - Hello World ”。 默认值:"%logger{20} - %m". -->
+    <property name="email_subject" value="【linkwechat-ai】【Error】: %logger" />
+
+    <!-- 日志根目录-->
+    <springProperty scope="context" name="log.path" source="logging.path"
+                    defaultValue="./logs/linkwe-ai"/>
+
+    <!-- 控制台输出 -->
+    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>${log.pattern}</pattern>
+        </encoder>
+    </appender>
+
+    <!-- 系统日志输出 -->
+    <!-- 循环文件输出(基于时间戳的分文件,是实际项目中用途最广的一种情况) -->
+    <appender name="file_debug" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${log.path}/debug/${app_name}.debug.log</file>
+        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+            <!-- rollover daily -->
+            <fileNamePattern>${log.path}/debug/${app_name}_%d{yyyy-MM-dd}.debug.%i.log</fileNamePattern>
+            <!-- each file should be at most 100MB, keep 60 days worth of history, but at most 20GB -->
+            <maxFileSize>50MB</maxFileSize>
+            <maxHistory>30</maxHistory>
+            <totalSizeCap>10GB</totalSizeCap>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${log.pattern}</pattern>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>DEBUG</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+    <!-- 异步输出 -->
+    <appender name="arollingfile_debug" class="ch.qos.logback.classic.AsyncAppender">
+        <!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
+        <discardingThreshold>0</discardingThreshold>
+        <!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
+        <queueSize>1</queueSize>
+        <!-- 添加附加的appender,最多只能添加一个 -->
+        <appender-ref ref="file_debug"/>
+    </appender>
+
+    <!-- 循环文件输出(基于时间戳的分文件,是实际项目中用途最广的一种情况) -->
+    <appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${log.path}/info/${app_name}.info.log</file>
+        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+            <!-- rollover daily -->
+            <fileNamePattern>${log.path}/info/${app_name}_%d{yyyy-MM-dd}.info.%i.log</fileNamePattern>
+            <!-- each file should be at most 100MB, keep 60 days worth of history, but at most 20GB -->
+            <maxFileSize>50MB</maxFileSize>
+            <maxHistory>30</maxHistory>
+            <totalSizeCap>10GB</totalSizeCap>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${log.pattern}</pattern>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>INFO</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+    <!-- 异步输出 -->
+    <appender name="arollingfile_info" class="ch.qos.logback.classic.AsyncAppender">
+        <!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
+        <discardingThreshold>0</discardingThreshold>
+        <!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
+        <queueSize>1</queueSize>
+        <!-- 添加附加的appender,最多只能添加一个 -->
+        <appender-ref ref="file_info"/>
+    </appender>
+
+    <!-- 循环文件输出(基于时间戳的分文件,是实际项目中用途最广的一种情况) -->
+    <appender name="file_warn" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${log.path}/warn/${app_name}.warn.log</file>
+        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+            <!-- rollover daily -->
+            <fileNamePattern>${log.path}/warn/${app_name}_%d{yyyy-MM-dd}.warn.%i.log</fileNamePattern>
+            <!-- each file should be at most 100MB, keep 60 days worth of history, but at most 20GB -->
+            <maxFileSize>50MB</maxFileSize>
+            <maxHistory>30</maxHistory>
+            <totalSizeCap>10GB</totalSizeCap>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${log.pattern}</pattern>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>WARN</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+    <!-- 异步输出 -->
+    <appender name="arollingfile_warn" class="ch.qos.logback.classic.AsyncAppender">
+        <!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
+        <discardingThreshold>0</discardingThreshold>
+        <!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
+        <queueSize>1</queueSize>
+        <!-- 添加附加的appender,最多只能添加一个 -->
+        <appender-ref ref="file_warn"/>
+    </appender>
+
+    <!-- 循环文件输出(基于时间戳的分文件,是实际项目中用途最广的一种情况) -->
+    <appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${log.path}/error/${app_name}.error.log</file>
+        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+            <!-- rollover daily -->
+            <fileNamePattern>${log.path}/error/${app_name}_%d{yyyy-MM-dd}.error.%i.log</fileNamePattern>
+            <!-- each file should be at most 100MB, keep 60 days worth of history, but at most 20GB -->
+            <maxFileSize>50MB</maxFileSize>
+            <maxHistory>30</maxHistory>
+            <totalSizeCap>10GB</totalSizeCap>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${log.pattern}</pattern>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>ERROR</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+    <!-- 异步输出 -->
+    <appender name="arollingfile_error" class="ch.qos.logback.classic.AsyncAppender">
+        <!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
+        <discardingThreshold>0</discardingThreshold>
+        <!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
+        <queueSize>1</queueSize>
+        <!-- 添加附加的appender,最多只能添加一个 -->
+        <appender-ref ref="file_error"/>
+    </appender>
+
+    <!-- ERROR邮件发送 -->
+    <appender name="EMAIL" class="ch.qos.logback.classic.net.SMTPAppender">
+        <smtpHost>${smtpHost}</smtpHost>
+        <smtpPort>${smtpPort}</smtpPort>
+        <username>${username}</username>
+        <password>${password}</password>
+       <!-- <asynchronousSending>true</asynchronousSending>-->
+        <SSL>${SSL}</SSL>
+        <!--<STARTTLS>true</STARTTLS>-->
+        <to>${email_to}</to>
+        <from>${email_from}</from>
+        <subject>${email_subject}</subject>
+        <!-- html格式-->
+        <layout class="ch.qos.logback.classic.html.HTMLLayout">
+            <Pattern>%date%level%thread%logger{0}%line%message</Pattern>
+        </layout>
+        <!-- 这里采用等级过滤器 指定等级相符才发送 -->
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>ERROR</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+        <cyclicBufferTracker class="ch.qos.logback.core.spi.CyclicBufferTracker">
+            <!-- 每个电子邮件只发送一个日志条目 -->
+            <bufferSize>1</bufferSize>
+        </cyclicBufferTracker>
+    </appender>
+
+
+    <!-- 系统模块日志级别控制  -->
+    <logger name="cn.linkwechat" level="info" />
+    <!-- Spring日志级别控制  -->
+    <logger name="org.springframework" level="warn" />
+
+    <!--系统操作日志-->
+    <root level="info">
+        <appender-ref ref="console" />
+        <appender-ref ref="arollingfile_debug" />
+        <appender-ref ref="arollingfile_info" />
+        <appender-ref ref="arollingfile_warn" />
+        <appender-ref ref="arollingfile_error" />
+        <!-- <appender-ref ref="alarm_error" />-->
+        <appender-ref ref="EMAIL" />
+    </root>
+
+</configuration>

+ 24 - 0
linkwe-ai/src/main/resources/spy.properties

@@ -0,0 +1,24 @@
+#3.2.1\u4EE5\u4E0A\u4F7F\u7528
+modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory
+#3.2.1\u4EE5\u4E0B\u4F7F\u7528\u6216\u8005\u4E0D\u914D\u7F6E
+#modulelist=com.p6spy.engine.logging.P6LogFactory,com.p6spy.engine.outage.P6OutageFactory
+# \u81EA\u5B9A\u4E49\u65E5\u5FD7\u6253\u5370
+logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger
+#\u65E5\u5FD7\u8F93\u51FA\u5230\u63A7\u5236\u53F0
+appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger
+# \u4F7F\u7528\u65E5\u5FD7\u7CFB\u7EDF\u8BB0\u5F55 sql
+#appender=com.p6spy.engine.spy.appender.Slf4JLogger
+# \u8BBE\u7F6E p6spy driver \u4EE3\u7406
+deregisterdrivers=true
+# \u53D6\u6D88JDBC URL\u524D\u7F00
+useprefix=true
+# \u914D\u7F6E\u8BB0\u5F55 Log \u4F8B\u5916,\u53EF\u53BB\u6389\u7684\u7ED3\u679C\u96C6\u6709error,info,batch,debug,statement,commit,rollback,result,resultset.
+excludecategories=info,debug,result,commit,resultset
+# \u65E5\u671F\u683C\u5F0F
+dateformat=yyyy-MM-dd HH:mm:ss
+# \u5B9E\u9645\u9A71\u52A8\u53EF\u591A\u4E2A
+#driverlist=org.h2.Driver
+# \u662F\u5426\u5F00\u542F\u6162SQL\u8BB0\u5F55
+outagedetection=true
+# \u6162SQL\u8BB0\u5F55\u6807\u51C6 2 \u79D2
+outagedetectioninterval=2

+ 13 - 0
linkwe-ai/src/test/java/com/linkwechat/LinkweAiApplicationTests.java

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

+ 19 - 21
linkwe-api/pom.xml

@@ -90,13 +90,15 @@
     </dependencies>
 
 
+
     <build>
         <finalName>lw-api</finalName>
         <plugins>
+            <!-- 引用Spring Boot Maven插件 -->
             <plugin>
                 <groupId>org.springframework.boot</groupId>
                 <artifactId>spring-boot-maven-plugin</artifactId>
-                <version>2.3.3.RELEASE</version>
+                <version>${springboot.maven.version}</version>
                 <executions>
                     <execution>
                         <goals>
@@ -105,30 +107,26 @@
                     </execution>
                 </executions>
             </plugin>
+            <!-- 引用jib-maven-plugin插件 -->
             <plugin>
-                <groupId>org.liquibase</groupId>
-                <artifactId>liquibase-maven-plugin</artifactId>
-                <version>4.8.0</version>
-                <dependencies>
-                    <dependency>
-                        <groupId>org.liquibase</groupId>
-                        <artifactId>liquibase-core</artifactId>
-                        <version>4.8.0</version>
-                    </dependency>
-                </dependencies>
+                <groupId>com.google.cloud.tools</groupId>
+                <artifactId>jib-maven-plugin</artifactId>
+                <version>${jib.maven.plugin.version}</version>
                 <configuration>
-                    <propertyFile>src/main/resources/liquibase-db.properties</propertyFile>
-                    <changeLogFile>src/main/resources/db/changelog-master.xml</changeLogFile>
-                    <diffChangeLogFile>src/main/resources/db/changelog/changelog_${maven.build.timestamp}.xml</diffChangeLogFile>
-                    <outputChangeLogFile>src/main/resources/db/changelog/changelog_original.xml</outputChangeLogFile>
-                    <dropFirst>false</dropFirst>
-                    <defaultSchemaName/>
-                    <verbose>true</verbose>
-                    <logging>debug</logging>
-                    <promptOnNonLocalDatabase>true</promptOnNonLocalDatabase>
+                    <to>
+                        <image>${docker.harbor.addr}/${docker.harbor.project}/${project.artifactId}:${docker.harbor.tag.version}</image>
+                        <auth>
+                            <username>${docker.harbor.username}</username>
+                            <password>${docker.harbor.password}</password>
+                        </auth>
+                    </to>
+                    <container>
+                        <jvmFlags>
+                            <jvmFlag>-Duser.timezone=Asia/Shanghai</jvmFlag>
+                        </jvmFlags>
+                    </container>
                 </configuration>
             </plugin>
         </plugins>
     </build>
-
 </project>

+ 2 - 1
linkwe-api/src/main/java/com/linkwechat/LinkWeApiApplication.java

@@ -2,6 +2,7 @@ package com.linkwechat;
 
 import com.github.pagehelper.autoconfigure.PageHelperAutoConfiguration;
 import com.linkwechat.common.config.fegin.FeginConfig;
+import com.linkwechat.common.constant.WeServerNameConstants;
 import org.mybatis.spring.annotation.MapperScan;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.boot.builder.SpringApplicationBuilder;
@@ -18,7 +19,7 @@ public class LinkWeApiApplication {
 
         new SpringApplicationBuilder(LinkWeApiApplication.class)
                 .properties("spring.config.name:bootstrap", "config/run/bootstrap.yml")
-                .properties("spring.application.name=linkwe-api")
+                .properties("spring.application.name="+ WeServerNameConstants.linkweApi)
                 .build().run(args);
         System.out.println("(♥◠‿◠)ノ゙  LinkWe-api启动成功   ლ(´ڡ`ლ)゙ ");
 

+ 2 - 3
linkwe-api/src/main/java/com/linkwechat/config/SwaggerConfig.java

@@ -1,6 +1,7 @@
 package com.linkwechat.config;
 
 import com.linkwechat.common.config.LinkWeChatConfig;
+import com.linkwechat.common.exception.wecom.WeComException;
 import com.linkwechat.common.utils.SecurityUtils;
 import io.swagger.annotations.ApiOperation;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -138,7 +139,5 @@ public class SwaggerConfig {
                 .build();
     }
 
-    public static void main(String[] args) {
-        System.out.println(SecurityUtils.encryptPassword("123456"));
-    }
+
 }

+ 264 - 41
linkwe-api/src/main/java/com/linkwechat/controller/WeCommunityKeywordGroupController.java

@@ -1,17 +1,46 @@
 package com.linkwechat.controller;
 
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.collection.ListUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.github.pagehelper.PageInfo;
+import com.linkwechat.common.annotation.Log;
+import com.linkwechat.common.constant.Constants;
 import com.linkwechat.common.core.controller.BaseController;
 import com.linkwechat.common.core.domain.AjaxResult;
+import com.linkwechat.common.core.page.PageDomain;
 import com.linkwechat.common.core.page.TableDataInfo;
+import com.linkwechat.common.core.page.TableSupport;
+import com.linkwechat.common.enums.BusinessType;
+import com.linkwechat.common.utils.ServletUtils;
+import com.linkwechat.common.utils.SnowFlakeUtil;
+import com.linkwechat.common.utils.poi.LwExcelUtil;
+import com.linkwechat.domain.WeGroup;
+import com.linkwechat.domain.WeKeyWordGroupSub;
+import com.linkwechat.domain.WeKeywordGroupViewCount;
+import com.linkwechat.domain.community.WeCommunityNewGroup;
 import com.linkwechat.domain.community.WeKeywordGroupTask;
+import com.linkwechat.domain.community.query.WeCommunityKeyWordGroupTableQuery;
+import com.linkwechat.domain.community.query.WeCommunityNewGroupQuery;
+import com.linkwechat.domain.community.vo.WeCommunityKeyWordGroupTableVo;
+import com.linkwechat.domain.community.vo.WeKeywordGroupViewCountVo;
+import com.linkwechat.domain.customer.query.WeCustomersQuery;
+import com.linkwechat.domain.customer.vo.WeCustomersVo;
 import com.linkwechat.service.IWeCommunityKeywordToGroupService;
+import com.linkwechat.service.IWeGroupService;
+import com.linkwechat.service.IWeKeyWordGroupSubService;
+import com.linkwechat.service.IWeKeywordGroupViewCountService;
 import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiParam;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
+
+import java.io.IOException;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.stream.Collectors;
 
 
 /**
@@ -24,77 +53,271 @@ public class WeCommunityKeywordGroupController extends BaseController {
     @Autowired
     private IWeCommunityKeywordToGroupService keywordToGroupService;
 
+
+    @Autowired
+    private IWeKeyWordGroupSubService iWeKeyWordGroupSubService;
+
+    @Autowired
+    private IWeKeywordGroupViewCountService iWeKeywordGroupViewCountService;
+
+
+    @Autowired
+    private IWeGroupService iWeGroupService;
+
+
     /**
-     * 添加新任务
-     *
-     * @param task 添加任务所需的数据
-     * @return 结果
+     * 申请构建主键
+     * @return
+     */
+    @GetMapping("/applyToBuildPrimaryKey")
+    public AjaxResult<String> applyToBuildPrimaryKey(){
+
+
+        return AjaxResult.success(SnowFlakeUtil.nextId());
+    }
+
+
+    /**
+     * 新增或更新关键词群基础信息
+     * @param groupTask
+     * @return
+     */
+    @PostMapping("/createOrUpdateBaseInfo")
+    public AjaxResult<WeKeywordGroupTask> createOrUpdateBaseInfo(@RequestBody WeKeywordGroupTask groupTask) throws IOException {
+
+        if(groupTask.getId()==null){
+            return AjaxResult.error("关键词群主键不可为空");
+        }
+        keywordToGroupService.createOrUpdate(groupTask);
+        return AjaxResult.success(groupTask);
+    }
+
+
+    /**
+     * 点击取消时触发(避免还未新建,导致群活码创建过多占位)
+     * @param groupTask
+     * @return
      */
-    @PostMapping(path = "/")
-    public AjaxResult addTask(@RequestBody @Validated WeKeywordGroupTask task) {
-        if (keywordToGroupService.isNameOccupied(task.getTaskName())) {
-            return AjaxResult.error("关键词拉群任务名称"+ task.getTaskName() +"已存在");
+    @PostMapping("/cancelCreateBaseInfo")
+    public AjaxResult cancelCreateBaseInfo(@RequestBody WeKeywordGroupTask groupTask){
+        if(groupTask.getId()==null){
+            return AjaxResult.error("关键词群主键不可为空");
         }
-        keywordToGroupService.save(task);
+        WeKeywordGroupTask keywordGroupTask = keywordToGroupService.getById(groupTask.getId());
+        if(null == keywordGroupTask){
+            iWeKeyWordGroupSubService.batchRemoveWeKeyWordGroupByKeyWordId(groupTask.getId());
+        }
+
         return AjaxResult.success();
     }
 
+
+    /**
+     * 获取关键词群列表
+     * @param task
+     * @return
+     */
+    @GetMapping("/findLists")
+    public TableDataInfo<List<WeKeywordGroupTask>> findLists(WeKeywordGroupTask task){
+        startPage();
+        List<WeKeywordGroupTask> groupTasks = keywordToGroupService.findLists(task);
+
+        return getDataTable(groupTasks);
+    }
+
+
+    /**
+     * 获取关键词群基础信息
+     * @param id
+     * @return
+     */
+    @GetMapping("/getKeyWordGroupBaseInfo/{id}")
+    public AjaxResult<WeKeywordGroupTask> getKeyWordGroupBaseInfo(@PathVariable Long id){
+
+        return AjaxResult.success(
+                keywordToGroupService.findBaseInfo(id,null,false)
+        );
+    }
+
+    /**
+     * 关键词群列表
+     * @return
+     */
+    @GetMapping("/findWeKeyWordGroupSubs")
+    public TableDataInfo<List<WeKeyWordGroupSub>> findWeKeyWordGroupSubs(WeKeyWordGroupSub keyWordGroupSub){
+                startPage();
+        List<WeKeyWordGroupSub> weKeyWordGroupSubs = iWeKeyWordGroupSubService.list(new LambdaQueryWrapper<WeKeyWordGroupSub>()
+                .eq(WeKeyWordGroupSub::getKeywordGroupId,keyWordGroupSub.getKeywordGroupId()));
+
+        return getDataTable(weKeyWordGroupSubs);
+    }
+
     /**
-     * 根据id及更新数据对指定任务进行更新
+     * 创建关键词群
+     * @param weKeyWordGroupSub
+     * @return
      */
-    @PutMapping("/{taskId}")
-    public AjaxResult updateTask(@PathVariable("taskId") Long taskId, @RequestBody @Validated WeKeywordGroupTask task) {
-        task.setTaskId(taskId);
-        WeKeywordGroupTask oldGroupTask = keywordToGroupService.getById(task.getTaskId());
-        if(null != oldGroupTask){
-            if(!oldGroupTask.getTaskName().equals(task.getTaskName())){
-                if (keywordToGroupService.isNameOccupied(task.getTaskName())) {
-                    return AjaxResult.error("关键词拉群任务名称"+ task.getTaskName() +"已存在");
-                }
-            }
+    @PostMapping("/createKeyWordGroupSub")
+    public AjaxResult<WeKeyWordGroupSub> createKeyWordGroupSub(@RequestBody WeKeyWordGroupSub weKeyWordGroupSub){
+
+        if(weKeyWordGroupSub.getKeywordGroupId()==null){
+            return AjaxResult.error("关键词群主键不可为空");
         }
-        keywordToGroupService.updateById(task);
+
+        iWeKeyWordGroupSubService.createWeKeyWordGroup(weKeyWordGroupSub);
+
+        return AjaxResult.success(weKeyWordGroupSub);
+    }
+
+
+
+    /**
+     * 更新关键词群
+     * @param weKeyWordGroupSub
+     * @return
+     */
+    @PostMapping("/updateKeyWordGroupSub")
+    public AjaxResult<WeKeyWordGroupSub> updateKeyWordGroupSub(@RequestBody WeKeyWordGroupSub weKeyWordGroupSub){
+
+
+        iWeKeyWordGroupSubService.updateWeKeyWordGroup(weKeyWordGroupSub);
+
+        return AjaxResult.success(weKeyWordGroupSub);
+    }
+
+
+    /**
+     * 批量更新关键词群(主要针对顺序的调整)
+     * @param weKeywordGroupTask
+     * @return
+     */
+    @PostMapping("/batchUpdateKeyWordGroupSub")
+    public AjaxResult batchUpdateKeyWordGroupSub(@RequestBody WeKeywordGroupTask weKeywordGroupTask){
+
+        List<WeKeyWordGroupSub> keyWordGroupSubs = weKeywordGroupTask.getKeyWordGroupSubs();
+
+        if(CollectionUtil.isNotEmpty(keyWordGroupSubs)){
+            iWeKeyWordGroupSubService.updateBatchById(keyWordGroupSubs);
+        }
+        return AjaxResult.success();
+
+    }
+
+
+    /**
+     * 删除关键词群
+     * @param ids
+     * @return
+     */
+    @DeleteMapping("/batchRemoveKeyWordGroup/{ids}")
+    public AjaxResult batchRemoveKeyWordGroup(@PathVariable Long[] ids){
+        ListUtil.toList(ids).forEach(id->{
+            iWeKeyWordGroupSubService.batchRemoveWeKeyWordGroupByKeyWordId(id);
+        });
         return AjaxResult.success();
     }
 
     /**
-     * 通过id列表批量删除任务
-     *
-     * @param ids id列表
-     * @return 结果
+     * 删除客户群活码
      */
-    @DeleteMapping(path = "/{ids}")
-    public AjaxResult batchDeleteTask(@PathVariable("ids") Long[] ids) {
-        keywordToGroupService.removeByIds(Arrays.asList(ids));
+    @DeleteMapping("/batchRemoveKeyWordGroupSub/{ids}")
+    public AjaxResult batchRemoveKeyWordGroupSub(@PathVariable Long[] ids) {
+
+        iWeKeyWordGroupSubService.batchRemoveWeKeyWordGroupByIds(Arrays.asList(ids));
         return AjaxResult.success();
     }
 
 
+    /**
+     * 获取详情头部统计
+     * @param keywordGroupId
+     * @return
+     */
+    @GetMapping("/countTab/{keywordGroupId}")
+    public AjaxResult<WeKeywordGroupViewCountVo> countTab(@PathVariable Long keywordGroupId){
+        return AjaxResult.success(
+                iWeKeywordGroupViewCountService.countTab(keywordGroupId)
+        );
+    }
+
 
     /**
-     * 根据过滤条件获取关键词拉群任务列表
+     * 折线图统计
+     * @param groupViewCount
+     * @return
      */
-    @ApiOperation(value = "获取关键词拉群任务列表")
-    @GetMapping(path = "/list")
-    public TableDataInfo<List<WeKeywordGroupTask>> list(WeKeywordGroupTask task) {
-        startPage();
-        List<WeKeywordGroupTask> taskList = keywordToGroupService.getTaskList(task);
-        return getDataTable(taskList);
+    @GetMapping("/countTrend")
+    public AjaxResult<List<WeKeywordGroupViewCountVo>> countTrend(WeKeywordGroupViewCount groupViewCount){
+
+        return AjaxResult.success(
+                iWeKeywordGroupViewCountService.countTrend(groupViewCount)
+        );
+    }
+
+
+    /**
+     * 数据明细
+     * @param query
+     * @return
+     */
+    @GetMapping("/findKeyWordGroupTable")
+   public TableDataInfo<WeCommunityKeyWordGroupTableVo> findKeyWordGroupTable(WeCommunityKeyWordGroupTableQuery query){
+        TableDataInfo tableDataInfo=new TableDataInfo();
+        PageInfo<WeCommunityKeyWordGroupTableVo> keyWordGroupTable =
+                iWeKeywordGroupViewCountService.findKeyWordGroupTable(query, TableSupport.buildPageRequest());
+        tableDataInfo.setTotal(keyWordGroupTable.getTotal());
+        List<WeCommunityKeyWordGroupTableVo> groupTableList = keyWordGroupTable.getList();
+        if(CollectionUtil.isNotEmpty(groupTableList)){
+            iWeKeywordGroupViewCountService.setJoinGroupNumber(groupTableList,query.getStates());
+        }
+        tableDataInfo.setRows(
+                groupTableList
+        );
+        return tableDataInfo;
     }
 
 
     /**
-     * 根据id获取任务详情
+     * 关键词群数据明细导出
      *
-     * @param taskId 任务id
-     * @return 任务详情
+     * @param query 请求参数
+     * @author WangYX
+     * @date 2023/08/23 14:00
+     */
+    @GetMapping("/exprotKeyWordGroupTable")
+    public void exprotKeyWordGroupTable(WeCommunityKeyWordGroupTableQuery query) {
+        List<WeCommunityKeyWordGroupTableVo> tableVos = iWeKeywordGroupViewCountService.exprotKeyWordGroupTable(query);
+        LwExcelUtil.exprotForWeb(
+                ServletUtils.getResponse(), WeCommunityKeyWordGroupTableVo.class,tableVos,"关键词群_" + System.currentTimeMillis()
+        );
+    }
+
+
+    /**
+     * 获取当前客户对应的群
+     * @param query
+     * @return
      */
-    @GetMapping(path = "/{taskId}")
-    public AjaxResult<WeKeywordGroupTask> getTask(@ApiParam("任务id") @PathVariable("taskId") Long taskId) {
-        return AjaxResult.success(keywordToGroupService.getTaskById(taskId));
+    @GetMapping("/findWeKeyWordGroupChatTable")
+    public TableDataInfo<WeGroup> findWeKeyWordGroupChatTable(WeCommunityKeyWordGroupTableQuery query){
+        List<WeGroup> weGroups =new ArrayList<>();
+        List<WeKeyWordGroupSub> weKeyWordGroupSubs = iWeKeyWordGroupSubService.list(new LambdaQueryWrapper<WeKeyWordGroupSub>()
+                .eq(WeKeyWordGroupSub::getKeywordGroupId, query.getKeywordGroupId()));
+
+        if(CollectionUtil.isNotEmpty(weKeyWordGroupSubs)){
+            startPage();
+            weGroups=iWeGroupService
+                    .findGroupByUserId(query.getExternalUserid()
+                            ,  weKeyWordGroupSubs.stream().map(WeKeyWordGroupSub::getGroupCodeState).collect(Collectors.joining(",")));
+        }
+
+        return getDataTable(weGroups);
     }
 
 
 
 
+
+
+
 }

+ 100 - 37
linkwe-api/src/main/java/com/linkwechat/controller/WeCommunityNewGroupController.java

@@ -2,31 +2,28 @@ package com.linkwechat.controller;
 
 import cn.hutool.core.collection.CollectionUtil;
 import cn.hutool.core.collection.ListUtil;
-import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
 import com.linkwechat.common.annotation.Log;
-import com.linkwechat.common.constant.HttpStatus;
 import com.linkwechat.common.core.controller.BaseController;
 import com.linkwechat.common.core.domain.AjaxResult;
 import com.linkwechat.common.core.page.TableDataInfo;
 import com.linkwechat.common.enums.BusinessType;
+import com.linkwechat.common.utils.ServletUtils;
 import com.linkwechat.common.utils.file.FileUtils;
+import com.linkwechat.common.utils.poi.LwExcelUtil;
+import com.linkwechat.domain.WeGroup;
 import com.linkwechat.domain.community.WeCommunityNewGroup;
-import com.linkwechat.domain.community.WeEmpleCode;
 import com.linkwechat.domain.community.query.WeCommunityNewGroupQuery;
-import com.linkwechat.domain.community.vo.WeCommunityNewGroupVo;
+import com.linkwechat.domain.community.vo.WeCommunityNewGroupTabCountVo;
+import com.linkwechat.domain.community.vo.WeCommunityNewGroupTableVo;
+import com.linkwechat.domain.community.vo.WeCommunityNewGroupTrendCountVo;
+import com.linkwechat.domain.live.WeLive;
 import com.linkwechat.service.IWeCommunityNewGroupService;
-import com.linkwechat.service.IWeEmpleCodeService;
-import io.swagger.annotations.ApiOperation;
-import io.swagger.annotations.ApiParam;
+import com.linkwechat.service.IWeGroupService;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
-
-import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.util.*;
-import java.util.stream.Collectors;
 
 
 /**
@@ -39,19 +36,17 @@ public class WeCommunityNewGroupController extends BaseController {
     @Autowired
     private IWeCommunityNewGroupService iWeCommunityNewGroupService;
 
-
     @Autowired
-    private IWeEmpleCodeService iWeEmpleCodeService;
-
+    private IWeGroupService iWeGroupService;
 
 
     /**
      * 新增新客自动拉群
      */
-    @PostMapping("/")
-    public AjaxResult add(@RequestBody @Validated WeCommunityNewGroupQuery weCommunityNewGroupQuery) {
+    @PostMapping("/add")
+    public AjaxResult add(@RequestBody WeCommunityNewGroup communityNewGroup) {
 
-        iWeCommunityNewGroupService.add(weCommunityNewGroupQuery);
+        iWeCommunityNewGroupService.add(communityNewGroup);
         return AjaxResult.success();
     }
 
@@ -63,14 +58,12 @@ public class WeCommunityNewGroupController extends BaseController {
      * @param id       待下载员工活码
      * @param response 响应
      */
-    @Log(title = "员工活码下载", businessType = BusinessType.OTHER)
     @GetMapping("/download")
     public void download(String id, HttpServletResponse response) throws IOException {
         WeCommunityNewGroup weCommunityNewGroup = iWeCommunityNewGroupService.getById(id);
 
         if(null != weCommunityNewGroup){
-            WeEmpleCode empleCode = iWeEmpleCodeService.selectWeEmpleCodeById(weCommunityNewGroup.getEmplCodeId());
-            FileUtils.downloadFile(empleCode.getQrCode(), response.getOutputStream());
+            FileUtils.downloadFile(weCommunityNewGroup.getEmplCodeUrl(), response.getOutputStream());
         }
     }
 
@@ -81,7 +74,6 @@ public class WeCommunityNewGroupController extends BaseController {
      * @param ids      新客自动拉群ids
      * @param response 输出
      */
-    @Log(title = "员工活码批量下载", businessType = BusinessType.OTHER)
     @GetMapping("/downloadBatch")
     public void downloadBatch(Long[] ids, HttpServletResponse response) throws IOException {
         List<WeCommunityNewGroup> weCommunityNewGroups = iWeCommunityNewGroupService.listByIds(ListUtil.toList(ids));
@@ -91,11 +83,10 @@ public class WeCommunityNewGroupController extends BaseController {
             List<FileUtils.FileEntity> fileList=new ArrayList<>();
 
             weCommunityNewGroups.stream().forEach(k->{
-                WeEmpleCode weEmpleCode = iWeEmpleCodeService.getById(k.getEmplCodeId());
                 fileList.add(
                         FileUtils.FileEntity.builder()
-                                .fileName(weEmpleCode.getScenario())
-                                .url(weEmpleCode.getQrCode())
+                                .fileName(k.getCodeName())
+                                .url(k.getEmplCodeUrl())
                                 .suffix(".jpg")
                                 .build()
                 );
@@ -109,9 +100,9 @@ public class WeCommunityNewGroupController extends BaseController {
      * 查询新客自动拉群列表
      */
     @GetMapping("/list")
-    public TableDataInfo<List<WeCommunityNewGroupVo>> list(WeCommunityNewGroup weCommunityNewGroup) {
+    public TableDataInfo<List<WeCommunityNewGroup>> list(WeCommunityNewGroup weCommunityNewGroup) {
         startPage();
-        List<WeCommunityNewGroupVo> communityNewGroupVos = iWeCommunityNewGroupService.selectWeCommunityNewGroupList(weCommunityNewGroup);
+        List<WeCommunityNewGroup> communityNewGroupVos = iWeCommunityNewGroupService.selectWeCommunityNewGroupList(weCommunityNewGroup);
         return getDataTable(communityNewGroupVos);
     }
 
@@ -120,29 +111,25 @@ public class WeCommunityNewGroupController extends BaseController {
      * 获取新客自动拉群详细信息
      */
     @GetMapping(value = "/{id}")
-    public AjaxResult<WeCommunityNewGroupVo> getInfo(@PathVariable("id") String id) {
-        List<WeCommunityNewGroupVo> communityNewGroupVos = iWeCommunityNewGroupService.selectWeCommunityNewGroupList(WeCommunityNewGroup.builder()
-                        .id(Long.valueOf(id))
-                .build());
+    public AjaxResult<WeCommunityNewGroup> findWeCommunityNewGroupById(@PathVariable("id") String id) {
+        WeCommunityNewGroup weCommunityNewGroup
+                = iWeCommunityNewGroupService.findWeCommunityNewGroupById(id);
 
-        return AjaxResult.success(communityNewGroupVos.stream().findFirst().get());
+        return AjaxResult.success(weCommunityNewGroup);
     }
 
     /**
      * 修改新客自动拉群
      */
-    @Log(title = "新客自动拉群", businessType = BusinessType.UPDATE)
-    @PutMapping("/{id}")
-    public AjaxResult edit(@PathVariable("id") String id,@RequestBody @Validated WeCommunityNewGroupQuery weCommunityNewGroupQuery) {
-        weCommunityNewGroupQuery.setId(Long.valueOf(id));
-        iWeCommunityNewGroupService.updateWeCommunityNewGroup(weCommunityNewGroupQuery);
+    @PutMapping("/edit")
+    public AjaxResult edit(@RequestBody WeCommunityNewGroup communityNewGroup) {
+        iWeCommunityNewGroupService.updateWeCommunityNewGroup(communityNewGroup);
         return AjaxResult.success();
     }
 
     /**
      * 删除新客自动拉群
      */
-    @Log(title = "新客自动拉群", businessType = BusinessType.DELETE)
     @DeleteMapping("/{ids}")
     public AjaxResult remove(@PathVariable Long[] ids) {
         iWeCommunityNewGroupService.removeByIds(ListUtil.toList(ids));
@@ -150,4 +137,80 @@ public class WeCommunityNewGroupController extends BaseController {
         return AjaxResult.success();
     }
 
+
+    /**
+     * 获取头部统计
+     * @param id
+     * @return
+     */
+    @GetMapping("/countTab/{id}")
+    public AjaxResult<WeCommunityNewGroupTabCountVo> countTab(@PathVariable String id){
+        return AjaxResult.success(
+                iWeCommunityNewGroupService.countTab(id)
+        );
+    }
+
+
+    /**
+     * 数据趋势
+     * @param newGroup
+     * @return
+     */
+    @GetMapping("/findTrendCountVo")
+    public AjaxResult<List<WeCommunityNewGroupTrendCountVo>> findTrendCountVo(WeCommunityNewGroup newGroup){
+        return AjaxResult.success(
+                iWeCommunityNewGroupService.findTrendCountVo(newGroup)
+        );
+    }
+
+
+    /**
+     * 数据明细
+     * @param weCommunityNewGroupQuery
+     * @return
+     */
+    @GetMapping("/findWeCommunityNewGroupTable")
+    public TableDataInfo<List<WeCommunityNewGroupTableVo>> findWeCommunityNewGroupTable(WeCommunityNewGroupQuery weCommunityNewGroupQuery){
+        startPage();
+
+        return getDataTable(
+                iWeCommunityNewGroupService.findWeCommunityNewGroupTable(weCommunityNewGroupQuery)
+        );
+    }
+
+
+    /**
+     * 数据明细导出
+     */
+    @GetMapping("/exprotWeCommunityNewGroupTable")
+    public void exprotWeCommunityNewGroupTable(WeCommunityNewGroupQuery weCommunityNewGroupQuery){
+        LwExcelUtil.exprotForWeb(
+                ServletUtils.getResponse(), WeCommunityNewGroupTableVo.class,
+                iWeCommunityNewGroupService.findWeCommunityNewGroupTable(weCommunityNewGroupQuery)
+                ,"新客拉群-数据明细"
+        );
+    }
+
+
+    /**
+     * 获取当前客户对应的群
+     * @param weCommunityNewGroupQuery
+     * @return
+     */
+    @GetMapping("/findWeCommunityNewGroupChatTable")
+    public TableDataInfo<WeGroup> findWeCommunityNewGroupChatTable(WeCommunityNewGroupQuery weCommunityNewGroupQuery){
+        List<WeGroup> weGroups =new ArrayList<>();
+        WeCommunityNewGroup weCommunityNewGroup = iWeCommunityNewGroupService.getById(weCommunityNewGroupQuery.getId());
+        if(null != weCommunityNewGroup){
+            startPage();
+            weGroups=iWeGroupService
+                    .findGroupByUserId(weCommunityNewGroupQuery.getExternalUserid()
+                            , weCommunityNewGroup.getGroupCodeState());
+        }
+
+        return getDataTable(weGroups);
+    }
+
+
+
 }

+ 142 - 60
linkwe-api/src/main/java/com/linkwechat/controller/WeCommunityPresTagGroupController.java

@@ -1,25 +1,36 @@
 package com.linkwechat.controller;
 
-import com.linkwechat.common.constant.HttpStatus;
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.collection.ListUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.linkwechat.common.core.controller.BaseController;
 import com.linkwechat.common.core.domain.AjaxResult;
 import com.linkwechat.common.core.page.TableDataInfo;
+import com.linkwechat.common.utils.ServletUtils;
 import com.linkwechat.common.utils.StringUtils;
+import com.linkwechat.common.utils.poi.LwExcelUtil;
+import com.linkwechat.domain.WeGroup;
+import com.linkwechat.domain.WeTag;
+import com.linkwechat.domain.community.WeCommunityNewGroup;
+import com.linkwechat.domain.community.query.WeCommunityNewGroupQuery;
+import com.linkwechat.domain.customer.query.WeCustomersQuery;
 import com.linkwechat.domain.taggroup.WePresTagGroupTask;
-import com.linkwechat.domain.taggroup.WePresTagGroupTaskStat;
-import com.linkwechat.domain.taggroup.vo.WePresTagGroupTaskVo;
-import com.linkwechat.domain.taggroup.vo.WePresTagTaskListVo;
+import com.linkwechat.domain.taggroup.query.WePresTagGroupTaskQuery;
+import com.linkwechat.domain.taggroup.vo.*;
+import com.linkwechat.service.IWeGroupService;
 import com.linkwechat.service.IWePresTagGroupTaskService;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
+import com.linkwechat.service.IWeTagService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
-import java.util.Date;
+import java.util.ArrayList;
 import java.util.List;
+import java.util.stream.Collectors;
 
-@Api(tags = "老客标签建群接口")
+/**
+ * 老客标签建群接口
+ */
 @RestController
 @RequestMapping(value = "/communityPresTagGroup")
 public class WeCommunityPresTagGroupController extends BaseController {
@@ -27,69 +38,62 @@ public class WeCommunityPresTagGroupController extends BaseController {
     @Autowired
     private IWePresTagGroupTaskService taskService;
 
+    @Autowired
+    private IWeGroupService iWeGroupService;
+
+
+    @Autowired
+    private IWeTagService iWeTagService;
+
 
     /**
      * 获取老客标签建群列表数据
      */
-    //  @PreAuthorize("@ss.hasPermi('wecom:communitytagGroup:list')")
     @GetMapping(path = "/list")
-    @ApiOperation(value = "获取老客标签建群任务分页数据", httpMethod = "GET")
-    public TableDataInfo<List<WePresTagTaskListVo>> getPage(
-            @RequestParam(value = "taskName", required = false) String taskName,
-            @RequestParam(value = "sendType", required = false) Integer sendType,
-            @RequestParam(value = "createBy", required = false) String createBy,
-            @RequestParam(value = "beginTime", required = false) String beginTime,
-            @RequestParam(value = "endTime", required = false) String endTime) {
+    public TableDataInfo<List<WePresTagGroupTask>> list(WePresTagGroupTask groupTask) {
         startPage();
-        List<WePresTagTaskListVo> result = taskService.selectTaskList(taskName, sendType, createBy, beginTime, endTime);
+        List<WePresTagGroupTask> result = taskService.selectTaskList(groupTask);
         return getDataTable(result);
     }
 
     /**
      * 新建老客标签建群任务
      */
-    //   @PreAuthorize("@ss.hasPermi('wecom:communitytagGroup:add')")
-    @PostMapping
-    @ApiOperation(value = "新建老客标签建群任务", httpMethod = "POST")
+    @PostMapping("/add")
     public AjaxResult add(@RequestBody @Validated WePresTagGroupTask task) {
-        // 检测任务名是否可用
-        if (taskService.isNameOccupied(task)) {
-            return AjaxResult.error("任务名已存在");
-        }
          taskService.add(task);
         return AjaxResult.success();
     }
 
     /**
-     * 根据获取任务详细信息
+     * 获取根据id详情
      */
-    //  @PreAuthorize("@ss.hasPermi('wecom:communitytagGroup:query')")
     @GetMapping(path = "/{id}")
-    @ApiOperation(value = "根据获取任务详细信息", httpMethod = "GET")
-    public AjaxResult getInfo(@PathVariable("id") Long id) {
-        WePresTagGroupTaskVo taskVo = taskService.getTaskById(id);
-        if (StringUtils.isNull(taskVo)) {
-            return AjaxResult.error(HttpStatus.NOT_FOUND, "群活码不存在");
+    public AjaxResult<WePresTagGroupTask> findWePresTagGroupById(@PathVariable("id") Long id) {
+        WePresTagGroupTask taskVo = taskService.getTaskById(id);
+        if(null != taskVo){
+            WeCustomersQuery weCustomersQuery = taskVo.getWeCustomersQuery();
+            if(null != weCustomersQuery && StringUtils.isNotEmpty(weCustomersQuery.getTagIds())){
+                List<WeTag> weTags = iWeTagService.list(new LambdaQueryWrapper<WeTag>()
+                        .in(WeTag::getTagId, weCustomersQuery.getTagIds().split(",")));
+                if(CollectionUtil.isNotEmpty(weTags)){
+                    weCustomersQuery.setTagNames(
+                            weTags.stream().map(WeTag::getName).collect(Collectors.joining(","))
+                    );
+                }
+            }
         }
+
         return AjaxResult.success(taskVo);
     }
 
     /**
      * 更新任务信息
      */
-    //    @PreAuthorize("@ss.hasPermi('wecom:communitytagGroup:edit')")
-    @PutMapping(path = "/{id}")
-    @ApiOperation(value = "更新任务信息", httpMethod = "PUT")
-    public AjaxResult update(@PathVariable("id") Long id, @RequestBody @Validated WePresTagGroupTask task) {
-
-        try {
-            // 保存新任务
-            task.setTaskId(id);
-            task.setUpdateTime(new Date());
-            taskService.updateTaskAndSendMsg(task);
-        } catch (Exception e) {
-            return AjaxResult.error(e.getMessage());
-        }
+    @PutMapping(path = "/edit")
+    public AjaxResult edit(@RequestBody WePresTagGroupTask task) {
+
+        taskService.updateTask(task);
 
         return AjaxResult.success();
     }
@@ -97,27 +101,105 @@ public class WeCommunityPresTagGroupController extends BaseController {
     /**
      * 批量删除老客标签建群任务
      */
-    //   @PreAuthorize("@ss.hasPermi('wecom:communitytagGroup:remove')")
-    @DeleteMapping(path = "/{ids}")
-    @ApiOperation(value = "批量删除老客标签建群任务", httpMethod = "DELETE")
+    @DeleteMapping(path = "/batchRemove/{ids}")
     public AjaxResult batchRemove(@PathVariable("ids") Long[] ids) {
-        return AjaxResult.success(taskService.batchRemoveTaskByIds(ids));
+        taskService.batchRemoveTaskByIds(ids);
+        return AjaxResult.success();
     }
 
+
+
     /**
-     * 根据老客标签建群id及过滤条件,获取其统计信息
+     * 获取头部统计
+     * @param id
+     * @return
      */
-    @GetMapping(path = "/stat/{id}")
-    public TableDataInfo<List<WePresTagGroupTaskStat>> getStatInfo(
-            @PathVariable("id") Long id,
-            @RequestParam(value = "customerName", required = false) String customerName,
-            @RequestParam(value = "isInGroup", required = false) Integer isInGroup,
-            @RequestParam(value = "isSent", required = false) Integer isSent
-    ) {
-        WePresTagGroupTask task = taskService.getById(id);
+    @GetMapping("/countTab/{id}")
+    public AjaxResult<WePresTagGroupTaskTabCountVo> countTab(@PathVariable String id){
+        return AjaxResult.success(
+                taskService.countTab(id)
+        );
+    }
+
+
+    /**
+     * 数据趋势
+     * @param task
+     * @return
+     */
+    @GetMapping("/findTrendCountVo")
+    public AjaxResult<List<WePresTagGroupTaskTrendCountVo>> findTrendCountVo(WePresTagGroupTask task){
+        return AjaxResult.success(
+                taskService.findTrendCountVo(task)
+        );
+    }
+
+
+    /**
+     * 数据明细
+     * @param wePresTagGroupTaskQuery
+     * @return
+     */
+    @GetMapping("/findWePresTagGroupTaskTable")
+    public TableDataInfo<List<WePresTagGroupTaskTableVo>> findWePresTagGroupTaskTable(WePresTagGroupTaskQuery wePresTagGroupTaskQuery){
         startPage();
-        List<WePresTagGroupTaskStat> stats = taskService.getTaskStat(id, customerName, isInGroup, isSent,
-                task.getSendType());
-        return getDataTable(stats);
+
+        return getDataTable(
+                taskService.findWePresTagGroupTaskTable(wePresTagGroupTaskQuery)
+        );
+    }
+
+
+    /**
+     * 数据明细导出
+     */
+    @GetMapping("/exprotWePresTagGroupTaskTable")
+    public void exprotWePresTagGroupTaskTable(){
+        LwExcelUtil.exprotForWeb(
+                ServletUtils.getResponse(), WePresTagGroupTaskTableVo.class,
+                taskService.findWePresTagGroupTaskTable(new WePresTagGroupTaskQuery())
+                ,"老客建群-数据明细"
+        );
     }
+
+
+
+    /**
+     * 同步发送结果
+     * @param id
+     * @return
+     */
+    @GetMapping("/synchExecuteResult/{id}")
+    public AjaxResult synchExecuteResult(@PathVariable String id){
+        taskService.synchExecuteResult(id);
+
+        return AjaxResult.success();
+
+    }
+
+    /**
+     * 获取当前客户对应的群
+     * @param wePresTagGroupTaskQuery
+     * @return
+     */
+    @GetMapping("/findWeCommunityNewGroupChatTable")
+    public TableDataInfo<WeGroup> findWeCommunityNewGroupChatTable(WePresTagGroupTaskQuery wePresTagGroupTaskQuery){
+        List<WeGroup> weGroups =new ArrayList<>();
+        WePresTagGroupTask wePresTagGroupTask = taskService.getById(wePresTagGroupTaskQuery.getId());
+        if(null != wePresTagGroupTask){
+            startPage();
+            weGroups=iWeGroupService
+                    .findGroupByUserId(wePresTagGroupTaskQuery.getExternalUserid()
+                            , wePresTagGroupTask.getGroupCodeState());
+        }
+
+        return getDataTable(weGroups);
+    }
+
+
+
+
+
+
+
 }

+ 0 - 2
linkwe-api/src/main/java/com/linkwechat/controller/WeContentTalkController.java

@@ -64,9 +64,7 @@ public class WeContentTalkController extends BaseController {
                 List<String> list = Arrays.asList(materialIds.split(","));
                 weContentTalkVo.setMaterialNum(list.size());
                 for (WeContentSendViewDto weContentSendViewDto : weContentSendViewDtoList) {
-//                    Long contentId = weContentSendViewDto.getContentId();
                     if (weContentTalkVo.getId().equals(weContentSendViewDto.getTalkId())) {
-                    //if (list.contains(contentId.toString()) && weContentTalkVo.getId().equals(weContentSendViewDto.getTalkId())) {
 
                         Integer sendTotalNum = weContentTalkVo.getSendTotalNum();
                         Integer viewTotalNum = weContentTalkVo.getViewTotalNum();

+ 33 - 50
linkwe-api/src/main/java/com/linkwechat/controller/WeCorpAccountController.java

@@ -1,17 +1,17 @@
 package com.linkwechat.controller;
 
-import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.linkwechat.common.config.LinkWeChatConfig;
 import com.linkwechat.common.core.controller.BaseController;
 import com.linkwechat.common.core.domain.AjaxResult;
-import com.linkwechat.common.utils.StringUtils;
 import com.linkwechat.domain.WeCorpAccount;
-import com.linkwechat.fegin.QwCorpClient;
+import com.linkwechat.domain.media.WeMessageTemplate;
+import com.linkwechat.domain.welcomemsg.WeDefaultWelcomeMsg;
 import com.linkwechat.service.IWeCorpAccountService;
+import com.linkwechat.service.IWeDefaultWelcomeMsgService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
-
-import javax.annotation.Resource;
+import java.util.List;
 
 
 @RestController
@@ -24,10 +24,10 @@ public class WeCorpAccountController extends BaseController {
     @Autowired
     private LinkWeChatConfig linkWeChatConfig;
 
+    @Autowired
+    private IWeDefaultWelcomeMsgService iWeDefaultWelcomeMsgService;
 
 
-    @Autowired
-    private  QwCorpClient qwCorpClient;
 
     /**
      * 获取当前租户信息
@@ -52,13 +52,8 @@ public class WeCorpAccountController extends BaseController {
         if (linkWeChatConfig.isDemoEnviron()) {
             return AjaxResult.error("当前为演示环境,无法修改配置");
         }
-
-        if (iWeCorpAccountService.saveOrUpdate(weCorpAccount)) {
-            qwCorpClient.removeAllWeAccessToken(weCorpAccount.getCorpId());
-            //商城配置
-            saveOrUpdateShopConfig(weCorpAccount);
-        }
-
+        weCorpAccount.setKfSecret(weCorpAccount.getAgentSecret());
+        weCorpAccount.setContactSecret(weCorpAccount.getAgentSecret());
         iWeCorpAccountService.addOrUpdate(weCorpAccount);
         return AjaxResult.success();
     }
@@ -87,43 +82,31 @@ public class WeCorpAccountController extends BaseController {
         return AjaxResult.success("操作成功", iWeCorpAccountService.getCustomerChurnNoticeSwitch());
     }
 
+
     /**
-     * 商城配置
-     *
-     * @param weCorpAccount
+     * 设置默认欢迎语
+     * @param attachments  WeDefaultWelcomeMsgVo welcomeMsgVo
+     * @return
      */
-    private void saveOrUpdateShopConfig(WeCorpAccount weCorpAccount) {
-        //商城系统新增或修改
-        try {
-            JSONObject jsonObject = new JSONObject();
-            //小程序配置
-            if (StringUtils.isNotBlank(weCorpAccount.getShopAppId())) {
-                jsonObject.put("wxapp_appId", weCorpAccount.getShopAppId().trim());
-            }
-            if (StringUtils.isNotBlank(weCorpAccount.getShopSecret())) {
-                jsonObject.put("wxapp_secret", weCorpAccount.getShopSecret().trim());
-            }
-            //支付配置
-            if (StringUtils.isNotBlank(weCorpAccount.getMerChantNumber())) {
-                jsonObject.put("wxpay_mchId", weCorpAccount.getMerChantNumber().trim());
-            }
-            if (StringUtils.isNotBlank(weCorpAccount.getMerChantSecret())) {
-                jsonObject.put("wxpay_mchKey", weCorpAccount.getMerChantSecret().trim());
-            }
-            if (StringUtils.isNotBlank(weCorpAccount.getCertP12Url())) {
-                jsonObject.put("wxpay_keyPath", weCorpAccount.getCertP12Url().trim());
-            }
-            //小程序消息消息推送配置
-            if (StringUtils.isNotBlank(weCorpAccount.getShopMaToken())) {
-                jsonObject.put("wechat_ma_token", weCorpAccount.getShopMaToken().trim());
-            }
-            if (StringUtils.isNotBlank(weCorpAccount.getShopMaEncodingaeskey())) {
-                jsonObject.put("wechat_ma_encodingaeskey", weCorpAccount.getShopMaEncodingaeskey().trim());
-            }
-
-        } catch (Exception e) {
-            e.printStackTrace();
-            logger.error("商城系统-小程序配置失败!!!");
-        }
+    @PostMapping("/editWelComeMsg")
+    public AjaxResult editWelComeMsg(@RequestBody List<WeMessageTemplate> attachments){
+        iWeDefaultWelcomeMsgService.saveOrUpdateBatchWeComeMsg(attachments);
+        return AjaxResult.success();
     }
+
+
+
+    /**
+     * 获取默认欢迎语
+     * @return
+     */
+    @GetMapping("/findDefaultWelcomeMsg")
+    public AjaxResult<WeDefaultWelcomeMsg> findDefaultWelcomeMsg(){
+
+        return AjaxResult.success(
+                iWeDefaultWelcomeMsgService.list(new LambdaQueryWrapper<WeDefaultWelcomeMsg>())
+        );
+    }
+
+
 }

+ 7 - 13
linkwe-api/src/main/java/com/linkwechat/controller/WeCustomerController.java

@@ -18,6 +18,7 @@ import com.linkwechat.common.enums.CustomerAddWay;
 import com.linkwechat.common.exception.CustomException;
 import com.linkwechat.common.utils.ServletUtils;
 import com.linkwechat.common.utils.StringUtils;
+import com.linkwechat.common.utils.poi.LwExcelUtil;
 import com.linkwechat.domain.WeCustomer;
 import com.linkwechat.domain.customer.WeBacthMakeCustomerTag;
 import com.linkwechat.domain.customer.WeMakeCustomerTag;
@@ -25,6 +26,7 @@ import com.linkwechat.domain.customer.query.WeCustomersQuery;
 import com.linkwechat.domain.customer.query.WeOnTheJobCustomerQuery;
 import com.linkwechat.domain.customer.vo.WeCustomerDetailInfoVo;
 import com.linkwechat.domain.customer.vo.WeCustomersVo;
+import com.linkwechat.domain.live.WeLive;
 import com.linkwechat.service.IWeCustomerService;
 import com.linkwechat.service.IWeSynchRecordService;
 import io.swagger.annotations.ApiOperation;
@@ -95,21 +97,12 @@ public class WeCustomerController extends BaseController {
     @GetMapping("/export")
     public void export(WeCustomersQuery query) {
         query.setDelFlag(Constants.COMMON_STATE);
-        List<WeCustomersVo> list = weCustomerService.findWeCustomerList(query, null);
-        try {
-            String fileName = URLEncoder.encode("客户信息表_" + System.currentTimeMillis(), "UTF-8").replaceAll("\\+", "%20");
-            HttpServletResponse response = ServletUtils.getResponse();
-            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
-            response.setCharacterEncoding("utf-8");
-            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
+        List<WeCustomersVo> weCustomersVos = weCustomerService.findWeCustomerList(query, null);
 
-            long currentTimeMillis = System.currentTimeMillis();
-            EasyExcel.write(response.getOutputStream(), WeCustomersVo.class).sheet().doWrite(list);
-            System.out.println("耗时:" + (System.currentTimeMillis() - currentTimeMillis));
+        LwExcelUtil.exprotForWeb(
+                ServletUtils.getResponse(), WeCustomersVo.class,weCustomersVos,"客户信息表_" + System.currentTimeMillis()
+        );
 
-        } catch (IOException e) {
-            e.printStackTrace();
-        }
     }
 
 
@@ -324,6 +317,7 @@ public class WeCustomerController extends BaseController {
             }
 
         }
+
         return AjaxResult.success();
     }
 

+ 2 - 1
linkwe-api/src/main/java/com/linkwechat/controller/WeCustomerLinkController.java

@@ -47,7 +47,8 @@ public class WeCustomerLinkController  extends BaseController {
         startPage();
         return getDataTable(
                 iWeCustomerLinkService.list(new LambdaQueryWrapper<WeCustomerLink>()
-                        .like(StringUtils.isNotEmpty(weCustomerLink.getLinkName()),WeCustomerLink::getLinkName,weCustomerLink.getLinkName()))
+                        .like(StringUtils.isNotEmpty(weCustomerLink.getLinkName()),WeCustomerLink::getLinkName,weCustomerLink.getLinkName())
+                        .orderByDesc(WeCustomerLink::getUpdateTime))
         );
 
     }

+ 0 - 1
linkwe-api/src/main/java/com/linkwechat/controller/WeFissionController.java

@@ -142,7 +142,6 @@ public class WeFissionController  extends BaseController {
     @GetMapping("/findWeFissionTrend")
     public AjaxResult<List<WeFissionTrendVo>> findWeFissionTrend(WeFission weFission){
 
-        startPage();
 
         return AjaxResult.success(
                 iWeFissionService.findWeFissionTrend(weFission)

+ 1 - 1
linkwe-api/src/main/java/com/linkwechat/controller/WeFormSurveyCatalogueController.java

@@ -65,7 +65,7 @@ public class WeFormSurveyCatalogueController extends BaseController {
     @GetMapping(value = "/getInfo/{id}")
     @ApiOperation(value = "查询表单详情", httpMethod = "GET")
     public AjaxResult<WeFormSurveyCatalogue> getInfo(@PathVariable("id") Long id) {
-        WeFormSurveyCatalogue info = weFormSurveyCatalogueService.getInfo(id);
+        WeFormSurveyCatalogue info = weFormSurveyCatalogueService.getInfo(id,null,null,false);
         return AjaxResult.success(info);
     }
 

+ 63 - 360
linkwe-api/src/main/java/com/linkwechat/controller/WeFormSurveyStatisticsController.java

@@ -1,8 +1,8 @@
 package com.linkwechat.controller;
 
 
-import cn.hutool.core.collection.CollectionUtil;
-import cn.hutool.core.date.DateField;
+
+
 import cn.hutool.core.date.DateTime;
 import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.util.ObjectUtil;
@@ -10,34 +10,26 @@ import com.alibaba.excel.EasyExcel;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.linkwechat.common.annotation.Log;
-import com.linkwechat.common.constant.SiteStatsConstants;
 import com.linkwechat.common.core.controller.BaseController;
 import com.linkwechat.common.core.domain.AjaxResult;
 import com.linkwechat.common.core.domain.vo.SysAreaVo;
 import com.linkwechat.common.core.page.TableDataInfo;
+import com.linkwechat.common.utils.DateUtils;
 import com.linkwechat.common.utils.ServletUtils;
-import com.linkwechat.common.utils.SnowFlakeUtil;
 import com.linkwechat.common.utils.StringUtils;
+import com.linkwechat.common.utils.poi.LwExcelUtil;
 import com.linkwechat.domain.*;
-import com.linkwechat.domain.form.query.WeFormSiteStasQuery;
+import com.linkwechat.domain.customer.vo.WeCustomersVo;
 import com.linkwechat.domain.form.query.WeFormSurveyRadioQuery;
 import com.linkwechat.domain.form.query.WeFormSurveyStatisticQuery;
 import com.linkwechat.domain.form.vo.WeFormSurveyAnswerVO;
-import com.linkwechat.domain.form.vo.WeFormSurveyStatisticsVO;
 import com.linkwechat.fegin.QwSysAreaClient;
 import com.linkwechat.service.*;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
-
-import javax.annotation.PostConstruct;
 import javax.annotation.Resource;
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
@@ -53,7 +45,6 @@ import java.util.stream.Collectors;
  */
 @RestController
 @RequestMapping("/form/statistic")
-@Api(tags = "智能表单统计接口")
 @Slf4j
 public class WeFormSurveyStatisticsController extends BaseController {
 
@@ -67,269 +58,100 @@ public class WeFormSurveyStatisticsController extends BaseController {
     private IWeFormSurveyAnswerService weFormSurveyAnswerService;
 
     @Autowired
+    private IWeFormSurveyCountService iWeFormSurveyCountService;
+
+    @Autowired
     private IWeFormSurveyCatalogueService weFormSurveyCatalogueService;
 
+
+
     @Resource
     private QwSysAreaClient qwSysAreaClient;
 
-    @Resource
-    private RedisTemplate redisTemplate;
-    @Resource
-    private IWeFormSurveySiteStasService weFormSurveySiteStasService;
+
 
 
     /**
      * 查询基本表单统计信息
      */
     @GetMapping("/getStatistics")
-    @ApiOperation(value = "查询基本表单统计信息", httpMethod = "GET")
     public AjaxResult getStatistics(WeFormSurveyStatistics query) {
         List<WeFormSurveyStatistics> Statistics = weFormSurveyStatisticsService.getStatistics(query);
         return AjaxResult.success(Statistics);
     }
 
 
-    @PostMapping("/lineChart")
-    @ApiOperation("折线图")
-    public AjaxResult lineChart(@RequestBody @Validated WeFormSurveyStatisticQuery query) {
-        String type = query.getType();
-        DateTime startTime = null;
-        DateTime endTime = null;
-        Map<String, Object> legendData = new HashMap<>();
-        String[] legendArray = new String[]{"总访问量", "总访问用户", "有效收集量"};
-        legendData.put("data", legendArray);
-        Map<String, Map<String, Object>> legendDataMap = new HashMap<>();
-        legendDataMap.put("legend", legendData);
-        Map<String, Object> xAxisData = new HashMap<>();
-        if (!type.equals("customization")) {
-            if (type.equals("week")) {
-                startTime = DateUtil.offsetWeek(new Date(), -1);
-            } else if (type.equals("month")) {
-                startTime = DateUtil.offsetMonth(new Date(), -1);
-            }
-            endTime = DateUtil.date();
-        } else {
-            startTime = DateUtil.date(query.getStartDate());
-            endTime =  DateUtil.date(query.getEndDate());
-        }
-        List<DateTime> timeList = DateUtil.rangeToList(startTime, endTime, DateField.DAY_OF_YEAR);
-        String[] xAxisArray = new String[timeList.size()];
-        //使用for循环得到数组
-        int[] totalVisitsArray = new int[timeList.size()];
-        int[] totalUserArray = new int[timeList.size()];
-        int[] collectionVolumeArray = new int[timeList.size()];
-        String[] collectionRateArray = new String[timeList.size()];
-        int[] averageTimeArray = new int[timeList.size()];
-
-        WeFormSurveyStatisticQuery surveyStatistics = new WeFormSurveyStatisticQuery();
-        surveyStatistics.setStartDate(startTime);
-        surveyStatistics.setEndDate(endTime);
-        surveyStatistics.setDataSource(query.getDataSource());
-        surveyStatistics.setBelongId(query.getBelongId());
-
-        List<WeFormSurveyStatistics> statisticsList = weFormSurveyStatisticsService.dataList(surveyStatistics);
-
-        for (int i = 0; i < timeList.size(); i++) {
-            xAxisArray[i] = timeList.get(i).toDateStr();
-
-            if (CollectionUtil.isNotEmpty(statisticsList)) {
-                int finalI = i;
-                List<WeFormSurveyStatistics> statistics = statisticsList.stream()
-                        .filter(statistic -> Objects.equals(DateUtil.formatDate(statistic.getCreateTime()), timeList.get(finalI).toDateStr()))
-                        .collect(Collectors.toList());
-                for (WeFormSurveyStatistics list : statistics) {
-                    Integer totalVisits = list.getTotalVisits();
-                    Integer totalUser = list.getTotalUser();
-                    Integer collectionVolume = list.getCollectionVolume();
-                    String collectionRate = list.getCollectionRate();
-                    Integer averageTime = list.getAverageTime();
-                    totalVisitsArray[i] = totalVisits;
-                    totalUserArray[i] = totalUser;
-                    collectionVolumeArray[i] = collectionVolume;
-                    collectionRateArray[i] = collectionRate;
-                    averageTimeArray[i] = averageTime;
-                }
-            } else {
-                totalVisitsArray[i] = 0;
-                totalUserArray[i] = 0;
-                collectionVolumeArray[i] = 0;
-                collectionRateArray[i] = "0";
-                averageTimeArray[i] = 0;
-            }
-        }
-        Map<String, Object> totalVisitsData = new HashMap<>();
-        Map<String, Object> totalUserData = new HashMap<>();
-        Map<String, Object> collectionVolumeData = new HashMap<>();
-        Map<String, Object> collectionRateData = new HashMap<>();
-        Map<String, Object> averageTimeData = new HashMap<>();
-        Map<String, Object> seriesMap = new HashMap<>();
-        totalVisitsData.put("data", totalVisitsArray);
-        totalVisitsData.put("name", "总访问量");
-        totalUserData.put("data", totalUserArray);
-        totalUserData.put("name", "总访问用户");
-        collectionVolumeData.put("data", collectionVolumeArray);
-        collectionVolumeData.put("name", "有效收集量");
-        collectionRateData.put("data", collectionRateArray);
-        collectionRateData.put("name", "收集率");
-        averageTimeData.put("data", averageTimeArray);
-        averageTimeData.put("name", "平均完成时间");
-        xAxisData.put("data", xAxisArray);
-        Map<String, Map<String, Object>> xAxisDataMap = new HashMap<>();
-        xAxisDataMap.put("xAxis", xAxisData);
-        List list = new ArrayList();
-        list.add(totalVisitsData);
-        list.add(totalUserData);
-        list.add(collectionVolumeData);
-        list.add(collectionRateData);
-        list.add(averageTimeData);
-        seriesMap.put("series", list);
-        Map map = new HashMap();
-        map.put("legend", legendData);
-        map.put("xAxis", xAxisData);
-        map.put("series", list);
-        return AjaxResult.success(map);
+    /**
+     * 折线图
+     * @param query
+     * @return
+     */
+    @GetMapping("/lineChart")
+    public AjaxResult lineChart(WeFormSurveyStatisticQuery query) {
+        WeFormSurveyCount weFormSurveyCount = WeFormSurveyCount.builder()
+                .channelsName(query.getDataSource())
+                .belongId(query.getBelongId())
+                .build();
+
+        weFormSurveyCount.setBeginTime(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD,query.getStartDate()));
+        weFormSurveyCount.setEndTime(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD,query.getEndDate()));
+        List<WeFormSurveyStatistics> weFormSurveyStatistics = iWeFormSurveyCountService.lineChart(weFormSurveyCount);
+
+        return AjaxResult.success(weFormSurveyStatistics);
     }
 
 
-    @PostMapping("/insertPieValue")
-    @ApiOperation("保存饼图数据")
-    public AjaxResult insertPieValue(@RequestBody @Validated WeFormSurveyStatisticQuery query) {
-       List<WeFormSurveyRadio> radioList = new LinkedList<>();
-        List pieList = JSONObject.parseObject(query.getAnswer(), List.class);
-        for (int i = 0; i < pieList.size(); i++) {
-            WeFormSurveyRadio tQuRadio = new WeFormSurveyRadio();
-            Map newMap = (Map) pieList.get(i);
-            String formCodeId = newMap.get("formCodeId").toString();
-            if (formCodeId.equals("6") || formCodeId.equals("7")
-                    || formCodeId.equals("8") || formCodeId.equals("9")) {
-                String defaultValue = newMap.get("defaultValue").toString();
-                String label = newMap.get("label").toString();
-                String formId = newMap.get("formId").toString();
-                if (!formCodeId.equals("9")) {
-                    String options = newMap.get("options").toString();
-                    tQuRadio.setOptions(options);
-                }
-                String questionNumber = newMap.get("questionNumber").toString();
-                tQuRadio.setFormCodeId(formCodeId);
-                tQuRadio.setLabel(label);
-                tQuRadio.setFormId(formId);
-                tQuRadio.setDefaultValue(defaultValue);
-                tQuRadio.setQuestionNumber(questionNumber);
-                if (StringUtils.isNotBlank(query.getDataSource())) {
-                    tQuRadio.setDataSource(query.getDataSource());
-                }
-                radioList.add(tQuRadio);
-            }
-        }
-        weFormSurveyRadioService.saveBatch(radioList);
-        return AjaxResult.success();
-    }
-
-    @PostMapping("/pieChart")
-    @ApiOperation(value = "饼图", httpMethod = "POST")
-    public AjaxResult pieChart(@RequestBody WeFormSurveyRadioQuery query) {
-        List<Map<String, Object>> resultList = new ArrayList<>();
-        query.setLabel("pie");
-        List<WeFormSurveyRadio> radioList = weFormSurveyRadioService.selectNumber(query);
-        for (WeFormSurveyRadio number : radioList) {
-            String questionNumber = number.getQuestionNumber();
-            String options = number.getOptions();
-            String label = number.getLabel();
-            WeFormSurveyRadioQuery newQuery = new WeFormSurveyRadioQuery();
-            newQuery.setQuestionNumber(questionNumber);
-            newQuery.setFormId(query.getFormId());
-            newQuery.setLabel("pie");
-            if (StringUtils.isNotBlank(query.getDataSource())) {
-                newQuery.setDataSource(query.getDataSource());
-            }
-            List<WeFormSurveyRadio> tQuRadios = weFormSurveyRadioService.selectDefaultValue(newQuery);
-            Map<String, Object> result = new HashMap<>();
-            List<Map<String, Object>> list = new ArrayList();
-            if (tQuRadios.size() > 0) {
-                for (WeFormSurveyRadio newList : tQuRadios) {
-                    Map<String, Object> map = new HashMap<>();
-                    String defaultValue = newList.getDefaultValue();
-                    WeFormSurveyRadioQuery newTQuRadio = new WeFormSurveyRadioQuery();
-                    newTQuRadio.setFormId(query.getFormId());
-                    if (StringUtils.isNotBlank(query.getDataSource())) {
-                        newTQuRadio.setDataSource(query.getDataSource());
-                    }
-                    newTQuRadio.setDefaultValue(defaultValue);
-                    newTQuRadio.setQuestionNumber(questionNumber);
-                    newTQuRadio.setLabel("pie");
-                    Integer value = weFormSurveyRadioService.countDefaultValue(newTQuRadio);
-                    map.put("value", value);
-                    if(ObjectUtil.equal("6",newList.getFormCodeId()) || ObjectUtil.equal("8",newList.getFormCodeId())){
-                        String[] split = options.split(",");
-                        map.put("name", split[Integer.parseInt(defaultValue)]);
-                    }else {
-                        map.put("name", defaultValue);
-                    }
-                    list.add(map);
-                }
-                result.put("questionNumber", questionNumber);
-                result.put("options", options);
-                result.put("label", label);
-                result.put("data", list);
 
-            }
-            resultList.add(result);
-        }
-        return AjaxResult.success(resultList);
-    }
 
 
+    /**
+     * 用户统计列表
+     * @param query
+     * @return
+     */
     @PostMapping("/customer")
-    @ApiOperation("用户统计列表")
     public TableDataInfo<List<WeFormSurveyAnswer>> customer(@RequestBody @Validated WeFormSurveyStatisticQuery query) {
         startPage();
         List<WeFormSurveyAnswer> customerList = weFormSurveyAnswerService.selectCustomerList(query);
         return getDataTable(customerList);
     }
 
-    @ApiOperation(value = "数据概览列表", httpMethod = "POST")
-    @PostMapping("/dataList")
-    public AjaxResult dataList(@RequestBody @Validated WeFormSurveyStatisticQuery query) {
-        String type = query.getType();
-        int count = 0;
-        if (StringUtils.isNotBlank(type) && type.equals("week")) {
-            query.setStartDate(DateUtil.offsetWeek(new Date(), -1));
-            query.setEndDate(DateUtil.date());
-        }
-        if (StringUtils.isNotBlank(type) && type.equals("month")) {
-            query.setStartDate(DateUtil.offsetMonth(new Date(), -1));
-            query.setEndDate(DateUtil.date());
-        }
-        List<WeFormSurveyStatistics> tSurveyList = weFormSurveyStatisticsService.dataList(query);
-        List<WeFormSurveyStatisticsVO> result = new ArrayList<>();
-        for (WeFormSurveyStatistics weFormSurveyStatistics : tSurveyList) {
-            WeFormSurveyStatisticsVO weFormSurveyStatisticsVO = new WeFormSurveyStatisticsVO();
-            weFormSurveyStatisticsVO.setCreateTime(DateUtil.offsetDay(weFormSurveyStatistics.getCreateTime(), -1));
-            weFormSurveyStatisticsVO.setTotalVisits(weFormSurveyStatistics.getTotalVisits());
-            weFormSurveyStatisticsVO.setTotalUser(weFormSurveyStatistics.getTotalUser());
-            weFormSurveyStatisticsVO.setCollectionRate(weFormSurveyStatistics.getCollectionRate());
-            weFormSurveyStatisticsVO.setCollectionVolume(weFormSurveyStatistics.getCollectionVolume());
-            weFormSurveyStatisticsVO.setAverageTime(weFormSurveyStatistics.getAverageTime());
-            result.add(weFormSurveyStatisticsVO);
-        }
 
-        count = tSurveyList.size();
-        Map<String, Object> resultMap = new HashMap<>();
-        resultMap.put("result", result);
-        resultMap.put("total", count);
-        if (tSurveyList.size() == 0) {
-            return AjaxResult.success("该时间段内数据为空!", resultMap);
-        }
-        return AjaxResult.success(resultMap);
+    /**
+     * 数据概览列表
+     * @param query
+     * @return
+     */
+    @GetMapping("/dataList")
+    public TableDataInfo dataList(WeFormSurveyStatisticQuery query) {
+
+        startPage();
+        List<WeFormSurveyStatistics> weFormSurveyStatistics = weFormSurveyStatisticsService.dataList(query);
+
+        return getDataTable(
+                weFormSurveyStatistics
+        );
+    }
+
+
+    /**
+     * 数据概览列表
+     * @param query
+     * @return
+     */
+    @GetMapping("/dataListExport")
+    public void dataListExport(WeFormSurveyStatisticQuery query) {
+        List<WeFormSurveyStatistics> weFormSurveyStatistics = weFormSurveyStatisticsService.dataList(query);
+        LwExcelUtil.exprotForWeb(
+                ServletUtils.getResponse(), WeFormSurveyStatistics.class,weFormSurveyStatistics,"智能表单数据报表_" + System.currentTimeMillis()
+        );
     }
 
 
     /**
      * 省级联动
      */
-    @Log(title = "省级联动")
     @PostMapping("/areaStatistic")
-    @ApiOperation("省级联动")
     public AjaxResult areaStatistic(@RequestBody WeFormSurveyRadioQuery query) {
         List<Map<String, Object>> resultList = new ArrayList<>();
         query.setLabel("area");
@@ -358,49 +180,11 @@ public class WeFormSurveyStatisticsController extends BaseController {
         return AjaxResult.success(resultList);
     }
 
-    /**
-     * 站点统计
-     *
-     * @return
-     */
-    @PostMapping("/siteStas")
-    @ApiOperation("站点统计")
-    public AjaxResult siteStas(@RequestBody @Validated WeFormSiteStasQuery weFormSiteStasQuery) {
-
-        Long belongId = weFormSiteStasQuery.getBelongId();
-        String dataSource = weFormSiteStasQuery.getDataSource();
-
-        WeFormSurveyCatalogue weFormSurveyCatalogue = weFormSurveyCatalogueService.getWeFormSurveyCatalogueById(belongId);
-        String channelsPath = weFormSurveyCatalogue.getChannelsPath();
-        String channelsName = weFormSurveyCatalogue.getChannelsName();
-        String[] paths = channelsPath.split(",");
-        String[] names = channelsName.split(",");
-
-        for (int i = 0; i < paths.length; i++) {
-            if (paths[i].equals(dataSource)) {
-                dataSource = names[i];
-                break;
-            }
-        }
-
-        //PV
-        String pvKey = StringUtils.format(SiteStatsConstants.PREFIX_KEY_PV, belongId, dataSource);
-        redisTemplate.opsForValue().increment(pvKey);
-        //IP
-        String ipKey = StringUtils.format(SiteStatsConstants.PREFIX_KEY_IP, belongId, dataSource);
-        log.info("请求的IP地址:{}", weFormSiteStasQuery.getIpAddr());
-        redisTemplate.opsForSet().add(ipKey, weFormSiteStasQuery.getIpAddr());
-
-
-        return AjaxResult.success();
-    }
 
 
     /**
      * 统计数据导出
      */
-    @ApiOperation("导出用户统计")
-    @Log(title = "导出用户统计")
     @PostMapping("/user/export")
     public void userExport(@RequestBody @Validated WeFormSurveyStatisticQuery query) {
         Date startTime = null;
@@ -452,59 +236,13 @@ public class WeFormSurveyStatisticsController extends BaseController {
 
 
     /**
-     * 统计数据导出
-     */
-    @ApiOperation("统计数据导出")
-    @Log(title = "统计数据导出")
-    @PostMapping("/data/export")
-    public void dataExport(@RequestBody @Validated WeFormSurveyStatisticQuery query) {
-        String type = query.getType();
-        if (StringUtils.isNotBlank(type) && type.equals("week")) {
-            query.setStartDate(DateUtil.offsetWeek(new Date(), -1));
-            query.setEndDate(DateUtil.date());
-        }
-        if (StringUtils.isNotBlank(type) && type.equals("month")) {
-            query.setStartDate(DateUtil.offsetMonth(new Date(), -1));
-            query.setEndDate(DateUtil.date());
-        }
-        List<WeFormSurveyStatistics> tSurveyList = weFormSurveyStatisticsService.dataList(query);
-
-        List<WeFormSurveyStatisticsVO> list = new ArrayList<>();
-        if (tSurveyList != null && tSurveyList.size() > 0) {
-            for (WeFormSurveyStatistics weFormSurveyStatistics : tSurveyList) {
-                WeFormSurveyStatisticsVO weFormSurveyStatisticsVO = new WeFormSurveyStatisticsVO();
-                weFormSurveyStatisticsVO.setCreateTime(DateUtil.offsetDay(weFormSurveyStatistics.getCreateTime(), -1));
-                weFormSurveyStatisticsVO.setTotalVisits(weFormSurveyStatistics.getTotalVisits());
-                weFormSurveyStatisticsVO.setTotalUser(weFormSurveyStatistics.getTotalUser());
-                weFormSurveyStatisticsVO.setCollectionRate(weFormSurveyStatistics.getCollectionRate());
-                weFormSurveyStatisticsVO.setCollectionVolume(weFormSurveyStatistics.getCollectionVolume());
-                weFormSurveyStatisticsVO.setAverageTime(weFormSurveyStatistics.getAverageTime());
-                list.add(weFormSurveyStatisticsVO);
-            }
-        }
-
-        try {
-            HttpServletResponse response = ServletUtils.getResponse();
-            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
-            response.setCharacterEncoding("utf-8");
-            String fileName = URLEncoder.encode("统计数据", "UTF-8").replaceAll("\\+", "%20");
-            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
-            EasyExcel.write(response.getOutputStream(), WeFormSurveyStatisticsVO.class).sheet("数据明细").doWrite(list);
-        } catch (IOException e) {
-            log.error("统计数据列表导出异常:query:{}", JSONObject.toJSONString(query), e);
-        }
-    }
-
-    /**
      * 问卷答案数据导出
      *
      * @param query
      * @throws IOException
      */
-    @ApiOperation("问卷答案数据导出")
-    @Log(title = "问卷答案数据导出")
     @GetMapping("/answer/export")
-    public void answerExport(WeFormSurveyStatisticQuery query) throws IOException {
+    public void answerExport(WeFormSurveyStatisticQuery query) throws  IOException {
         //时间类型处理
         String type = query.getType();
         if (StringUtils.isNotBlank(type) && type.equals("week")) {
@@ -633,40 +371,5 @@ public class WeFormSurveyStatisticsController extends BaseController {
     }
 
 
-    /**
-     * 表单站点统计初始化
-     *
-     * @author WangYX
-     * @date 2022/10/14 10:59
-     */
-    @PostConstruct
-    public void siteStasInit() {
-        log.info("表单站点统计初始化=>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
-        //所有的表单
-        List<WeFormSurveyCatalogue> weFormSurveyCatalogues = weFormSurveyCatalogueService.getListIgnoreTenantId();
-        //上次的站点统计的数据
-        List<WeFormSurveySiteStas> list = weFormSurveySiteStasService.list();
-        Map<Long, Integer> collect = list.stream().collect(Collectors.toMap(WeFormSurveySiteStas::getBelongId, WeFormSurveySiteStas::getTotalVisits, (key1, key2) -> key1));
-
-        if (weFormSurveyCatalogues != null && weFormSurveyCatalogues.size() > 0) {
-            for (WeFormSurveyCatalogue weFormSurveyCatalogue : weFormSurveyCatalogues) {
-                String channelsName = weFormSurveyCatalogue.getChannelsName();
-                if (StringUtils.isNotBlank(channelsName)) {
-                    String[] split = channelsName.split(",");
-                    for (String channelName : split) {
-                        //PV
-                        String pvKey = StringUtils.format(SiteStatsConstants.PREFIX_KEY_PV, weFormSurveyCatalogue.getId(), channelName);
-                        if (!redisTemplate.hasKey(pvKey)) {
-                            redisTemplate.opsForValue().set(pvKey, collect.get(weFormSurveyCatalogue.getId()) != null ? collect.get(weFormSurveyCatalogue.getId()) : 0);
-                        }
-                        //IP
-                        String ipKey = StringUtils.format(SiteStatsConstants.PREFIX_KEY_IP, weFormSurveyCatalogue.getId(), channelName);
-                        if (!redisTemplate.hasKey(ipKey)) {
-                            redisTemplate.opsForSet().add(ipKey, "");
-                        }
-                    }
-                }
-            }
-        }
-    }
+
 }

+ 57 - 0
linkwe-api/src/main/java/com/linkwechat/controller/WeGroupChatController.java

@@ -1,5 +1,7 @@
 package com.linkwechat.controller;
 
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.collection.ListUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.linkwechat.common.constant.SynchRecordConstants;
 import com.linkwechat.common.constant.WeConstans;
@@ -9,11 +11,15 @@ import com.linkwechat.common.core.domain.entity.SysUser;
 import com.linkwechat.common.core.page.TableDataInfo;
 import com.linkwechat.common.core.page.TableSupport;
 import com.linkwechat.common.utils.SecurityUtils;
+import com.linkwechat.common.utils.StringUtils;
+import com.linkwechat.domain.WeCustomer;
 import com.linkwechat.domain.WeCustomerTrajectory;
 import com.linkwechat.domain.WeGroupMember;
+import com.linkwechat.domain.customer.query.WeCustomersQuery;
 import com.linkwechat.domain.groupchat.query.WeGroupChatQuery;
 import com.linkwechat.domain.groupchat.query.WeMakeGroupTagQuery;
 import com.linkwechat.domain.groupchat.vo.LinkGroupChatListVo;
+import com.linkwechat.domain.groupchat.vo.WeCustomerDeduplicationVo;
 import com.linkwechat.service.*;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
@@ -153,4 +159,55 @@ public class WeGroupChatController extends BaseController {
                         .eq(WeCustomerTrajectory::getExternalUseridOrChatid,chatId))
         );
     }
+
+
+    /**
+     * 客群去重列表
+     * @param query
+     * @return
+     */
+    @GetMapping("/findDeduplications")
+    public TableDataInfo<WeCustomerDeduplicationVo> findDeduplications(WeGroupChatQuery query){
+        startPage();
+        return getDataTable(
+                weGroupMemberService.findWeCustomerDeduplication(query.getMemberName())
+        );
+    }
+
+
+    /**
+     * 客户加入或移除黑名单
+     * @return
+     */
+    @PostMapping("/joinOrRemoveBlackList")
+    public AjaxResult joinOrRemoveBlackList(@RequestBody WeCustomersQuery query){
+        String customerIds = query.getExternalUserids();
+        if(StringUtils.isNotEmpty(customerIds)){
+            List<WeCustomer> weCustomers = iWeCustomerService.list(new LambdaQueryWrapper<WeCustomer>()
+                    .in(WeCustomer::getExternalUserid, ListUtil.toList(customerIds.split(","))));
+            if(CollectionUtil.isNotEmpty(weCustomers)){
+                weCustomers.stream().forEach(k->{
+                    k.setIsJoinBlacklist(query.getIsJoinBlacklist());
+                });
+
+                iWeCustomerService.updateBatchById(weCustomers);
+            }
+
+        }
+        return AjaxResult.success();
+    }
+
+
+    /**
+     * 群去重提醒
+     * @param query
+     * @return
+     */
+   @PostMapping("/remindDuplicateMembers")
+   public AjaxResult remindDuplicateMembers(@RequestBody WeCustomersQuery query){
+
+        weGroupMemberService.remindDuplicateMembers(query.getExternalUserids());
+
+        return AjaxResult.success();
+   }
 }

+ 71 - 1
linkwe-api/src/main/java/com/linkwechat/controller/WeGroupCodeController.java

@@ -1,17 +1,33 @@
 package com.linkwechat.controller;
 
+import com.alibaba.excel.EasyExcel;
+import com.alibaba.excel.write.builder.ExcelWriterBuilder;
+import com.alibaba.fastjson.JSONObject;
+import com.github.pagehelper.PageInfo;
 import com.linkwechat.common.annotation.Log;
+import com.linkwechat.common.constant.WeConstans;
 import com.linkwechat.common.core.controller.BaseController;
 import com.linkwechat.common.core.domain.AjaxResult;
+import com.linkwechat.common.core.page.PageDomain;
 import com.linkwechat.common.core.page.TableDataInfo;
+import com.linkwechat.common.core.page.TableSupport;
+import com.linkwechat.common.core.redis.RedisService;
 import com.linkwechat.common.enums.BusinessType;
 import com.linkwechat.common.exception.CustomException;
+import com.linkwechat.common.utils.Base62NumUtil;
+import com.linkwechat.common.utils.ServletUtils;
 import com.linkwechat.common.utils.StringUtils;
 import com.linkwechat.common.utils.file.FileUtils;
 import com.linkwechat.domain.groupcode.entity.WeGroupCode;
 import com.linkwechat.domain.groupcode.vo.WeGroupChatInfoVo;
 import com.linkwechat.domain.groupcode.vo.WeGroupCodeCountTrendVo;
+import com.linkwechat.domain.qr.query.WeQrCodeListQuery;
+import com.linkwechat.domain.qr.vo.WeQrCodeDetailVo;
+import com.linkwechat.domain.qr.vo.WeQrCodeScanCountVo;
+import com.linkwechat.domain.qr.vo.WeQrCodeScanLineCountVo;
 import com.linkwechat.service.IWeGroupCodeService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.validation.annotation.Validated;
@@ -19,6 +35,7 @@ import org.springframework.web.bind.annotation.*;
 
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
+import java.net.URLEncoder;
 import java.text.ParseException;
 import java.util.Arrays;
 import java.util.List;
@@ -34,11 +51,15 @@ import java.util.stream.Collectors;
 @Slf4j
 @RestController
 @RequestMapping("/groupCode")
+@Api(tags = "群活码管理")
 public class WeGroupCodeController extends BaseController {
 
     @Autowired
     private IWeGroupCodeService groupCodeService;
 
+    @Autowired
+    private RedisService redisService;
+
 
 
     /**
@@ -74,7 +95,7 @@ public class WeGroupCodeController extends BaseController {
     @GetMapping("/getActualCode/{id}")
     public AjaxResult<WeGroupCode> getWeGroupCode(@PathVariable String id){
         return AjaxResult.success(
-                groupCodeService.getById(id)
+                groupCodeService.getDetail(id)
         );
     }
 
@@ -183,7 +204,56 @@ public class WeGroupCodeController extends BaseController {
         );
     }
 
+    @ApiOperation(value = "通过短链接获取群活码详情", httpMethod = "GET")
+    @GetMapping("/getByDetail/{shortUrl}")
+    public AjaxResult<WeQrCodeDetailVo> getGroupCodeInfoByShortUrl(@PathVariable("shortUrl") String shortUrl) {
+        long id = Base62NumUtil.decode(shortUrl);
+        WeGroupCode detail = groupCodeService.getDetail(String.valueOf(id));
+        redisService.increment(WeConstans.WE_SHORT_LINK_COMMON_KEY + WeConstans.OPEN_APPLET + "gqr:" +shortUrl);
+        return AjaxResult.success(detail);
+    }
 
+    @ApiOperation(value = "获取群活码总数统计", httpMethod = "GET")
+    @GetMapping("/scan/total")
+    public AjaxResult<WeQrCodeScanCountVo> getWeQrCodeScanTotalCount(WeGroupCode weGroupCode) {
+        WeQrCodeScanCountVo weQrCodeScanCount = groupCodeService.getWeQrCodeScanTotalCount(weGroupCode);
+        return AjaxResult.success(weQrCodeScanCount);
+    }
 
+    @ApiOperation(value = "获取群活码折线图统计", httpMethod = "GET")
+    @GetMapping("/scan/line")
+    public AjaxResult<List<WeQrCodeScanLineCountVo>> getWeQrCodeScanLineCount(WeGroupCode weGroupCode) {
+        List<WeQrCodeScanLineCountVo> weQrCodeScanCount = groupCodeService.getWeQrCodeScanLineCount(weGroupCode);
+        return AjaxResult.success(weQrCodeScanCount);
+    }
 
+    @ApiOperation(value = "获取群活码表格统计", httpMethod = "GET")
+    @GetMapping("/scan/sheet")
+    public TableDataInfo<List<WeQrCodeScanLineCountVo>> getWeQrCodeScanSheetCount(WeGroupCode weGroupCode) {
+        List<WeQrCodeScanLineCountVo> weQrCodeScanCount = groupCodeService.getWeQrCodeScanSheetCount(weGroupCode);
+        PageDomain pageDomain = TableSupport.buildPageRequest();
+        Integer pageNum = pageDomain.getPageNum();
+        Integer pageSize = pageDomain.getPageSize();
+        PageInfo<WeQrCodeScanLineCountVo> pageInfo = new PageInfo<>();
+        pageInfo.setTotal(weQrCodeScanCount.size());
+        pageInfo.setList(startPage(weQrCodeScanCount,pageNum,pageSize));
+        return getDataTable(pageInfo);
+    }
+
+    @ApiOperation(value = "获取群活码表格统计导出", httpMethod = "GET")
+    @GetMapping("/scan/sheet/export")
+    public void getWeQrCodeScanSheetExport(WeGroupCode weGroupCode) {
+        List<WeQrCodeScanLineCountVo> weQrCodeScanCount = groupCodeService.getWeQrCodeScanSheetCount(weGroupCode);
+        try {
+            HttpServletResponse response = ServletUtils.getResponse();
+            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
+            response.setCharacterEncoding("utf-8");
+            String fileName = URLEncoder.encode("群活码数据报表", "UTF-8").replaceAll("\\+", "%20");
+            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
+            ExcelWriterBuilder write = EasyExcel.write(response.getOutputStream(), WeQrCodeScanLineCountVo.class);
+            write.sheet("数据明细").doWrite(weQrCodeScanCount);
+        } catch (IOException e) {
+            log.error("获取活码表格统计导出异常:query:{}", JSONObject.toJSONString(weGroupCode), e);
+        }
+    }
 }

+ 15 - 15
linkwe-api/src/main/java/com/linkwechat/controller/WeGroupMessageTemplateController.java

@@ -23,7 +23,6 @@ import java.util.List;
  * @author ruoyi
  * @date 2021-10-27
  */
-@Api(tags = "群发消息管理")
 @RestController
 @RequestMapping("/groupmsg/template")
 public class WeGroupMessageTemplateController extends BaseController {
@@ -34,8 +33,6 @@ public class WeGroupMessageTemplateController extends BaseController {
     /**
      * 查询群发消息模板列表
      */
-    ////@PreAuthorize("@ss.hasPermi('linkwechat:template:list')")
-    @ApiOperation(value = "查询群发消息模板列表", httpMethod = "GET")
     @GetMapping("/list")
     public TableDataInfo<WeGroupMessageTemplate> list(WeGroupMessageTemplate weGroupMessageTemplate) {
         startPage();
@@ -47,8 +44,6 @@ public class WeGroupMessageTemplateController extends BaseController {
     /**
      * 获取群发消息模板详细信息
      */
-    ////@PreAuthorize("@ss.hasPermi('linkwechat:template:query')")
-    @ApiOperation(value = "获取群发消息模板详细信息", httpMethod = "GET")
     @GetMapping(value = "/{id}")
     public AjaxResult<WeGroupMessageDetailVo> getGroupMsgTemplateDetail(@PathVariable("id") Long id) {
         return AjaxResult.success(iWeGroupMessageTemplateService.getGroupMsgTemplateDetail(id));
@@ -57,8 +52,6 @@ public class WeGroupMessageTemplateController extends BaseController {
     /**
      * 新增群发消息模板
      */
-    ////@PreAuthorize("@ss.hasPermi('linkwechat:template:add')")
-    @ApiOperation(value = "新增群发消息模板", httpMethod = "POST")
     @PostMapping("/add")
     public AjaxResult addGroupMsgTemplate(@RequestBody WeAddGroupMessageQuery query){
         iWeGroupMessageTemplateService.addGroupMsgTemplate(query);
@@ -68,8 +61,6 @@ public class WeGroupMessageTemplateController extends BaseController {
     /**
      * 同步消息发送结果
      */
-    ////@PreAuthorize("@ss.hasPermi('linkwechat:template:remove')")
-    @ApiOperation(value = "同步消息发送结果", httpMethod = "GET")
     @GetMapping("/sync/{ids}")
     public AjaxResult sync(@PathVariable Long[] ids) {
         iWeGroupMessageTemplateService.syncGroupMsgSendResultByIds(Arrays.asList(ids));
@@ -79,8 +70,6 @@ public class WeGroupMessageTemplateController extends BaseController {
     /**
      * 取消定时发送
      */
-    ////@PreAuthorize("@ss.hasPermi('linkwechat:template:remove')")
-    @ApiOperation(value = "取消定时发送", httpMethod = "GET")
     @GetMapping("/cancel/{ids}")
     public AjaxResult cancel(@PathVariable Long[] ids) {
         iWeGroupMessageTemplateService.cancelByIds(Arrays.asList(ids));
@@ -90,8 +79,6 @@ public class WeGroupMessageTemplateController extends BaseController {
     /**
      * 群发成员发送任务列表
      */
-    ////@PreAuthorize("@ss.hasPermi('linkwechat:template:remove')")
-    @ApiOperation(value = "群发成员发送任务列表", httpMethod = "GET")
     @GetMapping("/task/list")
     public TableDataInfo<WeGroupMessageTask> groupMsgTaskList(WeGroupMessageTask task) {
         startPage();
@@ -102,12 +89,25 @@ public class WeGroupMessageTemplateController extends BaseController {
     /**
      * 群发成员发送任务列表
      */
-    ////@PreAuthorize("@ss.hasPermi('linkwechat:template:remove')")
-    @ApiOperation(value = "群发成员发送任务列表", httpMethod = "GET")
     @GetMapping("/send/result/list")
     public TableDataInfo<WeGroupMessageSendResult> groupMsgSendResultList(WeGroupMessageSendResult sendResult) {
         startPage();
         List<WeGroupMessageSendResult> sendResultList = iWeGroupMessageTemplateService.groupMsgSendResultList(sendResult);
         return getDataTable(sendResultList);
     }
+
+
+    /**
+     * 根据群发id获取群发内容明细数据
+     * @param id
+     * @return
+     */
+    @GetMapping("/findGroupMessageDetail/{id}")
+    public AjaxResult<WeAddGroupMessageQuery> findGroupMessageDetail(@PathVariable("id") Long id){
+
+        WeAddGroupMessageQuery groupMessageDetail = iWeGroupMessageTemplateService.findGroupMessageDetail(id);
+
+
+        return AjaxResult.success(groupMessageDetail);
+    }
 }

+ 96 - 0
linkwe-api/src/main/java/com/linkwechat/controller/WeIndexController.java

@@ -47,6 +47,11 @@ public class WeIndexController {
     @Autowired
     private IWeShortLinkService weShortLinkService;
 
+    @Autowired
+    private IWeQrCodeService weQrCodeService;
+
+    @Autowired
+    private IWeGroupCodeService iWeGroupCodeService;
 
     @Autowired
     private RedisService redisService;
@@ -134,6 +139,97 @@ public class WeIndexController {
     }
 
 
+    @ShortLinkView(prefix = "pqr:")
+    @ApiOperation(value = "活码短链换取长链", httpMethod = "GET")
+    @GetMapping(value = "/pqr/{shortUrl}")
+    public void getQrShort2LongUrl(HttpServletRequest request,
+                                 HttpServletResponse resp,
+                                 @PathVariable("shortUrl") String shortUrl) throws IOException {
+        log.info("活码短链换取长链 shortUrl:{}", shortUrl);
+
+        if (StringUtils.isEmpty(shortUrl) || Objects.equals("undefined",shortUrl)) {
+            return;
+        }
+        String ipAddr = IpUtils.getIpAddr(request);
+
+        String key = "we:qr:shortUrl:" + ipAddr + ":" + shortUrl;
+
+        JSONObject short2LongUrl = new JSONObject();
+        //判断键是否存在
+        Boolean hasKey = redisService.hasKey(key);
+        if (hasKey) {
+            short2LongUrl = (JSONObject) redisService.getCacheObject(key);
+        } else {
+            //尝试加锁
+            Boolean lock = redisService.tryLock(key, "lock", 2L);
+            if (lock) {
+                short2LongUrl = weQrCodeService.getShort2LongUrl(shortUrl);
+                log.info("活码短链换取长链的数据:{}", short2LongUrl.toJSONString());
+                if (StringUtils.isNotEmpty(short2LongUrl.getString("errorMsg"))) {
+                    redisService.setCacheObject(key, short2LongUrl, 5, TimeUnit.MINUTES);
+                } else {
+                    redisService.setCacheObject(key, short2LongUrl, 1, TimeUnit.DAYS);
+                }
+                //释放锁
+                redisService.unLock(key, "lock");
+            } else {
+                throw new WeComException("操作过于频繁,请稍后再试");
+            }
+        }
+        String result = ResourceUtil.readUtf8Str("templates/jump.html");
+        resp.setHeader("Content-Type", "text/html; charset=utf-8");
+        resp.setStatus(HttpServletResponse.SC_OK);
+        PrintWriter writer = resp.getWriter();
+        writer.write(StringUtils.format(result, short2LongUrl.toJSONString()).toCharArray());
+        writer.close();
+    }
+
+    @ShortLinkView(prefix = "gqr:")
+    @ApiOperation(value = "群活码短链换取长链", httpMethod = "GET")
+    @GetMapping(value = "/gqr/{shortUrl}")
+    public void getGroupQrShort2LongUrl(HttpServletRequest request,
+                                   HttpServletResponse resp,
+                                   @PathVariable("shortUrl") String shortUrl) throws IOException {
+        log.info("群活码短链换取长链 shortUrl:{}", shortUrl);
+
+        if (StringUtils.isEmpty(shortUrl) || Objects.equals("undefined",shortUrl)) {
+            return;
+        }
+        String ipAddr = IpUtils.getIpAddr(request);
+
+        String key = "we:gqr:shortUrl:" + ipAddr + ":" + shortUrl;
+
+        JSONObject short2LongUrl = new JSONObject();
+        //判断键是否存在
+        Boolean hasKey = redisService.hasKey(key);
+        if (hasKey) {
+            short2LongUrl = (JSONObject) redisService.getCacheObject(key);
+        } else {
+            //尝试加锁
+            Boolean lock = redisService.tryLock(key, "lock", 2L);
+            if (lock) {
+                short2LongUrl = iWeGroupCodeService.getShort2LongUrl(shortUrl);
+                log.info("群活码短链换取长链的数据:{}", short2LongUrl.toJSONString());
+                if (StringUtils.isNotEmpty(short2LongUrl.getString("errorMsg"))) {
+                    redisService.setCacheObject(key, short2LongUrl, 5, TimeUnit.MINUTES);
+                } else {
+                    redisService.setCacheObject(key, short2LongUrl, 1, TimeUnit.DAYS);
+                }
+                //释放锁
+                redisService.unLock(key, "lock");
+            } else {
+                throw new WeComException("操作过于频繁,请稍后再试");
+            }
+        }
+        String result = ResourceUtil.readUtf8Str("templates/jump.html");
+        resp.setHeader("Content-Type", "text/html; charset=utf-8");
+        resp.setStatus(HttpServletResponse.SC_OK);
+        PrintWriter writer = resp.getWriter();
+        writer.write(StringUtils.format(result, short2LongUrl.toJSONString()).toCharArray());
+        writer.close();
+    }
+
+
     @ShortLinkView(prefix = "l:")
     @ApiOperation(value = "获客助手短链换取长链", httpMethod = "GET")
     @GetMapping(value = "/l/{shortUrl}")

+ 8 - 4
linkwe-api/src/main/java/com/linkwechat/controller/WeLeadsController.java

@@ -14,6 +14,7 @@ import com.linkwechat.common.constant.HttpStatus;
 import com.linkwechat.common.core.controller.BaseController;
 import com.linkwechat.common.core.domain.AjaxResult;
 import com.linkwechat.common.core.page.TableDataInfo;
+import com.linkwechat.common.core.page.TableSupport;
 import com.linkwechat.common.enums.SexEnums;
 import com.linkwechat.common.enums.leads.leads.LeadsStatusEnum;
 import com.linkwechat.common.enums.leads.record.ImportSourceTypeEnum;
@@ -82,15 +83,18 @@ public class WeLeadsController extends BaseController {
         //检查公海是否存在
         checkExistSea(request.getSeaId());
         //获取列表
-        startPage();
-        List<WeLeadsVO> vos = weLeadsService.selectList(request);
-        TableDataInfo dataTable = getDataTable(vos);
+        List<WeLeadsVO> vos = weLeadsService.selectList(request, TableSupport.buildPageRequest());
+
         vos.forEach(i -> {
             //手机号脱敏
             i.setPhone(this.phoneDesensitization(i.getPhone()));
             i.setSourceStr(ImportSourceTypeEnum.of(i.getSource()).getDesc());
         });
-        dataTable.setRows(vos);
+        TableDataInfo dataTable = getDataTable(vos);
+        //设置总条数
+        dataTable.setTotal(
+                weLeadsSeaService.countLeadsList(request)
+        );
 
         return dataTable;
     }

+ 4 - 1
linkwe-api/src/main/java/com/linkwechat/controller/WeLeadsSeaController.java

@@ -130,7 +130,7 @@ public class WeLeadsSeaController extends BaseController {
         LambdaQueryWrapper<WeLeads> queryWrapper = Wrappers.lambdaQuery(WeLeads.class);
         queryWrapper.eq(WeLeads::getSeaId, weLeadsSea.getId());
         queryWrapper.eq(WeLeads::getDelFlag, Constants.COMMON_STATE);
-        List<WeLeads> list = weLeadsService.list();
+        List<WeLeads> list = weLeadsService.list(queryWrapper);
         List<Long> ids = list.stream().map(WeLeads::getId).collect(Collectors.toList());
         if (CollectionUtil.isNotEmpty(ids)) {
             LambdaUpdateWrapper<WeLeads> lambdaUpdate = Wrappers.lambdaUpdate(WeLeads.class);
@@ -199,6 +199,9 @@ public class WeLeadsSeaController extends BaseController {
             queryWrapper.eq(WeLeadsSea::getDelFlag, Constants.COMMON_STATE);
             List<WeLeadsSea> list = weLeadsSeaService.list(queryWrapper);
             seaList.addAll(list);
+            seaList.add(
+                    weLeadsSeaService.getById(new Long("1688498549743980545"))
+            );
         }
         seaList = seaList.stream().distinct().sorted(Comparator.comparing(WeLeadsSea::getId)).collect(Collectors.toList());
         List<WeLeadsSeaListVo> weLeadsSeaListVos = BeanUtil.copyToList(seaList, WeLeadsSeaListVo.class);

+ 0 - 8
linkwe-api/src/main/java/com/linkwechat/controller/WeLiveController.java

@@ -1,7 +1,6 @@
 package com.linkwechat.controller;
 
 
-import com.alibaba.excel.EasyExcel;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.linkwechat.common.core.controller.BaseController;
 import com.linkwechat.common.core.domain.AjaxResult;
@@ -9,7 +8,6 @@ import com.linkwechat.common.core.page.TableDataInfo;
 import com.linkwechat.common.utils.ServletUtils;
 import com.linkwechat.common.utils.StringUtils;
 import com.linkwechat.common.utils.poi.LwExcelUtil;
-import com.linkwechat.domain.kf.vo.WeKfRecordListVo;
 import com.linkwechat.domain.live.WeLive;
 import com.linkwechat.domain.live.WeLiveWatchUser;
 import com.linkwechat.domain.live.vo.WeLinveUserVo;
@@ -19,14 +17,8 @@ import com.linkwechat.service.IWeLiveTipService;
 import com.linkwechat.service.IWeLiveWatchUserService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
-
-import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.net.URLEncoder;
 import java.text.ParseException;
 import java.util.Arrays;
-import java.util.List;
 
 
 /**

+ 8 - 7
linkwe-api/src/main/java/com/linkwechat/controller/WeLxQrCodeController.java

@@ -6,6 +6,8 @@ import com.linkwechat.common.core.controller.BaseController;
 import com.linkwechat.common.core.domain.AjaxResult;
 import com.linkwechat.common.core.page.TableDataInfo;
 import com.linkwechat.common.utils.ServletUtils;
+import com.linkwechat.common.utils.poi.LwExcelUtil;
+import com.linkwechat.domain.customer.vo.WeCustomersVo;
 import com.linkwechat.domain.qr.query.WeLxQrAddQuery;
 import com.linkwechat.domain.qr.query.WeLxQrCodeListQuery;
 import com.linkwechat.domain.qr.query.WeLxQrCodeQuery;
@@ -95,14 +97,13 @@ public class WeLxQrCodeController extends BaseController {
 
     @ApiOperation(value = "导出活码列表统计", httpMethod = "GET")
     @GetMapping("/list/statistics/export")
-    public void qrCodeListStatisticsExport(WeLxQrCodeListQuery query) throws IOException {
+    public void qrCodeListStatisticsExport(WeLxQrCodeListQuery query){
+        weLxQrCodeService.statisticsParamsCheck(query);
         List<WeLxQrCodeSheetVo> list = weLxQrCodeService.getWeQrCodeListStatistics(query);
-        HttpServletResponse response = ServletUtils.getResponse();
-        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
-        response.setCharacterEncoding("utf-8");
-        String fileName = URLEncoder.encode("活码列表统计", "UTF-8").replaceAll("\\+", "%20");
-        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
-        EasyExcel.write(response.getOutputStream(), WeLxQrCodeSheetVo.class).sheet("活码列表统计").doWrite(list);
+
+        LwExcelUtil.exprotForWeb(
+                ServletUtils.getResponse(), WeLxQrCodeSheetVo.class,list,"活码列表统计_" + System.currentTimeMillis()
+        );
     }
 
 

+ 47 - 12
linkwe-api/src/main/java/com/linkwechat/controller/WeMaterialController.java

@@ -1,6 +1,9 @@
 package com.linkwechat.controller;
 
 import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.collection.ListUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.linkwechat.common.annotation.DataColumn;
 import com.linkwechat.common.annotation.DataScope;
@@ -17,6 +20,7 @@ import com.linkwechat.common.exception.CustomException;
 import com.linkwechat.common.utils.SnowFlakeUtil;
 import com.linkwechat.common.utils.StringUtils;
 import com.linkwechat.common.utils.bean.BeanUtils;
+import com.linkwechat.domain.WeTag;
 import com.linkwechat.domain.material.ao.PurePoster;
 import com.linkwechat.domain.material.ao.WePoster;
 import com.linkwechat.domain.material.ao.WePosterFontAO;
@@ -28,7 +32,9 @@ import com.linkwechat.domain.material.query.LinkMediaQuery;
 import com.linkwechat.domain.material.vo.*;
 import com.linkwechat.domain.wecom.vo.media.WeMediaVo;
 import com.linkwechat.service.IWeMaterialService;
+import com.linkwechat.service.IWeTagService;
 import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
@@ -49,6 +55,9 @@ public class WeMaterialController extends BaseController {
     @Resource
     private IWeMaterialService materialService;
 
+    @Autowired
+    private IWeTagService iWeTagService;
+
     @GetMapping("/material/list")
     @ApiOperation("查询素材列表")
     public TableDataInfo list(LinkMediaQuery query) {
@@ -156,18 +165,26 @@ public class WeMaterialController extends BaseController {
     public AjaxResult insert(@RequestBody WePoster poster) throws Exception {
         String materialName = poster.getMaterialName();
         if (materialName != null && materialName.length() > 60) {
-            throw new CustomException("海报标题不可超过60个字符!");
+            return AjaxResult.error("海报标题不可超过60个字符!");
         }
         String digest = poster.getDigest();
         if (digest != null && digest.length() > 100) {
-            throw new CustomException("海报描述不可超过100个字符!");
+            return AjaxResult.error("海报描述不可超过100个字符!");
         }
-        WeMaterial material = materialService.builderSimpleImg(poster);
-        material.setMediaType(MediaType.POSTER.getType());
-        material.setModuleType(poster.getModuleType());
-        boolean b = materialService.saveOrUpdate(material);
         WeMaterialVo weMaterialVo = new WeMaterialVo();
-        BeanUtils.copyProperties(material, weMaterialVo);
+        try {
+            WeMaterial material = materialService.builderSimpleImg(poster);
+            material.setMediaType(MediaType.POSTER.getType());
+            material.setModuleType(poster.getModuleType());
+            material.setTagIds(poster.getTagIds());
+            boolean b = materialService.saveOrUpdate(material);
+
+            BeanUtils.copyProperties(material, weMaterialVo);
+        }catch (Exception e){
+            return AjaxResult.error(e.getMessage());
+        }
+
+
         return AjaxResult.success(weMaterialVo);
     }
 
@@ -194,15 +211,23 @@ public class WeMaterialController extends BaseController {
         }
         String materialName = poster.getMaterialName();
         if (materialName != null && materialName.length() > 60) {
-            throw new CustomException("海报标题不可超过60个字符!");
+            return AjaxResult.error("海报标题不可超过60个字符!");
         }
         String digest = poster.getDigest();
         if (digest != null && digest.length() > 100) {
-            throw new CustomException("海报描述不可超过100个字符!");
+            return AjaxResult.error("海报描述不可超过100个字符!");
         }
         poster.setMediaType(null);
-        WeMaterial material = materialService.builderSimpleImg(poster);
-        materialService.saveOrUpdate(material);
+
+        WeMaterial material =new WeMaterial();
+        try {
+            material = materialService.builderSimpleImg(poster);
+            material.setTagIds(poster.getTagIds());
+            materialService.saveOrUpdate(material);
+        }catch (Exception e){
+            return AjaxResult.error(e.getMessage());
+        }
+
         return AjaxResult.success(material);
     }
 
@@ -215,6 +240,16 @@ public class WeMaterialController extends BaseController {
         if (StringUtils.isNotBlank(material.getMaterialName())) {
             vo.setTitle(material.getMaterialName());
         }
+        if(StringUtils.isNotEmpty(vo.getTagIds())){
+            List<WeTag> weTags = iWeTagService.list(new LambdaQueryWrapper<WeTag>()
+                    .in(WeTag::getTagId, ListUtil.toList(vo.getTagIds().split(","))));
+            if(CollectionUtil.isNotEmpty(weTags)){
+                vo.setTagNames(
+                        weTags.stream().map(WeTag::getName).collect(Collectors.joining(","))
+                );
+            }
+
+        }
         vo.setSampleImgPath(material.getMaterialUrl());
         vo.setBackgroundImgPath(material.getBackgroundImgUrl());
         return AjaxResult.success(vo);
@@ -228,7 +263,7 @@ public class WeMaterialController extends BaseController {
         List<WeMaterial> materials = materialService.lambdaQuery()
                 .eq(WeMaterial::getMediaType, MediaType.POSTER.getType()).eq(WeMaterial::getDelFlag, 0)
                 .eq(categoryId != null, WeMaterial::getCategoryId, categoryId)
-                .like(com.linkwechat.common.utils.StringUtils.isNotBlank(name), WeMaterial::getMaterialName, name)
+                .like(StringUtils.isNotBlank(name), WeMaterial::getMaterialName, name)
                 .orderByDesc(WeMaterial::getCreateTime).list();
         List<WePosterVo> posterList = materials.stream().map(m -> {
             WePosterVo vo = BeanUtil.copyProperties(m, WePosterVo.class);

+ 7 - 4
linkwe-api/src/main/java/com/linkwechat/controller/WeMomentsTaskController.java

@@ -154,19 +154,22 @@ public class WeMomentsTaskController extends BaseController {
     /**
      * 同步朋友圈
      *
-     * @param filterType 朋友圈类型 0:企业发表  1:个人发表  2:所有,包括个人创建以及企业创建,默认情况下为所有类型
+     * @param taskIds 多个任务id
      * @return {@link AjaxResult}
      * @author WangYX
      * @date 2023/06/12 10:53
      */
     @RepeatSubmit
     @ApiOperation("同步朋友圈")
-    @GetMapping("/sync/{filterType}")
-    public AjaxResult sync(@PathVariable(value = "filterType") Integer filterType) {
-        weMomentsTaskService.syncMoments(filterType);
+    @GetMapping("/sync/{taskIds}")
+    public AjaxResult sync(@PathVariable(value = "taskIds") List<String> taskIds) {
+        weMomentsTaskService.syncMoments(taskIds);
         return AjaxResult.success(WeConstans.SYNCH_TIP);
     }
 
+
+
+
     /**
      * 同步成员群发类型朋友圈
      * 成员群发类型朋友圈,员工完成任务后,调用该接口,同步企微数据

+ 6 - 4
linkwe-api/src/main/java/com/linkwechat/controller/WeOperationCenterController.java

@@ -7,6 +7,7 @@ import com.linkwechat.common.core.page.TableDataInfo;
 import com.linkwechat.common.utils.ServletUtils;
 import com.linkwechat.common.utils.poi.ExcelUtil;
 import com.linkwechat.common.utils.poi.LwExcelUtil;
+import com.linkwechat.domain.customer.vo.WeCustomersVo;
 import com.linkwechat.domain.operation.query.WeOperationCustomerQuery;
 import com.linkwechat.domain.operation.query.WeOperationGroupQuery;
 import com.linkwechat.domain.operation.vo.*;
@@ -276,7 +277,7 @@ public class WeOperationCenterController extends BaseController {
     @GetMapping("/session/customer/total/export")
     public void customerSessionTotalExport(WeOperationCustomerQuery query) {
         LwExcelUtil.exprotForWeb(
-                ServletUtils.getResponse(), WeSessionCustomerTotalCntVo.class,weOperationCenterService.getCustomerSessionTotalCnt(query),"会话总数"
+                ServletUtils.getResponse(), WeSessionCustomerTotalCntVo.class,weOperationCenterService.getCustomerSessionTotalCnt(query),"会话总数_"+ System.currentTimeMillis()
         );
     }
 
@@ -319,10 +320,11 @@ public class WeOperationCenterController extends BaseController {
      * @return
      */
     @GetMapping("/session/group/total/export")
-    public AjaxResult getGroupSessionTotalExport(WeOperationGroupQuery query) {
+    public void getGroupSessionTotalExport(WeOperationGroupQuery query) {
         List<WeSessionGroupTotalCntVo> groupSessionTotalCnt = weOperationCenterService.getGroupSessionTotalCnt(query);
-        ExcelUtil<WeSessionGroupTotalCntVo> util = new ExcelUtil<WeSessionGroupTotalCntVo>(WeSessionGroupTotalCntVo.class);
-        return util.exportExcel(groupSessionTotalCnt, "会话总数");
+        LwExcelUtil.exprotForWeb(
+                ServletUtils.getResponse(), WeSessionGroupTotalCntVo.class,groupSessionTotalCnt,"客群会话总数_" + System.currentTimeMillis()
+        );
     }
 
     /**

+ 6 - 1
linkwe-api/src/main/java/com/linkwechat/controller/WeProductOrderController.java

@@ -82,7 +82,12 @@ public class WeProductOrderController extends BaseController {
                     weProductOrderVo.setRefundStateStr(ProductRefundOrderStateEnum.of(weProductOrderRefundVo.getRefundState()).getMsg());
                 }
                 //客户类型
-                weProductOrderVo.setExternalTypeStr(weProductOrderVo.getExternalType() == 1 ? "微信" : "企业微信");
+                if(weProductOrderVo.getExternalType()!=null){
+                    weProductOrderVo.setExternalTypeStr(weProductOrderVo.getExternalType() == 1 ? "微信" : "企业微信");
+                }else{
+                    weProductOrderVo.setExternalTypeStr("未知");
+                }
+
                 result.add(weProductOrderVo);
             }
         }

+ 77 - 5
linkwe-api/src/main/java/com/linkwechat/controller/WeQrCodeController.java

@@ -1,25 +1,36 @@
 package com.linkwechat.controller;
 
 import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.alibaba.excel.EasyExcel;
+import com.alibaba.excel.write.builder.ExcelWriterBuilder;
+import com.alibaba.fastjson.JSONObject;
 import com.github.pagehelper.PageInfo;
 import com.linkwechat.common.annotation.Log;
+import com.linkwechat.common.constant.WeConstans;
 import com.linkwechat.common.core.controller.BaseController;
 import com.linkwechat.common.core.domain.AjaxResult;
+import com.linkwechat.common.core.page.PageDomain;
 import com.linkwechat.common.core.page.TableDataInfo;
+import com.linkwechat.common.core.page.TableSupport;
+import com.linkwechat.common.core.redis.RedisService;
 import com.linkwechat.common.enums.BusinessType;
 import com.linkwechat.common.exception.CustomException;
 import com.linkwechat.common.exception.wecom.WeComException;
+import com.linkwechat.common.utils.Base62NumUtil;
+import com.linkwechat.common.utils.ServletUtils;
 import com.linkwechat.common.utils.StringUtils;
 import com.linkwechat.common.utils.file.FileUtils;
+import com.linkwechat.domain.qirule.vo.WeQiRuleWeeklyDetailListVo;
 import com.linkwechat.domain.qr.query.WeQrAddQuery;
 import com.linkwechat.domain.qr.query.WeQrCodeListQuery;
-import com.linkwechat.domain.qr.vo.WeQrCodeDetailVo;
-import com.linkwechat.domain.qr.vo.WeQrCodeScanCountVo;
-import com.linkwechat.domain.qr.vo.WeQrScopeUserVo;
-import com.linkwechat.domain.qr.vo.WeQrScopeVo;
+import com.linkwechat.domain.qr.vo.*;
+import com.linkwechat.domain.shortlink.vo.WeShortLinkVo;
+import com.linkwechat.handler.WeQiRuleWeeklyUserDetailWriteHandler;
 import com.linkwechat.service.IWeQrCodeService;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
@@ -27,6 +38,7 @@ import org.springframework.web.bind.annotation.*;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
+import java.net.URLEncoder;
 import java.util.*;
 import java.util.stream.Collectors;
 
@@ -35,13 +47,16 @@ import java.util.stream.Collectors;
  * @description 活码管理
  * @date 2021/11/12 18:22
  **/
-
+@Slf4j
 @RestController
 @RequestMapping(value = "qr")
 @Api(tags = "活码管理")
 public class WeQrCodeController extends BaseController {
 
     @Autowired
+    private RedisService redisService;
+
+    @Autowired
     private IWeQrCodeService weQrCodeService;
 
     @ApiOperation(value = "新增活码", httpMethod = "POST")
@@ -97,6 +112,10 @@ public class WeQrCodeController extends BaseController {
         return AjaxResult.success(weQrCodeScanCount);
     }
 
+
+
+
+
     /**
      * 员工活码批量下载
      *
@@ -159,4 +178,57 @@ public class WeQrCodeController extends BaseController {
         weQrCodeService.updateQrMultiplePeople(state);
         return AjaxResult.success();
     }
+
+    @ApiOperation(value = "通过短链接获取活码详情", httpMethod = "GET")
+    @GetMapping("/getByDetail/{shortUrl}")
+    public AjaxResult<WeQrCodeDetailVo> getQrCodeInfoByShortUrl(@PathVariable("shortUrl") String shortUrl) {
+        long id = Base62NumUtil.decode(shortUrl);
+        WeQrCodeDetailVo qrDetail = weQrCodeService.getQrDetail(id);
+        redisService.increment(WeConstans.WE_SHORT_LINK_COMMON_KEY + WeConstans.OPEN_APPLET + "qr:" +shortUrl);
+        return AjaxResult.success(qrDetail);
+    }
+
+    @ApiOperation(value = "获取活码总数统计", httpMethod = "GET")
+    @GetMapping("/scan/total")
+    public AjaxResult<WeQrCodeScanCountVo> getWeQrCodeScanTotalCount(WeQrCodeListQuery qrCodeListQuery) {
+        WeQrCodeScanCountVo weQrCodeScanCount = weQrCodeService.getWeQrCodeScanTotalCount(qrCodeListQuery);
+        return AjaxResult.success(weQrCodeScanCount);
+    }
+
+    @ApiOperation(value = "获取活码折线图统计", httpMethod = "GET")
+    @GetMapping("/scan/line")
+    public AjaxResult<List<WeQrCodeScanLineCountVo>> getWeQrCodeScanLineCount(WeQrCodeListQuery qrCodeListQuery) {
+        List<WeQrCodeScanLineCountVo> weQrCodeScanCount = weQrCodeService.getWeQrCodeScanLineCount(qrCodeListQuery);
+        return AjaxResult.success(weQrCodeScanCount);
+    }
+
+    @ApiOperation(value = "获取活码表格统计", httpMethod = "GET")
+    @GetMapping("/scan/sheet")
+    public TableDataInfo<List<WeQrCodeScanLineCountVo>> getWeQrCodeScanSheetCount(WeQrCodeListQuery qrCodeListQuery) {
+        List<WeQrCodeScanLineCountVo> weQrCodeScanCount = weQrCodeService.getWeQrCodeScanSheetCount(qrCodeListQuery);
+        PageDomain pageDomain = TableSupport.buildPageRequest();
+        Integer pageNum = pageDomain.getPageNum();
+        Integer pageSize = pageDomain.getPageSize();
+        PageInfo<WeQrCodeScanLineCountVo> pageInfo = new PageInfo<>();
+        pageInfo.setTotal(weQrCodeScanCount.size());
+        pageInfo.setList(startPage(weQrCodeScanCount,pageNum,pageSize));
+        return getDataTable(pageInfo);
+    }
+
+    @ApiOperation(value = "获取活码表格统计导出", httpMethod = "GET")
+    @GetMapping("/scan/sheet/export")
+    public void getWeQrCodeScanSheetExport(WeQrCodeListQuery qrCodeListQuery) {
+        List<WeQrCodeScanLineCountVo> weQrCodeScanCount = weQrCodeService.getWeQrCodeScanSheetCount(qrCodeListQuery);
+        try {
+            HttpServletResponse response = ServletUtils.getResponse();
+            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
+            response.setCharacterEncoding("utf-8");
+            String fileName = URLEncoder.encode("活码数据报表", "UTF-8").replaceAll("\\+", "%20");
+            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
+            ExcelWriterBuilder write = EasyExcel.write(response.getOutputStream(), WeQrCodeScanLineCountVo.class);
+            write.sheet("数据明细").doWrite(weQrCodeScanCount);
+        } catch (IOException e) {
+            log.error("获取活码表格统计导出异常:query:{}", JSONObject.toJSONString(qrCodeListQuery), e);
+        }
+    }
 }

+ 3 - 2
linkwe-api/src/main/java/com/linkwechat/controller/WeSopController.java

@@ -20,6 +20,7 @@ public class WeSopController extends BaseController {
     private IWeSopBaseService iWeSopBaseService;
 
 
+
     /**
      * 获取sop列表
      * @param weSopBase  baseType sop基础类型(1:客户sop;2:客群sop)
@@ -109,7 +110,7 @@ public class WeSopController extends BaseController {
     public AjaxResult findGroupSopContent(String chatId, Integer executeSubState){
 
         return AjaxResult.success(
-                iWeSopBaseService.findGroupSopContent(chatId,executeSubState)
+                iWeSopBaseService.findGroupSopContent(1,chatId,executeSubState)
         );
     }
 
@@ -200,7 +201,7 @@ public class WeSopController extends BaseController {
     @PutMapping("/updateWeSop")
     public AjaxResult updateWeSop(@RequestBody WeSopBase weSopBase){
         WeSopBase weSopBasee = iWeSopBaseService.getById(weSopBase.getId());
-        if(weSopBasee.getSopState().equals(2)){
+        if(weSopBasee.getSopState().equals(1)){
            return AjaxResult.error("当前sop为执行中不可修改");
         }
 

+ 91 - 32
linkwe-api/src/main/java/com/linkwechat/controller/WeStoreCodeController.java

@@ -8,7 +8,6 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.linkwechat.common.annotation.Log;
 import com.linkwechat.common.core.controller.BaseController;
 import com.linkwechat.common.core.domain.AjaxResult;
-import com.linkwechat.common.core.domain.entity.SysDictData;
 import com.linkwechat.common.core.page.TableDataInfo;
 import com.linkwechat.common.enums.BusinessType;
 import com.linkwechat.common.utils.DateUtils;
@@ -18,12 +17,13 @@ import com.linkwechat.common.utils.StringUtils;
 import com.linkwechat.common.utils.file.FileUtils;
 import com.linkwechat.common.utils.poi.ExcelUtil;
 import com.linkwechat.common.utils.poi.LwExcelUtil;
-import com.linkwechat.domain.WeCustomerSeas;
-import com.linkwechat.domain.groupcode.entity.WeGroupCode;
+import com.linkwechat.domain.WeGroup;
 import com.linkwechat.domain.storecode.entity.WeStoreCode;
 import com.linkwechat.domain.storecode.entity.WeStoreCodeConfig;
 import com.linkwechat.domain.qr.WeQrAttachments;
-import com.linkwechat.domain.storecode.entity.WeStoreCodeCount;
+import com.linkwechat.domain.storecode.query.WeStoreCodeQuery;
+import com.linkwechat.domain.storecode.query.WxStoreCodeQuery;
+import com.linkwechat.domain.storecode.vo.WeStoreCodeTableVo;
 import com.linkwechat.domain.storecode.vo.WeStoreCodesVo;
 import com.linkwechat.domain.storecode.vo.datareport.WeStoreGroupReportVo;
 import com.linkwechat.domain.storecode.vo.datareport.WeStoreShopGuideReportVo;
@@ -34,14 +34,13 @@ import com.linkwechat.domain.storecode.vo.tab.WeStoreShopGuideTabVo;
 import com.linkwechat.domain.storecode.vo.tab.WeStoreTabVo;
 import com.linkwechat.domain.storecode.vo.trend.WeStoreGroupTrendVo;
 import com.linkwechat.domain.storecode.vo.trend.WeStoreShopGuideTrendVo;
+import com.linkwechat.service.IWeGroupService;
 import com.linkwechat.service.IWeQrAttachmentsService;
 import com.linkwechat.service.IWeStoreCodeConfigService;
 import com.linkwechat.service.IWeStoreCodeService;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
-
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.text.MessageFormat;
@@ -67,6 +66,9 @@ public class WeStoreCodeController extends BaseController {
     private IWeQrAttachmentsService attachmentsService;
 
     @Autowired
+    private IWeGroupService iWeGroupService;
+
+    @Autowired
     private MapUtils mapUtils;
 
 
@@ -86,6 +88,8 @@ public class WeStoreCodeController extends BaseController {
                             .eq(WeQrAttachments::getQrId, storeCodeConfig.getId())
                             .eq(WeQrAttachments::getBusinessType,2))
             );
+        }else{
+            storeCodeConfig=new WeStoreCodeConfig();
         }
 
         return AjaxResult.success(
@@ -187,12 +191,7 @@ public class WeStoreCodeController extends BaseController {
      */
     @PutMapping("/batchStartOrStop/{ids}")
     public AjaxResult batchStartOrStop(@PathVariable("ids") Long[] ids,@RequestBody WeStoreCode weStoreCode){
-
-        iWeStoreCodeService.update(WeStoreCode.builder()
-                .storeState(weStoreCode.getStoreState())
-                .build(), new LambdaQueryWrapper<WeStoreCode>()
-                .in(WeStoreCode::getId,Arrays.asList(ids)));
-
+        iWeStoreCodeService.batchUpdateState(weStoreCode.getStoreState(),ListUtil.toList(ids));
         return AjaxResult.success();
 
     }
@@ -266,6 +265,7 @@ public class WeStoreCodeController extends BaseController {
     public AjaxResult<List<WeStoreShopGuideTrendVo>> countStoreShopGuideTrend(WeStoreCode weStoreCode){
 
 
+
         return AjaxResult.success(
                 iWeStoreCodeService.countStoreShopGuideTrend(weStoreCode)
         );
@@ -394,6 +394,64 @@ public class WeStoreCodeController extends BaseController {
     }
 
 
+    /**
+     * 数据明细获取
+     * @param weStoreCodeQuery
+     * @return
+     */
+    @GetMapping("/findWeStoreCodeTables")
+    public TableDataInfo<List<WeStoreCodeTableVo>>  findWeStoreCodeTables(WeStoreCodeQuery weStoreCodeQuery){
+        startPage();
+        return getDataTable(
+                iWeStoreCodeService.findWeStoreCodeTables(weStoreCodeQuery)
+        );
+    }
+
+
+    /**
+     * 数据明细导出
+     * @param weStoreCodeQuery
+     * @return
+     */
+    @GetMapping("/weStoreCodeTablesExport")
+    public void weStoreCodeTablesExport(WeStoreCodeQuery weStoreCodeQuery) {
+
+        List<WeStoreCodeTableVo> weStoreCodeTables = iWeStoreCodeService.findWeStoreCodeTables(weStoreCodeQuery);
+
+
+        LwExcelUtil.exprotForWeb(
+                ServletUtils.getResponse(), WeStoreCodeTableVo.class,weStoreCodeTables,"数据明细_" + System.currentTimeMillis()
+        );
+
+    }
+
+
+
+
+    /**
+     * 获取当前客户对应的群
+     * @param weStoreCodeQuery
+     * @return
+     */
+    @GetMapping("/findWeStoreCodeGroupTables")
+    public TableDataInfo<WeGroup> findWeStoreCodeGroupTables(WeStoreCodeQuery weStoreCodeQuery){
+        List<WeGroup> weGroups =new ArrayList<>();
+        WeStoreCode weStoreCode = iWeStoreCodeService.getById(weStoreCodeQuery.getStoreCodeId());
+
+        if(null != weStoreCode){
+            startPage();
+            if(StringUtils.isNotEmpty(weStoreCode.getGroupCodeState())){
+                weGroups=iWeGroupService
+                        .findGroupByUserId(weStoreCodeQuery.getExternalUserid()
+                                , weStoreCode.getGroupCodeState());
+            }
+
+        }
+
+        return getDataTable(weGroups);
+    }
+
+
     /***************************************************************
      **************************统计数据报表相关 end********************
      ****************************************************************/
@@ -463,9 +521,7 @@ public class WeStoreCodeController extends BaseController {
                     k.setLatitude(lMap.get(MapUtils.lat));
                     k.setLongitude(lMap.get(MapUtils.lng));
                 });
-//                List<WeStoreCode> weStoreCodeList = iWeStoreCodeService.getBaseMapper().selectList(new LambdaQueryWrapper<WeStoreCode>()
-//                        .eq(WeStoreCode::getDelFlag, 0));
-//                List<String> lst = weStoreCodeList.stream().map(WeStoreCode::getStoreName).collect(Collectors.toList());
+
                 deduplicationSeasNoRepeat = deduplicationSeasNoRepeat.stream().filter(item -> item.getStoreName().length()<30).collect(Collectors.toList());
                 if(iWeStoreCodeService.saveBatch(deduplicationSeasNoRepeat)){
                     tip = MessageFormat.format(tip, new Object[]{new Integer(deduplicationSeasNoRepeat.size()).toString()});
@@ -486,18 +542,14 @@ public class WeStoreCodeController extends BaseController {
 
     /**
      * 获取附件门店
-     * @param storeCodeType 门店码类型(1:门店导购码;2:门店群活码)
-     * @param unionid 微信unionid
-     * @param longitude 经度
-     * @param latitude 纬度
-     * @param area 区域
+     * @param wxStoreCodeQuery 门店码类型(1:门店导购码;2:门店群活码)
      * @return
      */
     @GetMapping("/findStoreCode")
-    public AjaxResult<WeStoreCodesVo> findStoreCode(Integer storeCodeType, String unionid, String longitude, String latitude, String area){
+    public AjaxResult<WeStoreCodesVo> findStoreCode(WxStoreCodeQuery wxStoreCodeQuery){
 
         return AjaxResult.success(
-                iWeStoreCodeService.findStoreCode(storeCodeType,unionid,longitude,latitude,area)
+                iWeStoreCodeService.findStoreCode(wxStoreCodeQuery)
         );
     }
 
@@ -509,23 +561,30 @@ public class WeStoreCodeController extends BaseController {
      */
     @GetMapping("/findWeStoreCodeConfig")
     public AjaxResult<WeStoreCodeConfig> findWeStoreCodeConfig(Integer storeCodeType){
+        WeStoreCodeConfig weStoreCodeConfig=new WeStoreCodeConfig();
+        List<WeStoreCodeConfig> weStoreCodeConfigList = iWeStoreCodeConfigService.list(new LambdaQueryWrapper<WeStoreCodeConfig>()
+                .eq(WeStoreCodeConfig::getStoreCodeType, storeCodeType));
+
+        if(CollectionUtil.isNotEmpty(weStoreCodeConfigList)){
+            weStoreCodeConfig=weStoreCodeConfigList.stream().findFirst().get();
+        }
 
 
         return AjaxResult.success(
-                iWeStoreCodeConfigService.getWeStoreCodeConfig(storeCodeType)
+                weStoreCodeConfig
         );
     }
 
 
-    /**
-     * 记录用户扫码行为
-     * @return
-     */
-    @PostMapping("/countUserBehavior")
-    public AjaxResult countUserBehavior(@RequestBody WeStoreCodeCount weStoreCodeCount){
-        iWeStoreCodeService.countUserBehavior(weStoreCodeCount);
-        return AjaxResult.success();
-    }
+//    /**
+//     * 记录用户扫码行为
+//     * @return
+//     */
+//    @PostMapping("/countUserBehavior")
+//    public AjaxResult countUserBehavior(@RequestBody WeStoreCodeCount weStoreCodeCount){
+//        iWeStoreCodeService.countUserBehavior(weStoreCodeCount);
+//        return AjaxResult.success();
+//    }
 
 
 

+ 7 - 2
linkwe-api/src/main/java/com/linkwechat/interceptor/RequestContextInterceptor.java

@@ -37,8 +37,13 @@ public class RequestContextInterceptor implements HandlerInterceptor {
         SecurityContextHolder.setUserType(ServletUtils.getHeader(request, SecurityConstants.USER_TYPE));
         SecurityContextHolder.setUserKey(ServletUtils.getHeader(request, SecurityConstants.USER_KEY));
         String loginType = ServletUtils.getHeader(request, SecurityConstants.LOGIN_TYPE);
-        if(StringUtils.isNotEmpty(loginType) && ObjectUtil.notEqual("LinkWeChatAPI",loginType)){
-           throw new WeComException("token不合法");
+        if(StringUtils.isNotEmpty(loginType)){
+            if(ObjectUtil.notEqual("LinkWeChatAPI",loginType)||
+                    SecurityConstants.IS_FEGIN.equals(
+                            ServletUtils.getHeader(request, SecurityConstants.IS_FEGIN)
+                    )){
+                throw new WeComException("token不合法");
+            }
         }
         String loginUserStr = ServletUtils.getHeader(request, SecurityConstants.LOGIN_USER);
         if(StringUtils.isNotEmpty(loginUserStr)){

+ 1 - 1
linkwe-api/src/main/resources/logback-spring.xml

@@ -5,7 +5,7 @@
     <property name="app_name" value="linkwe-api"/>
 
     <!-- 日志输出格式 -->
-    <property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS,CTT} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
+    <property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} | %-5level | %thread | %logger{36}:%L | %M | %msg%n" />
 
     <!--  邮件 -->
     <!-- SMTP server的地址,必需指定。如网易的SMTP服务器地址是: smtp.163.com -->

+ 1 - 1
linkwe-api/src/main/resources/templates/jump.html

@@ -196,7 +196,7 @@
 <body>
   <div class="page full">
     <div id="public-web-container" class="hidden">
-      <p class="">正在打开 “仟微科技”...</p> <!-- replace -->
+      <p class="">正在打开 “scrm”...</p> <!-- replace -->
       <a id="public-web-jump-button" href="javascript:" class="weui-btn weui-btn_primary weui-btn_loading"
         onclick="openWeapp()">
         <span id="public-web-jump-button-loading" class="weui-primary-loading weui-primary-loading_transparent"><i

+ 24 - 2
linkwe-auth/pom.xml

@@ -104,13 +104,16 @@
 
     </dependencies>
 
+
+
     <build>
         <finalName>lw-auth</finalName>
         <plugins>
+            <!-- 引用Spring Boot Maven插件 -->
             <plugin>
                 <groupId>org.springframework.boot</groupId>
                 <artifactId>spring-boot-maven-plugin</artifactId>
-                <version>2.3.3.RELEASE</version>
+                <version>${springboot.maven.version}</version>
                 <executions>
                     <execution>
                         <goals>
@@ -119,7 +122,26 @@
                     </execution>
                 </executions>
             </plugin>
+            <!-- 引用jib-maven-plugin插件 -->
+            <plugin>
+                <groupId>com.google.cloud.tools</groupId>
+                <artifactId>jib-maven-plugin</artifactId>
+                <version>${jib.maven.plugin.version}</version>
+                <configuration>
+                    <to>
+                        <image>${docker.harbor.addr}/${docker.harbor.project}/${project.artifactId}:${docker.harbor.tag.version}</image>
+                        <auth>
+                            <username>${docker.harbor.username}</username>
+                            <password>${docker.harbor.password}</password>
+                        </auth>
+                    </to>
+                    <container>
+                        <jvmFlags>
+                            <jvmFlag>-Duser.timezone=Asia/Shanghai</jvmFlag>
+                        </jvmFlags>
+                    </container>
+                </configuration>
+            </plugin>
         </plugins>
     </build>
-
 </project>

+ 2 - 1
linkwe-auth/src/main/java/com/linkwechat/LinkWeAuthApplication.java

@@ -2,6 +2,7 @@ package com.linkwechat;
 
 import com.github.pagehelper.autoconfigure.PageHelperAutoConfiguration;
 import com.linkwechat.common.config.fegin.FeginConfig;
+import com.linkwechat.common.constant.WeServerNameConstants;
 import org.mybatis.spring.annotation.MapperScan;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
@@ -22,7 +23,7 @@ public class LinkWeAuthApplication {
     public static void main(String[] args) {
         new SpringApplicationBuilder(LinkWeAuthApplication.class)
                 .properties("spring.config.name:bootstrap", "config/run/bootstrap.yml")
-                .properties("spring.application.name=linkwe-auth")
+                .properties("spring.application.name="+ WeServerNameConstants.linkweAuth)
                 .build().run(args);
         System.out.println("(♥◠‿◠)ノ゙  LinkWe-auth启动成功   ლ(´ڡ`ლ)゙ ");
     }

+ 1 - 1
linkwe-auth/src/main/java/com/linkwechat/web/controller/system/SysConfigController.java

@@ -39,7 +39,7 @@ public class SysConfigController extends BaseController
     /**
      * 获取参数配置列表
      */
-    //@PreAuthorize("@ss.hasPermi('system:config:list')")
+//    @PreAuthorize("@ss.hasPermi('system:config:list')")
     @GetMapping("/list")
     public TableDataInfo list(SysConfig config)
     {

+ 12 - 0
linkwe-auth/src/main/java/com/linkwechat/web/domain/vo/RouterVo.java

@@ -51,6 +51,10 @@ public class RouterVo
      */
     private List<RouterVo> children;
 
+
+  /** 显示顺序 */
+    private Integer orderNum;
+
     public String getName()
     {
         return name;
@@ -130,4 +134,12 @@ public class RouterVo
     {
         this.children = children;
     }
+
+    public Integer getOrderNum() {
+        return orderNum;
+    }
+
+    public void setOrderNum(Integer orderNum) {
+        this.orderNum = orderNum;
+    }
 }

+ 8 - 5
linkwe-auth/src/main/java/com/linkwechat/web/interceptor/RequestContextInterceptor.java

@@ -58,9 +58,14 @@ public class RequestContextInterceptor implements HandlerInterceptor {
                 SecurityContextHolder.setUserKey(ServletUtils.getHeader(request, SecurityConstants.USER_KEY));
 
 
-                if(StringUtils.isNotEmpty(loginType) && ObjectUtil.notEqual("LinkWeChatAPI",loginType)){
-                    throw new WeComException("token不合法");
-                }
+//                if(StringUtils.isNotEmpty(loginType)){
+//                    if(ObjectUtil.notEqual("LinkWeChatAPI",loginType)||
+//                            SecurityConstants.IS_FEGIN.equals(
+//                                    ServletUtils.getHeader(request, SecurityConstants.IS_FEGIN)
+//                            )){
+//                        throw new WeComException("token不合法");
+//                    }
+//                }
 
 
             }
@@ -68,8 +73,6 @@ public class RequestContextInterceptor implements HandlerInterceptor {
 
 
 
-
-
         String loginUserStr = ServletUtils.getHeader(request, SecurityConstants.LOGIN_USER);
         if(StringUtils.isNotEmpty(loginUserStr)){
             SecurityContextHolder.set(SecurityConstants.Details.LOGIN_USER.getCode(), JSONObject.parseObject(loginUserStr,

+ 12 - 2
linkwe-auth/src/main/java/com/linkwechat/web/service/impl/SysMenuServiceImpl.java

@@ -138,6 +138,7 @@ public class SysMenuServiceImpl implements ISysMenuService {
             router.setPath(getRouterPath(menu));
             router.setComponent(getComponent(menu));
             router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon()));
+            router.setOrderNum(Integer.parseInt(menu.getOrderNum()));
             List<SysMenu> cMenus = menu.getChildren();
             if (!cMenus.isEmpty() && cMenus.size() > 0 && UserConstants.TYPE_DIR.equals(menu.getMenuType())) {
                 router.setAlwaysShow(true);
@@ -150,12 +151,21 @@ public class SysMenuServiceImpl implements ISysMenuService {
                 children.setComponent(menu.getComponent());
                 children.setName(StringUtils.capitalize(menu.getPath()));
                 children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon()));
+                children.setOrderNum(Integer.parseInt(menu.getOrderNum()));
                 childrenList.add(children);
-                router.setChildren(childrenList);
+                router.setChildren(this.sortByOrderNum(
+                        childrenList
+                ));
             }
             routers.add(router);
         }
-        return routers;
+        return this.sortByOrderNum(routers);
+    }
+
+    private List<RouterVo> sortByOrderNum(List<RouterVo> routerVoList) {
+        return routerVoList.stream()
+                .sorted(Comparator.comparingInt(RouterVo::getOrderNum))
+                .collect(Collectors.toList());
     }
 
     /**

+ 1 - 1
linkwe-auth/src/main/resources/logback-spring.xml

@@ -2,7 +2,7 @@
 <configuration scan="true" scanPeriod="60 seconds" debug="false">
 
     <!-- 日志输出格式 -->
-    <property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS,CTT} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
+    <property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} | %-5level | %thread | %logger{36}:%L | %M | %msg%n" />
 
     <!--  邮件 -->
     <!-- SMTP server的地址,必需指定。如网易的SMTP服务器地址是: smtp.163.com -->

+ 1 - 1
linkwe-auth/src/main/resources/mapper/system/SysUserMapper.xml

@@ -225,7 +225,7 @@
         <choose>
             <when test="sysUser.checkIsRoot">
                 <if test="sysUser.deptId != null">
-                    AND FIND_IN_SET(#{sysUser.deptId},d.ancestors) or d.dept_id=#{sysUser.deptId}
+                    AND (FIND_IN_SET(#{sysUser.deptId},d.ancestors) or d.dept_id=#{sysUser.deptId})
                 </if>
             </when>
             <otherwise>

+ 17 - 4
linkwe-common/pom.xml

@@ -304,17 +304,30 @@
             <groupId>ma.glasnost.orika</groupId>
             <artifactId>orika-core</artifactId>
         </dependency>
+        <dependency>
+            <groupId>io.minio</groupId>
+            <artifactId>minio</artifactId>
+        </dependency>
 
     </dependencies>
 
+
+
     <build>
         <plugins>
+            <!-- 引用Spring Boot Maven插件 -->
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>${springboot.maven.version}</version>
+            </plugin>
+            <!-- 引用jib-maven-plugin插件 -->
             <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-compiler-plugin</artifactId>
+                <groupId>com.google.cloud.tools</groupId>
+                <artifactId>jib-maven-plugin</artifactId>
+                <version>${jib.maven.plugin.version}</version>
                 <configuration>
-                    <source>8</source>
-                    <target>8</target>
+                    <skip>true</skip>
                 </configuration>
             </plugin>
         </plugins>

+ 1 - 1
linkwe-common/src/main/java/com/linkwechat/common/annotation/DataScope.java

@@ -18,7 +18,7 @@ public @interface DataScope
 {
 
     /**
-     * 业务类型 1-system 2-api
+     * 业务类型 1-按照部门查询 2-按照员工id查询
      * @return
      */
     public String type() default "1";

+ 10 - 145
linkwe-common/src/main/java/com/linkwechat/common/aop/DataScopeAspect.java

@@ -8,8 +8,10 @@ import com.linkwechat.common.core.domain.entity.SysRole;
 import com.linkwechat.common.core.domain.entity.SysUser;
 import com.linkwechat.common.core.domain.model.LoginUser;
 import com.linkwechat.common.enums.DataScopeType;
+import com.linkwechat.common.utils.DataScopeSqlUtils;
 import com.linkwechat.common.utils.SecurityUtils;
 import com.linkwechat.common.utils.StringUtils;
+import lombok.extern.slf4j.Slf4j;
 import org.aspectj.lang.JoinPoint;
 import org.aspectj.lang.annotation.Aspect;
 import org.aspectj.lang.annotation.Before;
@@ -22,6 +24,7 @@ import org.springframework.stereotype.Component;
  */
 @Aspect
 @Component
+@Slf4j
 public class DataScopeAspect {
 
     /**
@@ -38,89 +41,16 @@ public class DataScopeAspect {
     protected void handleDataScope(final JoinPoint joinPoint, DataScope controllerDataScope) {
         // 获取当前的用户
         LoginUser loginUser = SecurityUtils.getLoginUser();
+
         if (StringUtils.isNotNull(loginUser)) {
             SysUser currentUser = loginUser.getSysUser();
             // 如果是超级管理员,则不过滤数据
             if (StringUtils.isNotNull(currentUser) && !currentUser.isAdmin()) {
-//                dataScopeFilterForRole(joinPoint, currentUser, controllerDataScope);
                 dataScopeFilterForSysUser(joinPoint, currentUser, controllerDataScope);
             }
         }
     }
 
-//    /**
-//     * 数据范围过滤(角色绑定数据权限)
-//     *
-//     * @param joinPoint 切点
-//     * @param user      用户
-//     * @param controllerDataScope 部门别名
-//     */
-//    public static void dataScopeFilterForRole(JoinPoint joinPoint, SysUser user, DataScope controllerDataScope) {
-//        StringBuilder sqlString = new StringBuilder();
-//
-//        String type = controllerDataScope.type();
-//
-//        for (SysRole role : user.getRoles()) {
-//            String dataScope = role.getDataScope();
-//            if (DataScopeType.DATA_SCOPE_ALL.equals(dataScope)) {
-//                sqlString = new StringBuilder();
-//                break;
-//            } else if (DataScopeType.DATA_SCOPE_CUSTOM.equals(dataScope)) {
-//                if(type.equals("1")){
-//                    sqlString.append(StringUtils.format(
-//                            " OR {}.dept_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id = {} ) ", controllerDataScope.deptAlias(),
-//                            role.getRoleId()));
-//                }else {
-//                    DataColumn dataColumn = controllerDataScope.value()[0];
-//                    sqlString.append(StringUtils.format(
-//                            " or {}.{} in ( select distinct sud.{} from sys_role_dept srd inner join sys_user_dept sud on srd.dept_id= sud.dept_id and sud.del_flag = 0  where srd.role_id = {} )",
-//                            dataColumn.alias(), dataColumn.name(),dataColumn.userid(), role.getRoleId()));
-//                }
-//            } else if (DataScopeType.DATA_SCOPE_DEPT.equals(dataScope)) {
-//                if(type.equals("1")){
-//                    sqlString.append(StringUtils.format(" OR {}.dept_id = {} ", controllerDataScope.deptAlias(), user.getDeptId()));
-//                }else {
-//                    DataColumn dataColumn = controllerDataScope.value()[0];
-//                    sqlString.append(StringUtils.format(" or {}.{} in ( select {} from sys_user_dept where dept_id= {}  and del_flag = 0 ) ",
-//                            dataColumn.alias(), dataColumn.name(),dataColumn.userid(),user.getDept()));
-//                }
-//            } else if (DataScopeType.DATA_SCOPE_DEPT_AND_CHILD.equals(dataScope)) {
-//                if(type.equals("1")){
-//                    sqlString.append(StringUtils.format(
-//                            " OR {}.dept_id IN ( SELECT dept_id FROM sys_dept WHERE dept_id = {} or find_in_set( {} , ancestors ) )",
-//                            controllerDataScope.deptAlias(), user.getDeptId(), user.getDeptId()));
-//                }else {
-//                    DataColumn dataColumn = controllerDataScope.value()[0];
-//                    sqlString.append(StringUtils.format(
-//                            " or {}.{} in ( select distinct sud.{} from sys_dept sd inner join sys_user_dept sud on sd.dept_id = sud.dept_id and sud.del_flag = 0 where (sd.dept_id = {} or find_in_set( {} , sd.ancestors )) and sd.del_flag = 0 ) ",
-//                            dataColumn.alias(), dataColumn.name(), dataColumn.userid(), user.getDeptId(), user.getDeptId()));
-//                }
-//            } else if (DataScopeType.DATA_SCOPE_SELF.equals(dataScope)) {
-//                if(type.equals("1")){
-//                    if (StringUtils.isNotBlank(controllerDataScope.userAlias())) {
-//                        sqlString.append(StringUtils.format(" OR {}.user_id = {} ", controllerDataScope.userAlias(), user.getUserId()));
-//                    } else {
-//                        // 数据权限为仅本人且没有userAlias别名不查询任何数据
-//                        sqlString.append(" OR 1=0 ");
-//                    }
-//                }else {
-//                    DataColumn dataColumn = controllerDataScope.value()[0];
-//                    sqlString.append(StringUtils.format(" or {}.{} in ( select {} from sys_user where user_id = {} and del_flag = 0 ) ",
-//                            dataColumn.alias(), dataColumn.name(), dataColumn.userid(), user.getUserId()));
-//                }
-//            }
-//        }
-//
-//        if (StringUtils.isNotBlank(sqlString.toString()) && joinPoint.getArgs().length > 0) {
-//            Object params = joinPoint.getArgs()[0];
-//            if (StringUtils.isNotNull(params) && params instanceof BaseEntity) {
-//                BaseEntity baseEntity = (BaseEntity) params;
-//                baseEntity.getParams().put(DATA_SCOPE, " (" + sqlString.substring(4) + ")");
-//            }
-//        }
-//    }
-
-
     /**
      * 数据范围过滤(员工绑定数据权限)
      *
@@ -133,87 +63,22 @@ public class DataScopeAspect {
 
         if(null != user){
             DataScopeType type = DataScopeType.of(String.valueOf(user.getDataScope()));
-
+            log.error("DataScopeType"+type);
             switch (type){
                 case DATA_SCOPE_ALL:
-                    sqlString = new StringBuilder();
+                    sqlString=new StringBuilder();
                     return;
                 case DATA_SCOPE_CUSTOM:
-                    if(type.equals("1")){
-                        sqlString.append(StringUtils.format(
-                                " OR {}.dept_id IN ( SELECT dept_id FROM sys_user_manage_scop WHERE user_id = {} ) ", controllerDataScope.deptAlias(),
-                                user.getUserId()));
-                    }else {
-                        if(ArrayUtil.isNotEmpty(controllerDataScope.value())){
-                            DataColumn dataColumn = controllerDataScope.value()[0];
-                            sqlString.append(StringUtils.format(
-                                    " or {}.{} in ( select distinct sud.{} from sys_user_manage_scop srd inner join sys_user_dept sud on srd.dept_id= sud.dept_id and sud.del_flag = 0  where srd.user_id = {} )",
-                                    dataColumn.alias(), dataColumn.name(),dataColumn.userid(), user.getUserId()));
-                        }
-
-                    }
+                    sqlString.append( DataScopeSqlUtils.setWhereForSysUser(controllerDataScope,user));
                     break;
                 case DATA_SCOPE_DEPT:
-                    if(type.equals("1")){
-                        sqlString.append(StringUtils.format(" OR {}.dept_id = {} ", controllerDataScope.deptAlias(), user.getDeptId()));
-                    }else {
-
-
-                        if(StringUtils.isNotEmpty(user.getDeptIds())){
-                            if(ArrayUtil.isNotEmpty(controllerDataScope.value())){
-                                DataColumn dataColumn = controllerDataScope.value()[0];
-                                sqlString.append(StringUtils.format(" or {}.{} in (  SELECT {} from sys_user_dept where dept_id in ({}) ) ",
-                                        dataColumn.alias(), dataColumn.name(),dataColumn.userid(),user.getDeptIds()));
-                            }
-
-
-                        }else{
-                            if(user.getDeptId() != null){
-                                if(ArrayUtil.isNotEmpty(controllerDataScope.value())){
-                                    DataColumn dataColumn = controllerDataScope.value()[0];
-                                    sqlString.append(StringUtils.format(" or {}.{} in ( SELECT {} from sys_user_dept where dept_id in ({}) ) ",
-                                            dataColumn.alias(), dataColumn.name(),dataColumn.userid(),user.getDeptId()));
-                                }
-
-                            }
-                        }
-
-
-                    }
+                    sqlString.append(DataScopeSqlUtils.setWhereForDept(controllerDataScope, user));
                     break;
                 case DATA_SCOPE_DEPT_AND_CHILD:
-                    if(type.equals("1")){
-                        sqlString.append(StringUtils.format(
-                                " OR {}.dept_id IN ( SELECT dept_id FROM sys_dept WHERE dept_id = {} or find_in_set( {} , ancestors ) )",
-                                controllerDataScope.deptAlias(), user.getDeptId(), user.getDeptId()));
-                    }else {
-                        if(ArrayUtil.isNotEmpty(controllerDataScope.value())){
-
-                            DataColumn dataColumn = controllerDataScope.value()[0];
-                            sqlString.append(StringUtils.format(
-                                    " or {}.{} in ( select distinct sud.{} from sys_dept sd inner join sys_user_dept sud on sd.dept_id = sud.dept_id and sud.del_flag = 0 where (sd.dept_id = {} or find_in_set( {} , sd.ancestors )) and sd.del_flag = 0 ) ",
-                                    dataColumn.alias(), dataColumn.name(), dataColumn.userid(), user.getDeptId(), user.getDeptId()));
-                        }
-
-                    }
+                    sqlString.append(DataScopeSqlUtils.setWhereForDeptAndChild(controllerDataScope, user));
                     break;
                 case DATA_SCOPE_SELF:
-                    if(type.equals("1")){
-                        if (StringUtils.isNotBlank(controllerDataScope.userAlias())) {
-                            sqlString.append(StringUtils.format(" OR {}.user_id = {} ", controllerDataScope.userAlias(), user.getUserId()));
-                        } else {
-                            // 数据权限为仅本人且没有userAlias别名不查询任何数据
-                            sqlString.append(" OR 1=0 ");
-                        }
-                    }else {
-
-                        if(ArrayUtil.isNotEmpty(controllerDataScope.value())){
-                            DataColumn dataColumn = controllerDataScope.value()[0];
-                            sqlString.append(StringUtils.format(" or {}.{} in ( select {} from sys_user where user_id = {} and del_flag = 0 ) ",
-                                    dataColumn.alias(), dataColumn.name(), dataColumn.userid(), user.getUserId()));
-                        }
-
-                    }
+                    sqlString.append(DataScopeSqlUtils.setWhereForSelf(controllerDataScope, user));
                     break;
                 default:
                     break;

+ 32 - 0
linkwe-common/src/main/java/com/linkwechat/common/config/LinkWeChatConfig.java

@@ -64,6 +64,10 @@ public class LinkWeChatConfig {
     private String seasRedirectUrl;
 
 
+    /**
+     * 新客拉群h5地址
+     */
+    private String communityNewGroupUrl;
 
     /**
      * 老客标签建群地址
@@ -258,6 +262,34 @@ public class LinkWeChatConfig {
 
     private FincaceProxyConfig fincaceProxyConfig;
 
+    /**
+     * 混元大模型秘钥ID
+     */
+    private String txAiSecretId;
+    /**
+     * 混元大模型秘钥
+     */
+    private String txAiSecretKey;
+
+    /**
+     * 混元大模型地区
+     */
+    private String txAiRegion;
+    /**
+     * 活码短链域名
+     */
+    private String qrShortLinkDomainName;
+
+    /**
+     * 群活码短链域名
+     */
+    private String qrGroupShortLinkDomainName;
+
+
+    /**
+     * 关键词群h5链接
+     */
+    private String keyWordGroupUrl;
 
     public String getName() {
         return name;

+ 19 - 0
linkwe-common/src/main/java/com/linkwechat/common/config/mybatis/BatchSqlInjector.java

@@ -0,0 +1,19 @@
+package com.linkwechat.common.config.mybatis;
+
+
+import com.baomidou.mybatisplus.core.injector.AbstractMethod;
+import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
+import com.baomidou.mybatisplus.extension.injector.methods.InsertBatchSomeColumn;
+
+import java.util.List;
+
+
+public class BatchSqlInjector extends DefaultSqlInjector {
+    @Override
+    public List<AbstractMethod> getMethodList(Class<?> mapperClass) {
+        List<AbstractMethod> methodList = super.getMethodList(mapperClass);
+        methodList.add(new InsertBatchSomeColumn()); //添加InsertBatchSomeColumn方法
+        return methodList;
+    }
+
+}

+ 6 - 22
linkwe-common/src/main/java/com/linkwechat/common/config/mybatis/DataScopeHandler.java

@@ -14,66 +14,50 @@ public interface DataScopeHandler {
     /**
      * 全部数据权限
      *
-     * @param plainSelect
      * @param dataScope   数据范围注解
      * @param sysUser
      * @throws JSQLParserException SQL解析异常
      */
-    default void setWhereForAll(PlainSelect plainSelect, DataScope dataScope, SysUser sysUser){
+    default void setWhereForAll(DataScope dataScope, SysUser sysUser){
         // do nothing
     }
 
-    /**
-     * 自定数据权限(角色绑定部门)
-     *
-     * @param plainSelect
-     * @param dataScope   数据范围注解
-     * @param sysUser
-     * @param roleId
-     * @throws JSQLParserException SQL解析异常
-     */
-    String setWhereForCustom(PlainSelect plainSelect, DataScope dataScope, SysUser sysUser, Long roleId); /*{
-        throw new UnsupportedOperationException("暂不支持的数据权限类型");
-    }*/
+
 
 
     /**
      * 自定数据权限(员工绑定部门)
      *
-     * @param plainSelect
      * @param dataScope   数据范围注解
      * @param sysUser
      * @throws JSQLParserException SQL解析异常
      */
-    String setWhereForSysUser(PlainSelect plainSelect, DataScope dataScope, SysUser sysUser);
+    String setWhereForSysUser(DataScope dataScope, SysUser sysUser);
 
     /**
      * 部门数据权限
      *
-     * @param plainSelect
      * @param dataScope   数据范围注解
      * @param sysUser
      * @throws JSQLParserException SQL解析异常
      */
-    String setWhereForDept(PlainSelect plainSelect, DataScope dataScope, SysUser sysUser);
+    String setWhereForDept(DataScope dataScope, SysUser sysUser);
 
     /**
      * 部门及以下数据权限
      *
-     * @param plainSelect
      * @param dataScope   数据范围注解
      * @param sysUser
      * @throws JSQLParserException SQL解析异常
      */
-    String setWhereForDeptAndChild(PlainSelect plainSelect, DataScope dataScope, SysUser sysUser);
+    String setWhereForDeptAndChild(DataScope dataScope, SysUser sysUser);
 
     /**
      * 仅本人数据权限
      *
-     * @param plainSelect
      * @param dataScope   数据范围注解
      * @param sysUser
      * @throws JSQLParserException SQL解析异常
      */
-    String setWhereForSelf(PlainSelect plainSelect, DataScope dataScope, SysUser sysUser);
+    String setWhereForSelf(DataScope dataScope, SysUser sysUser);
 }

+ 9 - 53
linkwe-common/src/main/java/com/linkwechat/common/config/mybatis/DataScopeInterceptor.java

@@ -122,52 +122,6 @@ public class DataScopeInterceptor extends JsqlParserSupport implements InnerInte
         }
     }
 
-    /**
-     * 处理 PlainSelect(数据权限与角色绑定)
-     */
-    protected void processPlainSelect(PlainSelect plainSelect, DataScope dataScope) {
-        LoginUser loginUser = SecurityUtils.getLoginUser();
-        if (dataScope == null || loginUser ==null) {
-            return;
-        }
-
-        SysUser sysUser = loginUser.getSysUser();
-        List<SysRole> sysRoles = sysUser.getRoles();
-
-        StringBuilder sqlString = new StringBuilder();
-        for (SysRole sysRole : sysRoles) {
-            DataScopeType type = DataScopeType.of(sysRole.getDataScope());
-            switch (type) {
-                case DATA_SCOPE_ALL:
-                    pearlDataScopeHandler.setWhereForAll(plainSelect, dataScope, sysUser);
-                    return;
-                case DATA_SCOPE_CUSTOM:
-                    sqlString.append(pearlDataScopeHandler.setWhereForCustom(plainSelect, dataScope, sysUser, sysRole.getRoleId()));
-                    break;
-                case DATA_SCOPE_DEPT:
-                    sqlString.append(pearlDataScopeHandler.setWhereForDept(plainSelect, dataScope, sysUser));
-                    break;
-                case DATA_SCOPE_DEPT_AND_CHILD:
-                    sqlString.append(pearlDataScopeHandler.setWhereForDeptAndChild(plainSelect, dataScope, sysUser));
-                    break;
-                case DATA_SCOPE_SELF:
-                    sqlString.append(pearlDataScopeHandler.setWhereForSelf(plainSelect, dataScope, sysUser));
-                    break;
-                default:
-                    break;
-            }
-        }
-        try {
-            if(StringUtils.isNotEmpty(sqlString)){
-                Expression expression = CCJSqlParserUtil.parseCondExpression(" (" + sqlString.substring(4) + ")");
-                pearlDataScopeHandler.setWhere(plainSelect,expression);
-            }
-        } catch (JSQLParserException e) {
-            log.error("Failed to process, Error SQL:"+e);
-            throw ExceptionUtils.mpe("Failed to process, Error SQL: %s", e);
-        }
-
-    }
 
     /**
      * 处理 PlainSelect(数据权限与用户绑定)
@@ -179,27 +133,29 @@ public class DataScopeInterceptor extends JsqlParserSupport implements InnerInte
         }
 
         SysUser sysUser = loginUser.getSysUser();
+
+
+
         StringBuilder sqlString = new StringBuilder();
 
         if(null != sysUser){
             DataScopeType type = DataScopeType.of(String.valueOf(sysUser.getDataScope()));
 
-
             switch (type){
-                 case DATA_SCOPE_ALL:
-                    pearlDataScopeHandler.setWhereForAll(plainSelect, dataScope, sysUser);
+                case DATA_SCOPE_ALL:
+                    pearlDataScopeHandler.setWhereForAll(dataScope, sysUser);
                     return;
                 case DATA_SCOPE_CUSTOM:
-                    sqlString.append(pearlDataScopeHandler.setWhereForSysUser(plainSelect, dataScope, sysUser));
+                    sqlString.append(pearlDataScopeHandler.setWhereForSysUser(dataScope, sysUser));
                     break;
                 case DATA_SCOPE_DEPT:
-                    sqlString.append(pearlDataScopeHandler.setWhereForDept(plainSelect, dataScope, sysUser));
+                    sqlString.append(pearlDataScopeHandler.setWhereForDept(dataScope, sysUser));
                     break;
                 case DATA_SCOPE_DEPT_AND_CHILD:
-                    sqlString.append(pearlDataScopeHandler.setWhereForDeptAndChild(plainSelect, dataScope, sysUser));
+                    sqlString.append(pearlDataScopeHandler.setWhereForDeptAndChild(dataScope, sysUser));
                     break;
                 case DATA_SCOPE_SELF:
-                    sqlString.append(pearlDataScopeHandler.setWhereForSelf(plainSelect, dataScope, sysUser));
+                    sqlString.append(pearlDataScopeHandler.setWhereForSelf(dataScope, sysUser));
                     break;
                 default:
                     break;

+ 17 - 0
linkwe-common/src/main/java/com/linkwechat/common/config/mybatis/LwBaseMapper.java

@@ -0,0 +1,17 @@
+package com.linkwechat.common.config.mybatis;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+import java.util.Collection;
+
+public interface LwBaseMapper<T> extends BaseMapper<T> {
+    /**
+     * 批量插入 仅适用于mysql
+     *
+     * @param entityList 实体列表
+     * @return 影响行数
+     */
+    Integer insertBatchSomeColumn(Collection<T> entityList);
+
+
+}

+ 6 - 1
linkwe-common/src/main/java/com/linkwechat/common/config/mybatis/MybatisPlusConfig.java

@@ -26,7 +26,12 @@ public class MybatisPlusConfig {
         return interceptor;
     }
 
-    //pagehelper 分页配置
+    @Bean
+    public BatchSqlInjector easySqlInjector () {
+        return new BatchSqlInjector();
+    }
+
+        //pagehelper 分页配置
     @Bean
     public ConfigurationCustomizer mybatisConfigurationCustomizer() {
         return new ConfigurationCustomizer() {

+ 4 - 10
linkwe-common/src/main/java/com/linkwechat/common/config/mybatis/PearlDataScopeHandler.java

@@ -15,17 +15,11 @@ import net.sf.jsqlparser.statement.select.PlainSelect;
  **/
 public class PearlDataScopeHandler implements DataScopeHandler {
 
-    @Override
-    public String setWhereForCustom(PlainSelect plainSelect, DataScope dataScope, SysUser sysUser, Long roleId) {
-
-       return DataScopeSqlUtils.setWhereForRole(dataScope,roleId);
-    }
-
 
 
 
     @Override
-    public String setWhereForSysUser(PlainSelect plainSelect, DataScope dataScope, SysUser sysUser){
+    public String setWhereForSysUser(DataScope dataScope, SysUser sysUser){
 
 
         return DataScopeSqlUtils.setWhereForSysUser(dataScope,sysUser);
@@ -33,20 +27,20 @@ public class PearlDataScopeHandler implements DataScopeHandler {
     }
 
     @Override
-    public String setWhereForDept(PlainSelect plainSelect, DataScope dataScope, SysUser sysUser) {
+    public String setWhereForDept(DataScope dataScope, SysUser sysUser) {
 
 
         return DataScopeSqlUtils.setWhereForDept(dataScope, sysUser);
     }
 
     @Override
-    public String setWhereForDeptAndChild(PlainSelect plainSelect, DataScope dataScope, SysUser sysUser) {
+    public String setWhereForDeptAndChild(DataScope dataScope, SysUser sysUser) {
 
         return DataScopeSqlUtils.setWhereForDeptAndChild(dataScope, sysUser);
     }
 
     @Override
-    public String setWhereForSelf(PlainSelect plainSelect, DataScope dataScope, SysUser sysUser) {
+    public String setWhereForSelf(DataScope dataScope, SysUser sysUser) {
 
         return DataScopeSqlUtils.setWhereForSelf(dataScope, sysUser);
     }

+ 16 - 0
linkwe-common/src/main/java/com/linkwechat/common/config/mybatis/WeBaseMapper.java

@@ -0,0 +1,16 @@
+package com.linkwechat.common.config.mybatis;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+import java.util.Collection;
+
+public interface WeBaseMapper <T> extends BaseMapper<T> {
+    /**
+     * 批量插入 仅适用于mysql
+     *
+     * @param entityList 实体列表
+     * @return 影响行数
+     */
+    Integer insertBatchSomeColumn(Collection<T> entityList);
+
+}

+ 2 - 1
linkwe-common/src/main/java/com/linkwechat/common/constant/SecurityConstants.java

@@ -49,7 +49,8 @@ public class SecurityConstants {
     /**公众号密钥*/
     public static final String WE_APP_SECRET="weAppSecret";
 
-
+    /**Feign请求标识*/
+    public static final String IS_FEGIN="isFeign";
 
 
     /** 授权字段 */

+ 6 - 0
linkwe-common/src/main/java/com/linkwechat/common/constant/SynchRecordConstants.java

@@ -51,5 +51,11 @@ public class SynchRecordConstants {
      * 离职分配
      */
     public static final int SYNCH_LEAVE_USER = 9;
+
+
+    /**
+     * 商品图册订单
+     */
+    public static final int SYNCH_SPTC_ORDER=10;
 }
 

+ 29 - 0
linkwe-common/src/main/java/com/linkwechat/common/constant/WeComeStateContants.java

@@ -9,4 +9,33 @@ public class WeComeStateContants {
      * 群活码渠道标识前缀
      */
     public final static String QHM_STATE="qhm_";
+
+
+    /**
+     * 新客拉群渠道标识前缀
+     */
+    public final static String XKLQ_STATE="xklq_";
+
+    /**
+     * 标签建群
+     */
+    public final static String BQJQ_STATE="bqjq_";
+
+
+    /**
+     * 关键词群
+     */
+    public final static String GJCQ_STATE="gjcq_";
+
+
+    /**
+     * 门店活码导购渠道标识
+     */
+    public final static String MDDG_STATE="mddg_";
+
+
+    /**
+     * 门店群码渠道标识
+     */
+    public final static String MDQM_STATE="mdqm_";
 }

+ 3 - 0
linkwe-common/src/main/java/com/linkwechat/common/constant/WeConstans.java

@@ -217,6 +217,9 @@ public class WeConstans {
     //短链统计缓存key值前缀
     public static final String  WE_SHORT_LINK_KEY = "we_short_link:statistics:";
 
+    //通用短链统计缓存key前缀
+    public static final String WE_SHORT_LINK_COMMON_KEY = "we_short_link:common:statistics:";
+
     /**
      * 短链缓存命名空间
      */

+ 58 - 0
linkwe-common/src/main/java/com/linkwechat/common/constant/WeServerNameConstants.java

@@ -0,0 +1,58 @@
+package com.linkwechat.common.constant;
+
+/**
+ * 系统服务名称
+ */
+public class WeServerNameConstants {
+
+    /**
+     * linkwe-ai服务名称
+     */
+    public static String linkweAi="linkwe-ai";
+
+    /**
+     * linkwe-api服务名称
+     */
+    public static String linkweApi="linkwe-api";
+
+    /**
+     * linkwe-auth服务名称
+     */
+    public static String linkweAuth="linkwe-auth";
+
+
+    /**
+     * linkwe-event-task服务名称
+     */
+    public static String linkweEventTask="linkwe-event-task";
+
+
+    /**
+     * linkwe-file服务名称
+     */
+    public static String linkweFile="linkwe-file";
+
+
+    /**
+     * linkwe-gateway服务名称
+     */
+    public static String linkweGateway="linkwe-gateway";
+
+
+    /**
+     * linkwe-scheduler服务名称
+     */
+    public static String linkweScheduler="linkwe-scheduler";
+
+
+    /**
+     * linkwe-wecom服务名称
+     */
+    public static String linkweWecom="linkwe-wecom";
+
+
+    /**
+     * linkwe-wx-api服务名称
+     */
+    public static String linkweWxApi="linkwe-wx-api";
+}

+ 54 - 0
linkwe-common/src/main/java/com/linkwechat/common/core/controller/BaseController.java

@@ -54,6 +54,23 @@ public class BaseController {
         }
     }
 
+    protected void startPage(Integer pageNum, Integer pageSize) {
+        if (StringUtils.isNotNull(pageNum) && StringUtils.isNotNull(pageSize)) {
+            startPage(pageNum,pageSize,"","");
+        }
+    }
+
+    protected void startPage(Integer pageNum, Integer pageSize, String orderByColumn, String isAsc) {
+        if (StringUtils.isNotNull(pageNum) && StringUtils.isNotNull(pageSize)) {
+            String orderBy = "";
+            if (StringUtils.isNotEmpty(orderByColumn))
+            {
+                orderBy = SqlUtil.escapeOrderBySql(StringUtils.toUnderScoreCase(orderByColumn) + " " + (StringUtils.isEmpty(isAsc)?"asc":isAsc));
+            }
+            PageHelper.startPage(pageNum, pageSize, orderBy);
+        }
+    }
+
     /**
      * 响应请求分页数据
      */
@@ -96,4 +113,41 @@ public class BaseController {
     public String redirect(String url) {
         return StringUtils.format("redirect:{}", url);
     }
+
+    /**
+     * 开始分页
+     * @param list
+     * @param pageNum 页码
+     * @param pageSize 每页多少条数据
+     * @return
+     */
+    public static List startPage(List list, Integer pageNum,
+                                 Integer pageSize) {
+        if (list == null || list.size() == 0) {
+            return null;
+        }
+        int count = list.size(); // 记录总数
+        int pageCount = 0; // 页数
+        if (count % pageSize == 0) {
+            pageCount = count / pageSize;
+        } else {
+            pageCount = count / pageSize + 1;
+        }
+        if (pageNum > pageCount) {
+            pageNum = pageCount;
+        }
+
+        int fromIndex = 0; // 开始索引
+        int toIndex = 0; // 结束索引
+
+        if (pageNum != pageCount) {
+            fromIndex = (pageNum - 1) * pageSize;
+            toIndex = fromIndex + pageSize;
+        } else {
+            fromIndex = (pageNum - 1) * pageSize;
+            toIndex = count;
+        }
+
+        return list.subList(fromIndex, toIndex);
+    }
 }

+ 3 - 0
linkwe-common/src/main/java/com/linkwechat/common/core/domain/model/LoginUser.java

@@ -65,6 +65,9 @@ public class LoginUser implements Serializable
     /**朋友圈同步需要的字段*/
     private Integer filterType;
 
+    /**业务id,多个使用逗号隔开**/
+    private String businessIds;
+
     /**企业微信员工id集合*/
     private List<String> weUserIds;
 

+ 2 - 1
linkwe-common/src/main/java/com/linkwechat/common/core/page/TableSupport.java

@@ -36,7 +36,8 @@ public class TableSupport
     {
         PageDomain pageDomain = new PageDomain();
         pageDomain.setPageNum(ServletUtils.getParameterToInt(PAGE_NUM));
-        pageDomain.setPageSize(ServletUtils.getParameterToInt(PAGE_SIZE));
+        Integer parameterToInt = ServletUtils.getParameterToInt(PAGE_SIZE);
+        pageDomain.setPageSize(parameterToInt == null?10:ServletUtils.getParameterToInt(PAGE_SIZE));
         pageDomain.setOrderByColumn(ServletUtils.getParameter(ORDER_BY_COLUMN));
         pageDomain.setIsAsc(ServletUtils.getParameter(IS_ASC));
         return pageDomain;

+ 11 - 5
linkwe-common/src/main/java/com/linkwechat/common/core/redis/RedisService.java

@@ -1,10 +1,7 @@
 package com.linkwechat.common.core.redis;
 
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.data.redis.core.HashOperations;
-import org.springframework.data.redis.core.RedisTemplate;
-import org.springframework.data.redis.core.ValueOperations;
-import org.springframework.data.redis.core.ZSetOperations;
+import org.springframework.data.redis.core.*;
 import org.springframework.data.redis.core.script.DefaultRedisScript;
 import org.springframework.data.redis.core.script.RedisScript;
 import org.springframework.stereotype.Component;
@@ -216,7 +213,16 @@ public class RedisService {
      * @return 对象列表
      */
     public Collection<String> keys(final String pattern) {
-        return redisTemplate.keys(pattern);
+        List<String> keys = new ArrayList<>(); // 修改为List<String>
+        Cursor<byte[]> cursor = redisTemplate.getConnectionFactory()
+                .getConnection()
+                .scan(ScanOptions.scanOptions().match(pattern).count(1000).build());
+
+        while (cursor.hasNext()) {
+            keys.add(new String(cursor.next())); // 将byte[]转换为String并添加到keys列表中
+        }
+
+        return keys; // 返回Collection<String>类型的结果
     }
 
 

+ 56 - 0
linkwe-common/src/main/java/com/linkwechat/common/enums/CategoryMediaGroupType.java

@@ -0,0 +1,56 @@
+package com.linkwechat.common.enums;
+
+import cn.hutool.core.collection.ListUtil;
+import lombok.Getter;
+
+import java.util.List;
+
+@Getter
+public enum CategoryMediaGroupType {
+
+     MATERIAL_GROUP_TYPE(1,"素材中心", ListUtil.toList(
+             CategoryMediaType.IMAGE.getType(),
+             CategoryMediaType.VOICE.getType(),
+             CategoryMediaType.VIDEO.getType(),
+             CategoryMediaType.FILE.getType(),
+             CategoryMediaType.TEXT.getType(),
+             CategoryMediaType.POSTER.getType(),
+             CategoryMediaType.LIVE.getType(),
+             CategoryMediaType.CROWD.getType(),
+             CategoryMediaType.TRIP.getType(),
+             CategoryMediaType.IMAGE_TEXT.getType(),
+             CategoryMediaType.LINK.getType(),
+             CategoryMediaType.APPLET.getType(),
+             CategoryMediaType.ARTICLE.getType(),
+             CategoryMediaType.MURL.getType()
+     )),
+
+     TALK_GROUP_TYPE(2,"话术中心", ListUtil.toList(
+             CategoryMediaType.QY_TALK.getType(),
+             CategoryMediaType.KF_TALK.getType()
+     )),
+
+
+    TEMPLATE_GROUP_TYPE(3,"模板中心",ListUtil.toList(
+            CategoryMediaType.QFTLP.getType()
+    ));
+
+    private int value;
+    private String description;
+    private List<Integer> list;
+
+    CategoryMediaGroupType(int value,String description, List<Integer> list) {
+        this.value=value;
+        this.description = description;
+        this.list = list;
+    }
+
+    public static Boolean ofType(Integer materialType) {
+        for (CategoryMediaGroupType groupType : CategoryMediaGroupType.values()) {
+            if (groupType.getList().contains(materialType)) {
+                return true;
+            }
+        }
+        return false;
+    }
+}

+ 2 - 1
linkwe-common/src/main/java/com/linkwechat/common/enums/FileCosType.java

@@ -9,7 +9,8 @@ public enum FileCosType {
 
     FILE_COS_TYPE_TENANT(1,"腾讯云COS"),
     FILE_COS_TYPE_ALI(2,"阿里云OSS"),
-    FILE_COS_TYPE_QN(3,"七牛云Kodo");
+    FILE_COS_TYPE_QN(3,"七牛云Kodo"),
+    FILE_COS_TYPE_MINIO(4,"minio存储");
 
     private Integer type;
 

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно