Quellcode durchsuchen

微信公众号对接

亚洲 vor 2 Jahren
Ursprung
Commit
1d935f58f8
65 geänderte Dateien mit 12521 neuen und 9637 gelöschten Zeilen
  1. 1 0
      pom.xml
  2. 245 0
      sql/mysql/ruoyi-vue-pro.sql
  3. 7 0
      yudao-dependencies/pom.xml
  4. 1 1
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/SmsCallbackController.java
  5. 24 0
      yudao-module-wechat-mp/pom.xml
  6. 26 0
      yudao-module-wechat-mp/yudao-module-wechat-mp-api/pom.xml
  7. 16 0
      yudao-module-wechat-mp/yudao-module-wechat-mp-api/src/main/java/cn/iocoder/yudao/module/wechatMp/enums/ErrorCodeConstants.java
  8. 77 0
      yudao-module-wechat-mp/yudao-module-wechat-mp-biz/pom.xml
  9. 14 0
      yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/builder/AbstractBuilder.java
  10. 21 0
      yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/builder/ImageBuilder.java
  11. 19 0
      yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/builder/TextBuilder.java
  12. 137 0
      yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/config/WxMpConfig.java
  13. 103 0
      yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/controller/admin/account/WxAccountController.java
  14. 36 0
      yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/controller/admin/account/vo/WxAccountBaseVO.java
  15. 14 0
      yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/controller/admin/account/vo/WxAccountCreateReqVO.java
  16. 50 0
      yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/controller/admin/account/vo/WxAccountExcelVO.java
  17. 32 0
      yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/controller/admin/account/vo/WxAccountExportReqVO.java
  18. 34 0
      yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/controller/admin/account/vo/WxAccountPageReqVO.java
  19. 25 0
      yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/controller/admin/account/vo/WxAccountRespVO.java
  20. 18 0
      yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/controller/admin/account/vo/WxAccountUpdateReqVO.java
  21. 100 0
      yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/controller/admin/accountfans/WxAccountFansController.java
  22. 58 0
      yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/controller/admin/accountfans/vo/WxAccountFansBaseVO.java
  23. 14 0
      yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/controller/admin/accountfans/vo/WxAccountFansCreateReqVO.java
  24. 62 0
      yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/controller/admin/accountfans/vo/WxAccountFansExcelVO.java
  25. 67 0
      yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/controller/admin/accountfans/vo/WxAccountFansExportReqVO.java
  26. 69 0
      yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/controller/admin/accountfans/vo/WxAccountFansPageReqVO.java
  27. 19 0
      yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/controller/admin/accountfans/vo/WxAccountFansRespVO.java
  28. 18 0
      yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/controller/admin/accountfans/vo/WxAccountFansUpdateReqVO.java
  29. 34 0
      yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/convert/account/WxAccountConvert.java
  30. 34 0
      yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/convert/accountfans/WxAccountFansConvert.java
  31. 65 0
      yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/dal/dataobject/account/WxAccountDO.java
  32. 81 0
      yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/dal/dataobject/accountfans/WxAccountFansDO.java
  33. 38 0
      yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/dal/mysql/account/WxAccountMapper.java
  34. 58 0
      yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/dal/mysql/accountfans/WxAccountFansMapper.java
  35. 23 0
      yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/handler/KfSessionHandler.java
  36. 44 0
      yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/handler/LocationHandler.java
  37. 25 0
      yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/handler/LogHandler.java
  38. 32 0
      yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/handler/MenuHandler.java
  39. 184 0
      yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/handler/MsgHandler.java
  40. 22 0
      yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/handler/NullHandler.java
  41. 22 0
      yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/handler/ScanHandler.java
  42. 27 0
      yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/handler/StoreCheckNotifyHandler.java
  43. 164 0
      yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/handler/SubscribeHandler.java
  44. 54 0
      yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/handler/UnsubscribeHandler.java
  45. 29 0
      yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/mq/costomer/dict/WxConfigDataRefreshConsumer.java
  46. 19 0
      yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/mq/message/dict/WxConfigDataRefreshMessage.java
  47. 26 0
      yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/mq/producer/dict/WxMpConfigDataProducer.java
  48. 80 0
      yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/service/account/WxAccountService.java
  49. 97 0
      yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/service/account/WxAccountServiceImpl.java
  50. 81 0
      yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/service/accountfans/WxAccountFansService.java
  51. 90 0
      yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/service/accountfans/WxAccountFansServiceImpl.java
  52. 7 0
      yudao-server/pom.xml
  53. 1 1
      yudao-server/src/main/resources/admin-ui/libs/monaco-editor/vs/language/html/htmlMode.js
  54. 1 1
      yudao-server/src/main/resources/admin-ui/libs/monaco-editor/vs/language/html/htmlWorker.js
  55. 1 1
      yudao-server/src/main/resources/admin-ui/libs/monaco-editor/vs/language/typescript/tsWorker.js
  56. 5 5
      yudao-server/src/main/resources/admin-ui/static/js/4.js
  57. 3 3
      yudao-server/src/main/resources/admin-ui/static/js/chunk-vendors.js
  58. 1 1
      yudao-ui-admin/public/libs/monaco-editor/vs/language/html/htmlMode.js
  59. 1 1
      yudao-ui-admin/public/libs/monaco-editor/vs/language/html/htmlWorker.js
  60. 1 1
      yudao-ui-admin/public/libs/monaco-editor/vs/language/typescript/tsWorker.js
  61. 54 0
      yudao-ui-admin/src/api/wechatMp/wxAccount.js
  62. 54 0
      yudao-ui-admin/src/api/wechatMp/wxAccountFans.js
  63. 254 0
      yudao-ui-admin/src/views/wechatMp/wxAccount/index.vue
  64. 334 0
      yudao-ui-admin/src/views/wechatMp/wxAccountFans/index.vue
  65. 9168 9622
      yudao-ui-admin/yarn.lock

+ 1 - 0
pom.xml

@@ -18,6 +18,7 @@
         <module>yudao-module-system</module>
         <module>yudao-module-infra</module>
         <module>yudao-module-pay</module>
+        <module>yudao-module-wechat-mp</module>
     </modules>
 
     <name>${project.artifactId}</name>

+ 245 - 0
sql/mysql/ruoyi-vue-pro.sql

@@ -2647,3 +2647,248 @@ INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`,
 COMMIT;
 
 SET FOREIGN_KEY_CHECKS = 1;
+
+
+-- 公众号
+DROP TABLE IF EXISTS `wx_account`;
+CREATE TABLE `wx_account`  (
+  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',
+  `name` varchar(100) DEFAULT NULL COMMENT '公众号名称',
+  `account` varchar(100) DEFAULT NULL COMMENT '公众号账户',
+  `appid` varchar(100) DEFAULT NULL COMMENT '公众号appid',
+  `appsecret` varchar(100) DEFAULT NULL COMMENT '公众号密钥',
+  `url` varchar(100) DEFAULT NULL COMMENT '公众号url',
+  `token` varchar(100) DEFAULT NULL COMMENT '公众号token',
+  `aeskey` varchar(300) DEFAULT NULL COMMENT '加密密钥',
+  `qr_url` varchar(200) DEFAULT NULL COMMENT '二维码图片URL',
+  `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '备注',
+  `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
+  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
+  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+  `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
+  `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '公众号账户表';
+
+DROP TABLE IF EXISTS `wx_account_fans`;
+CREATE TABLE `wx_account_fans`  (
+  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',
+  `openid` varchar(100) DEFAULT NULL COMMENT '用户标识',
+  `subscribe_status` char(1) DEFAULT NULL COMMENT '订阅状态,0未关注,1已关注',
+  `subscribe_time` datetime DEFAULT NULL COMMENT '订阅时间',
+  `nickname` varbinary(2000) DEFAULT NULL COMMENT '昵称',
+  `gender` varchar(10) DEFAULT NULL COMMENT '性别,1男,2女,0未知',
+  `language` varchar(30) DEFAULT NULL COMMENT '语言',
+  `country` varchar(30) DEFAULT NULL COMMENT '国家',
+  `province` varchar(30) DEFAULT NULL COMMENT '省份',
+  `city` varchar(30) DEFAULT NULL COMMENT '城市',
+  `headimg_url` varchar(500) DEFAULT NULL COMMENT '头像地址',
+  `remark` varchar(500) DEFAULT NULL COMMENT '备注',
+  `wx_account_id` varchar(32) DEFAULT NULL COMMENT '微信公众号ID',
+  `wx_account_appid` varchar(100) DEFAULT NULL COMMENT '微信公众号appid',
+  `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
+  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
+  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+  `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
+  `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '微信公众号粉丝表';
+
+    DROP TABLE IF EXISTS `wx_account_fans_tag`;
+    CREATE TABLE `wx_account_fans_tag` (
+            `id` int(10) NOT NULL AUTO_INCREMENT COMMENT '主键',
+            `openid` varchar(100) DEFAULT NULL COMMENT '用户标识',
+            `tag_id` varchar(32) DEFAULT NULL COMMENT '标签ID',
+            `wx_account_id` varchar(32) DEFAULT NULL COMMENT '微信账号ID',
+            `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
+            `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+            `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
+            `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+            `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
+            `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
+    PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='粉丝标签关联表';
+
+    DROP TABLE IF EXISTS `wx_fans_msg`;
+    CREATE TABLE `wx_fans_msg` (
+            `id` int(10) NOT NULL AUTO_INCREMENT COMMENT '主键',
+            `openid` varchar(100) DEFAULT NULL COMMENT '用户标识',
+            `nickname` varbinary(2000) DEFAULT NULL COMMENT '昵称',
+            `headimg_url` varchar(500) DEFAULT NULL COMMENT '头像地址',
+            `wx_account_id` varchar(32) DEFAULT NULL COMMENT '微信账号ID',
+            `msg_type` varchar(32) DEFAULT NULL COMMENT '消息类型',
+            `content` varchar(500) DEFAULT NULL COMMENT '内容',
+            `res_content` text COMMENT '最近一条回复内容',
+            `is_res` varchar(32) DEFAULT NULL COMMENT '是否已回复',
+            `media_id` varchar(100) DEFAULT NULL COMMENT '微信素材ID',
+            `pic_url` varchar(500) DEFAULT NULL COMMENT '微信图片URL',
+            `pic_path` varchar(500) DEFAULT NULL COMMENT '本地图片路径',
+            `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
+            `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+            `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
+            `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+            `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
+            `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
+    PRIMARY KEY (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=30 DEFAULT CHARSET=utf8 COMMENT='粉丝消息表 ';
+
+    DROP TABLE IF EXISTS `wx_fans_msg_res`;
+    CREATE TABLE `wx_fans_msg_res` (
+            `id` int(10) NOT NULL AUTO_INCREMENT COMMENT '主键',
+            `fans_msg_id` varchar(32) DEFAULT NULL COMMENT '粉丝消息ID',
+            `res_content` text COMMENT '回复内容',
+            `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
+            `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+            `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
+            `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+            `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
+            `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
+    PRIMARY KEY (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8 COMMENT='回复粉丝消息历史表 ';
+
+
+    DROP TABLE IF EXISTS `wx_fans_tag`;
+    CREATE TABLE `wx_fans_tag` (
+            `id` int(10) NOT NULL AUTO_INCREMENT COMMENT '主键',
+            `name` varchar(32) DEFAULT NULL COMMENT '标签名称',
+            `count` int(11) DEFAULT NULL COMMENT '粉丝数量',
+            `wx_account_id` varchar(32) DEFAULT NULL COMMENT '微信账号ID',
+            `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
+            `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+            `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
+            `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+            `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
+            `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
+    PRIMARY KEY (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COMMENT='粉丝标签表';
+
+    DROP TABLE IF EXISTS `wx_media_upload`;
+    CREATE TABLE `wx_media_upload` (
+            `id` int(10) NOT NULL AUTO_INCREMENT COMMENT '主键',
+            `type` varchar(32) DEFAULT NULL COMMENT '类型',
+            `url` varchar(500) DEFAULT NULL COMMENT '图片URL',
+            `media_id` varchar(32) DEFAULT NULL COMMENT '素材ID',
+            `thumb_media_id` varchar(32) DEFAULT NULL COMMENT '缩略图素材ID',
+            `wx_account_id` varchar(32) DEFAULT NULL COMMENT '微信账号ID',
+            `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
+            `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+            `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
+            `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+            `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
+            `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
+    PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='微信素材上传表 ';
+
+    DROP TABLE IF EXISTS `wx_menu`;
+    CREATE TABLE `wx_menu` (
+            `id` int(10) NOT NULL AUTO_INCREMENT COMMENT '主键',
+            `parent_id` varchar(32) DEFAULT NULL COMMENT '父ID',
+            `menu_name` varchar(32) DEFAULT NULL COMMENT '菜单名称',
+            `menu_type` varchar(32) DEFAULT NULL COMMENT '菜单类型 1文本消息;2图文消息;3网址链接;4小程序',
+            `menu_level` varchar(32) DEFAULT NULL COMMENT '菜单等级',
+            `tpl_id` varchar(32) DEFAULT NULL COMMENT '模板ID',
+            `menu_url` varchar(255) DEFAULT NULL COMMENT '菜单URL',
+            `menu_sort` varchar(32) DEFAULT NULL COMMENT '排序',
+            `wx_account_id` varchar(32) DEFAULT NULL COMMENT '微信账号ID',
+            `miniprogram_appid` varchar(32) DEFAULT NULL COMMENT '小程序appid',
+            `miniprogram_pagepath` varchar(200) DEFAULT NULL COMMENT '小程序页面路径',
+            `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
+            `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+            `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
+            `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+            `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
+            `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
+    PRIMARY KEY (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=26 DEFAULT CHARSET=utf8 COMMENT='微信菜单表';
+
+
+    DROP TABLE IF EXISTS `wx_news_article_item`;
+    CREATE TABLE `wx_news_article_item` (
+            `id` int(10) NOT NULL AUTO_INCREMENT COMMENT '主键',
+            `title` varchar(32) DEFAULT NULL COMMENT '标题',
+            `digest` varchar(50) DEFAULT NULL COMMENT '摘要',
+            `author` varchar(32) DEFAULT NULL COMMENT '作者',
+            `show_cover_pic` char(1) DEFAULT NULL COMMENT '是否展示封面图片(0/1)',
+            `thumb_media_id` varchar(50) DEFAULT NULL COMMENT '上传微信,封面图片标识',
+            `content` text COMMENT '内容',
+            `content_source_url` varchar(50) DEFAULT NULL COMMENT '内容链接',
+            `order_no` int(11) DEFAULT NULL COMMENT '文章排序',
+            `pic_path` varchar(255) DEFAULT NULL COMMENT '图片路径',
+            `need_open_comment` varchar(32) DEFAULT NULL COMMENT '是否可以留言',
+            `only_fans_can_comment` varchar(32) DEFAULT NULL COMMENT '是否仅粉丝可以留言',
+            `news_id` varchar(32) DEFAULT NULL COMMENT '图文ID',
+            `wx_account_id` varchar(32) DEFAULT NULL COMMENT '微信账号ID',
+            `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
+            `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+            `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
+            `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+            `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
+            `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
+    PRIMARY KEY (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8 COMMENT='图文消息文章列表表 ';
+
+    DROP TABLE IF EXISTS `wx_news_template`;
+    CREATE TABLE `wx_news_template` (
+            `id` int(10) NOT NULL AUTO_INCREMENT COMMENT '主键 主键ID',
+            `tpl_name` varchar(32) DEFAULT NULL COMMENT '模板名称',
+            `is_upload` varchar(32) DEFAULT NULL COMMENT '是否已上传微信',
+            `media_id` varchar(50) DEFAULT NULL,
+  `wx_account_id` varchar(32) DEFAULT NULL COMMENT '微信账号ID',
+            `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
+            `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+            `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
+            `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+            `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
+            `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
+    PRIMARY KEY (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8 COMMENT='图文消息模板表';
+
+
+    DROP TABLE IF EXISTS `wx_receive_text`;
+    CREATE TABLE `wx_receive_text` (
+            `id` int(10) NOT NULL AUTO_INCREMENT COMMENT '主键',
+            `receive_text` varchar(32) DEFAULT NULL COMMENT '关键字',
+            `msg_type` varchar(32) DEFAULT NULL COMMENT '消息类型 1文本消息;2图文消息;',
+            `tpl_id` varchar(32) DEFAULT NULL COMMENT '模板ID',
+            `wx_account_id` varchar(32) DEFAULT NULL COMMENT '微信账号ID',
+            `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
+            `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+            `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
+            `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+            `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
+            `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
+    PRIMARY KEY (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 COMMENT='回复关键字表';
+
+
+    DROP TABLE IF EXISTS `wx_subscribe_text`;
+    CREATE TABLE `wx_subscribe_text` (
+            `id` int(10) NOT NULL AUTO_INCREMENT COMMENT '主键',
+            `msg_type` varchar(32) DEFAULT NULL COMMENT '消息类型 1文本消息;2图文消息;',
+            `tpl_id` varchar(32) DEFAULT NULL COMMENT '模板ID',
+            `wx_account_id` varchar(32) DEFAULT NULL COMMENT '微信账号ID',
+            `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
+            `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+            `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
+            `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+            `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
+            `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
+    PRIMARY KEY (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COMMENT='关注欢迎语表';
+
+
+    DROP TABLE IF EXISTS `wx_text_template`;
+    CREATE TABLE `wx_text_template` (
+            `id` int(10) NOT NULL AUTO_INCREMENT COMMENT '主键',
+            `tpl_name` varchar(32) DEFAULT NULL COMMENT '模板名字',
+            `content` varchar(255) DEFAULT NULL COMMENT '模板内容',
+            `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
+            `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+            `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
+            `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+            `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
+            `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
+    PRIMARY KEY (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 COMMENT='文本模板表';

+ 7 - 0
yudao-dependencies/pom.xml

@@ -64,6 +64,7 @@
         <tencentcloud-sdk-java.version>3.1.471</tencentcloud-sdk-java.version>
         <yunpian-java-sdk.version>1.2.7</yunpian-java-sdk.version>
         <justauth.version>1.4.0</justauth.version>
+        <weixin-java-mp.version>3.3.0</weixin-java-mp.version>
     </properties>
 
     <dependencyManagement>
@@ -567,6 +568,12 @@
                 <version>${justauth.version}</version>
             </dependency>
 
+            <dependency>
+                <groupId>com.github.binarywang</groupId>
+                <artifactId>weixin-java-mp</artifactId>
+                <version>${weixin-java-mp.version}</version>
+            </dependency>
+
         </dependencies>
     </dependencyManagement>
 

+ 1 - 1
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/SmsCallbackController.java

@@ -47,7 +47,7 @@ public class SmsCallbackController {
     }
 
     @PostMapping("/tencent")
-    @ApiOperation(value = "腾讯云短信的回调", notes = "参见 https://cloud.tencent.com/document/product/382/52077 文档")
+    @ApiOperation(value = "腾讯云短信的回调", notes = "参见 https://cloud.tencent.com/document/producer/382/52077 文档")
     @OperateLog(enable = false)
     public CommonResult<Boolean> receiveTencentSmsStatus(HttpServletRequest request) throws Throwable {
         String text = ServletUtil.getBody(request);

+ 24 - 0
yudao-module-wechat-mp/pom.xml

@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>yudao</artifactId>
+        <groupId>cn.iocoder.boot</groupId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <modules>
+        <module>yudao-module-wechat-mp-api</module>
+        <module>yudao-module-wechat-mp-biz</module>
+    </modules>
+    <artifactId>yudao-module-wechat-mp</artifactId>
+    <packaging>pom</packaging>
+
+    <name>${project.artifactId}</name>
+    <description>
+        微信公众号模块,主要实现 账号管理,粉丝管理 等功能。
+    </description>
+
+
+</project>

+ 26 - 0
yudao-module-wechat-mp/yudao-module-wechat-mp-api/pom.xml

@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>yudao-module-wechat-mp</artifactId>
+        <groupId>cn.iocoder.boot</groupId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>yudao-module-wechat-mp-api</artifactId>
+    <packaging>jar</packaging>
+
+    <name>${project.artifactId}</name>
+    <description>
+        微信公众号模块 API,暴露给其它模块调用
+    </description>
+
+    <dependencies>
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-common</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>

+ 16 - 0
yudao-module-wechat-mp/yudao-module-wechat-mp-api/src/main/java/cn/iocoder/yudao/module/wechatMp/enums/ErrorCodeConstants.java

@@ -0,0 +1,16 @@
+package cn.iocoder.yudao.module.wechatMp.enums;
+
+import cn.iocoder.yudao.framework.common.exception.ErrorCode;
+
+/**
+ * Member 错误码枚举类
+ *
+ * wechatMp 系统,使用 1-004-000-000 段
+ */
+public interface ErrorCodeConstants {
+
+    // ========== 用户相关  1004001000============
+    ErrorCode WX_ACCOUNT_NOT_EXISTS = new ErrorCode(1004001000, "用户不存在");
+    ErrorCode WX_ACCOUNT_FANS_NOT_EXISTS = new ErrorCode(1004001000, "用户不存在");
+
+}

+ 77 - 0
yudao-module-wechat-mp/yudao-module-wechat-mp-biz/pom.xml

@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>yudao-module-wechat-mp</artifactId>
+        <groupId>cn.iocoder.boot</groupId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <packaging>jar</packaging>
+
+    <artifactId>yudao-module-wechat-mp-biz</artifactId>
+
+    <name>${project.artifactId}</name>
+    <description>
+        微信公众号模块,主要实现 账号管理,粉丝管理 等功能。
+    </description>
+
+    <dependencies>
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-module-wechat-mp-api</artifactId>
+            <version>${revision}</version>
+        </dependency>
+
+        <!-- 业务组件 -->
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-spring-boot-starter-biz-operatelog</artifactId>
+        </dependency>
+
+        <!-- Web 相关 -->
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-spring-boot-starter-web</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-spring-boot-starter-security</artifactId>
+        </dependency>
+
+        <!-- DB 相关 -->
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-spring-boot-starter-mybatis</artifactId>
+        </dependency>
+
+        <!-- Test 测试相关 -->
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-spring-boot-starter-test</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-spring-boot-starter-excel</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-spring-boot-starter-mq</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-configuration-processor</artifactId>
+            <optional>true</optional>
+        </dependency>
+
+        <dependency>
+            <groupId>com.github.binarywang</groupId>
+            <artifactId>weixin-java-mp</artifactId>
+        </dependency>
+
+    </dependencies>
+
+</project>

+ 14 - 0
yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/builder/AbstractBuilder.java

@@ -0,0 +1,14 @@
+package cn.iocoder.yudao.module.wechatMp.builder;
+
+import me.chanjar.weixin.mp.api.WxMpService;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public abstract class AbstractBuilder {
+    protected final Logger logger = LoggerFactory.getLogger(getClass());
+
+    public abstract WxMpXmlOutMessage build(String content,
+                                            WxMpXmlMessage wxMessage, WxMpService service);
+}

+ 21 - 0
yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/builder/ImageBuilder.java

@@ -0,0 +1,21 @@
+package cn.iocoder.yudao.module.wechatMp.builder;
+
+import me.chanjar.weixin.mp.api.WxMpService;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlOutImageMessage;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
+
+public class ImageBuilder extends AbstractBuilder {
+
+    @Override
+    public WxMpXmlOutMessage build(String content, WxMpXmlMessage wxMessage,
+                                   WxMpService service) {
+
+        WxMpXmlOutImageMessage m = WxMpXmlOutMessage.IMAGE().mediaId(content)
+            .fromUser(wxMessage.getToUser()).toUser(wxMessage.getFromUser())
+            .build();
+
+        return m;
+    }
+
+}

+ 19 - 0
yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/builder/TextBuilder.java

@@ -0,0 +1,19 @@
+package cn.iocoder.yudao.module.wechatMp.builder;
+
+import me.chanjar.weixin.mp.api.WxMpService;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlOutTextMessage;
+
+public class TextBuilder extends AbstractBuilder {
+
+    @Override
+    public WxMpXmlOutMessage build(String content, WxMpXmlMessage wxMessage,
+                                   WxMpService service) {
+        WxMpXmlOutTextMessage m = WxMpXmlOutMessage.TEXT().content(content)
+            .fromUser(wxMessage.getToUser()).toUser(wxMessage.getFromUser())
+            .build();
+        return m;
+    }
+
+}

+ 137 - 0
yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/config/WxMpConfig.java

@@ -0,0 +1,137 @@
+package cn.iocoder.yudao.module.wechatMp.config;
+
+
+import cn.hutool.extra.spring.SpringUtil;
+import cn.iocoder.yudao.module.wechatMp.controller.admin.account.vo.WxAccountExportReqVO;
+import cn.iocoder.yudao.module.wechatMp.dal.dataobject.account.WxAccountDO;
+import cn.iocoder.yudao.module.wechatMp.handler.*;
+import cn.iocoder.yudao.module.wechatMp.service.account.WxAccountService;
+import com.google.common.collect.Maps;
+import lombok.extern.slf4j.Slf4j;
+import me.chanjar.weixin.common.api.WxConsts;
+import me.chanjar.weixin.mp.api.WxMpInMemoryConfigStorage;
+import me.chanjar.weixin.mp.api.WxMpMessageRouter;
+import me.chanjar.weixin.mp.api.WxMpService;
+import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
+import me.chanjar.weixin.mp.constant.WxMpEventConstants;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.util.CollectionUtils;
+
+import javax.annotation.PostConstruct;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@Component
+@Slf4j
+public class WxMpConfig implements InitializingBean {
+
+    private static Map<String, WxMpMessageRouter> routers = Maps.newHashMap();
+    private static Map<String, WxMpService> mpServices = Maps.newHashMap();
+
+    @Autowired
+    private WxAccountService wxAccountService;
+
+    /**
+     * 初始化公众号配置
+     */
+    public synchronized void initWxConfig() {
+        WxAccountExportReqVO req = new WxAccountExportReqVO();
+        List<WxAccountDO> wxAccountList = wxAccountService.getWxAccountList(req);
+        if (CollectionUtils.isEmpty(wxAccountList)) {
+            return;
+        }
+        WxMpConfig.init(wxAccountList);
+        log.info("加载公众号配置成功");
+    }
+
+    public static void init(List<WxAccountDO> wxAccountDOS) {
+        mpServices = wxAccountDOS.stream().map(wxAccountDO -> {
+            WxMpInMemoryConfigStorage configStorage = new WxMpInMemoryConfigStorage();
+            configStorage.setAppId(wxAccountDO.getAppid());
+            configStorage.setSecret(wxAccountDO.getAppsecret());
+            configStorage.setToken(wxAccountDO.getToken());
+            configStorage.setAesKey(wxAccountDO.getAeskey());
+
+            WxMpService service = new WxMpServiceImpl();
+            service.setWxMpConfigStorage(configStorage);
+            routers.put(wxAccountDO.getAppid(), newRouter(service));
+            return service;
+        }).collect(Collectors.toMap(s -> s.getWxMpConfigStorage().getAppId(), a -> a, (o, n) -> o));
+
+    }
+
+    public static Map<String, WxMpMessageRouter> getRouters() {
+        return routers;
+    }
+
+    public static Map<String, WxMpService> getMpServices() {
+        return mpServices;
+    }
+
+    private static WxMpMessageRouter newRouter(WxMpService wxMpService) {
+        final WxMpMessageRouter newRouter = new WxMpMessageRouter(wxMpService);
+        // 记录所有事件的日志 (异步执行)
+        newRouter.rule().handler(SpringUtil.getBean(LogHandler.class)).next();
+
+        // 接收客服会话管理事件
+        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
+                .event(WxMpEventConstants.CustomerService.KF_CREATE_SESSION)
+                .handler(SpringUtil.getBean(KfSessionHandler.class)).end();
+        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
+                .event(WxMpEventConstants.CustomerService.KF_CLOSE_SESSION)
+                .handler(SpringUtil.getBean(KfSessionHandler.class))
+                .end();
+        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
+                .event(WxMpEventConstants.CustomerService.KF_SWITCH_SESSION)
+                .handler(SpringUtil.getBean(KfSessionHandler.class)).end();
+
+        // 门店审核事件
+        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
+                .event(WxMpEventConstants.POI_CHECK_NOTIFY)
+                .handler(SpringUtil.getBean(StoreCheckNotifyHandler.class)).end();
+
+        // 自定义菜单事件
+        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
+                .event(WxConsts.MenuButtonType.CLICK).handler(SpringUtil.getBean(MenuHandler.class)).end();
+
+        // 点击菜单连接事件
+        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
+                .event(WxConsts.MenuButtonType.VIEW).handler(SpringUtil.getBean(NullHandler.class)).end();
+
+        // 关注事件
+        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
+                .event(WxConsts.EventType.SUBSCRIBE).handler(SpringUtil.getBean(SubscribeHandler.class))
+                .end();
+
+        // 取消关注事件
+        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
+                .event(WxConsts.EventType.UNSUBSCRIBE)
+                .handler(SpringUtil.getBean(UnsubscribeHandler.class)).end();
+
+        // 上报地理位置事件
+        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
+                .event(WxConsts.EventType.LOCATION).handler(SpringUtil.getBean(LocationHandler.class))
+                .end();
+
+        // 接收地理位置消息
+        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.LOCATION)
+                .handler(SpringUtil.getBean(LocationHandler.class)).end();
+
+        // 扫码事件
+        newRouter.rule().async(false).msgType(WxConsts.XmlMsgType.EVENT)
+                .event(WxConsts.EventType.SCAN).handler(SpringUtil.getBean(ScanHandler.class)).end();
+
+        // 默认
+        newRouter.rule().async(false).handler(SpringUtil.getBean(MsgHandler.class)).end();
+
+        return newRouter;
+    }
+
+    @Override
+    public void afterPropertiesSet() throws Exception {
+        initWxConfig();
+    }
+}

+ 103 - 0
yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/controller/admin/account/WxAccountController.java

@@ -0,0 +1,103 @@
+package cn.iocoder.yudao.module.wechatMp.controller.admin.account;
+
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+
+import org.springframework.validation.annotation.Validated;
+import org.springframework.security.access.prepost.PreAuthorize;
+import io.swagger.annotations.*;
+
+import javax.validation.*;
+import javax.servlet.http.*;
+import java.util.*;
+import java.io.IOException;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
+
+import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
+
+import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.*;
+
+import cn.iocoder.yudao.module.wechatMp.controller.admin.account.vo.*;
+import cn.iocoder.yudao.module.wechatMp.dal.dataobject.account.WxAccountDO;
+import cn.iocoder.yudao.module.wechatMp.convert.account.WxAccountConvert;
+import cn.iocoder.yudao.module.wechatMp.service.account.WxAccountService;
+
+@Api(tags = "管理后台 - 公众号账户")
+@RestController
+@RequestMapping("/wechatMp/wx-account")
+@Validated
+public class WxAccountController {
+
+    @Resource
+    private WxAccountService wxAccountService;
+
+    @PostMapping("/create")
+    @ApiOperation("创建公众号账户")
+    @PreAuthorize("@ss.hasPermission('wechatMp:wx-account:create')")
+    public CommonResult<Long> createWxAccount(@Valid @RequestBody WxAccountCreateReqVO createReqVO) {
+        return success(wxAccountService.createWxAccount(createReqVO));
+    }
+
+    @PutMapping("/update")
+    @ApiOperation("更新公众号账户")
+    @PreAuthorize("@ss.hasPermission('wechatMp:wx-account:update')")
+    public CommonResult<Boolean> updateWxAccount(@Valid @RequestBody WxAccountUpdateReqVO updateReqVO) {
+        wxAccountService.updateWxAccount(updateReqVO);
+        return success(true);
+    }
+
+    @DeleteMapping("/delete")
+    @ApiOperation("删除公众号账户")
+    @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class)
+    @PreAuthorize("@ss.hasPermission('wechatMp:wx-account:delete')")
+    public CommonResult<Boolean> deleteWxAccount(@RequestParam("id") Long id) {
+        wxAccountService.deleteWxAccount(id);
+        return success(true);
+    }
+
+    @GetMapping("/get")
+    @ApiOperation("获得公众号账户")
+    @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
+    @PreAuthorize("@ss.hasPermission('wechatMp:wx-account:query')")
+    public CommonResult<WxAccountRespVO> getWxAccount(@RequestParam("id") Long id) {
+        WxAccountDO wxAccount = wxAccountService.getWxAccount(id);
+        return success(WxAccountConvert.INSTANCE.convert(wxAccount));
+    }
+
+    @GetMapping("/list")
+    @ApiOperation("获得公众号账户列表")
+    @ApiImplicitParam(name = "ids", value = "编号列表", required = true, example = "1024,2048", dataTypeClass = List.class)
+    @PreAuthorize("@ss.hasPermission('wechatMp:wx-account:query')")
+    public CommonResult<List<WxAccountRespVO>> getWxAccountList(@RequestParam("ids") Collection<Long> ids) {
+        List<WxAccountDO> list = wxAccountService.getWxAccountList(ids);
+        return success(WxAccountConvert.INSTANCE.convertList(list));
+    }
+
+    @GetMapping("/page")
+    @ApiOperation("获得公众号账户分页")
+    @PreAuthorize("@ss.hasPermission('wechatMp:wx-account:query')")
+    public CommonResult<PageResult<WxAccountRespVO>> getWxAccountPage(@Valid WxAccountPageReqVO pageVO) {
+        PageResult<WxAccountDO> pageResult = wxAccountService.getWxAccountPage(pageVO);
+        return success(WxAccountConvert.INSTANCE.convertPage(pageResult));
+    }
+
+    @GetMapping("/export-excel")
+    @ApiOperation("导出公众号账户 Excel")
+    @PreAuthorize("@ss.hasPermission('wechatMp:wx-account:export')")
+    @OperateLog(type = EXPORT)
+    public void exportWxAccountExcel(@Valid WxAccountExportReqVO exportReqVO,
+                                     HttpServletResponse response) throws IOException {
+        List<WxAccountDO> list = wxAccountService.getWxAccountList(exportReqVO);
+        // 导出 Excel
+        List<WxAccountExcelVO> datas = WxAccountConvert.INSTANCE.convertList02(list);
+        ExcelUtils.write(response, "公众号账户.xls", "数据", WxAccountExcelVO.class, datas);
+    }
+
+}

+ 36 - 0
yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/controller/admin/account/vo/WxAccountBaseVO.java

@@ -0,0 +1,36 @@
+package cn.iocoder.yudao.module.wechatMp.controller.admin.account.vo;
+
+import lombok.*;
+import java.util.*;
+import io.swagger.annotations.*;
+import javax.validation.constraints.*;
+
+/**
+* 公众号账户 Base VO,提供给添加、修改、详细的子 VO 使用
+* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
+*/
+@Data
+public class WxAccountBaseVO {
+
+    @ApiModelProperty(value = "公众号名称")
+    private String name;
+
+    @ApiModelProperty(value = "公众号账户")
+    private String account;
+
+    @ApiModelProperty(value = "公众号appid")
+    private String appid;
+
+    @ApiModelProperty(value = "公众号密钥")
+    private String appsecret;
+
+    @ApiModelProperty(value = "公众号token")
+    private String token;
+
+    @ApiModelProperty(value = "加密密钥")
+    private String aeskey;
+
+    @ApiModelProperty(value = "备注")
+    private String remark;
+
+}

+ 14 - 0
yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/controller/admin/account/vo/WxAccountCreateReqVO.java

@@ -0,0 +1,14 @@
+package cn.iocoder.yudao.module.wechatMp.controller.admin.account.vo;
+
+import lombok.*;
+import java.util.*;
+import io.swagger.annotations.*;
+import javax.validation.constraints.*;
+
+@ApiModel("管理后台 - 公众号账户创建 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class WxAccountCreateReqVO extends WxAccountBaseVO {
+
+}

+ 50 - 0
yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/controller/admin/account/vo/WxAccountExcelVO.java

@@ -0,0 +1,50 @@
+package cn.iocoder.yudao.module.wechatMp.controller.admin.account.vo;
+
+import lombok.*;
+import java.util.*;
+import io.swagger.annotations.*;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+
+/**
+ * 公众号账户 Excel VO
+ *
+ * @author 芋道源码
+ */
+@Data
+public class WxAccountExcelVO {
+
+    @ExcelProperty("编号")
+    private Long id;
+
+    @ExcelProperty("公众号名称")
+    private String name;
+
+    @ExcelProperty("公众号账户")
+    private String account;
+
+    @ExcelProperty("公众号appid")
+    private String appid;
+
+    @ExcelProperty("公众号密钥")
+    private String appsecret;
+
+    @ExcelProperty("公众号url")
+    private String url;
+
+    @ExcelProperty("公众号token")
+    private String token;
+
+    @ExcelProperty("加密密钥")
+    private String aeskey;
+
+    @ExcelProperty("二维码图片URL")
+    private String qrUrl;
+
+    @ExcelProperty("备注")
+    private String remark;
+
+    @ExcelProperty("创建时间")
+    private Date createTime;
+
+}

+ 32 - 0
yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/controller/admin/account/vo/WxAccountExportReqVO.java

@@ -0,0 +1,32 @@
+package cn.iocoder.yudao.module.wechatMp.controller.admin.account.vo;
+
+import lombok.*;
+import java.util.*;
+import io.swagger.annotations.*;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@ApiModel(value = "管理后台 - 公众号账户 Excel 导出 Request VO", description = "参数和 WxAccountPageReqVO 是一致的")
+@Data
+public class WxAccountExportReqVO {
+
+    @ApiModelProperty(value = "公众号名称")
+    private String name;
+
+    @ApiModelProperty(value = "公众号账户")
+    private String account;
+
+    @ApiModelProperty(value = "公众号appid")
+    private String appid;
+
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    @ApiModelProperty(value = "开始创建时间")
+    private Date beginCreateTime;
+
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    @ApiModelProperty(value = "结束创建时间")
+    private Date endCreateTime;
+
+}

+ 34 - 0
yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/controller/admin/account/vo/WxAccountPageReqVO.java

@@ -0,0 +1,34 @@
+package cn.iocoder.yudao.module.wechatMp.controller.admin.account.vo;
+
+import lombok.*;
+import java.util.*;
+import io.swagger.annotations.*;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@ApiModel("管理后台 - 公众号账户分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class WxAccountPageReqVO extends PageParam {
+
+    @ApiModelProperty(value = "公众号名称")
+    private String name;
+
+    @ApiModelProperty(value = "公众号账户")
+    private String account;
+
+    @ApiModelProperty(value = "公众号appid")
+    private String appid;
+
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    @ApiModelProperty(value = "开始创建时间")
+    private Date beginCreateTime;
+
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    @ApiModelProperty(value = "结束创建时间")
+    private Date endCreateTime;
+
+}

+ 25 - 0
yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/controller/admin/account/vo/WxAccountRespVO.java

@@ -0,0 +1,25 @@
+package cn.iocoder.yudao.module.wechatMp.controller.admin.account.vo;
+
+import lombok.*;
+import java.util.*;
+import io.swagger.annotations.*;
+
+@ApiModel("管理后台 - 公众号账户 Response VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class WxAccountRespVO extends WxAccountBaseVO {
+
+    @ApiModelProperty(value = "编号", required = true)
+    private Long id;
+
+    @ApiModelProperty(value = "公众号url")
+    private String url;
+
+    @ApiModelProperty(value = "二维码图片URL")
+    private String qrUrl;
+
+    @ApiModelProperty(value = "创建时间", required = true)
+    private Date createTime;
+
+}

+ 18 - 0
yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/controller/admin/account/vo/WxAccountUpdateReqVO.java

@@ -0,0 +1,18 @@
+package cn.iocoder.yudao.module.wechatMp.controller.admin.account.vo;
+
+import lombok.*;
+import java.util.*;
+import io.swagger.annotations.*;
+import javax.validation.constraints.*;
+
+@ApiModel("管理后台 - 公众号账户更新 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class WxAccountUpdateReqVO extends WxAccountBaseVO {
+
+    @ApiModelProperty(value = "编号", required = true)
+    @NotNull(message = "编号不能为空")
+    private Long id;
+
+}

+ 100 - 0
yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/controller/admin/accountfans/WxAccountFansController.java

@@ -0,0 +1,100 @@
+package cn.iocoder.yudao.module.wechatMp.controller.admin.accountfans;
+
+import org.springframework.web.bind.annotation.*;
+import javax.annotation.Resource;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.security.access.prepost.PreAuthorize;
+import io.swagger.annotations.*;
+
+import javax.validation.constraints.*;
+import javax.validation.*;
+import javax.servlet.http.*;
+import java.util.*;
+import java.io.IOException;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
+
+import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
+import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.*;
+
+import cn.iocoder.yudao.module.wechatMp.controller.admin.accountfans.vo.*;
+import cn.iocoder.yudao.module.wechatMp.dal.dataobject.accountfans.WxAccountFansDO;
+import cn.iocoder.yudao.module.wechatMp.convert.accountfans.WxAccountFansConvert;
+import cn.iocoder.yudao.module.wechatMp.service.accountfans.WxAccountFansService;
+
+@Api(tags = "管理后台 - 微信公众号粉丝")
+@RestController
+@RequestMapping("/wechatMp/wx-account-fans")
+@Validated
+public class WxAccountFansController {
+
+    @Resource
+    private WxAccountFansService wxAccountFansService;
+
+    @PostMapping("/create")
+    @ApiOperation("创建微信公众号粉丝")
+    @PreAuthorize("@ss.hasPermission('wechatMp:wx-account-fans:create')")
+    public CommonResult<Long> createWxAccountFans(@Valid @RequestBody WxAccountFansCreateReqVO createReqVO) {
+        return success(wxAccountFansService.createWxAccountFans(createReqVO));
+    }
+
+    @PutMapping("/update")
+    @ApiOperation("更新微信公众号粉丝")
+    @PreAuthorize("@ss.hasPermission('wechatMp:wx-account-fans:update')")
+    public CommonResult<Boolean> updateWxAccountFans(@Valid @RequestBody WxAccountFansUpdateReqVO updateReqVO) {
+        wxAccountFansService.updateWxAccountFans(updateReqVO);
+        return success(true);
+    }
+
+    @DeleteMapping("/delete")
+    @ApiOperation("删除微信公众号粉丝")
+    @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class)
+    @PreAuthorize("@ss.hasPermission('wechatMp:wx-account-fans:delete')")
+    public CommonResult<Boolean> deleteWxAccountFans(@RequestParam("id") Long id) {
+        wxAccountFansService.deleteWxAccountFans(id);
+        return success(true);
+    }
+
+    @GetMapping("/get")
+    @ApiOperation("获得微信公众号粉丝")
+    @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
+    @PreAuthorize("@ss.hasPermission('wechatMp:wx-account-fans:query')")
+    public CommonResult<WxAccountFansRespVO> getWxAccountFans(@RequestParam("id") Long id) {
+        WxAccountFansDO wxAccountFans = wxAccountFansService.getWxAccountFans(id);
+        return success(WxAccountFansConvert.INSTANCE.convert(wxAccountFans));
+    }
+
+    @GetMapping("/list")
+    @ApiOperation("获得微信公众号粉丝列表")
+    @ApiImplicitParam(name = "ids", value = "编号列表", required = true, example = "1024,2048", dataTypeClass = List.class)
+    @PreAuthorize("@ss.hasPermission('wechatMp:wx-account-fans:query')")
+    public CommonResult<List<WxAccountFansRespVO>> getWxAccountFansList(@RequestParam("ids") Collection<Long> ids) {
+        List<WxAccountFansDO> list = wxAccountFansService.getWxAccountFansList(ids);
+        return success(WxAccountFansConvert.INSTANCE.convertList(list));
+    }
+
+    @GetMapping("/page")
+    @ApiOperation("获得微信公众号粉丝分页")
+    @PreAuthorize("@ss.hasPermission('wechatMp:wx-account-fans:query')")
+    public CommonResult<PageResult<WxAccountFansRespVO>> getWxAccountFansPage(@Valid WxAccountFansPageReqVO pageVO) {
+        PageResult<WxAccountFansDO> pageResult = wxAccountFansService.getWxAccountFansPage(pageVO);
+        return success(WxAccountFansConvert.INSTANCE.convertPage(pageResult));
+    }
+
+    @GetMapping("/export-excel")
+    @ApiOperation("导出微信公众号粉丝 Excel")
+    @PreAuthorize("@ss.hasPermission('wechatMp:wx-account-fans:export')")
+    @OperateLog(type = EXPORT)
+    public void exportWxAccountFansExcel(@Valid WxAccountFansExportReqVO exportReqVO,
+              HttpServletResponse response) throws IOException {
+        List<WxAccountFansDO> list = wxAccountFansService.getWxAccountFansList(exportReqVO);
+        // 导出 Excel
+        List<WxAccountFansExcelVO> datas = WxAccountFansConvert.INSTANCE.convertList02(list);
+        ExcelUtils.write(response, "微信公众号粉丝.xls", "数据", WxAccountFansExcelVO.class, datas);
+    }
+
+}

+ 58 - 0
yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/controller/admin/accountfans/vo/WxAccountFansBaseVO.java

@@ -0,0 +1,58 @@
+package cn.iocoder.yudao.module.wechatMp.controller.admin.accountfans.vo;
+
+import lombok.*;
+import java.util.*;
+import io.swagger.annotations.*;
+import javax.validation.constraints.*;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+/**
+* 微信公众号粉丝 Base VO,提供给添加、修改、详细的子 VO 使用
+* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
+*/
+@Data
+public class WxAccountFansBaseVO {
+
+    @ApiModelProperty(value = "用户标识")
+    private String openid;
+
+    @ApiModelProperty(value = "订阅状态,0未关注,1已关注")
+    private String subscribeStatus;
+
+    @ApiModelProperty(value = "订阅时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private Date subscribeTime;
+
+    @ApiModelProperty(value = "昵称")
+    private byte[] nickname;
+
+    @ApiModelProperty(value = "性别,1男,2女,0未知")
+    private String gender;
+
+    @ApiModelProperty(value = "语言")
+    private String language;
+
+    @ApiModelProperty(value = "国家")
+    private String country;
+
+    @ApiModelProperty(value = "省份")
+    private String province;
+
+    @ApiModelProperty(value = "城市")
+    private String city;
+
+    @ApiModelProperty(value = "头像地址")
+    private String headimgUrl;
+
+    @ApiModelProperty(value = "备注")
+    private String remark;
+
+    @ApiModelProperty(value = "微信公众号ID")
+    private String wxAccountId;
+
+    @ApiModelProperty(value = "微信公众号appid")
+    private String wxAccountAppid;
+
+}

+ 14 - 0
yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/controller/admin/accountfans/vo/WxAccountFansCreateReqVO.java

@@ -0,0 +1,14 @@
+package cn.iocoder.yudao.module.wechatMp.controller.admin.accountfans.vo;
+
+import lombok.*;
+import java.util.*;
+import io.swagger.annotations.*;
+import javax.validation.constraints.*;
+
+@ApiModel("管理后台 - 微信公众号粉丝创建 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class WxAccountFansCreateReqVO extends WxAccountFansBaseVO {
+
+}

+ 62 - 0
yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/controller/admin/accountfans/vo/WxAccountFansExcelVO.java

@@ -0,0 +1,62 @@
+package cn.iocoder.yudao.module.wechatMp.controller.admin.accountfans.vo;
+
+import lombok.*;
+import java.util.*;
+import io.swagger.annotations.*;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+
+/**
+ * 微信公众号粉丝 Excel VO
+ *
+ * @author 芋道源码
+ */
+@Data
+public class WxAccountFansExcelVO {
+
+    @ExcelProperty("编号")
+    private Long id;
+
+    @ExcelProperty("用户标识")
+    private String openid;
+
+    @ExcelProperty("订阅状态,0未关注,1已关注")
+    private String subscribeStatus;
+
+    @ExcelProperty("订阅时间")
+    private Date subscribeTime;
+
+    @ExcelProperty("昵称")
+    private byte[] nickname;
+
+    @ExcelProperty("性别,1男,2女,0未知")
+    private String gender;
+
+    @ExcelProperty("语言")
+    private String language;
+
+    @ExcelProperty("国家")
+    private String country;
+
+    @ExcelProperty("省份")
+    private String province;
+
+    @ExcelProperty("城市")
+    private String city;
+
+    @ExcelProperty("头像地址")
+    private String headimgUrl;
+
+    @ExcelProperty("备注")
+    private String remark;
+
+    @ExcelProperty("微信公众号ID")
+    private String wxAccountId;
+
+    @ExcelProperty("微信公众号appid")
+    private String wxAccountAppid;
+
+    @ExcelProperty("创建时间")
+    private Date createTime;
+
+}

+ 67 - 0
yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/controller/admin/accountfans/vo/WxAccountFansExportReqVO.java

@@ -0,0 +1,67 @@
+package cn.iocoder.yudao.module.wechatMp.controller.admin.accountfans.vo;
+
+import lombok.*;
+import java.util.*;
+import io.swagger.annotations.*;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@ApiModel(value = "管理后台 - 微信公众号粉丝 Excel 导出 Request VO", description = "参数和 WxAccountFansPageReqVO 是一致的")
+@Data
+public class WxAccountFansExportReqVO {
+
+    @ApiModelProperty(value = "用户标识")
+    private String openid;
+
+    @ApiModelProperty(value = "订阅状态,0未关注,1已关注")
+    private String subscribeStatus;
+
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    @ApiModelProperty(value = "开始订阅时间")
+    private Date beginSubscribeTime;
+
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    @ApiModelProperty(value = "结束订阅时间")
+    private Date endSubscribeTime;
+
+    @ApiModelProperty(value = "昵称")
+    private String nickname;
+
+    @ApiModelProperty(value = "性别,1男,2女,0未知")
+    private String gender;
+
+    @ApiModelProperty(value = "语言")
+    private String language;
+
+    @ApiModelProperty(value = "国家")
+    private String country;
+
+    @ApiModelProperty(value = "省份")
+    private String province;
+
+    @ApiModelProperty(value = "城市")
+    private String city;
+
+    @ApiModelProperty(value = "头像地址")
+    private String headimgUrl;
+
+    @ApiModelProperty(value = "备注")
+    private String remark;
+
+    @ApiModelProperty(value = "微信公众号ID")
+    private String wxAccountId;
+
+    @ApiModelProperty(value = "微信公众号appid")
+    private String wxAccountAppid;
+
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    @ApiModelProperty(value = "开始创建时间")
+    private Date beginCreateTime;
+
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    @ApiModelProperty(value = "结束创建时间")
+    private Date endCreateTime;
+
+}

+ 69 - 0
yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/controller/admin/accountfans/vo/WxAccountFansPageReqVO.java

@@ -0,0 +1,69 @@
+package cn.iocoder.yudao.module.wechatMp.controller.admin.accountfans.vo;
+
+import lombok.*;
+import java.util.*;
+import io.swagger.annotations.*;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@ApiModel("管理后台 - 微信公众号粉丝分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class WxAccountFansPageReqVO extends PageParam {
+
+    @ApiModelProperty(value = "用户标识")
+    private String openid;
+
+    @ApiModelProperty(value = "订阅状态,0未关注,1已关注")
+    private String subscribeStatus;
+
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    @ApiModelProperty(value = "开始订阅时间")
+    private Date beginSubscribeTime;
+
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    @ApiModelProperty(value = "结束订阅时间")
+    private Date endSubscribeTime;
+
+    @ApiModelProperty(value = "昵称")
+    private String nickname;
+
+    @ApiModelProperty(value = "性别,1男,2女,0未知")
+    private String gender;
+
+    @ApiModelProperty(value = "语言")
+    private String language;
+
+    @ApiModelProperty(value = "国家")
+    private String country;
+
+    @ApiModelProperty(value = "省份")
+    private String province;
+
+    @ApiModelProperty(value = "城市")
+    private String city;
+
+    @ApiModelProperty(value = "头像地址")
+    private String headimgUrl;
+
+    @ApiModelProperty(value = "备注")
+    private String remark;
+
+    @ApiModelProperty(value = "微信公众号ID")
+    private String wxAccountId;
+
+    @ApiModelProperty(value = "微信公众号appid")
+    private String wxAccountAppid;
+
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    @ApiModelProperty(value = "开始创建时间")
+    private Date beginCreateTime;
+
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    @ApiModelProperty(value = "结束创建时间")
+    private Date endCreateTime;
+
+}

+ 19 - 0
yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/controller/admin/accountfans/vo/WxAccountFansRespVO.java

@@ -0,0 +1,19 @@
+package cn.iocoder.yudao.module.wechatMp.controller.admin.accountfans.vo;
+
+import lombok.*;
+import java.util.*;
+import io.swagger.annotations.*;
+
+@ApiModel("管理后台 - 微信公众号粉丝 Response VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class WxAccountFansRespVO extends WxAccountFansBaseVO {
+
+    @ApiModelProperty(value = "编号", required = true)
+    private Long id;
+
+    @ApiModelProperty(value = "创建时间", required = true)
+    private Date createTime;
+
+}

+ 18 - 0
yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/controller/admin/accountfans/vo/WxAccountFansUpdateReqVO.java

@@ -0,0 +1,18 @@
+package cn.iocoder.yudao.module.wechatMp.controller.admin.accountfans.vo;
+
+import lombok.*;
+import java.util.*;
+import io.swagger.annotations.*;
+import javax.validation.constraints.*;
+
+@ApiModel("管理后台 - 微信公众号粉丝更新 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class WxAccountFansUpdateReqVO extends WxAccountFansBaseVO {
+
+    @ApiModelProperty(value = "编号", required = true)
+    @NotNull(message = "编号不能为空")
+    private Long id;
+
+}

+ 34 - 0
yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/convert/account/WxAccountConvert.java

@@ -0,0 +1,34 @@
+package cn.iocoder.yudao.module.wechatMp.convert.account;
+
+import java.util.*;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+
+import org.mapstruct.Mapper;
+import org.mapstruct.factory.Mappers;
+import cn.iocoder.yudao.module.wechatMp.controller.admin.account.vo.*;
+import cn.iocoder.yudao.module.wechatMp.dal.dataobject.account.WxAccountDO;
+
+/**
+ * 公众号账户 Convert
+ *
+ * @author 芋道源码
+ */
+@Mapper
+public interface WxAccountConvert {
+
+    WxAccountConvert INSTANCE = Mappers.getMapper(WxAccountConvert.class);
+
+    WxAccountDO convert(WxAccountCreateReqVO bean);
+
+    WxAccountDO convert(WxAccountUpdateReqVO bean);
+
+    WxAccountRespVO convert(WxAccountDO bean);
+
+    List<WxAccountRespVO> convertList(List<WxAccountDO> list);
+
+    PageResult<WxAccountRespVO> convertPage(PageResult<WxAccountDO> page);
+
+    List<WxAccountExcelVO> convertList02(List<WxAccountDO> list);
+
+}

+ 34 - 0
yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/convert/accountfans/WxAccountFansConvert.java

@@ -0,0 +1,34 @@
+package cn.iocoder.yudao.module.wechatMp.convert.accountfans;
+
+import java.util.*;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+
+import org.mapstruct.Mapper;
+import org.mapstruct.factory.Mappers;
+import cn.iocoder.yudao.module.wechatMp.controller.admin.accountfans.vo.*;
+import cn.iocoder.yudao.module.wechatMp.dal.dataobject.accountfans.WxAccountFansDO;
+
+/**
+ * 微信公众号粉丝 Convert
+ *
+ * @author 芋道源码
+ */
+@Mapper
+public interface WxAccountFansConvert {
+
+    WxAccountFansConvert INSTANCE = Mappers.getMapper(WxAccountFansConvert.class);
+
+    WxAccountFansDO convert(WxAccountFansCreateReqVO bean);
+
+    WxAccountFansDO convert(WxAccountFansUpdateReqVO bean);
+
+    WxAccountFansRespVO convert(WxAccountFansDO bean);
+
+    List<WxAccountFansRespVO> convertList(List<WxAccountFansDO> list);
+
+    PageResult<WxAccountFansRespVO> convertPage(PageResult<WxAccountFansDO> page);
+
+    List<WxAccountFansExcelVO> convertList02(List<WxAccountFansDO> list);
+
+}

+ 65 - 0
yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/dal/dataobject/account/WxAccountDO.java

@@ -0,0 +1,65 @@
+package cn.iocoder.yudao.module.wechatMp.dal.dataobject.account;
+
+import lombok.*;
+import java.util.*;
+import com.baomidou.mybatisplus.annotation.*;
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+
+/**
+ * 公众号账户 DO
+ *
+ * @author 芋道源码
+ */
+@TableName("wx_account")
+@KeySequence("wx_account_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxAccountDO extends BaseDO {
+
+    /**
+     * 编号
+     */
+    @TableId
+    private Long id;
+    /**
+     * 公众号名称
+     */
+    private String name;
+    /**
+     * 公众号账户
+     */
+    private String account;
+    /**
+     * 公众号appid
+     */
+    private String appid;
+    /**
+     * 公众号密钥
+     */
+    private String appsecret;
+    /**
+     * 公众号url
+     */
+    private String url;
+    /**
+     * 公众号token
+     */
+    private String token;
+    /**
+     * 加密密钥
+     */
+    private String aeskey;
+    /**
+     * 二维码图片URL
+     */
+    private String qrUrl;
+    /**
+     * 备注
+     */
+    private String remark;
+
+}

+ 81 - 0
yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/dal/dataobject/accountfans/WxAccountFansDO.java

@@ -0,0 +1,81 @@
+package cn.iocoder.yudao.module.wechatMp.dal.dataobject.accountfans;
+
+import lombok.*;
+import java.util.*;
+import com.baomidou.mybatisplus.annotation.*;
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+
+/**
+ * 微信公众号粉丝 DO
+ *
+ * @author 芋道源码
+ */
+@TableName("wx_account_fans")
+@KeySequence("wx_account_fans_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WxAccountFansDO extends BaseDO {
+
+    /**
+     * 编号
+     */
+    @TableId
+    private Long id;
+    /**
+     * 用户标识
+     */
+    private String openid;
+    /**
+     * 订阅状态,0未关注,1已关注
+     */
+    private String subscribeStatus;
+    /**
+     * 订阅时间
+     */
+    private Date subscribeTime;
+    /**
+     * 昵称
+     */
+    private byte[] nickname;
+    /**
+     * 性别,1男,2女,0未知
+     */
+    private String gender;
+    /**
+     * 语言
+     */
+    private String language;
+    /**
+     * 国家
+     */
+    private String country;
+    /**
+     * 省份
+     */
+    private String province;
+    /**
+     * 城市
+     */
+    private String city;
+    /**
+     * 头像地址
+     */
+    private String headimgUrl;
+    /**
+     * 备注
+     */
+    private String remark;
+    /**
+     * 微信公众号ID
+     */
+    private String wxAccountId;
+    /**
+     * 微信公众号appid
+     */
+    private String wxAccountAppid;
+
+}

+ 38 - 0
yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/dal/mysql/account/WxAccountMapper.java

@@ -0,0 +1,38 @@
+package cn.iocoder.yudao.module.wechatMp.dal.mysql.account;
+
+import java.util.*;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.module.wechatMp.dal.dataobject.account.WxAccountDO;
+import org.apache.ibatis.annotations.Mapper;
+import cn.iocoder.yudao.module.wechatMp.controller.admin.account.vo.*;
+
+/**
+ * 公众号账户 Mapper
+ *
+ * @author 芋道源码
+ */
+@Mapper
+public interface WxAccountMapper extends BaseMapperX<WxAccountDO> {
+
+    default PageResult<WxAccountDO> selectPage(WxAccountPageReqVO reqVO) {
+        return selectPage(reqVO, new LambdaQueryWrapperX<WxAccountDO>()
+                .likeIfPresent(WxAccountDO::getName, reqVO.getName())
+                .eqIfPresent(WxAccountDO::getAccount, reqVO.getAccount())
+                .eqIfPresent(WxAccountDO::getAppid, reqVO.getAppid())
+                .betweenIfPresent(WxAccountDO::getCreateTime, reqVO.getBeginCreateTime(), reqVO.getEndCreateTime())
+                .orderByDesc(WxAccountDO::getId));
+    }
+
+    default List<WxAccountDO> selectList(WxAccountExportReqVO reqVO) {
+        return selectList(new LambdaQueryWrapperX<WxAccountDO>()
+                .likeIfPresent(WxAccountDO::getName, reqVO.getName())
+                .eqIfPresent(WxAccountDO::getAccount, reqVO.getAccount())
+                .eqIfPresent(WxAccountDO::getAppid, reqVO.getAppid())
+                .betweenIfPresent(WxAccountDO::getCreateTime, reqVO.getBeginCreateTime(), reqVO.getEndCreateTime())
+                .orderByDesc(WxAccountDO::getId));
+    }
+
+}

+ 58 - 0
yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/dal/mysql/accountfans/WxAccountFansMapper.java

@@ -0,0 +1,58 @@
+package cn.iocoder.yudao.module.wechatMp.dal.mysql.accountfans;
+
+import java.util.*;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.module.wechatMp.dal.dataobject.accountfans.WxAccountFansDO;
+import org.apache.ibatis.annotations.Mapper;
+import cn.iocoder.yudao.module.wechatMp.controller.admin.accountfans.vo.*;
+
+/**
+ * 微信公众号粉丝 Mapper
+ *
+ * @author 芋道源码
+ */
+@Mapper
+public interface WxAccountFansMapper extends BaseMapperX<WxAccountFansDO> {
+
+    default PageResult<WxAccountFansDO> selectPage(WxAccountFansPageReqVO reqVO) {
+        return selectPage(reqVO, new LambdaQueryWrapperX<WxAccountFansDO>()
+                .eqIfPresent(WxAccountFansDO::getOpenid, reqVO.getOpenid())
+                .eqIfPresent(WxAccountFansDO::getSubscribeStatus, reqVO.getSubscribeStatus())
+                .betweenIfPresent(WxAccountFansDO::getSubscribeTime, reqVO.getBeginSubscribeTime(), reqVO.getEndSubscribeTime())
+                .likeIfPresent(WxAccountFansDO::getNickname, reqVO.getNickname())
+                .eqIfPresent(WxAccountFansDO::getGender, reqVO.getGender())
+                .eqIfPresent(WxAccountFansDO::getLanguage, reqVO.getLanguage())
+                .eqIfPresent(WxAccountFansDO::getCountry, reqVO.getCountry())
+                .eqIfPresent(WxAccountFansDO::getProvince, reqVO.getProvince())
+                .eqIfPresent(WxAccountFansDO::getCity, reqVO.getCity())
+                .eqIfPresent(WxAccountFansDO::getHeadimgUrl, reqVO.getHeadimgUrl())
+                .eqIfPresent(WxAccountFansDO::getRemark, reqVO.getRemark())
+                .eqIfPresent(WxAccountFansDO::getWxAccountId, reqVO.getWxAccountId())
+                .eqIfPresent(WxAccountFansDO::getWxAccountAppid, reqVO.getWxAccountAppid())
+                .betweenIfPresent(WxAccountFansDO::getCreateTime, reqVO.getBeginCreateTime(), reqVO.getEndCreateTime())
+                .orderByDesc(WxAccountFansDO::getId));
+    }
+
+    default List<WxAccountFansDO> selectList(WxAccountFansExportReqVO reqVO) {
+        return selectList(new LambdaQueryWrapperX<WxAccountFansDO>()
+                .eqIfPresent(WxAccountFansDO::getOpenid, reqVO.getOpenid())
+                .eqIfPresent(WxAccountFansDO::getSubscribeStatus, reqVO.getSubscribeStatus())
+                .betweenIfPresent(WxAccountFansDO::getSubscribeTime, reqVO.getBeginSubscribeTime(), reqVO.getEndSubscribeTime())
+                .likeIfPresent(WxAccountFansDO::getNickname, reqVO.getNickname())
+                .eqIfPresent(WxAccountFansDO::getGender, reqVO.getGender())
+                .eqIfPresent(WxAccountFansDO::getLanguage, reqVO.getLanguage())
+                .eqIfPresent(WxAccountFansDO::getCountry, reqVO.getCountry())
+                .eqIfPresent(WxAccountFansDO::getProvince, reqVO.getProvince())
+                .eqIfPresent(WxAccountFansDO::getCity, reqVO.getCity())
+                .eqIfPresent(WxAccountFansDO::getHeadimgUrl, reqVO.getHeadimgUrl())
+                .eqIfPresent(WxAccountFansDO::getRemark, reqVO.getRemark())
+                .eqIfPresent(WxAccountFansDO::getWxAccountId, reqVO.getWxAccountId())
+                .eqIfPresent(WxAccountFansDO::getWxAccountAppid, reqVO.getWxAccountAppid())
+                .betweenIfPresent(WxAccountFansDO::getCreateTime, reqVO.getBeginCreateTime(), reqVO.getEndCreateTime())
+                .orderByDesc(WxAccountFansDO::getId));
+    }
+
+}

+ 23 - 0
yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/handler/KfSessionHandler.java

@@ -0,0 +1,23 @@
+package cn.iocoder.yudao.module.wechatMp.handler;
+
+import me.chanjar.weixin.common.session.WxSessionManager;
+import me.chanjar.weixin.mp.api.WxMpMessageHandler;
+import me.chanjar.weixin.mp.api.WxMpService;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+@Component
+public class KfSessionHandler implements WxMpMessageHandler {
+
+    @Override
+    public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
+                                    Map<String, Object> context, WxMpService wxMpService,
+                                    WxSessionManager sessionManager) {
+        //TODO 对会话做处理
+        return null;
+    }
+
+}

+ 44 - 0
yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/handler/LocationHandler.java

@@ -0,0 +1,44 @@
+package cn.iocoder.yudao.module.wechatMp.handler;
+
+import cn.iocoder.yudao.module.wechatMp.builder.TextBuilder;
+import lombok.extern.slf4j.Slf4j;
+import me.chanjar.weixin.common.session.WxSessionManager;
+import me.chanjar.weixin.mp.api.WxMpMessageHandler;
+import me.chanjar.weixin.mp.api.WxMpService;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+import static me.chanjar.weixin.common.api.WxConsts.XmlMsgType;
+
+@Component
+@Slf4j
+public class LocationHandler implements WxMpMessageHandler {
+
+    @Override
+    public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
+                                    Map<String, Object> context, WxMpService wxMpService,
+                                    WxSessionManager sessionManager) {
+        if (wxMessage.getMsgType().equals(XmlMsgType.LOCATION)) {
+            //TODO 接收处理用户发送的地理位置消息
+            try {
+                String content = "感谢反馈,您的的地理位置已收到!";
+                return new TextBuilder().build(content, wxMessage, null);
+            } catch (Exception e) {
+                log.error("位置消息接收处理失败", e);
+                return null;
+            }
+        }
+
+        //上报地理位置事件
+       log.info("上报地理位置,纬度 : {},经度 : {},精度 : {}",
+            wxMessage.getLatitude(), wxMessage.getLongitude(), String.valueOf(wxMessage.getPrecision()));
+
+        //TODO  可以将用户地理位置信息保存到本地数据库,以便以后使用
+
+        return null;
+    }
+
+}

+ 25 - 0
yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/handler/LogHandler.java

@@ -0,0 +1,25 @@
+package cn.iocoder.yudao.module.wechatMp.handler;
+
+import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
+import lombok.extern.slf4j.Slf4j;
+import me.chanjar.weixin.common.session.WxSessionManager;
+import me.chanjar.weixin.mp.api.WxMpMessageHandler;
+import me.chanjar.weixin.mp.api.WxMpService;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+@Component
+@Slf4j
+public class LogHandler implements WxMpMessageHandler {
+    @Override
+    public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
+                                    Map<String, Object> context, WxMpService wxMpService,
+                                    WxSessionManager sessionManager) {
+        log.info("接收到请求消息,内容:{}", JsonUtils.toJsonString(wxMessage));
+        return null;
+    }
+
+}

+ 32 - 0
yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/handler/MenuHandler.java

@@ -0,0 +1,32 @@
+package cn.iocoder.yudao.module.wechatMp.handler;
+
+import me.chanjar.weixin.common.session.WxSessionManager;
+import me.chanjar.weixin.mp.api.WxMpMessageHandler;
+import me.chanjar.weixin.mp.api.WxMpService;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+import static me.chanjar.weixin.common.api.WxConsts.MenuButtonType;
+
+@Component
+public class MenuHandler implements WxMpMessageHandler {
+
+    @Override
+    public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
+                                    Map<String, Object> context, WxMpService weixinService,
+                                    WxSessionManager sessionManager) {
+
+        String msg = wxMessage.getEventKey();
+        if (MenuButtonType.VIEW.equals(wxMessage.getEvent())) {
+            return null;
+        }
+
+        return WxMpXmlOutMessage.TEXT().content(msg)
+            .fromUser(wxMessage.getToUser()).toUser(wxMessage.getFromUser())
+            .build();
+    }
+
+}

+ 184 - 0
yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/handler/MsgHandler.java

@@ -0,0 +1,184 @@
+package cn.iocoder.yudao.module.wechatMp.handler;
+
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.http.HtmlUtil;
+import cn.hutool.http.HttpUtil;
+import cn.hutool.json.JSONUtil;
+import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
+import cn.iocoder.yudao.module.wechatMp.builder.TextBuilder;
+import cn.iocoder.yudao.module.wechatMp.dal.dataobject.account.WxAccountDO;
+import cn.iocoder.yudao.module.wechatMp.service.account.WxAccountService;
+import lombok.extern.slf4j.Slf4j;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.session.WxSessionManager;
+import me.chanjar.weixin.mp.api.WxMpMessageHandler;
+import me.chanjar.weixin.mp.api.WxMpService;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
+import me.chanjar.weixin.mp.bean.result.WxMpUser;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import java.io.File;
+import java.io.UnsupportedEncodingException;
+import java.util.Map;
+
+import static me.chanjar.weixin.common.api.WxConsts.XmlMsgType;
+
+@Component
+@Slf4j
+public class MsgHandler implements WxMpMessageHandler {
+
+/*
+    @Autowired
+    WxReceiveTextService wxReceiveTextService;
+
+    @Autowired
+    WxTextTemplateService wxTextTemplateService;
+
+    @Autowired
+    WxAccountService wxAccountService;
+
+    @Autowired
+    WxFansMsgService wxFansMsgService;
+*/
+
+
+    @Override
+    public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
+                                    Map<String, Object> context, WxMpService weixinService,
+                                    WxSessionManager sessionManager) {
+       /* log.info( "收到信息内容:{}", JsonUtils.toJsonString(wxMessage) );
+        log.info( "关键字:{}", wxMessage.getContent() );
+
+        if (!wxMessage.getMsgType().equals(XmlMsgType.EVENT)) {
+            //可以选择将消息保存到本地
+
+            // 获取微信用户基本信息
+            try {
+                WxMpUser wxmpUser = weixinService.getUserService()
+                        .userInfo(wxMessage.getFromUser(), null);
+                if (wxmpUser != null) {
+                    WxAccountDO wxAccount = wxAccountService.findBy( WxAccountDO::getAccount,wxMessage.getToUser());
+                    if(wxAccount != null){
+
+                        if(wxMessage.getMsgType().equals( XmlMsgType.TEXT )){
+                            WxFansMsg wxFansMsg = new WxFansMsg();
+                            wxFansMsg.setOpenid( wxmpUser.getOpenId() );
+                            try {
+                                wxFansMsg.setNickname(wxmpUser.getNickname().getBytes("UTF-8"));
+                            } catch (UnsupportedEncodingException e) {
+                                e.printStackTrace();
+                            }
+                            wxFansMsg.setHeadimgUrl( wxmpUser.getHeadImgUrl() );
+                            wxFansMsg.setWxAccountId( String.valueOf( wxAccount.getId() ) );
+                            wxFansMsg.setMsgType( wxMessage.getMsgType());
+                            wxFansMsg.setContent( wxMessage.getContent() );
+                            wxFansMsg.setIsRes( "1" );
+                            wxFansMsg.setCreateTime( DateUtil.date() );
+                            wxFansMsg.setUpdateTime( DateUtil.date() );
+
+                            //组装回复消息
+                            String content = processContent(wxMessage);
+                            content = HtmlUtil.escape( content );
+                            wxFansMsg.setResContent( content  );
+
+                            wxFansMsgService.save( wxFansMsg );
+                            return new TextBuilder().build(content, wxMessage, weixinService);
+
+                        }
+                        if(wxMessage.getMsgType().equals( XmlMsgType.IMAGE )){
+                            WxFansMsg wxFansMsg = new WxFansMsg();
+                            wxFansMsg.setOpenid( wxmpUser.getOpenId() );
+                            try {
+                                wxFansMsg.setNickname(wxmpUser.getNickname().getBytes("UTF-8"));
+                            } catch (UnsupportedEncodingException e) {
+                                e.printStackTrace();
+                            }
+                            wxFansMsg.setHeadimgUrl( wxmpUser.getHeadImgUrl() );
+                            wxFansMsg.setWxAccountId( String.valueOf( wxAccount.getId() ) );
+                            wxFansMsg.setMsgType( wxMessage.getMsgType());
+                            wxFansMsg.setMediaId( wxMessage.getMediaId() );
+                            wxFansMsg.setPicUrl( wxMessage.getPicUrl() );
+
+                            File downloadDir = new File(downloadDirStr);
+                            if (!downloadDir.exists()) {
+                                downloadDir.mkdirs();
+                            }
+                            String filepath = downloadDirStr + String.valueOf( System.currentTimeMillis() ) + ".png";
+                            //微信pic url下载到本地,防止失效
+                            long size = HttpUtil.downloadFile(wxMessage.getPicUrl(), FileUtil.file(filepath));
+                            log.info("download pic size : {}",size);
+                            wxFansMsg.setPicPath( filepath );
+                            wxFansMsg.setIsRes( "0" );
+                            wxFansMsg.setCreateTime( DateUtil.date() );
+                            wxFansMsg.setUpdateTime( DateUtil.date() );
+                            wxFansMsgService.save( wxFansMsg );
+                        }
+
+                    }
+                }
+            } catch (WxErrorException e) {
+                if (e.getError().getErrorCode() == 48001) {
+                    log.info("该公众号没有获取用户信息权限!");
+                }
+            }
+
+        }
+
+        //当用户输入关键词如“你好”,“客服”等,并且有客服在线时,把消息转发给在线客服
+//        try {
+//            if (StringUtils.startsWithAny(wxMessage.getContent(), "你好", "客服")
+//                && weixinService.getKefuService().kfOnlineList()
+//                .getKfOnlineList().size() > 0) {
+//                return WxMpXmlOutMessage.TRANSFER_CUSTOMER_SERVICE()
+//                    .fromUser(wxMessage.getToUser())
+//                    .toUser(wxMessage.getFromUser()).build();
+//            }
+//        } catch (WxErrorException e) {
+//            e.printStackTrace();
+//        }
+
+        //组装默认回复消息
+        String content = defaultResponseContent;//默认
+        return new TextBuilder().build(content, wxMessage, weixinService);
+        */
+       return null;
+    }
+
+    //处理回复信息,优先级,关键字、智能机器人、默认值
+    String processContent(WxMpXmlMessage wxMessage){
+        String content = "";
+       /* content = processReceiveTextContent(wxMessage);
+        if(StringUtils.isNotBlank( content )){
+            return content;
+        }
+
+        content = defaultResponseContent;*/
+        return content;
+    }
+
+    //处理关键字
+    String processReceiveTextContent(WxMpXmlMessage wxMessage){
+        String content = "";
+      /*  WxAccountDO wxAccount = wxAccountService.findBy( WxAccountDO::getAccount,wxMessage.getToUser());
+        if(wxAccount != null){
+            WxReceiveText wxReceiveTextTpl = new WxReceiveText();
+            wxReceiveTextTpl.setWxAccountId( String.valueOf( wxAccount.getId() ) );
+            wxReceiveTextTpl.setReceiveText( wxMessage.getContent() );
+            List<WxReceiveText> wxReceiveTextList = wxReceiveTextService.findListByReceiveTest( wxReceiveTextTpl );
+            if(wxReceiveTextList != null && wxReceiveTextList.size() > 0){
+                WxReceiveText wxReceiveText = wxReceiveTextList.get( 0 );
+                WxTextTemplate wxTextTemplate = wxTextTemplateService.findById( Integer.parseInt( wxReceiveText.getTplId() ) );
+                content = wxTextTemplate.getContent();
+            }
+        }*/
+        return content;
+    }
+
+
+
+}

+ 22 - 0
yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/handler/NullHandler.java

@@ -0,0 +1,22 @@
+package cn.iocoder.yudao.module.wechatMp.handler;
+
+import me.chanjar.weixin.common.session.WxSessionManager;
+import me.chanjar.weixin.mp.api.WxMpMessageHandler;
+import me.chanjar.weixin.mp.api.WxMpService;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+@Component
+public class NullHandler implements WxMpMessageHandler {
+
+    @Override
+    public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
+                                    Map<String, Object> context, WxMpService wxMpService,
+                                    WxSessionManager sessionManager) {
+        return null;
+    }
+
+}

+ 22 - 0
yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/handler/ScanHandler.java

@@ -0,0 +1,22 @@
+package cn.iocoder.yudao.module.wechatMp.handler;
+
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.session.WxSessionManager;
+import me.chanjar.weixin.mp.api.WxMpMessageHandler;
+import me.chanjar.weixin.mp.api.WxMpService;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+@Component
+public class ScanHandler implements WxMpMessageHandler {
+
+    @Override
+    public WxMpXmlOutMessage handle(WxMpXmlMessage wxMpXmlMessage, Map<String, Object> map,
+                                    WxMpService wxMpService, WxSessionManager wxSessionManager) throws WxErrorException {
+        // 扫码事件处理
+        return null;
+    }
+}

+ 27 - 0
yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/handler/StoreCheckNotifyHandler.java

@@ -0,0 +1,27 @@
+package cn.iocoder.yudao.module.wechatMp.handler;
+
+import me.chanjar.weixin.common.session.WxSessionManager;
+import me.chanjar.weixin.mp.api.WxMpMessageHandler;
+import me.chanjar.weixin.mp.api.WxMpService;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * 门店审核事件处理
+ *
+ */
+@Component
+public class StoreCheckNotifyHandler implements WxMpMessageHandler {
+
+    @Override
+    public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
+                                    Map<String, Object> context, WxMpService wxMpService,
+                                    WxSessionManager sessionManager) {
+        // TODO 处理门店审核事件
+        return null;
+    }
+
+}

+ 164 - 0
yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/handler/SubscribeHandler.java

@@ -0,0 +1,164 @@
+package cn.iocoder.yudao.module.wechatMp.handler;
+
+import cn.hutool.core.date.DateUtil;
+import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
+import cn.iocoder.yudao.module.wechatMp.builder.TextBuilder;
+import cn.iocoder.yudao.module.wechatMp.controller.admin.accountfans.vo.WxAccountFansCreateReqVO;
+import cn.iocoder.yudao.module.wechatMp.controller.admin.accountfans.vo.WxAccountFansUpdateReqVO;
+import cn.iocoder.yudao.module.wechatMp.dal.dataobject.account.WxAccountDO;
+import cn.iocoder.yudao.module.wechatMp.dal.dataobject.accountfans.WxAccountFansDO;
+import cn.iocoder.yudao.module.wechatMp.service.account.WxAccountService;
+import cn.iocoder.yudao.module.wechatMp.service.accountfans.WxAccountFansService;
+import lombok.extern.slf4j.Slf4j;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.session.WxSessionManager;
+import me.chanjar.weixin.mp.api.WxMpMessageHandler;
+import me.chanjar.weixin.mp.api.WxMpService;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
+import me.chanjar.weixin.mp.bean.result.WxMpUser;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.io.UnsupportedEncodingException;
+import java.util.Map;
+
+@Component
+@Slf4j
+public class SubscribeHandler implements WxMpMessageHandler {
+
+   /* @Autowired
+    private WxTextTemplateService wxTextTemplateService;
+
+    @Autowired
+    private WxAccountService wxAccountService;
+
+    @Autowired
+    private WxSubscribeTextService wxSubscribeTextService;
+
+    @Autowired
+    private WxAccountFansService wxAccountFansService;
+
+    @Autowired
+    private WxAccountFansTagService wxAccountFansTagService;*/
+
+    @Override
+    public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
+                                    Map<String, Object> context, WxMpService weixinService,
+                                    WxSessionManager sessionManager) throws WxErrorException {
+
+        log.info("新关注用户 OPENID: " + wxMessage.getFromUser());
+/*
+
+        // 获取微信用户基本信息
+        try {
+            WxMpUser wxmpUser = weixinService.getUserService()
+                    .userInfo(wxMessage.getFromUser(), null);
+            if (wxmpUser != null) {
+                // 可以添加关注用户到本地数据库
+                WxAccountDO wxAccount = wxAccountService.findBy(WxAccountDO::getAccount, wxMessage.getToUser());
+                if (wxAccount != null) {
+                    WxAccountFansDO wxAccountFans = wxAccountFansService.findBy(WxAccountFansDO::getOpenid, wxmpUser.getOpenId());
+                    if (wxAccountFans == null) {//insert
+                        WxAccountFansCreateReqVO wxAccountFansCreateReqVO = new WxAccountFansCreateReqVO();
+                        wxAccountFansCreateReqVO.setOpenid(wxmpUser.getOpenId());
+                        wxAccountFansCreateReqVO.setSubscribeStatus(wxmpUser.getSubscribe() ? "1" : "0");
+                        wxAccountFansCreateReqVO.setSubscribeTime(DateUtil.date(wxmpUser.getSubscribeTime() * 1000L));
+                        try {
+                            wxAccountFansCreateReqVO.setNickname(wxmpUser.getNickname().getBytes("UTF-8"));
+                        } catch (UnsupportedEncodingException e) {
+                            e.printStackTrace();
+                        }
+                        wxAccountFansCreateReqVO.setGender(String.valueOf(wxmpUser.getSex()));
+                        wxAccountFansCreateReqVO.setLanguage(wxmpUser.getLanguage());
+                        wxAccountFansCreateReqVO.setCountry(wxmpUser.getCountry());
+                        wxAccountFansCreateReqVO.setProvince(wxmpUser.getProvince());
+                        wxAccountFansCreateReqVO.setCity(wxmpUser.getCity());
+                        wxAccountFansCreateReqVO.setHeadimgUrl(wxmpUser.getHeadImgUrl());
+                        wxAccountFansCreateReqVO.setRemark(wxmpUser.getRemark());
+                        wxAccountFansCreateReqVO.setWxAccountId(String.valueOf(wxAccount.getId()));
+                        wxAccountFansCreateReqVO.setWxAccountAppid(wxAccount.getAppid());
+                        wxAccountFansService.createWxAccountFans(wxAccountFansCreateReqVO);
+
+                        //process tags
+                        wxAccountFansTagService.processFansTags(wxAccount, wxmpUser);
+
+                    } else {//update
+                        WxAccountFansUpdateReqVO wxAccountFansUpdateReqVO = new WxAccountFansUpdateReqVO();
+                        wxAccountFansUpdateReqVO.setId(wxAccountFans.getId());
+                        wxAccountFansUpdateReqVO.setOpenid(wxmpUser.getOpenId());
+                        wxAccountFansUpdateReqVO.setSubscribeStatus(wxmpUser.getSubscribe() ? "1" : "0");
+                        wxAccountFansUpdateReqVO.setSubscribeTime(DateUtil.date(wxmpUser.getSubscribeTime() * 1000L));
+                        try {
+                            wxAccountFans.setNickname(wxmpUser.getNickname().getBytes("UTF-8"));
+                        } catch (UnsupportedEncodingException e) {
+                            e.printStackTrace();
+                        }
+                        wxAccountFansUpdateReqVO.setGender(String.valueOf(wxmpUser.getSex()));
+                        wxAccountFansUpdateReqVO.setLanguage(wxmpUser.getLanguage());
+                        wxAccountFansUpdateReqVO.setCountry(wxmpUser.getCountry());
+                        wxAccountFansUpdateReqVO.setProvince(wxmpUser.getProvince());
+                        wxAccountFansUpdateReqVO.setCity(wxmpUser.getCity());
+                        wxAccountFansUpdateReqVO.setHeadimgUrl(wxmpUser.getHeadImgUrl());
+                        wxAccountFansUpdateReqVO.setRemark(wxmpUser.getRemark());
+                        wxAccountFansUpdateReqVO.setWxAccountId(String.valueOf(wxAccount.getId()));
+                        wxAccountFansUpdateReqVO.setWxAccountAppid(wxAccount.getAppid());
+                        wxAccountFansService.updateWxAccountFans(wxAccountFansUpdateReqVO);
+
+                        //process tags
+                        wxAccountFansTagService.processFansTags(wxAccount, wxmpUser);
+
+                    }
+                }
+
+            }
+        } catch (WxErrorException e) {
+            if (e.getError().getErrorCode() == 48001) {
+                log.info("该公众号没有获取用户信息权限!");
+            }
+        }
+
+
+        WxMpXmlOutMessage responseResult = null;
+        try {
+            responseResult = this.handleSpecial(wxMessage);
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+        }
+
+        if (responseResult != null) {
+            return responseResult;
+        }
+
+        try {
+            String content = "感谢关注!";//默认
+            WxAccountDO wxAccount = wxAccountService.findBy(WxAccountDO::getAccount, wxMessage.getToUser());
+            if (wxAccount != null) {
+                WxSubscribeText wxSubscribeText = wxSubscribeTextService.findBy("wxAccountId", String.valueOf(wxAccount.getId()));
+                if (wxSubscribeText != null) {
+                    WxTextTemplate wxTextTemplate = wxTextTemplateService.findById(Integer.parseInt(wxSubscribeText.getTplId()));
+                    if (wxTextTemplate != null) {
+                        content = wxTextTemplate.getContent();
+                    }
+                }
+            }
+            log.info("wxMessage : {}", JsonUtils.toJsonString(wxMessage));
+            return new TextBuilder().build(content, wxMessage, weixinService);
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+        }
+*/
+
+        return null;
+    }
+
+    /**
+     * 处理特殊请求,比如如果是扫码进来的,可以做相应处理
+     */
+    private WxMpXmlOutMessage handleSpecial(WxMpXmlMessage wxMessage)
+            throws Exception {
+        //TODO
+        return null;
+    }
+
+}

+ 54 - 0
yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/handler/UnsubscribeHandler.java

@@ -0,0 +1,54 @@
+package cn.iocoder.yudao.module.wechatMp.handler;
+
+import cn.hutool.core.date.DateUtil;
+import cn.iocoder.yudao.module.wechatMp.controller.admin.accountfans.vo.WxAccountFansUpdateReqVO;
+import cn.iocoder.yudao.module.wechatMp.dal.dataobject.account.WxAccountDO;
+import cn.iocoder.yudao.module.wechatMp.dal.dataobject.accountfans.WxAccountFansDO;
+import cn.iocoder.yudao.module.wechatMp.service.account.WxAccountService;
+import cn.iocoder.yudao.module.wechatMp.service.accountfans.WxAccountFansService;
+import lombok.extern.slf4j.Slf4j;
+import me.chanjar.weixin.common.session.WxSessionManager;
+import me.chanjar.weixin.mp.api.WxMpMessageHandler;
+import me.chanjar.weixin.mp.api.WxMpService;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
+import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+@Component
+@Slf4j
+public class UnsubscribeHandler implements WxMpMessageHandler {
+
+    @Autowired
+    private WxAccountService wxAccountService;
+
+    @Autowired
+    private WxAccountFansService wxAccountFansService;
+
+    @Override
+    public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
+                                    Map<String, Object> context, WxMpService wxMpService,
+                                    WxSessionManager sessionManager) {
+        String openId = wxMessage.getFromUser();
+        log.info("取消关注用户 OPENID: " + openId);
+        // TODO 可以更新本地数据库为取消关注状态
+
+        WxAccountDO wxAccountDO = wxAccountService.findBy(WxAccountDO::getAccount, wxMessage.getToUser());
+        if (wxAccountDO != null) {
+            WxAccountFansDO wxAccountFansDO = wxAccountFansService.findBy(WxAccountFansDO::getOpenid, openId);
+            if (wxAccountFansDO != null) {
+                WxAccountFansUpdateReqVO wxAccountFansUpdateReqVO = new WxAccountFansUpdateReqVO();
+                wxAccountFansUpdateReqVO.setId(wxAccountDO.getId());
+                wxAccountFansDO.setSubscribeStatus("0");//取消订阅
+                wxAccountFansService.updateWxAccountFans(wxAccountFansUpdateReqVO);
+            }
+        }
+
+
+        return null;
+    }
+
+}

+ 29 - 0
yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/mq/costomer/dict/WxConfigDataRefreshConsumer.java

@@ -0,0 +1,29 @@
+package cn.iocoder.yudao.module.wechatMp.mq.costomer.dict;
+
+import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener;
+import cn.iocoder.yudao.module.wechatMp.config.WxMpConfig;
+import cn.iocoder.yudao.module.wechatMp.mq.message.dict.WxConfigDataRefreshMessage;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+
+/**
+ * 针对 {@link WxConfigDataRefreshMessage} 的消费者
+ *
+ * @author lyz
+ */
+@Component
+@Slf4j
+public class WxConfigDataRefreshConsumer extends AbstractChannelMessageListener<WxConfigDataRefreshMessage> {
+
+    @Resource
+    private WxMpConfig wxMpConfig;
+
+    @Override
+    public void onMessage(WxConfigDataRefreshMessage message) {
+        log.info("[onMessage][收到 WxConfigData 刷新消息]");
+        wxMpConfig.initWxConfig();
+    }
+
+}

+ 19 - 0
yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/mq/message/dict/WxConfigDataRefreshMessage.java

@@ -0,0 +1,19 @@
+package cn.iocoder.yudao.module.wechatMp.mq.message.dict;
+
+import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessage;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 微信配置数据刷新 Message
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class WxConfigDataRefreshMessage extends AbstractChannelMessage {
+
+    @Override
+    public String getChannel() {
+        return "wechat-mp.wx-config-data.refresh";
+    }
+
+}

+ 26 - 0
yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/mq/producer/dict/WxMpConfigDataProducer.java

@@ -0,0 +1,26 @@
+package cn.iocoder.yudao.module.wechatMp.mq.producer.dict;
+
+import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate;
+import cn.iocoder.yudao.module.wechatMp.mq.message.dict.WxConfigDataRefreshMessage;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+
+/**
+ * 微信配置数据相关消息的 Producer
+ */
+@Component
+public class WxMpConfigDataProducer {
+
+    @Resource
+    private RedisMQTemplate redisMQTemplate;
+
+    /**
+     * 发送 {@link WxConfigDataRefreshMessage} 消息
+     */
+    public void sendDictDataRefreshMessage() {
+        WxConfigDataRefreshMessage message = new WxConfigDataRefreshMessage();
+        redisMQTemplate.send(message);
+    }
+
+}

+ 80 - 0
yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/service/account/WxAccountService.java

@@ -0,0 +1,80 @@
+package cn.iocoder.yudao.module.wechatMp.service.account;
+
+import java.util.*;
+import javax.validation.*;
+
+import cn.iocoder.yudao.module.wechatMp.controller.admin.account.vo.*;
+import cn.iocoder.yudao.module.wechatMp.dal.dataobject.account.WxAccountDO;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
+
+/**
+ * 公众号账户 Service 接口
+ *
+ * @author 芋道源码
+ */
+public interface WxAccountService {
+
+    /**
+     * 创建公众号账户
+     *
+     * @param createReqVO 创建信息
+     * @return 编号
+     */
+    Long createWxAccount(@Valid WxAccountCreateReqVO createReqVO);
+
+    /**
+     * 更新公众号账户
+     *
+     * @param updateReqVO 更新信息
+     */
+    void updateWxAccount(@Valid WxAccountUpdateReqVO updateReqVO);
+
+    /**
+     * 删除公众号账户
+     *
+     * @param id 编号
+     */
+    void deleteWxAccount(Long id);
+
+    /**
+     * 获得公众号账户
+     *
+     * @param id 编号
+     * @return 公众号账户
+     */
+    WxAccountDO getWxAccount(Long id);
+
+    /**
+     * 获得公众号账户列表
+     *
+     * @param ids 编号
+     * @return 公众号账户列表
+     */
+    List<WxAccountDO> getWxAccountList(Collection<Long> ids);
+
+    /**
+     * 获得公众号账户分页
+     *
+     * @param pageReqVO 分页查询
+     * @return 公众号账户分页
+     */
+    PageResult<WxAccountDO> getWxAccountPage(WxAccountPageReqVO pageReqVO);
+
+    /**
+     * 获得公众号账户列表, 用于 Excel 导出
+     *
+     * @param exportReqVO 查询条件
+     * @return 公众号账户列表
+     */
+    List<WxAccountDO> getWxAccountList(WxAccountExportReqVO exportReqVO);
+
+    /**
+     * 查询账户
+     *
+     * @param field
+     * @param val
+     * @return
+     */
+    WxAccountDO findBy(SFunction<WxAccountDO,?> field, Object val);
+}

+ 97 - 0
yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/service/account/WxAccountServiceImpl.java

@@ -0,0 +1,97 @@
+package cn.iocoder.yudao.module.wechatMp.service.account;
+
+import cn.iocoder.yudao.module.wechatMp.mq.producer.dict.WxMpConfigDataProducer;
+import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+
+import org.springframework.validation.annotation.Validated;
+
+import java.util.*;
+
+import cn.iocoder.yudao.module.wechatMp.controller.admin.account.vo.*;
+import cn.iocoder.yudao.module.wechatMp.dal.dataobject.account.WxAccountDO;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+
+import cn.iocoder.yudao.module.wechatMp.convert.account.WxAccountConvert;
+import cn.iocoder.yudao.module.wechatMp.dal.mysql.account.WxAccountMapper;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.wechatMp.enums.ErrorCodeConstants.*;
+
+/**
+ * 公众号账户 Service 实现类
+ *
+ * @author 芋道源码
+ */
+@Service
+@Validated
+public class WxAccountServiceImpl implements WxAccountService {
+
+    @Resource
+    private WxAccountMapper wxAccountMapper;
+
+    @Resource
+    private WxMpConfigDataProducer wxMpConfigDataProducer;
+
+    @Override
+    public Long createWxAccount(WxAccountCreateReqVO createReqVO) {
+        // 插入
+        WxAccountDO wxAccount = WxAccountConvert.INSTANCE.convert(createReqVO);
+        wxAccountMapper.insert(wxAccount);
+        wxMpConfigDataProducer.sendDictDataRefreshMessage();
+        // 返回
+        return wxAccount.getId();
+    }
+
+    @Override
+    public void updateWxAccount(WxAccountUpdateReqVO updateReqVO) {
+        // 校验存在
+        this.validateWxAccountExists(updateReqVO.getId());
+        // 更新
+        WxAccountDO updateObj = WxAccountConvert.INSTANCE.convert(updateReqVO);
+        wxAccountMapper.updateById(updateObj);
+        wxMpConfigDataProducer.sendDictDataRefreshMessage();
+    }
+
+    @Override
+    public void deleteWxAccount(Long id) {
+        // 校验存在
+        this.validateWxAccountExists(id);
+        // 删除
+        wxAccountMapper.deleteById(id);
+        wxMpConfigDataProducer.sendDictDataRefreshMessage();
+    }
+
+    private void validateWxAccountExists(Long id) {
+        if (wxAccountMapper.selectById(id) == null) {
+            throw exception(WX_ACCOUNT_NOT_EXISTS);
+        }
+    }
+
+    @Override
+    public WxAccountDO getWxAccount(Long id) {
+        return wxAccountMapper.selectById(id);
+    }
+
+    @Override
+    public List<WxAccountDO> getWxAccountList(Collection<Long> ids) {
+        return wxAccountMapper.selectBatchIds(ids);
+    }
+
+    @Override
+    public PageResult<WxAccountDO> getWxAccountPage(WxAccountPageReqVO pageReqVO) {
+        return wxAccountMapper.selectPage(pageReqVO);
+    }
+
+    @Override
+    public List<WxAccountDO> getWxAccountList(WxAccountExportReqVO exportReqVO) {
+        return wxAccountMapper.selectList(exportReqVO);
+    }
+
+    @Override
+    public WxAccountDO findBy(SFunction<WxAccountDO, ?> field, Object val) {
+        return wxAccountMapper.selectOne(field, val);
+    }
+}

+ 81 - 0
yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/service/accountfans/WxAccountFansService.java

@@ -0,0 +1,81 @@
+package cn.iocoder.yudao.module.wechatMp.service.accountfans;
+
+import java.util.*;
+import javax.validation.*;
+
+import cn.iocoder.yudao.module.wechatMp.controller.admin.accountfans.vo.*;
+import cn.iocoder.yudao.module.wechatMp.dal.dataobject.account.WxAccountDO;
+import cn.iocoder.yudao.module.wechatMp.dal.dataobject.accountfans.WxAccountFansDO;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
+
+/**
+ * 微信公众号粉丝 Service 接口
+ *
+ * @author 芋道源码
+ */
+public interface WxAccountFansService {
+
+    /**
+     * 创建微信公众号粉丝
+     *
+     * @param createReqVO 创建信息
+     * @return 编号
+     */
+    Long createWxAccountFans(@Valid WxAccountFansCreateReqVO createReqVO);
+
+    /**
+     * 更新微信公众号粉丝
+     *
+     * @param updateReqVO 更新信息
+     */
+    void updateWxAccountFans(@Valid WxAccountFansUpdateReqVO updateReqVO);
+
+    /**
+     * 删除微信公众号粉丝
+     *
+     * @param id 编号
+     */
+    void deleteWxAccountFans(Long id);
+
+    /**
+     * 获得微信公众号粉丝
+     *
+     * @param id 编号
+     * @return 微信公众号粉丝
+     */
+    WxAccountFansDO getWxAccountFans(Long id);
+
+    /**
+     * 获得微信公众号粉丝列表
+     *
+     * @param ids 编号
+     * @return 微信公众号粉丝列表
+     */
+    List<WxAccountFansDO> getWxAccountFansList(Collection<Long> ids);
+
+    /**
+     * 获得微信公众号粉丝分页
+     *
+     * @param pageReqVO 分页查询
+     * @return 微信公众号粉丝分页
+     */
+    PageResult<WxAccountFansDO> getWxAccountFansPage(WxAccountFansPageReqVO pageReqVO);
+
+    /**
+     * 获得微信公众号粉丝列表, 用于 Excel 导出
+     *
+     * @param exportReqVO 查询条件
+     * @return 微信公众号粉丝列表
+     */
+    List<WxAccountFansDO> getWxAccountFansList(WxAccountFansExportReqVO exportReqVO);
+
+    /**
+     * 查询粉丝
+     *
+     * @param sFunction
+     * @param val
+     * @return
+     */
+    WxAccountFansDO findBy(SFunction<WxAccountFansDO, ?> sFunction, Object val);
+}

+ 90 - 0
yudao-module-wechat-mp/yudao-module-wechat-mp-biz/src/main/java/cn/iocoder/yudao/module/wechatMp/service/accountfans/WxAccountFansServiceImpl.java

@@ -0,0 +1,90 @@
+package cn.iocoder.yudao.module.wechatMp.service.accountfans;
+
+import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+
+import org.springframework.validation.annotation.Validated;
+
+import java.util.*;
+
+import cn.iocoder.yudao.module.wechatMp.controller.admin.accountfans.vo.*;
+import cn.iocoder.yudao.module.wechatMp.dal.dataobject.accountfans.WxAccountFansDO;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+
+import cn.iocoder.yudao.module.wechatMp.convert.accountfans.WxAccountFansConvert;
+import cn.iocoder.yudao.module.wechatMp.dal.mysql.accountfans.WxAccountFansMapper;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.wechatMp.enums.ErrorCodeConstants.*;
+
+/**
+ * 微信公众号粉丝 Service 实现类
+ *
+ * @author 芋道源码
+ */
+@Service
+@Validated
+public class WxAccountFansServiceImpl implements WxAccountFansService {
+
+    @Resource
+    private WxAccountFansMapper wxAccountFansMapper;
+
+    @Override
+    public Long createWxAccountFans(WxAccountFansCreateReqVO createReqVO) {
+        // 插入
+        WxAccountFansDO wxAccountFans = WxAccountFansConvert.INSTANCE.convert(createReqVO);
+        wxAccountFansMapper.insert(wxAccountFans);
+        // 返回
+        return wxAccountFans.getId();
+    }
+
+    @Override
+    public void updateWxAccountFans(WxAccountFansUpdateReqVO updateReqVO) {
+        // 校验存在
+        this.validateWxAccountFansExists(updateReqVO.getId());
+        // 更新
+        WxAccountFansDO updateObj = WxAccountFansConvert.INSTANCE.convert(updateReqVO);
+        wxAccountFansMapper.updateById(updateObj);
+    }
+
+    @Override
+    public void deleteWxAccountFans(Long id) {
+        // 校验存在
+        this.validateWxAccountFansExists(id);
+        // 删除
+        wxAccountFansMapper.deleteById(id);
+    }
+
+    private void validateWxAccountFansExists(Long id) {
+        if (wxAccountFansMapper.selectById(id) == null) {
+            throw exception(WX_ACCOUNT_FANS_NOT_EXISTS);
+        }
+    }
+
+    @Override
+    public WxAccountFansDO getWxAccountFans(Long id) {
+        return wxAccountFansMapper.selectById(id);
+    }
+
+    @Override
+    public List<WxAccountFansDO> getWxAccountFansList(Collection<Long> ids) {
+        return wxAccountFansMapper.selectBatchIds(ids);
+    }
+
+    @Override
+    public PageResult<WxAccountFansDO> getWxAccountFansPage(WxAccountFansPageReqVO pageReqVO) {
+        return wxAccountFansMapper.selectPage(pageReqVO);
+    }
+
+    @Override
+    public List<WxAccountFansDO> getWxAccountFansList(WxAccountFansExportReqVO exportReqVO) {
+        return wxAccountFansMapper.selectList(exportReqVO);
+    }
+
+    @Override
+    public WxAccountFansDO findBy(SFunction<WxAccountFansDO, ?> sFunction, Object val) {
+        return wxAccountFansMapper.selectOne(sFunction, val);
+    }
+}

+ 7 - 0
yudao-server/pom.xml

@@ -47,6 +47,7 @@
             <artifactId>yudao-module-bpm-biz-flowable</artifactId>
             <version>${revision}</version>
         </dependency>
+
 <!--        <dependency>-->
 <!--            <groupId>cn.iocoder.boot</groupId>-->
 <!--            <artifactId>yudao-module-bpm-biz-activiti</artifactId>-->
@@ -59,6 +60,12 @@
             <artifactId>spring-boot-configuration-processor</artifactId>
             <optional>true</optional>
         </dependency>
+        <!-- 微信公众号 -->
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-module-wechat-mp-biz</artifactId>
+            <version>${revision}</version>
+        </dependency>
 
         <!-- 服务保障相关 -->
         <dependency>

Datei-Diff unterdrückt, da er zu groß ist
+ 1 - 1
yudao-server/src/main/resources/admin-ui/libs/monaco-editor/vs/language/html/htmlMode.js


Datei-Diff unterdrückt, da er zu groß ist
+ 1 - 1
yudao-server/src/main/resources/admin-ui/libs/monaco-editor/vs/language/html/htmlWorker.js


Datei-Diff unterdrückt, da er zu groß ist
+ 1 - 1
yudao-server/src/main/resources/admin-ui/libs/monaco-editor/vs/language/typescript/tsWorker.js


Datei-Diff unterdrückt, da er zu groß ist
+ 5 - 5
yudao-server/src/main/resources/admin-ui/static/js/4.js


Datei-Diff unterdrückt, da er zu groß ist
+ 3 - 3
yudao-server/src/main/resources/admin-ui/static/js/chunk-vendors.js


Datei-Diff unterdrückt, da er zu groß ist
+ 1 - 1
yudao-ui-admin/public/libs/monaco-editor/vs/language/html/htmlMode.js


Datei-Diff unterdrückt, da er zu groß ist
+ 1 - 1
yudao-ui-admin/public/libs/monaco-editor/vs/language/html/htmlWorker.js


Datei-Diff unterdrückt, da er zu groß ist
+ 1 - 1
yudao-ui-admin/public/libs/monaco-editor/vs/language/typescript/tsWorker.js


+ 54 - 0
yudao-ui-admin/src/api/wechatMp/wxAccount.js

@@ -0,0 +1,54 @@
+import request from '@/utils/request'
+
+// 创建公众号账户
+export function createWxAccount(data) {
+  return request({
+    url: '/wechatMp/wx-account/create',
+    method: 'post',
+    data: data
+  })
+}
+
+// 更新公众号账户
+export function updateWxAccount(data) {
+  return request({
+    url: '/wechatMp/wx-account/update',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除公众号账户
+export function deleteWxAccount(id) {
+  return request({
+    url: '/wechatMp/wx-account/delete?id=' + id,
+    method: 'delete'
+  })
+}
+
+// 获得公众号账户
+export function getWxAccount(id) {
+  return request({
+    url: '/wechatMp/wx-account/get?id=' + id,
+    method: 'get'
+  })
+}
+
+// 获得公众号账户分页
+export function getWxAccountPage(query) {
+  return request({
+    url: '/wechatMp/wx-account/page',
+    method: 'get',
+    params: query
+  })
+}
+
+// 导出公众号账户 Excel
+export function exportWxAccountExcel(query) {
+  return request({
+    url: '/wechatMp/wx-account/export-excel',
+    method: 'get',
+    params: query,
+    responseType: 'blob'
+  })
+}

+ 54 - 0
yudao-ui-admin/src/api/wechatMp/wxAccountFans.js

@@ -0,0 +1,54 @@
+import request from '@/utils/request'
+
+// 创建微信公众号粉丝
+export function createWxAccountFans(data) {
+  return request({
+    url: '/wechatMp/wx-account-fans/create',
+    method: 'post',
+    data: data
+  })
+}
+
+// 更新微信公众号粉丝
+export function updateWxAccountFans(data) {
+  return request({
+    url: '/wechatMp/wx-account-fans/update',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除微信公众号粉丝
+export function deleteWxAccountFans(id) {
+  return request({
+    url: '/wechatMp/wx-account-fans/delete?id=' + id,
+    method: 'delete'
+  })
+}
+
+// 获得微信公众号粉丝
+export function getWxAccountFans(id) {
+  return request({
+    url: '/wechatMp/wx-account-fans/get?id=' + id,
+    method: 'get'
+  })
+}
+
+// 获得微信公众号粉丝分页
+export function getWxAccountFansPage(query) {
+  return request({
+    url: '/wechatMp/wx-account-fans/page',
+    method: 'get',
+    params: query
+  })
+}
+
+// 导出微信公众号粉丝 Excel
+export function exportWxAccountFansExcel(query) {
+  return request({
+    url: '/wechatMp/wx-account-fans/export-excel',
+    method: 'get',
+    params: query,
+    responseType: 'blob'
+  })
+}

+ 254 - 0
yudao-ui-admin/src/views/wechatMp/wxAccount/index.vue

@@ -0,0 +1,254 @@
+<template>
+  <div class="app-container">
+
+    <!-- 搜索工作栏 -->
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="公众号名称" prop="name">
+        <el-input v-model="queryParams.name" placeholder="请输入公众号名称" clearable @keyup.enter.native="handleQuery"/>
+      </el-form-item>
+      <el-form-item label="公众号账户" prop="account">
+        <el-input v-model="queryParams.account" placeholder="请输入公众号账户" clearable @keyup.enter.native="handleQuery"/>
+      </el-form-item>
+      <el-form-item label="公众号appid" prop="appid">
+        <el-input v-model="queryParams.appid" placeholder="请输入公众号appid" clearable @keyup.enter.native="handleQuery"/>
+      </el-form-item>
+      <el-form-item label="创建时间">
+        <el-date-picker v-model="dateRangeCreateTime" style="width: 240px" value-format="yyyy-MM-dd"
+                        type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <!-- 操作工具栏 -->
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
+                   v-hasPermi="['wechatMp:wx-account:create']">新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport" :loading="exportLoading"
+                   v-hasPermi="['wechatMp:wx-account:export']">导出</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <!-- 列表 -->
+    <el-table v-loading="loading" :data="list">
+      <el-table-column label="编号" align="center" prop="id" />
+      <el-table-column label="公众号名称" align="center" prop="name" />
+      <el-table-column label="公众号账户" align="center" prop="account" />
+      <el-table-column label="公众号appid" align="center" prop="appid" />
+      <el-table-column label="公众号密钥" align="center" prop="appsecret" />
+      <el-table-column label="公众号url" align="center" prop="url" />
+      <el-table-column label="公众号token" align="center" prop="token" />
+      <el-table-column label="加密密钥" align="center" prop="aeskey" />
+      <el-table-column label="二维码图片URL" align="center" prop="qrUrl" />
+      <el-table-column label="备注" align="center" prop="remark" />
+      <el-table-column label="创建时间" align="center" prop="createTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.createTime) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
+                     v-hasPermi="['wechatMp:wx-account:update']">修改</el-button>
+          <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
+                     v-hasPermi="['wechatMp:wx-account:delete']">删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 分页组件 -->
+    <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
+                @pagination="getList"/>
+
+    <!-- 对话框(添加 / 修改) -->
+    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="公众号名称" prop="name">
+          <el-input v-model="form.name" placeholder="请输入公众号名称" />
+        </el-form-item>
+        <el-form-item label="公众号账户" prop="account">
+          <el-input v-model="form.account" placeholder="请输入公众号账户" />
+        </el-form-item>
+        <el-form-item label="公众号appid" prop="appid">
+          <el-input v-model="form.appid" placeholder="请输入公众号appid" />
+        </el-form-item>
+        <el-form-item label="公众号密钥" prop="appsecret">
+          <el-input v-model="form.appsecret" placeholder="请输入公众号密钥" />
+        </el-form-item>
+        <el-form-item label="公众号token" prop="token">
+          <el-input v-model="form.token" placeholder="请输入公众号token" />
+        </el-form-item>
+        <el-form-item label="加密密钥" prop="aeskey">
+          <el-input v-model="form.aeskey" placeholder="请输入加密密钥" />
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+          <el-input v-model="form.remark" placeholder="请输入备注" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { createWxAccount, updateWxAccount, deleteWxAccount, getWxAccount, getWxAccountPage, exportWxAccountExcel } from "@/api/wechatMp/wxAccount";
+
+export default {
+  name: "WxAccount",
+  components: {
+  },
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 公众号账户列表
+      list: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      dateRangeCreateTime: [],
+      // 查询参数
+      queryParams: {
+        pageNo: 1,
+        pageSize: 10,
+        name: null,
+        account: null,
+        appid: null,
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 查询列表 */
+    getList() {
+      this.loading = true;
+      // 处理查询参数
+      let params = {...this.queryParams};
+      this.addBeginAndEndTime(params, this.dateRangeCreateTime, 'createTime');
+      // 执行查询
+      getWxAccountPage(params).then(response => {
+        this.list = response.data.list;
+        this.total = response.data.total;
+        this.loading = false;
+      });
+    },
+    /** 取消按钮 */
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    /** 表单重置 */
+    reset() {
+      this.form = {
+        id: undefined,
+        name: undefined,
+        account: undefined,
+        appid: undefined,
+        appsecret: undefined,
+        token: undefined,
+        aeskey: undefined,
+        remark: undefined,
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNo = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.dateRangeCreateTime = [];
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加公众号账户";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id;
+      getWxAccount(id).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改公众号账户";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (!valid) {
+          return;
+        }
+        // 修改的提交
+        if (this.form.id != null) {
+          updateWxAccount(this.form).then(response => {
+            this.$modal.msgSuccess("修改成功");
+            this.open = false;
+            this.getList();
+          });
+          return;
+        }
+        // 添加的提交
+        createWxAccount(this.form).then(response => {
+          this.$modal.msgSuccess("新增成功");
+          this.open = false;
+          this.getList();
+        });
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const id = row.id;
+      this.$modal.confirm('是否确认删除公众号账户编号为"' + id + '"的数据项?').then(function() {
+          return deleteWxAccount(id);
+        }).then(() => {
+          this.getList();
+          this.$modal.msgSuccess("删除成功");
+        }).catch(() => {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      // 处理查询参数
+      let params = {...this.queryParams};
+      params.pageNo = undefined;
+      params.pageSize = undefined;
+      this.addBeginAndEndTime(params, this.dateRangeCreateTime, 'createTime');
+      // 执行导出
+      this.$modal.confirm('是否确认导出所有公众号账户数据项?').then(() => {
+          this.exportLoading = true;
+          return exportWxAccountExcel(params);
+        }).then(response => {
+          this.$download.excel(response, '公众号账户.xls');
+          this.exportLoading = false;
+        }).catch(() => {});
+    }
+  }
+};
+</script>

+ 334 - 0
yudao-ui-admin/src/views/wechatMp/wxAccountFans/index.vue

@@ -0,0 +1,334 @@
+<template>
+  <div class="app-container">
+
+    <!-- 搜索工作栏 -->
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="用户标识" prop="openid">
+        <el-input v-model="queryParams.openid" placeholder="请输入用户标识" clearable @keyup.enter.native="handleQuery"/>
+      </el-form-item>
+      <el-form-item label="订阅状态,0未关注,1已关注" prop="subscribeStatus">
+        <el-select v-model="queryParams.subscribeStatus" placeholder="请选择订阅状态,0未关注,1已关注" clearable size="small">
+          <el-option label="请选择字典生成" value="" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="订阅时间">
+        <el-date-picker v-model="dateRangeSubscribeTime" style="width: 240px" value-format="yyyy-MM-dd"
+                        type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" />
+      </el-form-item>
+      <el-form-item label="昵称" prop="nickname">
+        <el-input v-model="queryParams.nickname" placeholder="请输入昵称" clearable @keyup.enter.native="handleQuery"/>
+      </el-form-item>
+      <el-form-item label="性别,1男,2女,0未知" prop="gender">
+        <el-input v-model="queryParams.gender" placeholder="请输入性别,1男,2女,0未知" clearable @keyup.enter.native="handleQuery"/>
+      </el-form-item>
+      <el-form-item label="语言" prop="language">
+        <el-input v-model="queryParams.language" placeholder="请输入语言" clearable @keyup.enter.native="handleQuery"/>
+      </el-form-item>
+      <el-form-item label="国家" prop="country">
+        <el-input v-model="queryParams.country" placeholder="请输入国家" clearable @keyup.enter.native="handleQuery"/>
+      </el-form-item>
+      <el-form-item label="省份" prop="province">
+        <el-input v-model="queryParams.province" placeholder="请输入省份" clearable @keyup.enter.native="handleQuery"/>
+      </el-form-item>
+      <el-form-item label="城市" prop="city">
+        <el-input v-model="queryParams.city" placeholder="请输入城市" clearable @keyup.enter.native="handleQuery"/>
+      </el-form-item>
+      <el-form-item label="头像地址" prop="headimgUrl">
+        <el-input v-model="queryParams.headimgUrl" placeholder="请输入头像地址" clearable @keyup.enter.native="handleQuery"/>
+      </el-form-item>
+      <el-form-item label="备注" prop="remark">
+        <el-input v-model="queryParams.remark" placeholder="请输入备注" clearable @keyup.enter.native="handleQuery"/>
+      </el-form-item>
+      <el-form-item label="微信公众号ID" prop="wxAccountId">
+        <el-input v-model="queryParams.wxAccountId" placeholder="请输入微信公众号ID" clearable @keyup.enter.native="handleQuery"/>
+      </el-form-item>
+      <el-form-item label="微信公众号appid" prop="wxAccountAppid">
+        <el-input v-model="queryParams.wxAccountAppid" placeholder="请输入微信公众号appid" clearable @keyup.enter.native="handleQuery"/>
+      </el-form-item>
+      <el-form-item label="创建时间">
+        <el-date-picker v-model="dateRangeCreateTime" style="width: 240px" value-format="yyyy-MM-dd"
+                        type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <!-- 操作工具栏 -->
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
+                   v-hasPermi="['wechatMp:wx-account-fans:create']">新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport" :loading="exportLoading"
+                   v-hasPermi="['wechatMp:wx-account-fans:export']">导出</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <!-- 列表 -->
+    <el-table v-loading="loading" :data="list">
+      <el-table-column label="编号" align="center" prop="id" />
+      <el-table-column label="用户标识" align="center" prop="openid" />
+      <el-table-column label="订阅状态,0未关注,1已关注" align="center" prop="subscribeStatus" />
+      <el-table-column label="订阅时间" align="center" prop="subscribeTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.subscribeTime) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="昵称" align="center" prop="nickname" />
+      <el-table-column label="性别,1男,2女,0未知" align="center" prop="gender" />
+      <el-table-column label="语言" align="center" prop="language" />
+      <el-table-column label="国家" align="center" prop="country" />
+      <el-table-column label="省份" align="center" prop="province" />
+      <el-table-column label="城市" align="center" prop="city" />
+      <el-table-column label="头像地址" align="center" prop="headimgUrl" />
+      <el-table-column label="备注" align="center" prop="remark" />
+      <el-table-column label="微信公众号ID" align="center" prop="wxAccountId" />
+      <el-table-column label="微信公众号appid" align="center" prop="wxAccountAppid" />
+      <el-table-column label="创建时间" align="center" prop="createTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.createTime) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
+                     v-hasPermi="['wechatMp:wx-account-fans:update']">修改</el-button>
+          <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
+                     v-hasPermi="['wechatMp:wx-account-fans:delete']">删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 分页组件 -->
+    <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
+                @pagination="getList"/>
+
+    <!-- 对话框(添加 / 修改) -->
+    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="用户标识" prop="openid">
+          <el-input v-model="form.openid" placeholder="请输入用户标识" />
+        </el-form-item>
+        <el-form-item label="订阅状态,0未关注,1已关注" prop="subscribeStatus">
+          <el-radio-group v-model="form.subscribeStatus">
+            <el-radio label="1">请选择字典生成</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="订阅时间" prop="subscribeTime">
+          <el-date-picker clearable v-model="form.subscribeTime" type="date" value-format="timestamp" placeholder="选择订阅时间" />
+        </el-form-item>
+        <el-form-item label="昵称" prop="nickname">
+          <el-input v-model="form.nickname" placeholder="请输入昵称" />
+        </el-form-item>
+        <el-form-item label="性别,1男,2女,0未知" prop="gender">
+          <el-input v-model="form.gender" placeholder="请输入性别,1男,2女,0未知" />
+        </el-form-item>
+        <el-form-item label="语言" prop="language">
+          <el-input v-model="form.language" placeholder="请输入语言" />
+        </el-form-item>
+        <el-form-item label="国家" prop="country">
+          <el-input v-model="form.country" placeholder="请输入国家" />
+        </el-form-item>
+        <el-form-item label="省份" prop="province">
+          <el-input v-model="form.province" placeholder="请输入省份" />
+        </el-form-item>
+        <el-form-item label="城市" prop="city">
+          <el-input v-model="form.city" placeholder="请输入城市" />
+        </el-form-item>
+        <el-form-item label="头像地址" prop="headimgUrl">
+          <el-input v-model="form.headimgUrl" placeholder="请输入头像地址" />
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+          <el-input v-model="form.remark" placeholder="请输入备注" />
+        </el-form-item>
+        <el-form-item label="微信公众号ID" prop="wxAccountId">
+          <el-input v-model="form.wxAccountId" placeholder="请输入微信公众号ID" />
+        </el-form-item>
+        <el-form-item label="微信公众号appid" prop="wxAccountAppid">
+          <el-input v-model="form.wxAccountAppid" placeholder="请输入微信公众号appid" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { createWxAccountFans, updateWxAccountFans, deleteWxAccountFans, getWxAccountFans, getWxAccountFansPage, exportWxAccountFansExcel } from "@/api/wechatMp/wxAccountFans";
+
+export default {
+  name: "WxAccountFans",
+  components: {
+  },
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 导出遮罩层
+      exportLoading: false,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 微信公众号粉丝列表
+      list: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      dateRangeSubscribeTime: [],
+      dateRangeCreateTime: [],
+      // 查询参数
+      queryParams: {
+        pageNo: 1,
+        pageSize: 10,
+        openid: null,
+        subscribeStatus: null,
+        nickname: null,
+        gender: null,
+        language: null,
+        country: null,
+        province: null,
+        city: null,
+        headimgUrl: null,
+        remark: null,
+        wxAccountId: null,
+        wxAccountAppid: null,
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 查询列表 */
+    getList() {
+      this.loading = true;
+      // 处理查询参数
+      let params = {...this.queryParams};
+      this.addBeginAndEndTime(params, this.dateRangeSubscribeTime, 'subscribeTime');
+      this.addBeginAndEndTime(params, this.dateRangeCreateTime, 'createTime');
+      // 执行查询
+      getWxAccountFansPage(params).then(response => {
+        this.list = response.data.list;
+        this.total = response.data.total;
+        this.loading = false;
+      });
+    },
+    /** 取消按钮 */
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    /** 表单重置 */
+    reset() {
+      this.form = {
+        id: undefined,
+        openid: undefined,
+        subscribeStatus: undefined,
+        subscribeTime: undefined,
+        nickname: undefined,
+        gender: undefined,
+        language: undefined,
+        country: undefined,
+        province: undefined,
+        city: undefined,
+        headimgUrl: undefined,
+        remark: undefined,
+        wxAccountId: undefined,
+        wxAccountAppid: undefined,
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNo = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.dateRangeSubscribeTime = [];
+      this.dateRangeCreateTime = [];
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加微信公众号粉丝";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id;
+      getWxAccountFans(id).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改微信公众号粉丝";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (!valid) {
+          return;
+        }
+        // 修改的提交
+        if (this.form.id != null) {
+          updateWxAccountFans(this.form).then(response => {
+            this.$modal.msgSuccess("修改成功");
+            this.open = false;
+            this.getList();
+          });
+          return;
+        }
+        // 添加的提交
+        createWxAccountFans(this.form).then(response => {
+          this.$modal.msgSuccess("新增成功");
+          this.open = false;
+          this.getList();
+        });
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const id = row.id;
+      this.$modal.confirm('是否确认删除微信公众号粉丝编号为"' + id + '"的数据项?').then(function() {
+          return deleteWxAccountFans(id);
+        }).then(() => {
+          this.getList();
+          this.$modal.msgSuccess("删除成功");
+        }).catch(() => {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      // 处理查询参数
+      let params = {...this.queryParams};
+      params.pageNo = undefined;
+      params.pageSize = undefined;
+      this.addBeginAndEndTime(params, this.dateRangeSubscribeTime, 'subscribeTime');
+      this.addBeginAndEndTime(params, this.dateRangeCreateTime, 'createTime');
+      // 执行导出
+      this.$modal.confirm('是否确认导出所有微信公众号粉丝数据项?').then(() => {
+          this.exportLoading = true;
+          return exportWxAccountFansExcel(params);
+        }).then(response => {
+          this.$download.excel(response, '微信公众号粉丝.xls');
+          this.exportLoading = false;
+        }).catch(() => {});
+    }
+  }
+};
+</script>

Datei-Diff unterdrückt, da er zu groß ist
+ 9168 - 9622
yudao-ui-admin/yarn.lock