diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..186ea45ad2f6d1e937ec214b5c8c6c6d81baf90c --- /dev/null +++ b/.gitignore @@ -0,0 +1,21 @@ +target +bak +.pmd +.project +.settings +.classpath +.idea.xml +.idea +*.class +*.bak +*.iml +*.ipr +*.iws +bak +null/ +tree.log +tmp/ +velocity.log +.DS_Store +logs +.m2 diff --git a/.mvn/wrapper/MavenWrapperDownloader.java b/.mvn/wrapper/MavenWrapperDownloader.java new file mode 100644 index 0000000000000000000000000000000000000000..b901097f2db6e50097dc0b222204a88f8cea1609 --- /dev/null +++ b/.mvn/wrapper/MavenWrapperDownloader.java @@ -0,0 +1,117 @@ +/* + * Copyright 2007-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import java.net.*; +import java.io.*; +import java.nio.channels.*; +import java.util.Properties; + +public class MavenWrapperDownloader { + + private static final String WRAPPER_VERSION = "0.5.6"; + /** + * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. + */ + private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" + + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; + + /** + * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to + * use instead of the default one. + */ + private static final String MAVEN_WRAPPER_PROPERTIES_PATH = + ".mvn/wrapper/maven-wrapper.properties"; + + /** + * Path where the maven-wrapper.jar will be saved to. + */ + private static final String MAVEN_WRAPPER_JAR_PATH = + ".mvn/wrapper/maven-wrapper.jar"; + + /** + * Name of the property which should be used to override the default download url for the wrapper. + */ + private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; + + public static void main(String args[]) { + System.out.println("- Downloader started"); + File baseDirectory = new File(args[0]); + System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); + + // If the maven-wrapper.properties exists, read it and check if it contains a custom + // wrapperUrl parameter. + File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); + String url = DEFAULT_DOWNLOAD_URL; + if(mavenWrapperPropertyFile.exists()) { + FileInputStream mavenWrapperPropertyFileInputStream = null; + try { + mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); + Properties mavenWrapperProperties = new Properties(); + mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); + url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); + } catch (IOException e) { + System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); + } finally { + try { + if(mavenWrapperPropertyFileInputStream != null) { + mavenWrapperPropertyFileInputStream.close(); + } + } catch (IOException e) { + // Ignore ... + } + } + } + System.out.println("- Downloading from: " + url); + + File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); + if(!outputFile.getParentFile().exists()) { + if(!outputFile.getParentFile().mkdirs()) { + System.out.println( + "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); + } + } + System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); + try { + downloadFileFromURL(url, outputFile); + System.out.println("Done"); + System.exit(0); + } catch (Throwable e) { + System.out.println("- Error downloading"); + e.printStackTrace(); + System.exit(1); + } + } + + private static void downloadFileFromURL(String urlString, File destination) throws Exception { + if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { + String username = System.getenv("MVNW_USERNAME"); + char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); + Authenticator.setDefault(new Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(username, password); + } + }); + } + URL website = new URL(urlString); + ReadableByteChannel rbc; + rbc = Channels.newChannel(website.openStream()); + FileOutputStream fos = new FileOutputStream(destination); + fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); + fos.close(); + rbc.close(); + } + +} diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..2cc7d4a55c0cd0092912bf49ae38b3a9e3fd0054 Binary files /dev/null and b/.mvn/wrapper/maven-wrapper.jar differ diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000000000000000000000000000000000000..642d572ce90e5085986bdd9c9204b9404f028084 --- /dev/null +++ b/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,2 @@ +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar diff --git a/LOG_PATH_IS_UNDEFINED/sys-error.log b/LOG_PATH_IS_UNDEFINED/sys-error.log new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/LOG_PATH_IS_UNDEFINED/sys-info.log b/LOG_PATH_IS_UNDEFINED/sys-info.log new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/LOG_PATH_IS_UNDEFINED/sys-user.log b/LOG_PATH_IS_UNDEFINED/sys-user.log new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/README.md b/README.md index de7c19be389f88d1c057baa626f50558452fb1c5..e374557e18e69ab7f65aaa803550264d5d4197ee 100644 --- a/README.md +++ b/README.md @@ -1,46 +1,84 @@ -# LinkWeChat +

+

-### 平台介绍 +

+ logo +

-LinkWeChat,是一款基于企业微信的开源SCRM系统,为企业构建私域流量系统的综合解决方案,显著提升企业社交运营效率! -![输入图片说明](https://images.gitee.com/uploads/images/2020/0825/144910_68578056_409467.png "屏幕截图.png") +
-#### 应用场景: -泛零售、电商行业企业微信用户,提供多种工具多渠道多方式添加客户到企业微信好友,通过营销互动与客户标签管理等建立强连接。 +[![star](https://gitee.com/LinkWeChat/link-wechat/badge/star.svg?theme=gvp)](https://gitee.com/LinkWeChat/link-wechat/stargazers) +[![fork](https://gitee.com/LinkWeChat/link-wechat/badge/fork.svg?theme=gvp)](https://gitee.com/LinkWeChat/link-wechat/members) +![LinkWeChat](https://img.shields.io/badge/LinkWeChat-V1.5-brightgreen) +![license](http://img.shields.io/badge/license-GPL%203.0-orange) -#### 内置功能 +
-![输入图片说明](https://images.gitee.com/uploads/images/2020/0825/145413_3a0cab42_409467.png "屏幕截图.png") +

+

+

+

+--- + **

如果您觉得我们的开源项目很有帮助,请帮忙点击右上方的 :star: Star ,您的认可就是我们最大的动力,谢谢支持!:heart:

** +--- + +[LinkWeChat 官方帮助手册——语雀](https://www.yuque.com/linkwechat/help) + +### 产品简介 + +> LinkWeChat, Link to WeChat. + +基于人工智能的企业微信 SCRM 系统——LinkWeChat基于企业微信开放能力,不仅集成了企微基础的客户管理和后台管理功能,而且通过引流获客、客情维系、社群运营等灵活高效的客户运营模块,让客户与企业之间建立强链接关系,同时进一步通过多元化的客户营销工具,帮助企业提高客户运营效率,强化营销能力,拓展盈利空间,是企业私域流量管理与营销的综合解决方案。 + +![输入图片说明](https://images.gitee.com/uploads/images/2021/1101/012040_64b8b918_1480777.png "仟微助手企业微信SCRM智能营销系统-V1.5_13.png") + +#### 功能特性 + +系统分为八大模块: + +* **运营中心** :客户、客群、会话等全功能数据报表,数据一目了然; +* **引流获客** :活码、群活码、公海、客服等多渠道引流,实现精准获客; +* **客户中心** :助力企业搭建私域流量池,高效运营客户; +* **客情维系** :企业客户运营精细化,朋友圈、红包工具提高客户活跃度; +* **社群运营** :客群运营场景全覆盖,快速拉群; +* **全能营销** :提供多类型、多场景客户营销工具; +* **企业风控** :会话合规存档,敏感内容全局风控; +* **企业管理** :组织架构、自建应用全融合,实现“一个后台”; + + +![输入图片说明](https://images.gitee.com/uploads/images/2020/1231/232207_6a0f4a67_1480777.png "LinkWeChat 企业微信私域流量营销专家-V1.0.4_13.png") ### 环境部署 + #### 准备工作 -``` +```java JDK >= 1.8 (推荐1.8版本) -Mysql >= 5.5.0 (推荐5.7版本) +Mysql >= 5.7.0 (推荐5.7版本) +Mysql >= 5.7.0 (推荐5.7版本) Redis >= 3.0 Maven >= 3.0 Node >= 10 ``` + #### 运行系统 ##### 后端运行 -- 导入IDEA中 -- 创建数据库LW-vue并导入数据脚本 -- 打开运行com.linkwechat. LinkWeChatApplication.java - +- 导入 `IDEA` 中 +- 创建数据库 `LW-vue` 并导入数据脚本 +- 打开运行 `com.linkwechat.LinkWeChatApplication.java` ##### 前端运行 -``` +```bash # 进入项目目录 cd linkwe-ui @@ -53,51 +91,54 @@ npm install --registry=https://registry.npm.taobao.org # 本地开发 启动项目 npm run serve ``` -4、打开浏览器,输入:http://localhost:80 (默认账户 admin/admin123) -若能正确展示登录页面,并能成功登录,菜单及页面展示正常,则表明环境搭建成功 + +打开浏览器,输入 `http://localhost:80 `,默认账密为:`admin/admin123` 。 + +若能正确展示登录页面,并能成功登录,菜单及页面展示正常,则表明环境搭建成功。 ##### 必要配置 1、修改数据库连接 -- 编辑resources目录下的application-druid.yml -- url: 服务器地址 -- username: 账号 -- password: 密码 +- 编辑 `resources` 目录下的 `application-druid.yml` +- `url` : 服务器地址 +- `username` : 账号 +- `password `: 密码 + +数据库脚本:[https://gitee.com/LinkWeChat_admin/link-we-chat-db/tree/master](https://gitee.com/LinkWeChat_admin/link-we-chat-db/tree/master) 2、开发环境配置 -- 编辑resources目录下的application.yml -- port: 端口 -- context-path: 部署路径 +- 编辑 `resources` 目录下的 `application.yml` +- `port` : 端口 +- `context-path` : 部署路径 #### 部署系统 -##### 后端部署 +##### 后端部署 -- bin/package.bat 在项目的目录下执行 -- 然后会在项目下生成 target文件夹包含 war 或jar (多模块生成在linkwe-admin) -- 1、jar部署方式 -- 使用命令行执行:java –jar LinkWeChat.jar -- 2、war部署方式 -- pom.xml packaging修改为war 放入tomcat服务器webapps +- `bin/package.bat` 在项目的目录下执行 +- 然后会在项目下生成 ` target` 文件夹包含 `war` 或 `jar `(多模块生成在 `linkwe-admin`) +- `jar` 部署方式:使用命令行执行 `java –jar LinkWeChat.jar` +- `war` 部署方式:`pom.xml packaging` 修改为 `war` 放入 `tomcat` 服务器 `webapps` ##### 前端部署 当项目开发完毕,只需要运行一行命令就可以打包你的应用 -``` +```bash # 打包正式环境 npm run build:prod # 打包预发布环境 npm run build:stage ``` -构建打包成功之后,会在根目录生成 dist 文件夹,里面就是构建打包好的文件,通常是 ***.js 、***.css、index.html 等静态文件。 -通常情况下 dist 文件夹的静态文件发布到你的 nginx 或者静态服务器即可,其中的 index.html 是后台服务的入口页面。 +构建打包成功之后,会在根目录生成 `dist` 文件夹,里面就是构建打包好的文件,通常是 `.js` 、`.css`、`index.html` 等静态文件。 + +通常情况下 `dist` 文件夹的静态文件发布到你的 `nginx` 或者静态服务器即可,其中的 `index.html` 是后台服务的入口页面。 ### 项目介绍 @@ -171,31 +212,33 @@ com.linkwechat #### 核心技术 -- 前端技术栈 ES6、vue、vuex、vue-router、vue-cli、axios、element-ui +- 前端技术栈 `ES6`、`vue`、`vuex`、`vue-router`、`vue-cli`、`axios`、`element-ui` + +- 后端技术栈 `SpringBoot`、`MyBatis-plus`、`Spring Security`、`Jwt` -- 后端技术栈 SpringBoot、MyBatis-plus、Spring Security、Jwt +#### 业务架构 -#### 最终业务架构 +利用 NLP 技术对聊天记录进行智能语义分析,实现敏感词自动告警及自动打标签功能。 -![输入图片说明](https://images.gitee.com/uploads/images/2020/1015/154502_abf65cfb_409467.png "屏幕截图.png") +![输入图片说明](https://images.gitee.com/uploads/images/2020/1231/232301_2dcf24b2_1480777.png "LinkWeChat 企业微信私域流量营销专家-V1.0.4_22.png") #### 在线体验 - 演示演示:http://106.13.201.219/ 演示账号/密码:test/123456 +演示地址:http://demo.linkwechat.cn/ -#### 开发进度 +演示账号/密码:Wecome/123456 -![输入图片说明](https://images.gitee.com/uploads/images/2020/1015/095236_c808865f_409467.png "屏幕截图.png") +#### 开发进度 -### 联系作者加入交流群 +![输入图片说明](https://images.gitee.com/uploads/images/2021/0521/161235_092f96cb_1480777.png "LinkWeChat 1.0.png") -![输入图片说明](https://images.gitee.com/uploads/images/2020/0924/140420_fb631f6a_409467.png "屏幕截图.png") +### 联系作者加入群 +![输入图片说明](https://images.gitee.com/uploads/images/2021/0414/093533_899b0110_1480777.png "江冬勤-linkwechat咨询.png") ### 特别鸣谢 - - 感谢[RuoYi-Vue](https://gitee.com/y_project/RuoYi-Vue?_from=gitee_search)提供框架代码。 - + +感谢[RuoYi-Vue](https://gitee.com/y_project/RuoYi-Vue?_from=gitee_search)提供框架代码。 ### 部分演示图,持续更新 @@ -205,11 +248,90 @@ com.linkwechat ![输入图片说明](https://images.gitee.com/uploads/images/2020/1014/092306_99975664_409467.png "屏幕截图.png") ![输入图片说明](https://images.gitee.com/uploads/images/2020/1014/092338_503e44f7_409467.png "屏幕截图.png") ![输入图片说明](https://images.gitee.com/uploads/images/2020/1014/092358_e465cb54_409467.png "屏幕截图.png") +![输入图片说明](https://images.gitee.com/uploads/images/2020/1109/094122_dfd73b9e_409467.png "屏幕截图.png") +![输入图片说明](https://images.gitee.com/uploads/images/2020/1109/094154_e5052872_409467.png "屏幕截图.png") + +### 合作伙伴 + +![输入图片说明](https://images.gitee.com/uploads/images/2020/1231/234054_ede1ef54_1480777.png "LinkWeChat 企业微信私域流量营销专家-V1.0.4_33.png") ### 版权声明 -LinkWeChat开源版遵循[GPL-3.0](https://gitee.com/LinkWeChat/link-wechat/blob/master/LICENSE)开源协议发布,并提供免费使用,但不允许修改后和衍生的代码做为闭源的商业软件发布和销售! +LinkWeChat 开源版遵循 [GPL-3.0](https://gitee.com/LinkWeChat/link-wechat/blob/master/LICENSE) 开源协议发布,并提供免费使用,但 **绝不允许修改后和衍生的代码做为闭源的商业软件发布和销售!** + +### 捐赠支持 + +#### 来一杯卡布奇诺 + +如果您觉得我们的开源项目 `LinkWeChat` 对您有帮助,那就请项目开发者们来一杯卡布奇诺吧!当前我们接受来自于**微信**、**支付宝**或者**码云**的捐赠,请在捐赠时备注自己的昵称或附言。 + +您的捐赠将用于支付该项目的一些费用支出,并激励开发者们以便更好的推动项目的发展,同时欢迎捐赠**公网服务器**用于提高在线演示系统体验。 + +![输入图片说明](https://images.gitee.com/uploads/images/2021/0222/221344_727a0e80_1480777.png "image-20210222214357456.png") + +#### 长期捐赠 + +如果您是企业的经营者并且有计划将 `LinkWeChat` 用在公司的经营产品中,欢迎进行长期捐赠。长期捐赠有商业上的益处有: + +* 积极响应,快速维护,及时更新; +* 企业名称、Logo 及官网链接将长期展示在开源仓库、`LinkWeChat` 官网及宣发材料中; +* 捐赠金额同比例抵扣未来 `LinkWeChat` 的付费产品价格。 + +如果您对长期赞助 `LinkWeChat` 团队感兴趣,或者有其他好想法,欢迎联系开发团队微信 `sxjiangdongqin`,或发送邮件到 iamxiarui@foxmail.com。 + +#### 捐赠记录 + +`LinkWeChat` 全体开发团队感谢以下全部小伙伴们的赞助(排名不分先后): + +| 昵称 | 金额 | 渠道 | 时间 | 附言 | +| :------: | :-----: | :--: | :-----------------: | :----------------: | +| yang | ¥10.00 | 码云 | 2021-02-22 22:08:59 | 感谢您的开源项目! | +| 水库浪子 | ¥1.00 | 码云 | 2021-02-22 22:09:03 | 感谢您的开源项目! | +| 楼* | ¥166.60 | 微信 | 2021-02-22 22:27:25 | 希望这个好项目能长久发展 | +| joygezxp | ¥66.60 | 微信 | 2021-02-22 22:39:41 | 愿项目一路666 | +| iamxiarui | ¥10.00 | 微信 | 2021-02-22 22:37:52 | 坚持开源不容易 | +| godricV | ¥10.00 | 微信 | 2021-02-22 22:28:55 | 感谢您的开源项目! | +| *标 | ¥20.00 | 微信 | 2021-03-05 16:03:19 | 感谢您的开源项目! | +| *涯 | ¥30.00 | 微信 | 2021-03-09 12:14:02 | 加油,感谢开源! | +| *魂 | ¥30.00 | 微信 | 2021-03-11 10:52:47 | 感谢开源供大家学习 | +| *J | ¥10.00 | 微信 | 2021-03-12 14:20:22 | 感谢开源供大家学习 | +| 杨*源 | ¥10.00 | 码云 | 2021-03-23 11:07:22 | 期待月底的大更新 | +| 骆*升 | ¥66.66 | 支付宝 | 2021-03-23 11:31:58 | 感谢开源供大家学习 | +| 曲*旭 | ¥20.00 | 码云 | 2021-03-23 11:31:58 | 感谢您的开源项目! | +| 郑* | ¥ 50.00 | 码云 | 2021-03-23 11:31:58 | 虽然之前做过类似的,还是感谢下开源和分享的奉献精神 | +| *喵 | ¥ 66.00 | 微信 | 2021-03-24 11:06:31 | 感谢您的开源项目! | +| q*s | ¥ 50.00 | 微信 | 2021-03-29 19:57:49 | 感谢您的开源项目! | +| *海 | ¥ 1.00 | 微信 | 2021-03-30 10:47:03 | 感谢您的开源项目! | +| m*r | ¥ 50.00 | 微信 | 2021-03-30 17:55:30 | 感谢您的开源项目! | +| *祺 | ¥ 20.00 | 支付宝 | 2021-03-30 19:03:59 | 感谢您的开源项目! | +| *桥 | ¥ 66.66 | 支付宝 | 2021-04-07 16:38:31 | 祝项目一路 666 | +| *力 | ¥ 66.00 | 微信 | 2021-04-09 10:30:11 | 支持开源 | +| *生 | ¥ 66.00 | 微信 | 2021-04-15 21:36:01 | 支持开源 | +| Q*N | ¥ 10.00 | 微信 | 2021-04-19 20:24:11 | 感谢分享 | +| 大*k | ¥ 10.00 | 微信 | 2021-04-22 12:25:02 | 感谢您的开源 | +| J*s | ¥ 10.00 | 微信 | 2021-05-19 17:33:10 | 感谢您的开源 | +| *茶 | ¥ 10.00 | 微信 | 2021-05-17 20:46:05 | 感谢您的开源 | + + +`LinkWeChat` 全体开发团队感谢以下全部合作伙伴的服务器赞助(排名不分先后): + +| 公司/个人名称 | 服务器 | +| :------: | :-----: | +| 上海六感科技有限公司 | 八核 16G 服务器一台 | +| Happy | 两核 8G 服务器一台 | +| 平山阑槛倚晴空 | 两核 4G 服务器一台 | + + +#### 捐赠用途 + +患难与共,风雨同舟。 + +LinkWeChat 开源团队将目前所收项目捐赠全额捐出,仅尽绵薄之力,在此我们也感谢大家的捐赠和支持,希望河南尽早渡过难关。 +同时也希望 LinkWeChat 不仅能为国内开源社区建设做一点贡献,也能为社会产生一些价值。 +![输入图片说明](https://images.gitee.com/uploads/images/2021/0722/233536_67c02015_1480777.png "屏幕截图.png") +--- + **如果您觉得我们的开源项目很有帮助,请帮忙点击右上方的 :star: Star ,您的认可就是我们最大的动力,谢谢支持!:heart:** \ No newline at end of file diff --git a/RELEASES.md b/RELEASES.md new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/build_docker.sh b/build_docker.sh new file mode 100644 index 0000000000000000000000000000000000000000..a6dcf8c3b5dde388f2057e1f957e6ecd31581105 --- /dev/null +++ b/build_docker.sh @@ -0,0 +1,28 @@ +#!/bin/bash +######################################################## +############### LinkWeChat Docker 部署脚本 ############## +######################################################## +LOG=$1 +PROJ_HOME=$PWD +echo "$PROJ_HOME" +CLEAN_BUILD="clean" +BUILD_CODE="install" +BUILD_DOCKER="docker:build" + +showLog(){ + if [ "$1" == '--log' -o "$1" == '-l' ]; then + $PROJ_HOME/mvnw "$2" + else + $PROJ_HOME/mvnw "$2" > /dev/null + fi +} + +cd "$PROJ_HOME" +echo '开始从代码构建LinkWeChat' +showLog "$LOG" "$CLEAN_BUILD" +showLog "$LOG" "$BUILD_CODE" +echo '构建完成' +cd "$PROJ_HOME"/linkwe-admin +echo '开始构建Docker镜像' +showLog "$LOG" "$BUILD_DOCKER" +echo 'Docker镜像构建完成' \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000000000000000000000000000000000000..b9477a38b63303467e8d179a3e2f1e3a4c2947ff --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,28 @@ +version: '3.3' + +# 如需配置变量,请在environment中进行变量配置 +services: + api: + image: linkwechat + container_name: linkwechat + environment: + - JAVA_OPTS=-Xms4096m -Xmx4096m -Duser.timezone=Asia/Shanghai + - TZ=Asia/Shanghai + - NACOS_SERVER + # 如果使用nacos,以下变量可以不进行配置 + - ES_ADDRESS + - DB_HOST + - DB_PORT + - DB_NAME + - DB_USER + - DB_PASS + - REDIS_HOST + - REDIS_PORT + ports: + - 8090 + volumes: + - ./logs:/logs + # 上传文件地址,请根据实际${ruoyi.profile}自行修改映射 + - ./pic:/app/project/pic + - ./tmp:/tmp + restart: always \ No newline at end of file diff --git a/linkwe-admin/pom.xml b/linkwe-admin/pom.xml index 50d6829a4aa43d4ab50534254d81d5a30164896e..44b100849a0d1b41d1569bb9a0d1f45143318684 100644 --- a/linkwe-admin/pom.xml +++ b/linkwe-admin/pom.xml @@ -24,6 +24,12 @@ true + + + org.hibernate.validator + hibernate-validator + + io.springfox @@ -68,6 +74,35 @@ 5.6.24 + + + + com.google.protobuf + protobuf-java + + + + + + io.github.leejoker + linkwechat-nacos-starter + + + + + + + javax.xml.bind + jaxb-api + + + + + + org.projectlombok + lombok + + @@ -96,6 +131,36 @@ ${project.artifactId} + + com.spotify + docker-maven-plugin + 1.1.1 + + ${parent.artifactId} + ${basedir}/src/main/docker + + ${parent.version} + + + + ${project.build.finalName}.jar + + + + / + ${project.build.directory} + ${project.build.finalName}.jar + + + + + + javax.activation + activation + 1.1.1 + + + ${project.artifactId} diff --git a/linkwe-admin/src/main/docker/Dockerfile b/linkwe-admin/src/main/docker/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..edfe17e61169203dd9de342dcd8d81ee7080e47b --- /dev/null +++ b/linkwe-admin/src/main/docker/Dockerfile @@ -0,0 +1,17 @@ +FROM openjdk:8-alpine + +RUN set -xe && apk --no-cache add ttf-dejavu fontconfig + +# 设置时区 +ADD Shanghai /usr/share/zoneinfo/Asia/ +RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \ + && echo "Asia/Shanghai" > /etc/timezone + +VOLUME /tmp + +#设置字符集 +ENV LANG en_US.UTF-8 +ARG JAR_FILE +ADD $JAR_FILE app.jar + +ENTRYPOINT ["sh","-c","java -server $JAVA_OPTS -jar /app.jar"] \ No newline at end of file diff --git a/linkwe-admin/src/main/docker/Shanghai b/linkwe-admin/src/main/docker/Shanghai new file mode 100644 index 0000000000000000000000000000000000000000..d7f92e2fa5868addab98170099181375634ab1ca Binary files /dev/null and b/linkwe-admin/src/main/docker/Shanghai differ diff --git a/linkwe-admin/src/main/java/com/linkwechat/LinkWeChatApplication.java b/linkwe-admin/src/main/java/com/linkwechat/LinkWeChatApplication.java index 9381985b798337e5abab58d53d6a7fb31b42be88..472e53ac769799aa437dad69e424556d5686bc49 100644 --- a/linkwe-admin/src/main/java/com/linkwechat/LinkWeChatApplication.java +++ b/linkwe-admin/src/main/java/com/linkwechat/LinkWeChatApplication.java @@ -1,38 +1,35 @@ package com.linkwechat; +import com.dtflys.forest.springboot.annotation.ForestScan; import com.github.pagehelper.autoconfigure.PageHelperAutoConfiguration; -import com.thebeastshop.forest.springboot.annotation.ForestScan; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; -import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; -import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; +import org.springframework.scheduling.annotation.EnableAsync; /** * 启动程序 - * + * * @author ruoyi */ -@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class, PageHelperAutoConfiguration.class }) +@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, PageHelperAutoConfiguration.class}) @MapperScan("com.linkwechat.*.mapper") -@ForestScan(basePackages = "com.linkwechat.wecom.client") -public class LinkWeChatApplication -{ - public static void main(String[] args) - { +@ForestScan(basePackages = {"com.linkwechat.wecom.client", "com.linkwechat.wecom.wxclient"}) +@EnableAsync +public class LinkWeChatApplication { + public static void main(String[] args) { - - SpringApplication.run(LinkWeChatApplication.class, args); - System.out.println("(♥◠‿◠)ノ゙ LinkWeChat启动成功 ლ(´ڡ`ლ)゙ \n" + - " .-------. ____ __ \n" + - " | _ _ \\ \\ \\ / / \n" + - " | ( ' ) | \\ _. / ' \n" + - " |(_ o _) / _( )_ .' \n" + - " | (_,_).' __ ___(_ o _)' \n" + - " | |\\ \\ | || |(_,_)' \n" + - " | | \\ `' /| `-' / \n" + - " | | \\ / \\ / \n" + - " ''-' `'-' `-..-' "); + SpringApplication.run(LinkWeChatApplication.class, args); + System.out.println("(♥◠‿◠)ノ゙ LinkWeChat启动成功 ლ(´ڡ`ლ)゙ \n" + + " .-------. ____ __ \n" + + " | _ _ \\ \\ \\ / / \n" + + " | ( ' ) | \\ _. / ' \n" + + " |(_ o _) / _( )_ .' \n" + + " | (_,_).' __ ___(_ o _)' \n" + + " | |\\ \\ | || |(_,_)' \n" + + " | | \\ `' /| `-' / \n" + + " | | \\ / \\ / \n" + + " ''-' `'-' `-..-' "); } } diff --git a/linkwe-admin/src/main/java/com/linkwechat/web/controller/common/CommonController.java b/linkwe-admin/src/main/java/com/linkwechat/web/controller/common/CommonController.java index 20472616a09fcf2013cbb25288aeac15252f3d76..631c3b42b2333288f68e42244573ca6b2ecb9108 100644 --- a/linkwe-admin/src/main/java/com/linkwechat/web/controller/common/CommonController.java +++ b/linkwe-admin/src/main/java/com/linkwechat/web/controller/common/CommonController.java @@ -4,9 +4,12 @@ import com.linkwechat.common.config.RuoYiConfig; import com.linkwechat.common.config.ServerConfig; import com.linkwechat.common.constant.Constants; import com.linkwechat.common.core.domain.AjaxResult; +import com.linkwechat.common.core.domain.FileVo; import com.linkwechat.common.utils.StringUtils; import com.linkwechat.common.utils.file.FileUploadUtils; import com.linkwechat.common.utils.file.FileUtils; +import com.linkwechat.framework.web.domain.server.SysFile; +import com.linkwechat.framework.web.service.FileService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -30,6 +33,10 @@ public class CommonController { @Autowired private ServerConfig serverConfig; + + @Autowired + private FileService fileService; + /** * 通用下载请求 * @@ -96,4 +103,46 @@ public class CommonController { FileUtils.writeBytes(downloadPath, response.getOutputStream()); } + + /** + * 网络资源通用下载 + */ + @GetMapping("/common/download/url") + public void webResourceDownload(String url, HttpServletRequest request, HttpServletResponse response) throws Exception { + FileUtils.downloadFile(url, response.getOutputStream()); + } + + + /** + * 通用上传请求 + */ + @PostMapping("/common/uploadFile2Cos") + public AjaxResult uploadFile2Cos(MultipartFile file){ + try { + + SysFile sysFile + = fileService.upload(file); + return AjaxResult.success( + FileVo.builder() + .fileName(sysFile.getFileName()) + .url(sysFile.getImgUrlPrefix()+sysFile.getFileName()) + .build() + ); + } catch (Exception e) { + return AjaxResult.error("不支持当前文件上传或文件过大建议传20MB以内的文件"); + } + } + + + /** + * 获取图片 + */ + @GetMapping("/common/findImage") + public void findImage(HttpServletResponse response,String fileName){ + fileService.findImage(fileName,response); + } + + + + } diff --git a/linkwe-admin/src/main/java/com/linkwechat/web/controller/system/SysLoginController.java b/linkwe-admin/src/main/java/com/linkwechat/web/controller/system/SysLoginController.java index b9bdd43d137ede96b711235a4fe2bdd3b985daa2..9b76fb6602f226571458703bf4c24a22cf6ab234 100644 --- a/linkwe-admin/src/main/java/com/linkwechat/web/controller/system/SysLoginController.java +++ b/linkwe-admin/src/main/java/com/linkwechat/web/controller/system/SysLoginController.java @@ -1,20 +1,26 @@ package com.linkwechat.web.controller.system; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.linkwechat.common.constant.Constants; import com.linkwechat.common.core.domain.AjaxResult; +import com.linkwechat.common.core.domain.entity.SysDept; import com.linkwechat.common.core.domain.entity.SysMenu; import com.linkwechat.common.core.domain.entity.SysUser; +import com.linkwechat.common.core.domain.entity.WeCorpAccount; import com.linkwechat.common.core.domain.model.LoginBody; import com.linkwechat.common.core.domain.model.LoginUser; import com.linkwechat.common.utils.ServletUtils; import com.linkwechat.framework.web.service.SysLoginService; import com.linkwechat.framework.web.service.SysPermissionService; import com.linkwechat.framework.web.service.TokenService; +import com.linkwechat.system.service.ISysDeptService; import com.linkwechat.system.service.ISysMenuService; -import com.linkwechat.wecom.client.WeAccessTokenClient; -import com.linkwechat.wecom.domain.WeCorpAccount; +import com.linkwechat.system.service.ISysUserService; +import com.linkwechat.wecom.client.WeUserClient; import com.linkwechat.wecom.domain.dto.WeLoginUserInfoDto; +import com.linkwechat.wecom.domain.dto.WeUserInfoDto; import com.linkwechat.wecom.service.IWeCorpAccountService; +import org.apache.commons.collections4.CollectionUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; @@ -50,8 +56,13 @@ public class SysLoginController @Autowired - private WeAccessTokenClient weAccessTokenClient; + private WeUserClient weUserClient; + @Autowired + private ISysDeptService iSysDeptService; + + @Autowired + private ISysUserService sysUserService; /** @@ -87,6 +98,15 @@ public class SysLoginController Set roles = permissionService.getRolePermission(user); // 权限集合 Set permissions = permissionService.getMenuPermission(user); + + List sysDepts = iSysDeptService.selectDeptList(SysDept.builder().parentId(new Long(0)).build()); + + if(!CollectionUtils.isEmpty(sysDepts)){ + user.setCompanyName( + sysDepts.stream().findFirst().get().getDeptName() + ); + } + //校验用户是否拥有可用corpid WeCorpAccount wxCorpAccount = iWxCorpAccountService.findValidWeCorpAccount(); @@ -115,47 +135,76 @@ public class SysLoginController return AjaxResult.success(menuService.buildMenus(menus)); } - /** - * 获取企业扫码登录相关参数 - * @return - */ - @GetMapping("/findWxQrLoginInfo") - public AjaxResult findQrLoginParm(){ - - WeCorpAccount validWeCorpAccount - = iWxCorpAccountService.findValidWeCorpAccount(); - if(null != validWeCorpAccount){ - validWeCorpAccount.setContactSecret(null); - validWeCorpAccount.setCorpSecret(null); - validWeCorpAccount.setProviderSecret(null); - } - - return AjaxResult.success(validWeCorpAccount); - } - - - - /** - * 扫码登录微信端回调 - * @param auth_code - * @return - */ - @GetMapping("/wxQrLogin") - public AjaxResult wxQrLogin(String auth_code){ - - AjaxResult ajax = AjaxResult.success(); - - WeLoginUserInfoDto loginInfo = weAccessTokenClient.getLoginInfo(auth_code); - if( null != loginInfo.getUser_info()){ - - String token = loginService.noPwdLogin(loginInfo.getUser_info().getUserid()); - ajax.put(Constants.TOKEN, token); - - } - - return ajax; - - } +// /** +// * 获取企业扫码登录相关参数 +// * @return +// */ +// @GetMapping("/findWxQrLoginInfo") +// public AjaxResult findQrLoginParm(){ +// +// WeCorpAccount validWeCorpAccount +// = iWxCorpAccountService.findValidWeCorpAccount(); +// if(null != validWeCorpAccount){ +// validWeCorpAccount.setContactSecret(null); +// validWeCorpAccount.setCorpSecret(null); +// validWeCorpAccount.setProviderSecret(null); +// } +// +// return AjaxResult.success(validWeCorpAccount); +// } + + + +// /** +// * 扫码登录微信端回调 +// * @param auth_code 授权code +// * @param agentId 应用id +// * @return +// */ +// @GetMapping("/wxQrLogin") +// public AjaxResult wxQrLogin(String auth_code, String agentId){ +// +// AjaxResult ajax = AjaxResult.success(); +// +// WeUserInfoDto userInfo = weUserClient.getUserInfo(auth_code, agentId); +// if( null != userInfo){ +// SysUser sysUser = sysUserService.selectUserByCorpUserId(userInfo.getUserId()); +// if (null != sysUser){ +// String token = loginService.noPwdLogin(sysUser.getUserName()); +// ajax.put(Constants.TOKEN, token); +// }else { +// return AjaxResult.error("请绑定后再登录"); +// } +// } +// return ajax; +// } + + + +// /** +// * 通过企业id和企业密钥登录 +// * @param corpId +// * @param corpSecret +// * @return +// */ +// @GetMapping("/corpLogin") +// public AjaxResult corpLogin(String corpId,String corpSecret){ +// +// WeCorpAccount weCorpAccount = iWxCorpAccountService.getOne(new LambdaQueryWrapper() +// .eq(WeCorpAccount::getCorpId, corpId) +// .eq(WeCorpAccount::getCorpSecret, corpSecret) +// .eq(WeCorpAccount::getDelFlag, Constants.NORMAL_CODE)); +// +// +// if(weCorpAccount == null){ +// +// return AjaxResult.error("当前企业id与企业密码不匹配或不存在"); +// } +// +// return AjaxResult.success( +// loginService.noPwdLogin(weCorpAccount.getCorpAccount()) +// ); +// } } diff --git a/linkwe-admin/src/main/java/com/linkwechat/web/controller/system/SysProfileController.java b/linkwe-admin/src/main/java/com/linkwechat/web/controller/system/SysProfileController.java index c589ead67327f270554e6b210fccf33afb8779d3..4938d26575a8e13f4fa58da2e43d9b936448748c 100644 --- a/linkwe-admin/src/main/java/com/linkwechat/web/controller/system/SysProfileController.java +++ b/linkwe-admin/src/main/java/com/linkwechat/web/controller/system/SysProfileController.java @@ -38,6 +38,11 @@ public class SysProfileController extends BaseController @Autowired private TokenService tokenService; + + @Autowired + private RuoYiConfig ruoYiConfig; + + /** * 个人信息 */ @@ -80,25 +85,30 @@ public class SysProfileController extends BaseController @PutMapping("/updatePwd") public AjaxResult updatePwd(String oldPassword, String newPassword) { - LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest()); - String userName = loginUser.getUsername(); - String password = loginUser.getPassword(); - if (!SecurityUtils.matchesPassword(oldPassword, password)) - { - return AjaxResult.error("修改密码失败,旧密码错误"); - } - if (SecurityUtils.matchesPassword(newPassword, password)) - { - return AjaxResult.error("新密码不能与旧密码相同"); - } - if (userService.resetUserPwd(userName, SecurityUtils.encryptPassword(newPassword)) > 0) - { - // 更新缓存用户密码 - loginUser.getUser().setPassword(SecurityUtils.encryptPassword(newPassword)); - tokenService.setLoginUser(loginUser); - return AjaxResult.success(); + + if(ruoYiConfig.isEditPwd()){ + LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest()); + String userName = loginUser.getUsername(); + String password = loginUser.getPassword(); + if (!SecurityUtils.matchesPassword(oldPassword, password)) + { + return AjaxResult.error("修改密码失败,旧密码错误"); + } + if (SecurityUtils.matchesPassword(newPassword, password)) + { + return AjaxResult.error("新密码不能与旧密码相同"); + } + if (userService.resetUserPwd(userName, SecurityUtils.encryptPassword(newPassword)) > 0) + { + // 更新缓存用户密码 + loginUser.getUser().setPassword(SecurityUtils.encryptPassword(newPassword)); + tokenService.setLoginUser(loginUser); + return AjaxResult.success(); + } + return AjaxResult.error("修改密码异常,请联系管理员"); + }else{ + return AjaxResult.error("当前环境密码不可修改"); } - return AjaxResult.error("修改密码异常,请联系管理员"); } /** diff --git a/linkwe-admin/src/main/java/com/linkwechat/web/controller/system/SysUserController.java b/linkwe-admin/src/main/java/com/linkwechat/web/controller/system/SysUserController.java index 41c2c59c94c06d845bad23cd6e3706937a615769..8a3f0fd8097510bb75e1138fab1bf7ba63cb3071 100644 --- a/linkwe-admin/src/main/java/com/linkwechat/web/controller/system/SysUserController.java +++ b/linkwe-admin/src/main/java/com/linkwechat/web/controller/system/SysUserController.java @@ -1,5 +1,6 @@ package com.linkwechat.web.controller.system; +import cn.hutool.core.collection.CollectionUtil; import com.linkwechat.common.annotation.Log; import com.linkwechat.common.constant.UserConstants; import com.linkwechat.common.core.controller.BaseController; @@ -17,19 +18,23 @@ import com.linkwechat.framework.web.service.TokenService; import com.linkwechat.system.service.ISysPostService; import com.linkwechat.system.service.ISysRoleService; import com.linkwechat.system.service.ISysUserService; +import com.linkwechat.wecom.domain.WeUser; +import com.linkwechat.wecom.service.IWeUserService; import io.swagger.annotations.ApiOperation; +import io.vertx.ext.auth.User; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; +import javax.servlet.http.HttpServletRequest; import java.util.List; import java.util.stream.Collectors; /** * 用户信息 - * + * * @author ruoyi */ @RestController @@ -48,6 +53,10 @@ public class SysUserController extends BaseController @Autowired private TokenService tokenService; + + @Autowired + private IWeUserService iWeUserService; + /** * 获取用户列表 */ @@ -56,6 +65,7 @@ public class SysUserController extends BaseController public TableDataInfo list(SysUser user) { startPage(); + List list = userService.selectUserList(user); return getDataTable(list); } @@ -193,4 +203,27 @@ public class SysUserController extends BaseController user.setUpdateBy(SecurityUtils.getUsername()); return toAjax(userService.updateUserStatus(user)); } + + + @GetMapping("/findCurrentLoginUser") + public AjaxResult findCurrentLoginUser(HttpServletRequest request){ + String userId=""; + LoginUser loginUser = tokenService.getLoginUser(request); + if(null != loginUser){ + SysUser user = loginUser.getUser(); + if(null != user){ + List weUsers = iWeUserService.getList(WeUser.builder() + .mobile(user.getPhonenumber()) + .build()); + if(CollectionUtil.isNotEmpty(weUsers)){ + userId=weUsers.get(0).getUserId(); + + } + } + + } + return AjaxResult.success(userId); + } + + } diff --git a/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeCallBackController.java b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeCallBackController.java new file mode 100644 index 0000000000000000000000000000000000000000..95ca6259a2310033d1f0dd3d367de0305a206d27 --- /dev/null +++ b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeCallBackController.java @@ -0,0 +1,71 @@ +package com.linkwechat.web.controller.wecom; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.linkwechat.common.core.domain.entity.WeCorpAccount; +import com.linkwechat.common.utils.wecom.WxCryptUtil; +import com.linkwechat.web.controller.common.CommonController; +import com.linkwechat.wecom.service.IWeCorpAccountService; +import com.linkwechat.wecom.service.event.WeEventPublisherService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiModelProperty; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletRequest; + +/** + * @author danmo + * @description 企微回调通知接口 + * @date 2020/11/6 17:31 + **/ +@Api(tags = "企微回调通知") +@Slf4j +@RestController +@RequestMapping("/wecom/callback") +public class WeCallBackController extends CommonController { + @Autowired + private WeEventPublisherService weEventPublisherService; + + @Autowired + private IWeCorpAccountService weCorpAccountService; + + @ApiModelProperty("post数据接收") + @PostMapping(value = "/recive/{corpId}") + public String recive(@RequestBody String msg, @RequestParam(name = "msg_signature") String signature, + String timestamp, String nonce,@PathVariable("corpId") String corpId) { + WeCorpAccount corpAccount = weCorpAccountService.getCorpAccountByCorpId(corpId); + WxCryptUtil wxCryptUtil = new WxCryptUtil(corpAccount.getToken(), corpAccount.getEncodingAesKey(), corpId); + try { + String decrypt = wxCryptUtil.decrypt(signature, timestamp, nonce, msg); + weEventPublisherService.register(decrypt); + return decrypt; + } catch (Exception e) { + e.printStackTrace();; + String sRespData = WxCryptUtil.getTextRespData("success"); + return wxCryptUtil.encrypt(sRespData); + } + } + + @ApiModelProperty("get数据校验") + @GetMapping(value = "/recive/{corpId}") + public String recive(HttpServletRequest request,@PathVariable("corpId") String corpId) { + // 微信加密签名 + String sVerifyMsgSig = request.getParameter("msg_signature"); + // 时间戳 + String sVerifyTimeStamp = request.getParameter("timestamp"); + // 随机数 + String sVerifyNonce = request.getParameter("nonce"); + // 随机字符串 + String sVerifyEchoStr = request.getParameter("echostr"); + + WeCorpAccount corpAccount = weCorpAccountService.getCorpAccountByCorpId(corpId); + WxCryptUtil wxCryptUtil = new WxCryptUtil(corpAccount.getToken(), corpAccount.getEncodingAesKey(), corpId); + try { + return wxCryptUtil.verifyURL(sVerifyMsgSig, sVerifyTimeStamp, sVerifyNonce, sVerifyEchoStr); + } catch (Exception e) { + return "error"; + } + } +} diff --git a/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeCategoryController.java b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeCategoryController.java index df146fd562790bae963bd927d4a759f7fe5b024a..fa7636c87de33d810abc9314eaf5d20cad5c7565 100644 --- a/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeCategoryController.java +++ b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeCategoryController.java @@ -1,17 +1,23 @@ package com.linkwechat.web.controller.wecom; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.linkwechat.common.annotation.Log; +import com.linkwechat.common.constant.Constants; import com.linkwechat.common.core.controller.BaseController; import com.linkwechat.common.core.domain.AjaxResult; import com.linkwechat.common.core.domain.Tree; import com.linkwechat.common.enums.BusinessType; import com.linkwechat.wecom.domain.WeCategory; +import com.linkwechat.wecom.domain.vo.WeCategoryVo; import com.linkwechat.wecom.service.IWeCategoryService; +import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import java.util.ArrayList; import java.util.List; /** @@ -22,63 +28,79 @@ import java.util.List; */ @RestController @RequestMapping("/wecom/category") +@Api(tags = "企业微信素材分类") public class WeCategoryController extends BaseController { @Autowired private IWeCategoryService weCategoryService; - /** - * 类目树 - */ - @PreAuthorize("@ss.hasPermi('wechat:category:list')") + + +// @PreAuthorize("@ss.hasPermi('wechat:category:list')") @GetMapping("/list") @ApiOperation("类目树") - public List> list(@RequestParam("mediaType") String mediaType) { - return weCategoryService.findWeCategoryByMediaType(mediaType); + public AjaxResult list(@RequestParam("mediaType") String mediaType) { + return AjaxResult.success(weCategoryService.findWeCategoryByMediaType(mediaType)); } /** * 通过id查询类目详细信息 */ - @PreAuthorize("@ss.hasPermi('wechat:category:query')") +// @PreAuthorize("@ss.hasPermi('wechat:category:query')") @GetMapping(value = "/{id}") @ApiOperation("通过id查询类目详细信息") - public AjaxResult getInfo(@PathVariable("id") Long id) { - return AjaxResult.success(weCategoryService.findWeCategoryById(id)); + public AjaxResult getInfo(@PathVariable("id") Long id) { + return AjaxResult.success(weCategoryService.getById(id)); } /** * 添加类目 */ - @PreAuthorize("@ss.hasPermi('wechat:category:add')") +// @PreAuthorize("@ss.hasPermi('wechat:category:add')") @Log(title = "添加类目", businessType = BusinessType.INSERT) @PostMapping @ApiOperation("添加类目") - public AjaxResult add(@RequestBody WeCategory category) { - return toAjax(weCategoryService.insertWeCategory(category)); + public AjaxResult add(@Validated @RequestBody WeCategory category) { + weCategoryService.insertWeCategory(category); + return AjaxResult.success(); } /** * 更新目录 */ - @PreAuthorize("@ss.hasPermi('wechat:category:edit')") +// @PreAuthorize("@ss.hasPermi('wechat:category:edit')") @Log(title = "更新目录", businessType = BusinessType.UPDATE) @PutMapping @ApiOperation("更新目录") - public AjaxResult edit(@RequestBody WeCategory category) { - return toAjax(weCategoryService.updateWeCategory(category)); + public AjaxResult edit(@Validated @RequestBody WeCategory category) { + weCategoryService.updateWeCategory(category); + return AjaxResult.success(); } /** * 删除类目 */ - @PreAuthorize("@ss.hasPermi('wechat:category:remove')") +// @PreAuthorize("@ss.hasPermi('wechat:category:remove')") Constants.DELETE_CODE @Log(title = "删除类目", businessType = BusinessType.DELETE) @DeleteMapping("/{ids}") @ApiOperation("删除类目") public AjaxResult remove(@PathVariable Long[] ids) { - return toAjax(weCategoryService.deleteWeCategoryByIds(ids)); + weCategoryService.deleteWeCategoryById(ids); +// List categorys=new ArrayList<>(); +// for (Long id:ids) { +// categorys.add( +// WeCategory.builder() +// .id(id) +// .delFlag("55") +// .build() +// ); +// } +// weCategoryService.updateBatchById(categorys); + + return AjaxResult.success(); } + + } diff --git a/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeChatCollectionController.java b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeChatCollectionController.java new file mode 100644 index 0000000000000000000000000000000000000000..d9450b2bbd3516446308aa613b20a080dbe997bb --- /dev/null +++ b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeChatCollectionController.java @@ -0,0 +1,68 @@ +package com.linkwechat.web.controller.wecom; + +import com.linkwechat.common.annotation.Log; +import com.linkwechat.common.core.controller.BaseController; +import com.linkwechat.common.core.domain.AjaxResult; +import com.linkwechat.common.core.page.TableDataInfo; +import com.linkwechat.common.enums.BusinessType; +import com.linkwechat.wecom.domain.dto.WeChatCollectionDto; +import com.linkwechat.wecom.domain.vo.WeChatSideVo; +import com.linkwechat.wecom.service.IWeChatCollectionService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 聊天工具 侧边栏栏 素材收藏 + * + * @author kwen + */ +@RequestMapping(value = "/wecom/chat/collection") +@RestController +public class WeChatCollectionController extends BaseController { + + + @Autowired + private IWeChatCollectionService weChatCollectionService; + + + /** + * 添加收藏 + */ + //@PreAuthorize("@ss.hasPermi('chat:collection:add')") + @Log(title = "添加收藏", businessType = BusinessType.INSERT) + @PostMapping("addCollection") + public AjaxResult addCollection(@RequestBody WeChatCollectionDto chatCollectionDto) { + boolean b = + weChatCollectionService.addCollection(chatCollectionDto.getMaterialId(), chatCollectionDto.getUserId()); + if(weChatCollectionService.addCollection(chatCollectionDto.getMaterialId(), chatCollectionDto.getUserId())){ + return AjaxResult.success(); + } + return AjaxResult.success("当前素材不可重复收藏"); + } + + + /** + * 取消收藏 + */ + // @PreAuthorize("@ss.hasPermi('chat:collection:delete')") + // @Log(title = "取消收藏", businessType = BusinessType.UPDATE) + @PostMapping(value = "cancleCollection") + public AjaxResult cancleCollection(@RequestBody WeChatCollectionDto chatCollectionDto) { + return toAjax(weChatCollectionService.cancleCollection(chatCollectionDto.getMaterialId(), chatCollectionDto.getUserId())); + } + + /** + * 收藏列表 + */ + // @PreAuthorize("@ss.hasPermi('chat:collection:list')") + @GetMapping("/list") + public TableDataInfo list(@RequestParam(value = "userId") String userId,@RequestParam(value = "keyword",required = false) String keyword) { + startPage(); + List collections = weChatCollectionService.collections(userId,keyword); + return getDataTable(collections); + } + +} diff --git a/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeChatContactMsgController.java b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeChatContactMsgController.java new file mode 100644 index 0000000000000000000000000000000000000000..cd2c3d238fa4ef0e3b437522df39dcc4426c5000 --- /dev/null +++ b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeChatContactMsgController.java @@ -0,0 +1,168 @@ +package com.linkwechat.web.controller.wecom; + +import com.alibaba.fastjson.JSONObject; +import com.linkwechat.common.annotation.Log; +import com.linkwechat.common.core.controller.BaseController; +import com.linkwechat.common.core.domain.AjaxResult; +import com.linkwechat.common.core.page.TableDataInfo; +import com.linkwechat.common.enums.BusinessType; +import com.linkwechat.common.utils.poi.ExcelUtil; +import com.linkwechat.wecom.domain.WeChatContactMsg; +import com.linkwechat.wecom.domain.vo.WeChatContactMsgVo; +import com.linkwechat.wecom.service.IWeChatContactMsgService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.Arrays; +import java.util.List; + +/** + * 会话消息Controller + * + * @author ruoyi + * @date 2021-07-28 + */ +@Api(tags = "会话存档管理") +@RequiredArgsConstructor(onConstructor_ = @Autowired) +@RestController +@RequestMapping("/chat/msg" ) +public class WeChatContactMsgController extends BaseController { + + private final IWeChatContactMsgService iWeChatContactMsgService; + + /** + * 查询会话消息列表 + */ + @ApiOperation("查询会话消息列表") + @PreAuthorize("@ss.hasPermi('linkwechat:msg:list')") + @GetMapping("/list") + public TableDataInfo> list(WeChatContactMsg weChatContactMsg) { + startPage(); + List list = iWeChatContactMsgService.queryList(weChatContactMsg); + return getDataTable(list); + } + + /** + * 导出会话消息列表 + */ + @ApiOperation("导出会话消息列表") + @PreAuthorize("@ss.hasPermi('linkwechat:msg:export')" ) + @Log(title = "会话消息" , businessType = BusinessType.EXPORT) + @GetMapping("/export" ) + public AjaxResult export(WeChatContactMsg weChatContactMsg) { + List list = iWeChatContactMsgService.queryList(weChatContactMsg); + ExcelUtil util = new ExcelUtil(WeChatContactMsg.class); + return util.exportExcel(list, "msg" ); + } + + /** + * 获取会话消息详细信息 + */ + @ApiOperation("获取会话消息详细信息") + @PreAuthorize("@ss.hasPermi('linkwechat:msg:query')" ) + @GetMapping(value = "/{id}" ) + public AjaxResult getInfo(@PathVariable("id" ) Long id) { + return AjaxResult.success(iWeChatContactMsgService.getById(id)); + } + + /** + * 新增会话消息 + */ + @ApiOperation("新增会话消息") + @PreAuthorize("@ss.hasPermi('linkwechat:msg:add')" ) + @Log(title = "会话消息" , businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody WeChatContactMsg weChatContactMsg) { + return toAjax(iWeChatContactMsgService.save(weChatContactMsg) ? 1 : 0); + } + + /** + * 修改会话消息 + */ + @ApiOperation("修改会话消息") + @PreAuthorize("@ss.hasPermi('linkwechat:msg:edit')" ) + @Log(title = "会话消息" , businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody WeChatContactMsg weChatContactMsg) { + return toAjax(iWeChatContactMsgService.updateById(weChatContactMsg) ? 1 : 0); + } + + /** + * 删除会话消息 + */ + @ApiOperation("删除会话消息") + @PreAuthorize("@ss.hasPermi('linkwechat:msg:remove')" ) + @Log(title = "会话消息" , businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}" ) + public AjaxResult remove(@PathVariable Long[] ids) { + return toAjax(iWeChatContactMsgService.removeByIds(Arrays.asList(ids)) ? 1 : 0); + } + + /** + * 外部联系人/单聊 会话列表 + */ + @ApiOperation("外部联系人 会话列表") + @Log(title = "外部联系人 会话列表" , businessType = BusinessType.OTHER) + @GetMapping("/selectExternalChatList/{fromId}" ) + public AjaxResult> selectExternalChatList(@PathVariable("fromId") String fromId) { + return AjaxResult.success(iWeChatContactMsgService.selectExternalChatList(fromId)); + } + + /** + * 外部联系人/单聊 会话列表 + */ + @ApiOperation("单聊 会话列表") + @Log(title = "单聊 会话列表" , businessType = BusinessType.OTHER) + @GetMapping("/selectAloneChatList" ) + public AjaxResult> selectAloneChatList(WeChatContactMsg weChatContactMsg) { + return AjaxResult.success(iWeChatContactMsgService.selectAloneChatList(weChatContactMsg)); + } + + /** + * 内部联系人 会话列表 + */ + @ApiOperation("内部联系人 会话列表") + @Log(title = "内部联系人 会话列表" , businessType = BusinessType.OTHER) + @GetMapping("/selectInternalChatList/{fromId}" ) + public AjaxResult> selectInternalChatList(@PathVariable("fromId") String fromId) { + return AjaxResult.success(iWeChatContactMsgService.selectInternalChatList(fromId)); + } + + /** + * 群聊 会话列表 + */ + @ApiOperation("群聊 会话列表") + @Log(title = "群聊 会话列表" , businessType = BusinessType.OTHER) + @GetMapping("/selectGroupChatList/{fromId}" ) + public AjaxResult> selectGroupChatList(@PathVariable("fromId") String fromId) { + return AjaxResult.success(iWeChatContactMsgService.selectGroupChatList(fromId)); + } + + /** + * 全文检索 会话列表 + */ + @ApiOperation("全文检索 会话列表") + @Log(title = "全文检索 会话列表" , businessType = BusinessType.OTHER) + @GetMapping("/selectFullSearchChatList" ) + public TableDataInfo> selectFullSearchChatList(WeChatContactMsg weChatContactMsg) { + startPage(); + List list = iWeChatContactMsgService.selectFullSearchChatList(weChatContactMsg); + return getDataTable(list); + } + + /** + * 全文检索 会话列表 + */ + @ApiOperation("全文检索 导出列表") + @Log(title = "全文检索 导出列表" , businessType = BusinessType.OTHER) + @GetMapping("/selectFullSearchChatList/export" ) + public AjaxResult fullSearchChatListExport(WeChatContactMsg weChatContactMsg) { + List list = iWeChatContactMsgService.selectFullSearchChatList(weChatContactMsg); + ExcelUtil util = new ExcelUtil(WeChatContactMsgVo.class); + return util.exportExcel(list, "msg" ); + } +} diff --git a/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeChatItemController.java b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeChatItemController.java new file mode 100644 index 0000000000000000000000000000000000000000..09e0fde82e13cb0aec32c70f51582af3c7747773 --- /dev/null +++ b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeChatItemController.java @@ -0,0 +1,119 @@ +package com.linkwechat.web.controller.wecom; + +import cn.hutool.core.collection.CollectionUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.linkwechat.common.annotation.Log; +import com.linkwechat.common.core.controller.BaseController; +import com.linkwechat.common.core.domain.AjaxResult; +import com.linkwechat.common.core.page.TableDataInfo; +import com.linkwechat.common.enums.BusinessType; +import com.linkwechat.common.enums.MediaType; +import com.linkwechat.wecom.domain.WeChatItem; +import com.linkwechat.wecom.domain.WeMaterial; +import com.linkwechat.wecom.domain.dto.WeChatItemDto; +import com.linkwechat.wecom.domain.vo.WeChatSideVo; +import com.linkwechat.wecom.service.IWeChatItemService; +import com.linkwechat.wecom.service.IWeMaterialService; +import com.linkwechat.wecom.service.IWePosterService; +import io.swagger.annotations.ApiOperation; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 聊天工具侧边栏 + * + * @author kewen + */ +@RequestMapping(value = "/wecom/chat/item") +@RestController +public class WeChatItemController extends BaseController { + + @Autowired + private IWeChatItemService weChatItemService; + + @Autowired + private IWeMaterialService materialService; + + @Resource + private IWePosterService wePosterService; + + + + + + // @PreAuthorize("@ss.hasPermi('wecom:material:list')") + @GetMapping("/mList") + @ApiOperation("获取侧边栏选中或者未选中素材") + public TableDataInfo mList(@RequestParam(value = "categoryId", required = false) String categoryId + , @RequestParam(value = "search", required = false) String search,@RequestParam(value = "mediaType") String mediaType) { + startPage(); + List list; + if(StringUtils.isNotBlank(mediaType) && mediaType.equals(MediaType.POSTER.getType())){ + list = wePosterService.list(StringUtils.isBlank(categoryId)?null:Long.valueOf(categoryId),search).stream().map(wePoster -> { + WeMaterial weMaterial = new WeMaterial(); + weMaterial.setMaterialName(wePoster.getTitle()); + weMaterial.setMaterialUrl(wePoster.getSampleImgPath()); + weMaterial.setCategoryId(wePoster.getCategoryId()); + weMaterial.setId(wePoster.getId()); + return weMaterial; + }).collect(Collectors.toList()); + }else { + list = materialService.findWeMaterials(categoryId, search,mediaType); + } + + if(CollectionUtil.isNotEmpty(list)){ + List weChatItems = weChatItemService.list(new LambdaQueryWrapper() + .in(WeChatItem::getMaterialId,list.stream().map(WeMaterial::getId).collect(Collectors.toList()))); + if(CollectionUtil.isNotEmpty(weChatItems)){ + list.stream().forEach(k->{ + k.setIsCheck( + weChatItems.stream().filter(item -> item.getMaterialId() + .equals(k.getId())).findFirst().isPresent()?true:false + ); + }); + } + } + + return getDataTable(list); + } + + + /** + * 侧边栏抓取素材 + */ +// @PreAuthorize("@ss.hasPermi('chat:item:add')") + @Log(title = "侧边栏抓取素材", businessType = BusinessType.INSERT) + @PutMapping + public AjaxResult add(@RequestBody WeChatItemDto chatItemDto) { + return toAjax(weChatItemService.checkItems(chatItemDto)); + } + + /** + * h5素材列表 + */ + //@PreAuthorize("@ss.hasPermi('chat:item:list')") + @GetMapping("/list") + public TableDataInfo list(@RequestParam(value = "sideId") Long sideId + , @RequestParam(value = "keyword", required = false) String keyword,@RequestParam(value = "mediaType") String mediaType,@RequestParam(value = "userId") String userId) { + startPage(); + List weChatSideVos; + if(mediaType.equals("5")){ + weChatSideVos=weChatItemService.findChatPostsItems(sideId,keyword,mediaType,userId); + }else{ + weChatSideVos + = weChatItemService.chatItems(sideId,keyword,mediaType,userId); + } + return getDataTable(weChatSideVos); + } + + + + + +} diff --git a/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeChatSideController.java b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeChatSideController.java new file mode 100644 index 0000000000000000000000000000000000000000..9bc6eddf6532697e9bfbb4a0021fdbff5d242e9e --- /dev/null +++ b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeChatSideController.java @@ -0,0 +1,60 @@ +package com.linkwechat.web.controller.wecom; + +import com.linkwechat.common.annotation.Log; +import com.linkwechat.common.core.controller.BaseController; +import com.linkwechat.common.core.domain.AjaxResult; +import com.linkwechat.common.core.page.TableDataInfo; +import com.linkwechat.common.enums.BusinessType; +import com.linkwechat.wecom.domain.WeChatSide; +import com.linkwechat.wecom.service.IWeChatSideService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 聊天工具侧边栏 + * + * @author kewen + */ +@RequestMapping(value = "/wecom/chat/side") +@RestController +public class WeChatSideController extends BaseController { + + + @Autowired + public IWeChatSideService weChatSideService; + + /** + * 群发侧边栏列表 + */ +// @PreAuthorize("@ss.hasPermi('chat:side:list')") + @GetMapping("/list") + public TableDataInfo list() { + startPage(); + List weChatSides = weChatSideService.chatSides("0"); + return getDataTable(weChatSides); + } + + /** + * 更新侧边栏信息 + */ +// @PreAuthorize("@ss.hasPermi('chat:side:edit')") + @Log(title = "更新侧边栏信息", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody WeChatSide weChatSide) { + return toAjax(weChatSideService.updateWeChatSide(weChatSide)); + } + + /** + * 群发侧边栏列表 + */ + @GetMapping("/h5List") + public TableDataInfo h5List() { + startPage(); + List weChatSides = weChatSideService.chatSides("1"); + return getDataTable(weChatSides); + } + +} diff --git a/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeCommunityGroupSopController.java b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeCommunityGroupSopController.java new file mode 100644 index 0000000000000000000000000000000000000000..c00d8ec20fa0ea43a663c96f0c5d515b20e40de6 --- /dev/null +++ b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeCommunityGroupSopController.java @@ -0,0 +1,153 @@ +package com.linkwechat.web.controller.wecom; + +import com.linkwechat.common.constant.HttpStatus; +import com.linkwechat.common.core.controller.BaseController; +import com.linkwechat.common.core.domain.AjaxResult; +import com.linkwechat.common.core.page.TableDataInfo; +import com.linkwechat.common.utils.SecurityUtils; +import com.linkwechat.wecom.domain.WeGroupSop; +import com.linkwechat.wecom.domain.dto.WeGroupSopDto; +import com.linkwechat.wecom.domain.vo.WeGroupSopVo; +import com.linkwechat.wecom.service.IWeGroupSopService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 社区运营 - 群sop controller + */ +@Api(description = "新客自动拉群 Controller") +@RestController +@RequestMapping(value = "/wecom/communityGroupSop") +public class WeCommunityGroupSopController extends BaseController { + + @Autowired + private IWeGroupSopService groupSopService; + + /** + * 通过过滤条件获取群sop列表 + * + * @param ruleName 规则名称 + * @param createBy 创建者 + * @param beginTime 创建区间 - 开始时间 + * @param endTime 创建区间 - 结束时间 + * @return 群sop规则列表 + */ + @ApiOperation(value = "通过过滤条件获取群sop列表", httpMethod = "GET") +// @PreAuthorize("@ss.hasPermi('wecom:communityGroupSop:list')") + @GetMapping(path = "/list") + public TableDataInfo> getSopList( + @RequestParam(value = "ruleName", required = false) String ruleName, + @RequestParam(value = "createBy", required = false) String createBy, + @RequestParam(value = "beginTime", required = false) String beginTime, + @RequestParam(value = "endTime", required = false) String endTime + ) + { + startPage(); + List groupSopVoList = groupSopService.getGroupSopList(ruleName, createBy, beginTime, endTime); + return getDataTable(groupSopVoList); + } + + /** + * 新增SOP规则 + * + * @param groupSopDto 更新数据 + * @return 结果 + */ + @ApiOperation(value = "新增SOP规则", httpMethod = "POST") +// @PreAuthorize("@ss.hasPermi('wecom:communityGroupSop:add')") + @PostMapping(path = "/") + public AjaxResult addGroupSop(@Validated @RequestBody WeGroupSopDto groupSopDto) { + + WeGroupSop weGroupSop = new WeGroupSop(); + BeanUtils.copyProperties(groupSopDto, weGroupSop); + + if (groupSopService.isNameOccupied(weGroupSop)) { + return AjaxResult.error(HttpStatus.BAD_REQUEST, "规则名称已存在"); + } + weGroupSop.setCreateBy(SecurityUtils.getUsername()); + // 群聊id列表 + List groupIdList = groupSopDto.getChatIdList(); + // 素材URL + List materialIdList = groupSopDto.getMaterialIdList(); + // 上传的图片的URl列表 + List picList = groupSopDto.getPicList(); + int affectedRows = groupSopService.addGroupSop(weGroupSop, groupIdList, materialIdList, picList); + if (affectedRows > 0) { + // 添加成功后进行异步消息推送 + groupSopService.sendMessage(groupIdList); + } + return toAjax(affectedRows); + } + + /** + * 通过规则id获取sop规则 + * + * @param ruleId 规则id + * @return 结果 + */ + @ApiOperation(value = "通过规则id获取sop规则详情", httpMethod = "GET") +// @PreAuthorize("@ss.hasPermi('wecom:communityGroupSop:query')") + @GetMapping(path = "/{ruleId}") + public AjaxResult getGroupSop(@PathVariable("ruleId") Long ruleId) { + WeGroupSopVo groupSopVo = groupSopService.getGroupSopById(ruleId); + if (null == groupSopVo) { + return AjaxResult.error(HttpStatus.NOT_FOUND, "该群SOP规则不存在"); + } + return AjaxResult.success(groupSopVo); + } + + /** + * 更改SOP规则 + * + * @param ruleId SOP规则 id + * @param groupSopDto 更新数据 + * @return 结果 + */ + @ApiOperation(value = "更改SOP规则", httpMethod = "PUT") +// @PreAuthorize("@ss.hasPermi('wecom:communityGroupSop:edit')") + @PutMapping(path = "/{ruleId}") + public AjaxResult updateGroupSop(@PathVariable Long ruleId, @Validated @RequestBody WeGroupSopDto groupSopDto) { + // 校验是否存在 + if (null == groupSopService.getGroupSopById(ruleId)) { + return AjaxResult.error(HttpStatus.NOT_FOUND, "该群SOP规则不存在"); + } + WeGroupSop weGroupSop = new WeGroupSop(); + weGroupSop.setRuleId(ruleId); + BeanUtils.copyProperties(groupSopDto, weGroupSop); + + // 校验规则名是否可用 + if (groupSopService.isNameOccupied(weGroupSop)) { + return AjaxResult.error(HttpStatus.BAD_REQUEST, "规则名称已存在"); + } + + weGroupSop.setUpdateBy(SecurityUtils.getUsername()); + // 群聊id列表 + List groupIdList = groupSopDto.getChatIdList(); + // 素材id列表 + List materialIdList = groupSopDto.getMaterialIdList(); + // 上传的图片的URl列表 + List picList = groupSopDto.getPicList(); + return toAjax(groupSopService.updateGroupSop(weGroupSop, groupIdList, materialIdList, picList)); + } + + /** + * 根据id列表批量删除群sop规则 + * + * @param ids 群sop规则列表 + * @return 结果 + */ + @ApiOperation(value = "根据id列表批量删除群sop规则", httpMethod = "DELETE") +// @PreAuthorize("@ss.hasPermi('wecom:communityGroupSop:remove')") + @DeleteMapping(path = "/{ids}") + public AjaxResult batchDeleteSopRule(@PathVariable("ids") Long[] ids) { + return toAjax(groupSopService.batchRemoveGroupSopByIds(ids)); + } + +} diff --git a/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeCommunityH5Controller.java b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeCommunityH5Controller.java new file mode 100644 index 0000000000000000000000000000000000000000..94ffc7cdeb9e3c6de62bb90248a0f80217adeef7 --- /dev/null +++ b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeCommunityH5Controller.java @@ -0,0 +1,121 @@ +package com.linkwechat.web.controller.wecom; + +import com.linkwechat.common.core.controller.BaseController; +import com.linkwechat.common.core.domain.AjaxResult; +import com.linkwechat.common.core.domain.entity.SysUser; +import com.linkwechat.common.core.page.TableDataInfo; +import com.linkwechat.common.enums.CommunityTaskType; +import com.linkwechat.system.service.ISysUserService; +import com.linkwechat.wecom.domain.WeKeywordGroupTask; +import com.linkwechat.wecom.service.IWeCommunityKeywordToGroupService; +import com.linkwechat.wecom.service.IWeGroupSopService; +import com.linkwechat.wecom.service.IWePresTagGroupTaskService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.ArrayList; +import java.util.List; + +/** + * 社区运营H5接口 + * + * @Author Hang + * @Date 2021/3/24 10:54 + */ +@RestController +@RequestMapping(value = "/wecom/community/h5") +public class WeCommunityH5Controller extends BaseController { + + @Autowired + IWePresTagGroupTaskService tagGroupTaskService; + + @Autowired + IWeGroupSopService sopService; + + @Autowired + IWeCommunityKeywordToGroupService keywordToGroupService; + + @Autowired + ISysUserService userService; + + /** + * 获取任务对应的执行人列表 + * @param taskId 任务id + * @param type 任务类型 1:标签建群任务 2:sop任务 + * @return + */ + @GetMapping("/scope/{taskId}") + public AjaxResult getTaskScopeList(@PathVariable("taskId") Long taskId, @RequestParam(value = "type") Integer type) { + if (type.equals(CommunityTaskType.TAG.getType())) { + return AjaxResult.success(tagGroupTaskService.getScopeListByTaskId(taskId)); + } else { + return AjaxResult.success(sopService.getScopeListByRuleId(taskId)); + } + } + + /** + * h5页面根据员工id获取老客标签建群和群sop任务信息 + * + * @param emplId 员工id + * @param type 数据类型,0:全部数据 1:老客标签建群数据 2:群SOP数据 + * @return + */ + @GetMapping("/{emplId}") + public AjaxResult getEmplTask(@PathVariable("emplId") String emplId, @RequestParam(value = "type") Integer type) { + AjaxResult res = AjaxResult.success(); + if (type.equals(CommunityTaskType.TAG.getType())) { + // 老客标签建群数据 + res.put("todo", tagGroupTaskService.getFollowerTaskList(emplId, 0)); + res.put("done", tagGroupTaskService.getFollowerTaskList(emplId, 1)); + } else if (type.equals(CommunityTaskType.SOP.getType())) { + // 群SOP数据 + res.put("todo", sopService.getEmplTaskList(emplId, false)); + res.put("done", sopService.getEmplTaskList(emplId, true)); + } else { + // 全部数据 + List todoList = new ArrayList(); + List doneList = new ArrayList(); + todoList.addAll(tagGroupTaskService.getFollowerTaskList(emplId, 0)); + todoList.addAll(sopService.getEmplTaskList(emplId, false)); + res.put("todo", todoList); + doneList.addAll(tagGroupTaskService.getFollowerTaskList(emplId, 1)); + doneList.addAll(sopService.getEmplTaskList(emplId, true)); + res.put("done", doneList); + } + SysUser user = userService.selectUserByUserName(emplId); + boolean isAdmin = user != null && user.isAdmin(); + res.put("isAdmin", isAdmin); + return res; + } + + /** + * 员工发送老客标签建群任务信息或者发送sop到其客户群之后,变更其任务状态 + * + * @param taskId 老客标签建群时代表任务id,sop时,代表规则id + * @param emplId 老客标签建群时代表员工id,sop时,代表群主 + * @param type 类型 0:老客标签建群 1:sop + * @return 结果 + */ + @GetMapping("/changeStatus") + public AjaxResult changeStatus(@RequestParam("taskId") Long taskId, @RequestParam("emplId") String emplId, @RequestParam("type") Integer type) { + if (type.equals(0)) { + + return toAjax(tagGroupTaskService.updateFollowerTaskStatus(taskId, emplId)); + } else { + return toAjax(sopService.updateChatSopStatus(taskId, emplId)); + } + } + + /** + * 用于支持H5页面的名称和关键字检索 + * + * @param word 过滤字符 + * @return 结果 + */ + @GetMapping(path = "/filter") + public TableDataInfo filter(@RequestParam("word") String word) { + startPage(); + List taskList = keywordToGroupService.filterByNameOrKeyword(word); + return getDataTable(taskList); + } +} diff --git a/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeCommunityKeywordGroupController.java b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeCommunityKeywordGroupController.java new file mode 100644 index 0000000000000000000000000000000000000000..3e6517d0c96b3cba53b71a1064165af4246e5a16 --- /dev/null +++ b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeCommunityKeywordGroupController.java @@ -0,0 +1,101 @@ +package com.linkwechat.web.controller.wecom; + +import com.linkwechat.common.core.controller.BaseController; +import com.linkwechat.common.core.domain.AjaxResult; +import com.linkwechat.common.core.page.TableDataInfo; +import com.linkwechat.common.utils.SecurityUtils; +import com.linkwechat.wecom.domain.WeKeywordGroupTask; +import com.linkwechat.wecom.service.IWeCommunityKeywordToGroupService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.Date; +import java.util.List; + +/** + * 关键词拉群controller + */ +@Api(tags = "关键词拉群") +@RestController +@RequestMapping(value = "/wecom/communityKeywordGroup") +public class WeCommunityKeywordGroupController extends BaseController { + + @Autowired + private IWeCommunityKeywordToGroupService service; + + + /** + * 根据过滤条件获取关键词拉群任务列表 + */ + @ApiOperation(value = "获取关键词拉群任务列表") +// @PreAuthorize("@ss.hasPermi('wecom:communityKeyword:list')") + @GetMapping(path = "/list") + public TableDataInfo> list(WeKeywordGroupTask task) { + startPage(); + List taskList = service.getTaskList(task); + return getDataTable(taskList); + } + + /** + * 根据id获取任务详情 + * + * @param taskId 任务id + * @return 任务详情 + */ + @ApiOperation(value = "获取任务详情") + // @PreAuthorize("@ss.hasPermi('wecom:communityKeyword:query')") + @GetMapping(path = "/{taskId}") + public AjaxResult getTask(@ApiParam("任务id") @PathVariable("taskId") Long taskId) { + return AjaxResult.success(service.getTaskById(taskId)); + } + + /** + * 添加新任务 + * + * @param task 添加任务所需的数据 + * @return 结果 + */ + @ApiOperation(value = "添加新任务") + // @PreAuthorize("@ss.hasPermi('wecom:communityKeyword:add')") + @PostMapping(path = "/") + public AjaxResult addTask(@RequestBody @Validated WeKeywordGroupTask task) { + if (service.isNameOccupied(task)) { + return AjaxResult.error("关键词拉群任务名称"+ task.getTaskName() +"已存在"); + } + task.setCreateBy(SecurityUtils.getUsername()); + task.setCreateTime(new Date()); + return toAjax(service.addTask(task)); + } + + /** + * 根据id及更新数据对指定任务进行更新 + */ + @ApiOperation(value = "更新任务") + // @PreAuthorize("@ss.hasPermi('wecom:communityKeyword:edit')") + @PutMapping("/{taskId}") + public AjaxResult updateTask( + @ApiParam("任务id") @PathVariable("taskId") Long taskId, @RequestBody @Validated WeKeywordGroupTask task) { + task.setTaskId(taskId); + task.setUpdateBy(SecurityUtils.getUsername()); + task.setUpdateTime(new Date()); + return toAjax(service.updateTask(task)); + } + + /** + * 通过id列表批量删除任务 + * + * @param ids id列表 + * @return 结果 + */ + @ApiOperation(value = "批量删除任务") + // @PreAuthorize("@ss.hasPermi('wecom:communityKeyword:remove')") + @DeleteMapping(path = "/{ids}") + public AjaxResult batchDeleteTask(@ApiParam("待删除任务id数组") @PathVariable("ids") Long[] ids) { + return toAjax(service.batchRemoveTaskByIds(ids)); + } + +} diff --git a/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeCommunityNewGroupController.java b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeCommunityNewGroupController.java new file mode 100644 index 0000000000000000000000000000000000000000..706a1758e298e9e3f34eeb388b61076add39c55f --- /dev/null +++ b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeCommunityNewGroupController.java @@ -0,0 +1,164 @@ +package com.linkwechat.web.controller.wecom; + +import com.linkwechat.common.annotation.Log; +import com.linkwechat.common.constant.HttpStatus; +import com.linkwechat.common.core.controller.BaseController; +import com.linkwechat.common.core.domain.AjaxResult; +import com.linkwechat.common.core.page.TableDataInfo; +import com.linkwechat.common.enums.BusinessType; +import com.linkwechat.common.utils.file.FileUtils; +import com.linkwechat.wecom.domain.WeCommunityNewGroup; +import com.linkwechat.wecom.domain.WeEmpleCode; +import com.linkwechat.wecom.domain.dto.WeCommunityNewGroupDto; +import com.linkwechat.wecom.domain.vo.WeCommunityNewGroupVo; +import com.linkwechat.wecom.service.IWeCommunityNewGroupService; +import com.linkwechat.wecom.service.IWeEmpleCodeService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.*; +import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +/** + * 社群运营 新客自动拉群 Controller + * + * @author kewen + * @date 2021-02-19 + */ +@Api(tags = "新客自动拉群 Controller") +@RestController +@RequestMapping(value = "/wecom/communityNewGroup") +public class WeCommunityNewGroupController extends BaseController { + + @Autowired + private IWeCommunityNewGroupService weCommunityNewGroupService; + + @Autowired + private IWeEmpleCodeService weEmpleCodeService; + + /** + * 新增新客自动拉群 + */ + @ApiOperation(value = "新增新客自动拉群", httpMethod = "POST") + // @PreAuthorize("@ss.hasPermi('wecom:communityNewGroup:add')") + @Log(title = "新客自动拉群", businessType = BusinessType.INSERT) + @PostMapping("/") + public AjaxResult add(@RequestBody @Validated WeCommunityNewGroupDto communityNewGroupDto) { + return toAjax(weCommunityNewGroupService.add(communityNewGroupDto)); + } + + /** + * 单个下载 + * + * @param id 待下载员工活码 + * @param request 请求 + * @param response 响应 + */ + @ApiOperation(value = "员工活码下载", httpMethod = "GET") + // @PreAuthorize("@ss.hasPermi('wecom:code:download')") + @Log(title = "员工活码下载", businessType = BusinessType.OTHER) + @GetMapping("/download") + public void download(String id, HttpServletRequest request, HttpServletResponse response) { + Optional communityNewGroupVo = weCommunityNewGroupService.selectWeCommunityNewGroupById(Long.valueOf(id)); + communityNewGroupVo.ifPresent(e -> { + try { + WeEmpleCode empleCode = weEmpleCodeService.selectWeEmpleCodeById(e.getEmplCodeId()); + FileUtils.downloadFile(empleCode.getQrCode(), response.getOutputStream()); + } catch (IOException exc) { + exc.printStackTrace(); + } + }); + } + + /** + * 员工活码批量下载 + * + * @param ids 新客自动拉群ids + * @param request 请求 + * @param response 输出 + */ + @ApiOperation(value = "员工活码批量下载", httpMethod = "GET") + // @PreAuthorize("@ss.hasPermi('wecom:code:downloadBatch')") + @Log(title = "员工活码批量下载", businessType = BusinessType.OTHER) + @GetMapping("/downloadBatch") + public void downloadBatch(Long[] ids, HttpServletRequest request, HttpServletResponse response) { + List> fileList = weCommunityNewGroupService + .selectWeCommunityNewGroupByIds(Arrays.asList(ids)) + .stream() + .map(e -> { + WeEmpleCode code = weEmpleCodeService.getById(e.getEmplCodeId()); + Map fileMap = new HashMap<>(); + fileMap.put("fileName", code.getScenario()+".jpg"); + fileMap.put("url", code.getQrCode()); + return fileMap; + }) + .collect(Collectors.toList()); + try { + FileUtils.batchDownloadFile(fileList, response.getOutputStream()); + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * 查询新客自动拉群列表 + */ + @ApiOperation(value = "查询新客自动拉群列表", httpMethod = "GET") + // @PreAuthorize("@ss.hasPermi('wecom:communityNewGroup:list')") + @GetMapping("/list") + public TableDataInfo> list(WeCommunityNewGroup weCommunityNewGroup) { + startPage(); + List communityNewGroupVos = weCommunityNewGroupService.selectWeCommunityNewGroupList(weCommunityNewGroup); + return getDataTable(communityNewGroupVos); + } + + /** + * 获取新客自动拉群详细信息 + */ + @ApiOperation(value = "获取新客自动拉群详细信息", httpMethod = "GET") + // @PreAuthorize("@ss.hasPermi('wecom:communityNewGroup:query')") + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("id") @ApiParam("主键ID") String id) { + Optional communityNewGroupVo = weCommunityNewGroupService.selectWeCommunityNewGroupById(Long.valueOf(id)); + if (communityNewGroupVo.isPresent()) { + return AjaxResult.success(communityNewGroupVo); + } + return AjaxResult.error(HttpStatus.NOT_FOUND, "新客拉群信息不存在"); + } + + /** + * 修改新客自动拉群 + */ + @ApiOperation(value = "修改新客自动拉群", httpMethod = "PUT") + // @PreAuthorize("@ss.hasPermi('wecom:communityNewGroup:edit')") + @Log(title = "新客自动拉群", businessType = BusinessType.UPDATE) + @PutMapping("/{id}") + public AjaxResult edit(@PathVariable("id") String id, @RequestBody @Validated WeCommunityNewGroupDto communityNewGroupDto) { + return toAjax(weCommunityNewGroupService.updateWeCommunityNewGroup(Long.valueOf(id), communityNewGroupDto)); + } + + /** + * 删除新客自动拉群 + */ + @ApiOperation(value = "删除新客自动拉群", httpMethod = "DELETE") + // @PreAuthorize("@ss.hasPermi('wecom:communityNewGroup:remove')") + @Log(title = "新客自动拉群", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable Long[] ids) { + return toAjax(weCommunityNewGroupService.batchRemoveWeCommunityNewGroupByIds(Arrays.asList(ids))); + } + +} + diff --git a/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeCommunityPresTagGroupController.java b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeCommunityPresTagGroupController.java new file mode 100644 index 0000000000000000000000000000000000000000..f01c1506545bbf644450b6fecff1b3d005ae8142 --- /dev/null +++ b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeCommunityPresTagGroupController.java @@ -0,0 +1,132 @@ +package com.linkwechat.web.controller.wecom; + + +import com.linkwechat.common.constant.HttpStatus; +import com.linkwechat.common.core.controller.BaseController; +import com.linkwechat.common.core.domain.AjaxResult; +import com.linkwechat.common.core.page.TableDataInfo; +import com.linkwechat.common.utils.SecurityUtils; +import com.linkwechat.common.utils.StringUtils; +import com.linkwechat.wecom.domain.WePresTagGroupTask; +import com.linkwechat.wecom.domain.WePresTagGroupTaskStat; +import com.linkwechat.wecom.domain.vo.WePresTagGroupTaskVo; +import com.linkwechat.wecom.domain.vo.WePresTagTaskListVO; +import com.linkwechat.wecom.service.IWePresTagGroupTaskService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.Date; +import java.util.List; + +@Api("老客标签建群接口") +@RestController +@RequestMapping(value = "/wecom/communityPresTagGroup") +public class WeCommunityPresTagGroupController extends BaseController { + + @Autowired + IWePresTagGroupTaskService taskService; + + + /** + * 获取老客标签建群列表数据 + */ + // @PreAuthorize("@ss.hasPermi('wecom:communitytagGroup:list')") + @GetMapping(path = "/list") + @ApiOperation(value = "获取老客标签建群任务分页数据", httpMethod = "GET") + public TableDataInfo> getPage( + @RequestParam(value = "taskName", required = false) String taskName, + @RequestParam(value = "sendType", required = false) Integer sendType, + @RequestParam(value = "createBy", required = false) String createBy, + @RequestParam(value = "beginTime", required = false) String beginTime, + @RequestParam(value = "endTime", required = false) String endTime) { + startPage(); + List result = taskService.selectTaskList(taskName, sendType, createBy, beginTime, endTime); + return getDataTable(result); + } + + /** + * 新建老客标签建群任务 + */ + // @PreAuthorize("@ss.hasPermi('wecom:communitytagGroup:add')") + @PostMapping + @ApiOperation(value = "新建老客标签建群任务", httpMethod = "POST") + public AjaxResult add(@RequestBody @Validated WePresTagGroupTask task) { + // 检测任务名是否可用 + if (taskService.isNameOccupied(task)) { + return AjaxResult.error("任务名已存在"); + } + task.setCreateBy(SecurityUtils.getUsername()); + int affectedRows = taskService.add(task); + // 再发送消息 + if (affectedRows > 0) taskService.sendMessage(task); + return toAjax(affectedRows); + } + + /** + * 根据获取任务详细信息 + */ + // @PreAuthorize("@ss.hasPermi('wecom:communitytagGroup:query')") + @GetMapping(path = "/{id}") + @ApiOperation(value = "根据获取任务详细信息", httpMethod = "GET") + public AjaxResult getInfo(@PathVariable("id") Long id) { + WePresTagGroupTaskVo taskVo = taskService.getTaskById(id); + if (StringUtils.isNull(taskVo)) { + return AjaxResult.error(HttpStatus.NOT_FOUND, "群活码不存在"); + } + return AjaxResult.success(taskVo); + } + + /** + * 更新任务信息 + */ + // @PreAuthorize("@ss.hasPermi('wecom:communitytagGroup:edit')") + @PutMapping(path = "/{id}") + @ApiOperation(value = "更新任务信息", httpMethod = "PUT") + public AjaxResult update(@PathVariable("id") Long id, @RequestBody @Validated WePresTagGroupTask task) { + + try { + // 保存新任务 + task.setTaskId(id); + task.setUpdateBy(SecurityUtils.getUsername()); + task.setUpdateTime(new Date()); + taskService.updateTaskAndSendMsg(task); + }catch (Exception e){ + return AjaxResult.error(e.getMessage()); + } + + return AjaxResult.success(); + } + + /** + * 批量删除老客标签建群任务 + */ + // @PreAuthorize("@ss.hasPermi('wecom:communitytagGroup:remove')") + @DeleteMapping(path = "/{ids}") + @ApiOperation(value = "批量删除老客标签建群任务", httpMethod = "DELETE") + public AjaxResult batchRemove(@PathVariable("ids") Long[] ids) { + return toAjax(taskService.batchRemoveTaskByIds(ids)); + } + + /** + * 根据老客标签建群id及过滤条件,获取其统计信息 + */ + // @PreAuthorize("@ss.hasPermi('wecom:communitytagGroup:query')") + @GetMapping(path = "/stat/{id}") + public TableDataInfo> getStatInfo( + @PathVariable("id") Long id, + @RequestParam(value = "customerName", required = false) String customerName, + @RequestParam(value = "isInGroup", required = false) Integer isInGroup, + @RequestParam(value = "isSent", required = false) Integer isSent + ) { + + WePresTagGroupTask task = taskService.getById(id); + startPage(); + List stats = taskService.getTaskStat(id, customerName, isInGroup, isSent, task.getSendType()); + return getDataTable(stats); + } + + +} diff --git a/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeCorpAccountController.java b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeCorpAccountController.java index 17be9619de5d570bfea7b3fa94182fd160f00362..2260b847156946f4bd1e1ec8d4a0bc5512acf3bb 100644 --- a/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeCorpAccountController.java +++ b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeCorpAccountController.java @@ -1,90 +1,72 @@ package com.linkwechat.web.controller.wecom; import com.linkwechat.common.annotation.Log; -import com.linkwechat.common.core.controller.BaseController; import com.linkwechat.common.core.domain.AjaxResult; -import com.linkwechat.common.core.page.TableDataInfo; +import com.linkwechat.common.core.domain.entity.WeCorpAccount; import com.linkwechat.common.enums.BusinessType; -import com.linkwechat.wecom.domain.WeCorpAccount; import com.linkwechat.wecom.service.IWeCorpAccountService; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; -import java.util.List; - -/** - * 企业id相关配置Controller - * - * @author ruoyi - * @date 2020-08-24 - */ @RestController -@RequestMapping("/wecom/corp") -public class WeCorpAccountController extends BaseController -{ +@RequestMapping(value = "/wecom/corp") +public class WeCorpAccountController { + @Autowired - private IWeCorpAccountService weCorpAccountService; + private IWeCorpAccountService iWeCorpAccountService; + /** - * 查询企业id相关配置列表 + * 获取当前企业可用密钥 + * @return */ - @PreAuthorize("@ss.hasPermi('wechat:corp:list')") - @GetMapping("/list") - public TableDataInfo list(WeCorpAccount weCorpAccount) - { - startPage(); - List list = weCorpAccountService.selectWeCorpAccountList(weCorpAccount); - return getDataTable(list); + @GetMapping("/findCurrentCorpAccount") + public AjaxResult findCurrentCorpAccount(){ + + return AjaxResult.success( + iWeCorpAccountService.findValidWeCorpAccount() + ); } /** - * 获取企业id相关配置详细信息 + * 新增或更新企业配置相关 + * @param weCorpAccount + * @return */ - @PreAuthorize("@ss.hasPermi('wechat:corp:query')") - @GetMapping(value = "/{id}") - public AjaxResult getInfo(@PathVariable("id") Long id) + @Log(title = "新增或更新企业配置相关", businessType = BusinessType.INSERT) + @PostMapping("/addOrUpdate") + public AjaxResult addOrUpdate(@RequestBody WeCorpAccount weCorpAccount) { - return AjaxResult.success(weCorpAccountService.selectWeCorpAccountById(id)); - } + iWeCorpAccountService.saveOrUpdate(weCorpAccount); - /** - * 新增企业id相关配置 - */ - @PreAuthorize("@ss.hasPermi('wechat:corp:add')") - @Log(title = "新增企业id相关配置", businessType = BusinessType.INSERT) - @PostMapping - public AjaxResult add(@Validated @RequestBody WeCorpAccount weCorpAccount) - { - return toAjax(weCorpAccountService.insertWeCorpAccount(weCorpAccount)); + return AjaxResult.success(); } + /** - * 修改企业id相关配置 + * 客户流失通知开关 + * @param status + * @return */ - @PreAuthorize("@ss.hasPermi('wechat:corp:edit')") - @Log(title = "修改企业id相关配置", businessType = BusinessType.UPDATE) - @PutMapping - public AjaxResult edit(@Validated @RequestBody WeCorpAccount weCorpAccount) + @Log(title = "客户流失通知开关", businessType = BusinessType.UPDATE) + @PutMapping("/startCustomerChurnNoticeSwitch/{status}") + public AjaxResult startCustomerChurnNoticeSwitch(@PathVariable String status) { - return toAjax(weCorpAccountService.updateWeCorpAccount(weCorpAccount)); + iWeCorpAccountService.startCustomerChurnNoticeSwitch(status); + + return AjaxResult.success(); } + /** - * 启用有效企业微信账号 + * 客户流失通知开关查询 + * @return */ - @PreAuthorize("@ss.hasPermi('wechat:corp:startVailWeCorpAccount')") - @Log(title = "启用有效企业微信账号", businessType = BusinessType.DELETE) - @PutMapping("/startVailWeCorpAccount/{corpId}") - public AjaxResult startWeCorpAccount(@PathVariable String corpId) + @Log(title = "客户流失通知开关查询", businessType = BusinessType.OTHER) + @GetMapping("/getCustomerChurnNoticeSwitch") + public AjaxResult getCustomerChurnNoticeSwitch() { - return toAjax(weCorpAccountService.startVailWeCorpAccount(corpId)); + return AjaxResult.success("操作成功",iWeCorpAccountService.getCustomerChurnNoticeSwitch()); } - - - - - } diff --git a/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeCustomerController.java b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeCustomerController.java index 83d3df7228364c0e3ac98a47f5db777a7e165432..227364ba8c1d2c51bc164d6fbbdbf41ea5ef9bb8 100644 --- a/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeCustomerController.java +++ b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeCustomerController.java @@ -1,32 +1,36 @@ package com.linkwechat.web.controller.wecom; -import java.util.List; +import cn.hutool.core.collection.CollectionUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.linkwechat.common.annotation.Log; import com.linkwechat.common.constant.WeConstans; import com.linkwechat.common.core.controller.BaseController; import com.linkwechat.common.core.domain.AjaxResult; import com.linkwechat.common.core.page.TableDataInfo; import com.linkwechat.common.enums.BusinessType; -import com.linkwechat.common.utils.poi.ExcelUtil; +import com.linkwechat.common.enums.TrackState; +import com.linkwechat.common.enums.TrajectoryType; +import com.linkwechat.common.exception.CustomException; +import com.linkwechat.common.utils.StringUtils; +import com.linkwechat.wecom.constants.SynchRecordConstants; +import com.linkwechat.wecom.domain.*; +import com.linkwechat.wecom.domain.vo.WeLeaveUserInfoAllocateVo; import com.linkwechat.wecom.domain.vo.WeMakeCustomerTag; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; -import com.linkwechat.wecom.domain.WeCustomer; +import com.linkwechat.wecom.domain.vo.WeOnTheJobCustomerVo; import com.linkwechat.wecom.service.IWeCustomerService; +import com.linkwechat.wecom.service.IWeCustomerTrajectoryService; +import com.linkwechat.wecom.service.IWeSynchRecordService; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Lazy; +import org.springframework.web.bind.annotation.*; +import java.util.Date; +import java.util.List; /** * 企业微信客户Controller - * + * * @author ruoyi * @date 2020-09-13 */ @@ -34,69 +38,55 @@ import com.linkwechat.wecom.service.IWeCustomerService; @RequestMapping("/wecom/customer") public class WeCustomerController extends BaseController { + @Autowired + @Lazy private IWeCustomerService weCustomerService; - /** - * 查询企业微信客户列表 - */ - @PreAuthorize("@ss.hasPermi('customerManage:customer:list')") - @GetMapping("/list") - public TableDataInfo list(WeCustomer weCustomer) - { - startPage(); - List list = weCustomerService.selectWeCustomerList(weCustomer); - return getDataTable(list); - } + @Autowired + private IWeCustomerTrajectoryService iWeCustomerTrajectoryService; - /** - * 根据员工ID获取客户 - * @return - */ - @PreAuthorize("@ss.hasPermi('customerManage:customer:list')") - @GetMapping("/getCustomersByUserId/{userId}") - public AjaxResult getCustomersByUserId(@PathVariable String userId){ + @Autowired + private IWeSynchRecordService iWeSynchRecordService; - return AjaxResult.success(weCustomerService.getCustomersByUserId(userId)); - } -// /** -// * 导出企业微信客户列表 -// */ -// @PreAuthorize("@ss.hasPermi('wecom:customer:export')") -// @Log(title = "企业微信客户", businessType = BusinessType.EXPORT) -// @GetMapping("/export") -// public AjaxResult export(WeCustomer weCustomer) -// { -// List list = weCustomerService.selectWeCustomerList(weCustomer); -// ExcelUtil util = new ExcelUtil(WeCustomer.class); -// return util.exportExcel(list, "customer"); -// } + /********************************************************************************** + **************************************客户列表************************************* + *********************************************************************************/ /** - * 获取企业微信客户详细信息 + * 查询企业微信客户列表(分页) */ - @PreAuthorize("@ss.hasPermi('customerManage:customer:view')") - @GetMapping(value = "/{id}") - public AjaxResult getInfo(@PathVariable("id") Long id) + @GetMapping("/findWeCustomerList") + @ApiOperation("查询企业微信客户列表") + public TableDataInfo findWeCustomerList(WeCustomerList weCustomerList) { - return AjaxResult.success(weCustomerService.selectWeCustomerById(id)); + startPage(); + List list = weCustomerService.findWeCustomerList(weCustomerList); + TableDataInfo dataTable = getDataTable(list); + dataTable.setLastSyncTime( + iWeSynchRecordService.findUpdateLatestTime(SynchRecordConstants.SYNCH_CUSTOMER) + );//最近同步时间 + dataTable.setNoRepeatCustomerTotal( + weCustomerService.noRepeatCountCustomer(weCustomerList) + );//去重客户数 + + return dataTable; } - /** - * 修改企业微信客户 + * 查询企业微信客户列表(不分页) */ - @PreAuthorize("@ss.hasPermi('wecom:customer:edit')") - @Log(title = "企业微信客户", businessType = BusinessType.UPDATE) - @PutMapping - public AjaxResult edit(@Validated @RequestBody WeCustomer weCustomer) + @GetMapping("/findAllWeCustomerList") + @ApiOperation("查询企业微信客户列表") + public AjaxResult findAllWeCustomerList(WeCustomerList weCustomerList) { - weCustomerService.saveOrUpdate(weCustomer); - return AjaxResult.success(); + return AjaxResult.success( + weCustomerService.findWeCustomerList(weCustomerList) + ); } @@ -104,24 +94,28 @@ public class WeCustomerController extends BaseController * 客户同步接口 * @return */ - @PreAuthorize("@ss.hasPermi('customerManage:customer:sync')") @Log(title = "企业微信客户同步接口", businessType = BusinessType.DELETE) @GetMapping("/synchWeCustomer") - public AjaxResult synchWeCustomer(){ + public AjaxResult synchWeCustomer() { + + try { + weCustomerService.synchWeCustomer(); + }catch (CustomException e){ + return AjaxResult.error(e.getMessage()); + } - weCustomerService.synchWeCustomer(); return AjaxResult.success(WeConstans.SYNCH_TIP); } + /** * 客户打标签 * @param weMakeCustomerTag * @return */ - @PreAuthorize("@ss.hasPermi('customerManage/customer:makeTag')") @Log(title = "客户打标签", businessType = BusinessType.UPDATE) @PostMapping("/makeLabel") public AjaxResult makeLabel(@RequestBody WeMakeCustomerTag weMakeCustomerTag){ @@ -133,18 +127,117 @@ public class WeCustomerController extends BaseController /** - * 移除客户标签 + * 在职继承 + * @param weOnTheJobCustomerVo * @return */ - @PreAuthorize("@ss.hasPermi('customerManage:customer:removeTag')") - @Log(title = "移除客户标签", businessType = BusinessType.DELETE) - @DeleteMapping("/removeLabel") - public AjaxResult removeLabel(@RequestBody WeMakeCustomerTag weMakeCustomerTag){ + @Log(title="在职继承",businessType = BusinessType.UPDATE) + @PostMapping("/jobExtends") + public AjaxResult jobExtends(@RequestBody WeOnTheJobCustomerVo weOnTheJobCustomerVo){ + + try { + weCustomerService.allocateOnTheJobCustomer( + weOnTheJobCustomerVo + ); + }catch (Exception e){ + return AjaxResult.error(e.getMessage()); + } - weCustomerService.removeLabel(weMakeCustomerTag); return AjaxResult.success(); + } + + + /********************************************************************************** + **************************************客户详情************************************* + *********************************************************************************/ + /** + * 客户详情基础(基础信息+社交关系) + * @param externalUserid + * @param userId + * @param + * @return + */ + @GetMapping("/findWeCustomerBaseInfo") + public AjaxResult findWeCustomerBaseInfo(String externalUserid,String userId,@RequestParam(defaultValue = "0") Integer delFlag){ + + return AjaxResult.success( + weCustomerService.findWeCustomerDetail(externalUserid,userId,delFlag) + ); } + + /** + * 客户画像汇总 + * @param externalUserid + * @return + */ + @GetMapping("/findWeCustomerInfoSummary") + public AjaxResult findWeCustomerInfoSummary(String externalUserid,@RequestParam(defaultValue = "0") Integer delFlag){ + + + return AjaxResult.success( + weCustomerService.findWeCustomerInfoSummary(externalUserid,null,delFlag) + ); + } + + + /** + * 单个跟进人客户 + * @param externalUserid + * @param userId + * @return + */ + @GetMapping("/findWeCustomerInfoByUserId") + public AjaxResult findWeCustomerInfoByUserId(String externalUserid,String userId,@RequestParam(defaultValue = "0") Integer delFlag){ + + + + return AjaxResult.success( + weCustomerService.findWeCustomerInfoByUserId(externalUserid,userId,delFlag) + ); + } + + + /** + * 跟进记录 + * @param externalUserid + * @param userId + * @return + */ + @GetMapping("/followUpRecord") + public TableDataInfo followUpRecord(String externalUserid,String userId,Integer trajectoryType){ + + startPage(); + + List weCustomerTrajectories = iWeCustomerTrajectoryService + .followUpRecord(externalUserid, userId, trajectoryType); + + return getDataTable(weCustomerTrajectories); + } + + + /** + * 客户轨迹 + * @param externalUserid + * @param userId + * @param trajectoryType 轨迹类型:1:信息动态;2:社交动态;3:活动规则;4:待办动态 + * @return + */ + @GetMapping("/findTrajectory") + public AjaxResult findTrajectory(String externalUserid,String userId,Integer trajectoryType){ + + List weCustomerTrajectories = iWeCustomerTrajectoryService + .list(new LambdaQueryWrapper() + .eq(StringUtils.isNotEmpty(externalUserid),WeCustomerTrajectory::getExternalUserid, externalUserid) + .eq(StringUtils.isNotEmpty(userId),WeCustomerTrajectory::getUserId, userId) + .eq(trajectoryType !=null,WeCustomerTrajectory::getTrajectoryType,trajectoryType) + ); + + return AjaxResult.success(weCustomerTrajectories); + } + + + } diff --git a/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeCustomerMessagePushController.java b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeCustomerMessagePushController.java new file mode 100644 index 0000000000000000000000000000000000000000..a4e95fa2229c33bebea6efcd81f704b2ac8b7ec8 --- /dev/null +++ b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeCustomerMessagePushController.java @@ -0,0 +1,113 @@ +package com.linkwechat.web.controller.wecom; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.linkwechat.common.annotation.Log; +import com.linkwechat.common.core.controller.BaseController; +import com.linkwechat.common.core.domain.AjaxResult; +import com.linkwechat.common.core.page.TableDataInfo; +import com.linkwechat.common.enums.BusinessType; +import com.linkwechat.wecom.domain.dto.message.AsyncResultDto; +import com.linkwechat.wecom.domain.dto.message.CustomerMessagePushDto; +import com.linkwechat.wecom.domain.vo.CustomerMessagePushVo; +import com.linkwechat.wecom.domain.vo.WeCustomerMessageResultVo; +import com.linkwechat.wecom.service.IWeCustomerMessageOriginalService; +import com.linkwechat.wecom.service.IWeCustomerMessagePushService; +import com.linkwechat.wecom.service.IWeCustomerMessgaeResultService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Lazy; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.web.bind.annotation.*; + +import java.text.ParseException; +import java.util.List; + +/** + * @description: 企业微信 群发消息 controller + * @author: KeWen + * @create: 2020-12-01 20:23 + **/ +@Slf4j +@RestController +@RequestMapping("/wecom/customerMessagePush") +public class WeCustomerMessagePushController extends BaseController { + + + @Autowired + private IWeCustomerMessagePushService weCustomerMessagePushService; + + @Autowired + private IWeCustomerMessageOriginalService weCustomerMessageOriginalService; + + @Autowired + private IWeCustomerMessgaeResultService weCustomerMessgaeResultService; + + + /** + * 新增群发消息发送 + */ + // @PreAuthorize("@ss.hasPermi('customerMessagePush:push:add')") + @Log(title = "新增群发消息发送", businessType = BusinessType.INSERT) + @PostMapping(value = "add") + public AjaxResult add(@RequestBody CustomerMessagePushDto customerMessagePushDto) { + try { + + weCustomerMessagePushService.addWeCustomerMessagePush(customerMessagePushDto); + + } catch (JsonProcessingException | ParseException | CloneNotSupportedException e) { + e.printStackTrace(); + return AjaxResult.error("群发失败"); + } + return AjaxResult.success(); + } + + + /** + * 群发消息列表 + */ + // @PreAuthorize("@ss.hasPermi('customerMessagePush:push:list')") + @GetMapping(value = "/list") + public TableDataInfo list(@RequestParam(value = "sender", required = false) String sender + , @RequestParam(value = "content", required = false) String content + , @RequestParam(value = "pushType", required = false) String pushType + , @RequestParam(value = "beginTime", required = false) String beginTime + , @RequestParam(value = "endTime", required = false) String endTime) { + startPage(); + List list = weCustomerMessagePushService.customerMessagePushs(sender, content, pushType, beginTime, endTime); + return getDataTable(list); + } + + /** + * 群发消息详情 + */ + // @PreAuthorize("@ss.hasPermi('customerMessagePush:push:view')") + @GetMapping(value = "/getInfo") + public AjaxResult getInfo(@RequestParam(value = "messageId") Long messageId) { + CustomerMessagePushVo customerMessagePushVo = weCustomerMessageOriginalService.CustomerMessagePushDetail(messageId); + return AjaxResult.success(customerMessagePushVo); + } + + /** + * 群发消息结果列表 + */ + // @PreAuthorize("@ss.hasPermi('customerMessagePush:push:pushResults')") + @GetMapping(value = "/pushResults") + public TableDataInfo customerMessagePushResult(@RequestParam(value = "messageId") Long messageId, @RequestParam(value = "status") String status) { + startPage(); + List weCustomerMessageResuls = weCustomerMessgaeResultService.customerMessagePushs(messageId, status); + return getDataTable(weCustomerMessageResuls); + } + + /** + * 同步消息发送结果 + */ + // @PreAuthorize("@ss.hasPermi('customerMessagePush:push:asyncResult')") + @PostMapping(value = "asyncResult") + public AjaxResult asyncResult(@RequestBody AsyncResultDto asyncResultDto) throws JsonProcessingException { + weCustomerMessageOriginalService.asyncResult(asyncResultDto); + return AjaxResult.success(); + } + +} diff --git a/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeCustomerPortraitController.java b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeCustomerPortraitController.java new file mode 100644 index 0000000000000000000000000000000000000000..c00e083afd8666dbc8e320fd5947084b14104eb5 --- /dev/null +++ b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeCustomerPortraitController.java @@ -0,0 +1,297 @@ +package com.linkwechat.web.controller.wecom; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.linkwechat.common.constant.Constants; +import com.linkwechat.common.constant.WeConstans; +import com.linkwechat.common.core.controller.BaseController; +import com.linkwechat.common.core.domain.AjaxResult; +import com.linkwechat.common.core.page.TableDataInfo; +import com.linkwechat.wecom.domain.*; +import com.linkwechat.wecom.domain.vo.WeMakeCustomerTag; +import com.linkwechat.wecom.service.*; +import org.aspectj.weaver.loadtime.Aj; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * @description: 客户画像相关controller + * @author: HaoN + * @create: 2021-03-03 15:10 + **/ +@RestController +@RequestMapping("/wecom/portrait") +public class WeCustomerPortraitController extends BaseController { + + + @Autowired + private IWeCustomerService iWeCustomerService; + + + + + @Autowired + private IWeTagService iWeTagService; + + @Autowired + private IWeTagGroupService iWeTagGroupService; + + + @Autowired + private IWeUserService iWeUserService; + + + @Autowired + private IWeGroupService iWeGroupService; + + + + @Autowired + private IWeCustomerTrajectoryService iWeCustomerTrajectoryService; + + + @Autowired + IWeMomentsService iWeMomentsService; + + + + /** + * 根据客户id和当前企业员工id获取客户详细信息 + * @param externalUserid + * @param userId + * @return + */ + @GetMapping(value = "/findWeCustomerInfo") + public AjaxResult findWeCustomerInfo(String externalUserid, String userId) throws Exception { + + return AjaxResult.success( + iWeCustomerService.findCustomerByOperUseridAndCustomerId(externalUserid,userId) + ); + } + + + /** + * 客户画像资料更新 + * @param weCustomerPortrait + * @return + */ + @PostMapping(value = "/updateWeCustomerInfo") + public AjaxResult updateWeCustomerInfo(@RequestBody WeCustomerPortrait weCustomerPortrait){ + + + + iWeCustomerService.updateWeCustomerPortrait(weCustomerPortrait); + + + return AjaxResult.success(); + } + + + + + + + /** + * 获取当前系统所有可用标签 + * @param userId 员工id + * @return + */ + @GetMapping(value = "/findAllTags") + public AjaxResult findAllTags(Integer groupTagType,String userId){ + + if(groupTagType.equals(new Integer(1))){//企业标签 + return AjaxResult.success( + iWeTagGroupService.selectWeTagGroupList( + WeTagGroup.builder() + .groupTagType(1) + .build() + ) + ); + } + return AjaxResult.success( + iWeTagService.list( + new LambdaQueryWrapper() + .eq(WeTag::getDelFlag,new Integer(0)) + .eq(WeTag::getOwner,userId) + ) + + ); + + } + + + /** + * 客户画像个人标签库新增 + * @param weTagGroup + * @return + */ + @PostMapping("/addOrUpdatePersonTags") + public AjaxResult addOrUpdatePersonTags(@RequestBody WeTagGroup weTagGroup){ + List weTags = weTagGroup.getWeTags(); + if(CollectionUtil.isNotEmpty(weTags)){ + weTags.stream().forEach(k->{ + k.setGroupId(weTagGroup.getGroupId()); + k.setTagType(new Integer(3)); + }); + iWeTagService.saveOrUpdateBatch(weTags); + } + return AjaxResult.success(); + } + + + /** + * 个人标签删除 + * @param ids + * @return + */ + @DeleteMapping("/deletePersonTag/{ids}") + public AjaxResult deletePersonTag(@PathVariable String[] ids){ + iWeTagService.removeByIds(CollectionUtil.newArrayList(ids)); + + return AjaxResult.success(); + } + + + + + /** + * 更新客户画像标签 + * @param weMakeCustomerTag + * @return + */ + @PostMapping(value = "/updateWeCustomerPorTraitTag") + public AjaxResult updateWeCustomerPorTraitTag(@RequestBody WeMakeCustomerTag weMakeCustomerTag){ + + + iWeCustomerService.makeLabel(weMakeCustomerTag); + + return AjaxResult.success(); + } + + + /** + * 查看客户添加的员工 + * @param externalUserid + * @return + */ + @GetMapping(value = "/findAddaddEmployes/{externalUserid}") + public AjaxResult findaddEmployes(@PathVariable String externalUserid){ + return AjaxResult.success( + iWeUserService.findWeUserByCustomerId(externalUserid) + ); + } + + + /** + * 获取用户添加的群 + * @param externalUserid + * @param userId + * @return + */ + @GetMapping(value = "/findAddGroupNum") + public AjaxResult findAddGroupNum(String externalUserid,String userId){ + + return AjaxResult.success( + iWeGroupService.findWeGroupByCustomer(userId,externalUserid) + ); + } + + + /** + * 获取轨迹信息 + * @param trajectoryType + * @return + */ + @GetMapping(value = "/findTrajectory") + public TableDataInfo findTrajectory(String userId,String externalUserid,Integer trajectoryType){ + startPage(); + LambdaQueryWrapper ne = new LambdaQueryWrapper() + .ne(WeCustomerTrajectory::getStatus, Constants.DELETE_CODE) + .eq(WeCustomerTrajectory::getUserId,userId) + .eq(WeCustomerTrajectory::getExternalUserid,externalUserid) + .orderByDesc(WeCustomerTrajectory::getCreateTime); + if(trajectoryType != null){ + ne.eq(WeCustomerTrajectory::getTrajectoryType, trajectoryType); + } + return getDataTable( + iWeCustomerTrajectoryService.list(ne) + ); + + } + + + /** + *编辑跟进动态 + * @param trajectory + * @return + */ + @PostMapping(value = "/addOrEditWaitHandle") + public AjaxResult addOrEditWaitHandle(@RequestBody WeCustomerTrajectory trajectory){ + + + iWeCustomerService.addOrEditWaitHandle(trajectory); + + return AjaxResult.success(); + } + + + /** + * 删除轨迹 + * @param trajectoryId + * @return + */ + @DeleteMapping(value = "/removeTrajectory/{trajectoryId}") + public AjaxResult removeTrajectory(@PathVariable String trajectoryId){ + iWeCustomerTrajectoryService.updateById(WeCustomerTrajectory.builder() + .id(trajectoryId) + .status(Constants.DELETE_CODE) + .build()); + return AjaxResult.success(); + } + + + /** + * 完成待办 + * @param trajectoryId + * @return + */ + @DeleteMapping(value = "/handleWait/{trajectoryId}") + public AjaxResult handleWait(@PathVariable String trajectoryId){ + iWeCustomerTrajectoryService.updateById(WeCustomerTrajectory.builder() + .id(trajectoryId) + .status(Constants.HANDLE_SUCCESS) + .build()); + return AjaxResult.success(); + } + + + + /** + * 个人朋友圈互动数据同步 + * @param userId + * @return + */ + @GetMapping("/synchMomentsInteracte/{userId}") + public AjaxResult synchMomentsInteracte(@PathVariable String userId){ + + iWeMomentsService.synchMomentsInteracte(CollectionUtil.newArrayList(userId)); + + return AjaxResult.success(WeConstans.SYNCH_TIP); + } + + + + + + + + + + + + + +} diff --git a/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeCustomerSeasController.java b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeCustomerSeasController.java new file mode 100644 index 0000000000000000000000000000000000000000..4f7ff987997e95a44f5e5c28b51e5438607e60db --- /dev/null +++ b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeCustomerSeasController.java @@ -0,0 +1,279 @@ +package com.linkwechat.web.controller.wecom; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.collection.ListUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.linkwechat.common.core.controller.BaseController; +import com.linkwechat.common.core.domain.AjaxResult; +import com.linkwechat.common.core.page.TableDataInfo; +import com.linkwechat.common.enums.CommunityTaskType; +import com.linkwechat.common.exception.CustomException; +import com.linkwechat.common.utils.DateUtils; +import com.linkwechat.common.utils.SnowFlakeUtil; +import com.linkwechat.common.utils.StringUtils; +import com.linkwechat.common.utils.ValidateUtils; +import com.linkwechat.common.utils.poi.ExcelUtil; +import com.linkwechat.wecom.domain.WeCustomerSeas; +import com.linkwechat.wecom.domain.vo.CustomerSeasRecordVo; +import com.linkwechat.wecom.service.IWeCustomerMessagePushService; +import com.linkwechat.wecom.service.IWeCustomerSeasService; +import com.linkwechat.wecom.service.IWeMessagePushService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.text.MessageFormat; +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +/** + * 客户公海相关 + */ +@RestController +@RequestMapping("/wecom/seas") +public class WeCustomerSeasController extends BaseController { + + @Autowired + private IWeCustomerSeasService iWeCustomerSeasService; + + + + + + + /** + * 客户公海模版下载 + * @return + */ + @GetMapping("/importTemplate") + public AjaxResult importTemplate() + { + + ExcelUtil util = new ExcelUtil(WeCustomerSeas.class); + return util.importTemplateExcel( DateUtils.dateTimeNow(DateUtils.YYYY_MM_DD)+"_客户公海"); + } + + + + /** + * 导入公海数据 + * @param file + * @param weCustomerSea + * @return + */ + @PostMapping("/importData") + public AjaxResult importData(MultipartFile file, WeCustomerSeas weCustomerSea) throws Exception { + ExcelUtil util = new ExcelUtil(WeCustomerSeas.class); + List weCustomerSeas = util.importExcel(file.getInputStream()); + String tip=new String("成功导入{0}条,去重复{1}条"); + if(CollectionUtil.isNotEmpty(weCustomerSeas)){ + + if(StringUtils.isEmpty(weCustomerSea.getAddUserName())&&StringUtils.isEmpty(weCustomerSea.getAddUserId())){ + return AjaxResult.error("分配人不可为空!"); + } + //过滤不符合规范的手机号 + List noRuleWeCustomerSeas + = weCustomerSeas.stream().filter(s -> ValidateUtils.isMobile(s.getPhone())).collect(Collectors.toList()); + + if(CollectionUtil.isEmpty(noRuleWeCustomerSeas)){ + return AjaxResult.error("请传入合法手机号!"); + } + + //过滤字段为空的数据 + List deduplicationSeas = noRuleWeCustomerSeas.stream().filter(s -> StringUtils.isNotEmpty(s.getCustomerName()) + || StringUtils.isNotEmpty(s.getPhone())).collect(Collectors.toList()); + if(CollectionUtil.isEmpty(deduplicationSeas)){ + return AjaxResult.error("导入用户数据不能为空!"); + } + //根据手机号去重(去除excel中重复的号码) + List deduplicationSeasNoRepeat=deduplicationSeas.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> + new TreeSet<>(Comparator.comparing(WeCustomerSeas :: getPhone))), ArrayList::new)); + + + //根据手机号去除数据库与excel中重复号码 + List dbExist = iWeCustomerSeasService.list(new LambdaQueryWrapper() + .in(WeCustomerSeas::getPhone, deduplicationSeasNoRepeat.stream() + .map(WeCustomerSeas::getPhone).collect(Collectors.toList()))); + if(CollectionUtil.isNotEmpty(dbExist)){ + List noRepetWeCustomerSeas + = deduplicationSeasNoRepeat.stream().filter(item -> + !dbExist.stream().map(e->e.getPhone()).collect(Collectors.toList()) + .contains(item.getPhone())).collect(Collectors.toList()); + deduplicationSeasNoRepeat.clear(); + deduplicationSeasNoRepeat.addAll( + noRepetWeCustomerSeas + ); + } + + + if(CollectionUtil.isNotEmpty(deduplicationSeasNoRepeat)){ + + Long tabaleExcelId= SnowFlakeUtil.nextId(); + + List userIds = ListUtil.toList(weCustomerSea.getAddUserId().split(",")); + List userNames = ListUtil.toList(weCustomerSea.getAddUserName().split(",")); + + IntStream.range(0,deduplicationSeasNoRepeat.size()).forEach(i->{ + WeCustomerSeas k = deduplicationSeasNoRepeat.get(i); + if(Objects.nonNull(k)){ + k.setTagIds(weCustomerSea.getTagIds()); + k.setTagNames(weCustomerSea.getTagNames()); + k.setAddUserId( userIds.get(Math.floorMod(i, userIds.size()))); + k.setAddUserName(userNames.get(Math.floorMod(i, userNames.size()))); + k.setTableExcelName(file.getOriginalFilename()); + k.setTableExcelId(tabaleExcelId); + } + }); + if(iWeCustomerSeasService.saveBatch(deduplicationSeasNoRepeat)){ + //发送提醒 + deduplicationSeasNoRepeat.stream().collect(Collectors.groupingBy(WeCustomerSeas::getAddUserId)).forEach((k,v)->{ + + iWeCustomerSeasService.remidUser(ListUtil.toList(k),v.size()); + + + }); + + } + + tip = MessageFormat.format(tip, new Object[]{new Integer(deduplicationSeasNoRepeat.size()).toString(), + new Integer( weCustomerSeas.size()-deduplicationSeasNoRepeat.size()).toString()}); + + }else{ + tip = MessageFormat.format(tip, new Object[] { "0",weCustomerSeas.size() }); + } + + + ; + }else{ + return AjaxResult.error("导入用户数据不能为空!"); + } + + return AjaxResult.success(tip); + } + + + /** + * 获取公海客户列表 + * @param weCustomerSea + * @return + */ + @GetMapping("list") + public TableDataInfo list(WeCustomerSeas weCustomerSea){ + + startPage(); + List weCustomerSeas = iWeCustomerSeasService.list( + new LambdaQueryWrapper() + .like(StringUtils.isNotEmpty(weCustomerSea.getPhone()),WeCustomerSeas::getPhone,weCustomerSea.getPhone()) + .like(StringUtils.isNotEmpty(weCustomerSea.getCustomerName()),WeCustomerSeas::getCustomerName,weCustomerSea.getCustomerName()) + .like(StringUtils.isNotEmpty(weCustomerSea.getAddUserName()),WeCustomerSeas::getAddUserName,weCustomerSea.getAddUserName()) + .eq(weCustomerSea.getAddState() !=null ,WeCustomerSeas::getAddState,weCustomerSea.getAddState()) + .orderByDesc(WeCustomerSeas::getCreateTime) + ); + + return getDataTable(weCustomerSeas); + } + + + /** + * 删除公海客户 + * @param ids + * @return + */ + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable Long[] ids) + { + iWeCustomerSeasService.removeByIds( + ListUtil.toList(ids) + ); + return AjaxResult.success(); + } + + + /** + * 提醒员工 + * @param ids + * @return + */ + @PostMapping("/remidUser/{ids}") + public AjaxResult remidUser(@PathVariable Long[] ids){ + + List weCustomerSeas + = iWeCustomerSeasService.listByIds(ListUtil.toList(ids)); + + if(CollectionUtil.isNotEmpty(weCustomerSeas)){ + weCustomerSeas.stream().collect(Collectors.groupingBy(WeCustomerSeas::getAddUserId)).forEach((k,v)->{ + iWeCustomerSeasService.remidUser(ListUtil.toList(k),v.size()); + + + + }); + + } + + return AjaxResult.success(); + } + + + /** + * 获取指定员工所拥有的状态(移动端) + * @param userId + * @param addState + * @return + */ + @GetMapping("/findEmployeeCustomer") + public TableDataInfo findEmployeeCustomer(String userId,Integer addState){ + startPage(); + List weCustomerSeas = iWeCustomerSeasService.list(new LambdaQueryWrapper() + .eq(StringUtils.isNotEmpty(userId),WeCustomerSeas::getAddUserId, userId) + .eq(addState != null,WeCustomerSeas::getAddState, addState)); + + return getDataTable(weCustomerSeas); + } + + + /** + * 详情头部统计 + * @return + */ + @GetMapping("/countCustomerSeas") + public AjaxResult countCustomerSeas(){ + + return AjaxResult.success( + iWeCustomerSeasService.countCustomerSeas() + ); + } + + + /** + * 导入记录或员工添加统计 + * @param groupByType 1:获取导入记录数据 2:员工添加统计 + * @return + */ + @GetMapping("/findSeasRecord") + public TableDataInfo findSeasRecord(@RequestParam(defaultValue = "1") Integer groupByType){ + startPage(); + List seasRecord = iWeCustomerSeasService.findSeasRecord(groupByType); + + return getDataTable(seasRecord); + } + + + /** + * 设置公海客户状态 + * @return + */ + @PostMapping("/setState") + public AjaxResult setState(@RequestBody WeCustomerSeas weCustomerSea){ + if(StringUtils.isEmpty(weCustomerSea.getPhone())){ + return AjaxResult.error("手机号不可为空"); + } + iWeCustomerSeasService.update(WeCustomerSeas.builder().addState(new Integer(1)).build() + ,new LambdaQueryWrapper().eq(WeCustomerSeas::getPhone,weCustomerSea.getPhone())); + + return AjaxResult.success(); + } + + + +} diff --git a/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeDepartmentController.java b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeDepartmentController.java index 1f5c2ee70cd9586de6d2b66f28b1ba3ef44b2d22..124646976f9f6eba3818ed78bc47da2a5c88e3f8 100644 --- a/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeDepartmentController.java +++ b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeDepartmentController.java @@ -9,37 +9,33 @@ import com.linkwechat.wecom.service.IWeDepartmentService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; + import java.util.List; /** * 企业微信组织架构相关Controller - * + * * @author ruoyi * @date 2020-09-01 */ -@Api("微信组织架构相关接口") +@Api(tags = "微信组织架构相关接口") @RestController @RequestMapping("/wecom/department") -public class WeDepartmentController extends BaseController -{ +public class WeDepartmentController extends BaseController { @Autowired private IWeDepartmentService weDepartmentService; - /** * 查询企业微信组织架构相关列表 */ - @PreAuthorize("@ss.hasPermi('contacts:organization:list')") + // @PreAuthorize("@ss.hasPermi('contacts:organization:list')") @GetMapping("/list") @ApiOperation("获取部门列表") - public AjaxResult list() - { - - List list = weDepartmentService.selectWeDepartmentList(); + public AjaxResult> list() { + List list = weDepartmentService.getList(); return AjaxResult.success(list); } @@ -47,39 +43,36 @@ public class WeDepartmentController extends BaseController /** * 新增企业微信组织架构相关 */ - @PreAuthorize("@ss.hasPermi('contacts:organization:addMember')") + // @PreAuthorize("@ss.hasPermi('contacts:organization:addMember')") @Log(title = "企业微信组织架构相关", businessType = BusinessType.INSERT) @PostMapping @ApiOperation("添加部门") - public AjaxResult add(@Validated @RequestBody WeDepartment weDepartment) - { - weDepartmentService.insertWeDepartment(weDepartment); + public AjaxResult add(@Validated @RequestBody WeDepartment weDepartment) { + weDepartmentService.insert(weDepartment); return AjaxResult.success(); } /** * 修改企业微信组织架构相关 */ - @PreAuthorize("@ss.hasPermi('contacts:organization:editDep')") + // @PreAuthorize("@ss.hasPermi('contacts:organization:editDep')") @Log(title = "企业微信组织架构相关", businessType = BusinessType.UPDATE) @PutMapping @ApiOperation("更新部门") - public AjaxResult edit(@RequestBody WeDepartment weDepartment) - { - weDepartmentService.updateWeDepartment(weDepartment); + public AjaxResult edit(@RequestBody WeDepartment weDepartment) { + weDepartmentService.update(weDepartment); return AjaxResult.success(); } /** * 删除企业微信组织架构相关 */ - @PreAuthorize("@ss.hasPermi('wecom:department:remove')") + // @PreAuthorize("@ss.hasPermi('wecom:department:remove')") @Log(title = "企业微信组织架构相关", businessType = BusinessType.DELETE) - @DeleteMapping("/{ids}") - public AjaxResult remove(@PathVariable String[] ids) - { + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable Long[] ids) { - weDepartmentService.deleteWeDepartmentByIds(ids); + weDepartmentService.deleteByIds(ids); return AjaxResult.success(); } diff --git a/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeEmpleCodeController.java b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeEmpleCodeController.java index 9ccd8f0b69525e180f6ab1c09c595c598fa0bb44..b376d2638d8004418d66745ef6a4391441a60f1e 100644 --- a/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeEmpleCodeController.java +++ b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeEmpleCodeController.java @@ -1,38 +1,50 @@ package com.linkwechat.web.controller.wecom; -import cn.hutool.core.collection.ListUtil; import com.linkwechat.common.annotation.Log; import com.linkwechat.common.core.controller.BaseController; import com.linkwechat.common.core.domain.AjaxResult; import com.linkwechat.common.core.page.TableDataInfo; import com.linkwechat.common.enums.BusinessType; +import com.linkwechat.common.exception.CustomException; +import com.linkwechat.common.exception.wecom.WeComException; +import com.linkwechat.common.utils.StringUtils; +import com.linkwechat.common.utils.file.FileUtils; import com.linkwechat.wecom.domain.WeEmpleCode; +import com.linkwechat.wecom.domain.WeFlowerCustomerRel; import com.linkwechat.wecom.service.IWeEmpleCodeService; +import com.linkwechat.wecom.service.IWeFlowerCustomerRelService; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; -import java.util.List; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.*; +import java.util.stream.Collectors; /** * 员工活码Controller - * + * * @author ruoyi * @date 2020-10-04 */ @RestController @RequestMapping("/wecom/code") -public class WeEmpleCodeController extends BaseController -{ +public class WeEmpleCodeController extends BaseController { @Autowired private IWeEmpleCodeService weEmpleCodeService; + + @Autowired + private IWeFlowerCustomerRelService weFlowerCustomerRelService; + /** * 查询员工活码列表 */ - @PreAuthorize("@ss.hasPermi('wecom:code:list')") + // @PreAuthorize("@ss.hasPermi('wecom:code:list')") @GetMapping("/list") - public TableDataInfo list(WeEmpleCode weEmpleCode) - { + public TableDataInfo list(WeEmpleCode weEmpleCode) { startPage(); List list = weEmpleCodeService.selectWeEmpleCodeList(weEmpleCode); return getDataTable(list); @@ -42,43 +54,143 @@ public class WeEmpleCodeController extends BaseController /** * 获取员工活码详细信息 */ - @PreAuthorize("@ss.hasPermi('wecom:code:query')") + // @PreAuthorize("@ss.hasPermi('wecom:code:query')") @GetMapping(value = "/{id}") - public AjaxResult getInfo(@PathVariable("id") Long id) - { + public AjaxResult getInfo(@PathVariable("id") Long id) { return AjaxResult.success(weEmpleCodeService.selectWeEmpleCodeById(id)); } /** * 新增员工活码 */ - @PreAuthorize("@ss.hasPermi('wecom:code:add')") + // @PreAuthorize("@ss.hasPermi('wecom:code:add')") @Log(title = "员工活码", businessType = BusinessType.INSERT) - @PostMapping - public AjaxResult add(@RequestBody WeEmpleCode weEmpleCode) - { - return toAjax(weEmpleCodeService.insertWeEmpleCode(weEmpleCode)); + @PostMapping("/add") + public AjaxResult add(@RequestBody @Validated WeEmpleCode weEmpleCode) { + try { + weEmpleCodeService.insertWeEmpleCode(weEmpleCode); + return AjaxResult.success(); + } catch (Exception e) { + e.printStackTrace(); + if (e instanceof WeComException){ + return AjaxResult.error(e.getMessage()); + }else { + return AjaxResult.error("请求接口异常!"); + } + } + + } + + /** + * 批量新增员工活码 + */ + // @PreAuthorize("@ss.hasPermi('wecom:code:batchAdd')") + @Log(title = "批量新增员工活码", businessType = BusinessType.INSERT) + @PostMapping("/batchAdd") + public AjaxResult batchAdd(@RequestBody @Validated WeEmpleCode weEmpleCode) { + try { + weEmpleCodeService.insertWeEmpleCodeBatch(weEmpleCode); + return AjaxResult.success(); + } catch (Exception e) { + e.printStackTrace(); + if (e instanceof WeComException){ + return AjaxResult.error(e.getMessage()); + }else { + return AjaxResult.error("请求接口异常!"); + } + } } /** * 修改员工活码 */ - @PreAuthorize("@ss.hasPermi('wecom:code:edit')") + // @PreAuthorize("@ss.hasPermi('wecom:code:edit')") @Log(title = "员工活码", businessType = BusinessType.UPDATE) - @PutMapping - public AjaxResult edit(@RequestBody WeEmpleCode weEmpleCode) - { - return toAjax(weEmpleCodeService.updateWeEmpleCode(weEmpleCode)); + @PutMapping("/update") + public AjaxResult edit(@RequestBody WeEmpleCode weEmpleCode) { + weEmpleCodeService.updateWeEmpleCode(weEmpleCode); + + return AjaxResult.success(); } /** * 删除员工活码 */ - @PreAuthorize("@ss.hasPermi('wecom:code:remove')") + // @PreAuthorize("@ss.hasPermi('wecom:code:remove')") @Log(title = "员工活码", businessType = BusinessType.DELETE) - @DeleteMapping("/{ids}") - public AjaxResult remove(@PathVariable String[] ids) - { - return toAjax(weEmpleCodeService.batchRemoveWeEmpleCodeIds(ListUtil.toList(ids))); + @DeleteMapping("/delete/{ids}") + public AjaxResult remove(@PathVariable String ids) { + List idList = Arrays.stream(StringUtils.split(ids, ",")).collect(Collectors.toList()); + return toAjax(weEmpleCodeService.batchRemoveWeEmpleCodeIds(idList)); + } + + + /** + * 获取员工二维码 + * @param userIds 员工id + * @param departmentIds 部门id + */ + // @PreAuthorize("@ss.hasPermi('wecom:code:qrcode')") + @Log(title = "获取员工二维码", businessType = BusinessType.DELETE) + @GetMapping("/getQrcode") + public AjaxResult getQrcode(String userIds, String departmentIds) { + return AjaxResult.success(weEmpleCodeService.getQrcode(userIds,departmentIds)); + } + + /** + * 员工活码批量下载 + * + * @param ids 员工活码ids + * @param request 请求 + * @param response 输出 + * @throws Exception + */ + // @PreAuthorize("@ss.hasPermi('wecom:code:downloadBatch')") + @Log(title = "员工活码批量下载", businessType = BusinessType.OTHER) + @GetMapping("/downloadBatch") + public void downloadBatch(String ids, HttpServletRequest request, HttpServletResponse response){ + List> fileList = Arrays + .stream(Optional.ofNullable(ids).orElse("").split(",")) + .filter(StringUtils::isNotEmpty) + .map(id -> { + WeEmpleCode code = weEmpleCodeService.getById(id); + Map fileMap = new HashMap<>(); + fileMap.put("fileName", code.getUseUserName() + "-" + code.getScenario()+".jpg"); + fileMap.put("url", code.getQrCode()); + return fileMap;}) + .collect(Collectors.toList()); + try { + FileUtils.batchDownloadFile(fileList, response.getOutputStream()); + } catch (Exception e) { + e.printStackTrace(); + } + } + + // @PreAuthorize("@ss.hasPermi('wecom:code:download')") + @Log(title = "员工活码下载", businessType = BusinessType.OTHER) + @GetMapping("/download") + public void download(String id, HttpServletRequest request, HttpServletResponse response){ + WeEmpleCode weEmpleCode = weEmpleCodeService.selectWeEmpleCodeById(Long.valueOf(id)); + if (StringUtils.isEmpty(weEmpleCode.getQrCode())){ + throw new CustomException("活码不存在"); + }else { + try { + FileUtils.downloadFile(weEmpleCode.getQrCode(), response.getOutputStream()); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + + /** + * 成员添加客户统计 + * @return + */ + // @PreAuthorize("@ss.hasPermi('wecom:code:getUserAddCustomerStat')") + @Log(title = "成员添加客户统计", businessType = BusinessType.OTHER) + @GetMapping("/getUserAddCustomerStat") + public AjaxResult getUserAddCustomerStat(WeFlowerCustomerRel weFlowerCustomerRel){ + return AjaxResult.success(weFlowerCustomerRelService.getUserAddCustomerStat(weFlowerCustomerRel)); } } diff --git a/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeExceptionController.java b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeExceptionController.java new file mode 100644 index 0000000000000000000000000000000000000000..70b9cc72770ade1f7b59ec554c7d835c0e39d793 --- /dev/null +++ b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeExceptionController.java @@ -0,0 +1,44 @@ +package com.linkwechat.web.controller.wecom; + +import com.linkwechat.common.core.domain.AjaxResult; +import com.linkwechat.common.exception.wecom.WeComException; +import lombok.extern.slf4j.Slf4j; +import org.springframework.validation.ObjectError; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.servlet.ModelAndView; + +import java.util.List; + +/** + * @author danmo + * @description 统一异常处理 + * @date 2021/6/4 16:55 + **/ +@Slf4j +@RestControllerAdvice(basePackages = "com.linkwechat.web.controller.wecom") +public class WeExceptionController { + + @ExceptionHandler(WeComException.class) + public AjaxResult weComException(WeComException ex){ + return AjaxResult.error(ex.getCode(),ex.getMessage()); + } + + @ExceptionHandler({MethodArgumentNotValidException.class}) + public AjaxResult customException(MethodArgumentNotValidException e) { + // 获取参数校验失败信息 + List list = e.getBindingResult().getAllErrors(); + StringBuilder errorMsg = new StringBuilder(); + for (ObjectError error : list){ + errorMsg.append(error.getDefaultMessage()).append("\n"); + } + return AjaxResult.error(errorMsg.toString()); + } + + @ExceptionHandler(Exception.class) + public AjaxResult runtimeException(Exception ex){ + log.error("接口异常拦截 ex:{}",ex); + return AjaxResult.error(); + } +} diff --git a/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeGroupCodeActualController.java b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeGroupCodeActualController.java index aabe56e42222f917ee7be1e59ada4ca80a1f7f56..edd1300863e0ca576e63bc34ab44d66b041c5a2f 100644 --- a/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeGroupCodeActualController.java +++ b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeGroupCodeActualController.java @@ -1,103 +1,110 @@ package com.linkwechat.web.controller.wecom; -import java.util.List; import com.linkwechat.common.annotation.Log; +import com.linkwechat.common.constant.HttpStatus; import com.linkwechat.common.core.controller.BaseController; import com.linkwechat.common.core.domain.AjaxResult; import com.linkwechat.common.core.page.TableDataInfo; import com.linkwechat.common.enums.BusinessType; -import com.linkwechat.common.utils.poi.ExcelUtil; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import com.linkwechat.common.utils.StringUtils; import com.linkwechat.wecom.domain.WeGroupCodeActual; import com.linkwechat.wecom.service.IWeGroupCodeActualService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; /** * 实际群码Controller - * + * * @author ruoyi * @date 2020-10-07 */ @RestController @RequestMapping("/wecom/actual") -public class WeGroupCodeActualController extends BaseController -{ +public class WeGroupCodeActualController extends BaseController { @Autowired private IWeGroupCodeActualService weGroupCodeActualService; /** * 查询实际群码列表 */ - @PreAuthorize("@ss.hasPermi('wecom:actual:list')") + // @PreAuthorize("@ss.hasPermi('wecom:actual:list')") @GetMapping("/list") - public TableDataInfo list(WeGroupCodeActual weGroupCodeActual) - { + public TableDataInfo list(WeGroupCodeActual weGroupCodeActual) { startPage(); List list = weGroupCodeActualService.selectWeGroupCodeActualList(weGroupCodeActual); return getDataTable(list); } - - /** - * 导出实际群码列表 - */ - @PreAuthorize("@ss.hasPermi('wecom:actual:export')") - @Log(title = "实际群码", businessType = BusinessType.EXPORT) - @GetMapping("/export") - public AjaxResult export(WeGroupCodeActual weGroupCodeActual) - { - List list = weGroupCodeActualService.selectWeGroupCodeActualList(weGroupCodeActual); - ExcelUtil util = new ExcelUtil(WeGroupCodeActual.class); - return util.exportExcel(list, "actual"); - } +// +// /** +// * 导出实际群码列表 +// */ +// @PreAuthorize("@ss.hasPermi('wecom:actual:export')") +// @Log(title = "实际群码", businessType = BusinessType.EXPORT) +// @GetMapping("/export") +// public AjaxResult export(WeGroupCodeActual weGroupCodeActual) +// { +// List list = weGroupCodeActualService.selectWeGroupCodeActualList(weGroupCodeActual); +// ExcelUtil util = new ExcelUtil(WeGroupCodeActual.class); +// return util.exportExcel(list, "actual"); +// } /** * 获取实际群码详细信息 */ - @PreAuthorize("@ss.hasPermi('wecom:actual:query')") + // @PreAuthorize("@ss.hasPermi('wecom:actual:query')") @GetMapping(value = "/{id}") - public AjaxResult getInfo(@PathVariable("id") Long id) - { - return AjaxResult.success(weGroupCodeActualService.selectWeGroupCodeActualById(id)); + public AjaxResult getInfo(@PathVariable("id") Long id) { + WeGroupCodeActual weGroupCodeActual = weGroupCodeActualService.selectWeGroupCodeActualById(id); + if (StringUtils.isNull(weGroupCodeActual)) { + return AjaxResult.error(HttpStatus.NOT_FOUND, "数据不存在"); + } + return AjaxResult.success(weGroupCodeActual); } /** - * 新增实际群码 + * 新增实际群码查询 */ - @PreAuthorize("@ss.hasPermi('wecom:actual:add')") + // @PreAuthorize("@ss.hasPermi('wecom:actual:add')") @Log(title = "实际群码", businessType = BusinessType.INSERT) @PostMapping - public AjaxResult add(@RequestBody WeGroupCodeActual weGroupCodeActual) - { + public AjaxResult add(@Validated @RequestBody WeGroupCodeActual weGroupCodeActual) { + // 唯一性检查 + if (!weGroupCodeActualService.checkChatIdUnique(weGroupCodeActual)) { + return AjaxResult.error("新增实际群码失败, 该群聊二维码已存在"); + } return toAjax(weGroupCodeActualService.insertWeGroupCodeActual(weGroupCodeActual)); } /** * 修改实际群码 */ - @PreAuthorize("@ss.hasPermi('wecom:actual:edit')") + // @PreAuthorize("@ss.hasPermi('wecom:actual:edit')") @Log(title = "实际群码", businessType = BusinessType.UPDATE) @PutMapping - public AjaxResult edit(@RequestBody WeGroupCodeActual weGroupCodeActual) - { + public AjaxResult edit(@RequestBody WeGroupCodeActual weGroupCodeActual) { + WeGroupCodeActual original = weGroupCodeActualService.selectWeGroupCodeActualById(weGroupCodeActual.getId()); + if (StringUtils.isNull(original)) { + return AjaxResult.error(HttpStatus.NOT_FOUND, "数据不存在"); + } + // 实际码对应客户群变化时,检查其唯一性 + if (!original.getChatId().equals(weGroupCodeActual.getChatId()) && + !weGroupCodeActualService.checkChatIdUnique(weGroupCodeActual)) { + return AjaxResult.error("修改实际群码失败, 该群聊二维码已存在"); + } return toAjax(weGroupCodeActualService.updateWeGroupCodeActual(weGroupCodeActual)); } /** * 删除实际群码 */ - @PreAuthorize("@ss.hasPermi('wecom:actual:remove')") + // @PreAuthorize("@ss.hasPermi('wecom:actual:remove')") @Log(title = "实际群码", businessType = BusinessType.DELETE) - @DeleteMapping("/{ids}") - public AjaxResult remove(@PathVariable Long[] ids) - { + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable Long[] ids) { return toAjax(weGroupCodeActualService.deleteWeGroupCodeActualByIds(ids)); } } diff --git a/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeGroupCodeController.java b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeGroupCodeController.java index cfb8fc4bc25bb99b4615f61d4ca117bb2f8d54e6..4bdd11780d679b37a9a70b0456f5959ea0bcdb44 100644 --- a/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeGroupCodeController.java +++ b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeGroupCodeController.java @@ -1,105 +1,229 @@ package com.linkwechat.web.controller.wecom; -import java.util.List; - import com.linkwechat.common.annotation.Log; +import com.linkwechat.common.constant.HttpStatus; +import com.linkwechat.common.constant.WeConstans; import com.linkwechat.common.core.controller.BaseController; import com.linkwechat.common.core.domain.AjaxResult; import com.linkwechat.common.core.page.TableDataInfo; import com.linkwechat.common.enums.BusinessType; -import com.linkwechat.common.utils.poi.ExcelUtil; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import com.linkwechat.common.utils.QREncode; +import com.linkwechat.common.utils.SecurityUtils; +import com.linkwechat.common.utils.StringUtils; +import com.linkwechat.common.utils.file.FileUtils; +import com.linkwechat.framework.web.domain.server.SysFile; +import com.linkwechat.framework.web.service.FileService; import com.linkwechat.wecom.domain.WeGroupCode; +import com.linkwechat.wecom.domain.WeGroupCodeActual; import com.linkwechat.wecom.service.IWeGroupCodeService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.*; +import java.util.stream.Collectors; /** * 客户群活码Controller - * + * * @author ruoyi * @date 2020-10-07 */ +@Api(tags = "群活码") @RestController @RequestMapping("/wecom/groupCode") -public class WeGroupCodeController extends BaseController -{ +public class WeGroupCodeController extends BaseController { + @Autowired - private IWeGroupCodeService weGroupCodeService; + IWeGroupCodeService groupCodeService; + + @Autowired + FileService fileService; + + @Value("${H5.domainPrefix}") + private String h5DomainPrefix; /** * 查询客户群活码列表 */ - @PreAuthorize("@ss.hasPermi('wecom:code:list')") + @ApiOperation(value = "查询客户群活码列表", httpMethod = "GET") +// @PreAuthorize("@ss.hasPermi('drainageCode:group:list')") @GetMapping("/list") - public TableDataInfo list(WeGroupCode weGroupCode) - { + public TableDataInfo list(WeGroupCode weGroupCode) { startPage(); - List list = weGroupCodeService.selectWeGroupCodeList(weGroupCode); + List list = groupCodeService.selectWeGroupCodeList(weGroupCode); return getDataTable(list); } /** - * 导出客户群活码列表 + * 批量下载群活码 */ - @PreAuthorize("@ss.hasPermi('wecom:code:export')") - @Log(title = "客户群活码", businessType = BusinessType.EXPORT) - @GetMapping("/export") - public AjaxResult export(WeGroupCode weGroupCode) - { - List list = weGroupCodeService.selectWeGroupCodeList(weGroupCode); - ExcelUtil util = new ExcelUtil(WeGroupCode.class); - return util.exportExcel(list, "code"); + @ApiOperation(value = "批量下载群活码", httpMethod = "GET") + // @PreAuthorize("@ss.hasPermi('drainageCode:group:downloadBatch')") + @Log(title = "群活码批量下载", businessType = BusinessType.OTHER) + @GetMapping("/downloadBatch") + public void downloadBatch(String ids, HttpServletRequest request, HttpServletResponse response) { + // 构建文件信息列表 + List> fileList = Arrays + .stream(Optional.ofNullable(ids).orElse("").split(",")) + .filter(StringUtils::isNotEmpty) + .map(id -> { + WeGroupCode code = groupCodeService.getById(id); + Map fileMap = new HashMap<>(); + fileMap.put("fileName", code.getActivityName() + ".png"); + fileMap.put("url", code.getCodeUrl()); + return fileMap; + }) + .collect(Collectors.toList()); + try { + FileUtils.batchDownloadFile(fileList, response.getOutputStream()); + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * 下载群活码 + */ + @ApiOperation(value = "群活码下载", httpMethod = "GET") + // @PreAuthorize("@ss.hasPermi('drainageCode:group:download')") + @Log(title = "群活码下载", businessType = BusinessType.OTHER) + @GetMapping("/download") + public void download(String id, HttpServletResponse response) { + WeGroupCode weGroupCode = groupCodeService.getById(Long.valueOf(id)); + try { + FileUtils.downloadFile(weGroupCode.getCodeUrl(), response.getOutputStream()); + } catch (IOException e) { + e.printStackTrace(); + } } /** * 获取客户群活码详细信息 */ - @PreAuthorize("@ss.hasPermi('wecom:code:query')") + @ApiOperation(value = "获取客户群活码详细信息", httpMethod = "GET") + // @PreAuthorize("@ss.hasPermi('drainageCode:group:query')") @GetMapping(value = "/{id}") - public AjaxResult getInfo(@PathVariable("id") Long id) - { - return AjaxResult.success(weGroupCodeService.selectWeGroupCodeById(id)); + public AjaxResult getInfo(@PathVariable("id") Long id) { + WeGroupCode weGroupCode = groupCodeService.getById(id); + if (StringUtils.isNull(weGroupCode)) { + return AjaxResult.error(HttpStatus.NOT_FOUND, "数据不存在"); + } + List weGroupCodeActualList = groupCodeService.selectActualList(weGroupCode.getId()); + weGroupCode.setActualList(weGroupCodeActualList); + return AjaxResult.success(weGroupCode); } /** * 新增客户群活码 */ - @PreAuthorize("@ss.hasPermi('wecom:code:add')") + @ApiOperation(value = "新增客户群活码", httpMethod = "POST") + // @PreAuthorize("@ss.hasPermi('drainageCode:group:add')") @Log(title = "客户群活码", businessType = BusinessType.INSERT) @PostMapping - public AjaxResult add(@RequestBody WeGroupCode weGroupCode) - { - return toAjax(weGroupCodeService.insertWeGroupCode(weGroupCode)); + public AjaxResult add(@Validated @RequestBody WeGroupCode weGroupCode) { + // 活码名唯一性检查 + if (groupCodeService.isNameOccupied(weGroupCode)) { + return AjaxResult.error("添加群活码失败,活码名称 " + weGroupCode.getActivityName() + " 已存在"); + } + AjaxResult ajax = AjaxResult.success(); + weGroupCode.setCreateBy(SecurityUtils.getUsername()); + weGroupCode.setCreateTime(new Date()); + try { + // 二维码内容,即该二维码扫码后跳转的页面URL + String content = h5DomainPrefix + "/mobile/#/groupCode?id=" + weGroupCode.getId(); + SysFile sysFile = fileService.upload(QREncode.getQRCodeMultipartFile(content, weGroupCode.getAvatarUrl())); + weGroupCode.setCodeUrl(sysFile.getImgUrlPrefix() + sysFile.getFileName()); + } catch (Exception e) { + return AjaxResult.error("创建群活码失败,请稍后再试"); + } + groupCodeService.insertWeGroupCode(weGroupCode); + ajax.put("id", weGroupCode.getId()); + return ajax; } /** * 修改客户群活码 */ - @PreAuthorize("@ss.hasPermi('wecom:code:edit')") + @ApiOperation(value = "修改客户群活码", httpMethod = "PUT") + // @PreAuthorize("@ss.hasPermi('drainageCode:group:edit')") @Log(title = "客户群活码", businessType = BusinessType.UPDATE) - @PutMapping - public AjaxResult edit(@RequestBody WeGroupCode weGroupCode) - { - return toAjax(weGroupCodeService.updateWeGroupCode(weGroupCode)); + @PutMapping(value = "/{id}") + public AjaxResult edit(@PathVariable("id") Long id, @RequestBody WeGroupCode weGroupCode) { + // 活码名唯一性检查 + weGroupCode.setId(id); + if (groupCodeService.isNameOccupied(weGroupCode)) { + return AjaxResult.error("添加群活码失败,活码名称 " + weGroupCode.getActivityName() + " 已存在"); + } + weGroupCode.setUpdateBy(SecurityUtils.getUsername()); + weGroupCode.setUpdateTime(new Date()); + try { + // 二维码内容,即该二维码扫码后跳转的页面URL TODO + String content = h5DomainPrefix + "/mobile/#/groupCode?id=" + weGroupCode.getId(); + SysFile sysFile = fileService.upload(QREncode.getQRCodeMultipartFile(content, weGroupCode.getAvatarUrl())); + weGroupCode.setCodeUrl(sysFile.getImgUrlPrefix() + sysFile.getFileName()); + } catch (Exception e) { + return AjaxResult.error("创建群活码失败,请稍后再试"); + } + return toAjax(groupCodeService.updateWeGroupCode(weGroupCode)); } /** * 删除客户群活码 */ - @PreAuthorize("@ss.hasPermi('wecom:code:remove')") + @ApiOperation(value = "删除客户群活码", httpMethod = "DELETE") + // @PreAuthorize("@ss.hasPermi('drainageCode:group:remove')") @Log(title = "客户群活码", businessType = BusinessType.DELETE) - @DeleteMapping("/{ids}") - public AjaxResult remove(@PathVariable Long[] ids) - { - return toAjax(weGroupCodeService.deleteWeGroupCodeByIds(ids)); + @DeleteMapping("/{ids}") + public AjaxResult batchRemove(@PathVariable Long[] ids) { + return toAjax(groupCodeService.deleteWeGroupCodeByIds(ids)); + } + + /** + * 从群活码获取第一个可用的实际码(实际埋点记录扫码次数) + */ + @ApiOperation(value = "从群活码获取第一个可用的实际码", httpMethod = "GET") + @GetMapping("/getActualCode/{groupCodeId}") + public AjaxResult getActual(@PathVariable("groupCodeId") String id) { + WeGroupCode groupCode = groupCodeService.getById(id); + + //统计扫码次数 + groupCodeService.countScanTimes(groupCode); + + List actualCodeList = groupCodeService.selectActualList(groupCode.getId()); + WeGroupCodeActual groupCodeActual = null; + for (WeGroupCodeActual item : actualCodeList) { + // 获取第一个可用的实际码 + if (item.getStatus().intValue() == WeConstans.WE_GROUP_CODE_ENABLE) { + groupCodeActual = item; + break; + } + } + if (StringUtils.isNotNull(groupCodeActual)) { + AjaxResult ajax = AjaxResult.success(); + + HashMap data = new HashMap<>(); + data.put("activityName", groupCode.getActivityName()); + data.put("tipMsg", groupCode.getTipMsg()); + data.put("guide", groupCode.getGuide()); + data.put("actualQRCode", groupCodeActual.getActualGroupQrCode()); + data.put("isOpenTip", groupCode.getShowTip().toString()); + data.put("serviceQrCode", groupCode.getCustomerServerQrCode()); + data.put("groupName", groupCodeActual.getChatGroupName()); + ajax.put("data", data); + return ajax; + } else { + // 找不到可用的实际群活码也不要抛出错误,否则前端H5页面不好处理。 + return AjaxResult.success("没有可用的实际群活码!"); + } } + + } diff --git a/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeGroupController.java b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeGroupController.java index d2b5c29aeb0473aceaebe92493b120e48aad5c41..ac456b0f8d0d3298916283155d788caf724b4041 100644 --- a/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeGroupController.java +++ b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeGroupController.java @@ -1,20 +1,26 @@ package com.linkwechat.web.controller.wecom; +import cn.hutool.core.collection.CollectionUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.linkwechat.common.constant.WeConstans; import com.linkwechat.common.core.controller.BaseController; import com.linkwechat.common.core.domain.AjaxResult; import com.linkwechat.common.core.page.TableDataInfo; +import com.linkwechat.common.exception.CustomException; +import com.linkwechat.wecom.constants.SynchRecordConstants; import com.linkwechat.wecom.domain.WeGroup; import com.linkwechat.wecom.domain.WeGroupMember; +import com.linkwechat.wecom.domain.vo.WeMakeGroupTagVo; import com.linkwechat.wecom.service.IWeGroupMemberService; import com.linkwechat.wecom.service.IWeGroupService; +import com.linkwechat.wecom.service.IWeGroupTagRelService; +import com.linkwechat.wecom.service.IWeSynchRecordService; +import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.web.bind.annotation.*; import java.util.List; @@ -34,17 +40,57 @@ public class WeGroupController extends BaseController { @Autowired private IWeGroupMemberService weGroupMemberService; - @PreAuthorize("@ss.hasPermi('customerManage:group:list')") + + @Autowired + private IWeGroupTagRelService iWeGroupTagRelService; + + @Autowired + private IWeSynchRecordService iWeSynchRecordService; + + // @PreAuthorize("@ss.hasPermi('customerManage:group:list')") @GetMapping({"/list"}) public TableDataInfo list(WeGroup weGroup) { startPage(); List list = this.weGroupService.selectWeGroupList(weGroup); - return getDataTable(list); + TableDataInfo dataTable = getDataTable(list); + dataTable.setLastSyncTime( + iWeSynchRecordService.findUpdateLatestTime(SynchRecordConstants.SYNCH_CUSTOMER_GROUP) + );//最近同步时间 + return dataTable; + } + + + /** + * 群详情 + * @param chatId + * @return + */ + @GetMapping("/chatDetail/{chatId}") + public AjaxResult chatDetail(@PathVariable String chatId){ + List weGroups = this.weGroupService.selectWeGroupList(WeGroup.builder() + .chatId(chatId) + .build()); + if(CollectionUtil.isNotEmpty(weGroups)){ + return AjaxResult.success(weGroups.stream().findFirst().get()); + } + return AjaxResult.success(); } + /** + * 获取所有群接口(不分页) + * @param weGroup + * @return + */ + @GetMapping({"/allList"}) + public AjaxResult allList(WeGroup weGroup) { + + return AjaxResult.success( + this.weGroupService.selectWeGroupList(weGroup) + ); + } - @PreAuthorize("@ss.hasPermi('customerManage:group:view')") + // @PreAuthorize("@ss.hasPermi('customerManage:group:view')") @GetMapping({"/members"}) public TableDataInfo list(WeGroupMember weGroupMember) { startPage(); @@ -56,13 +102,15 @@ public class WeGroupController extends BaseController { * 同步客户群 * @return */ - @PreAuthorize("@ss.hasPermi('customerManage:group:sync')") + // @PreAuthorize("@ss.hasPermi('customerManage:group:sync')") @GetMapping({"/synchWeGroup"}) public AjaxResult synchWeGroup(){ - - weGroupService.synchWeGroup(); - + try { + weGroupService.synchWeGroup(); + }catch (CustomException e){ + return AjaxResult.error(e.getMessage()); + } return AjaxResult.success(WeConstans.SYNCH_TIP); } @@ -72,7 +120,7 @@ public class WeGroupController extends BaseController { * @param userId * @return */ - @PreAuthorize("@ss.hasPermi('customerManage:group:sync')") + // @PreAuthorize("@ss.hasPermi('customerManage:group:sync')") @GetMapping({"/getGroupsByUserId/{userId}"}) public AjaxResult getGroupsByUserId(@PathVariable String userId){ @@ -80,4 +128,19 @@ public class WeGroupController extends BaseController { return AjaxResult.success(weGroupService .list(new LambdaQueryWrapper().eq(WeGroup::getOwner,userId))); } + + + /** + * 编辑群标签 + * @return + */ + @PostMapping("/makeGroupTag") + @ApiOperation("编辑群标签") + public AjaxResult makeGroupTag(@RequestBody WeMakeGroupTagVo weMakeGroupTagVo){ + + iWeGroupTagRelService.makeGroupTag(weMakeGroupTagVo); + + return AjaxResult.success(); + } + } diff --git a/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeGroupMessageTemplateController.java b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeGroupMessageTemplateController.java new file mode 100644 index 0000000000000000000000000000000000000000..b240b60b064f2a2aa0344f1c50d781325ba83969 --- /dev/null +++ b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeGroupMessageTemplateController.java @@ -0,0 +1,120 @@ +package com.linkwechat.web.controller.wecom; + +import com.linkwechat.common.annotation.Log; +import com.linkwechat.common.core.controller.BaseController; +import com.linkwechat.common.core.domain.AjaxResult; +import com.linkwechat.common.core.page.TableDataInfo; +import com.linkwechat.common.enums.BusinessType; +import com.linkwechat.wecom.domain.WeGroupMessageSendResult; +import com.linkwechat.wecom.domain.WeGroupMessageTask; +import com.linkwechat.wecom.domain.WeGroupMessageTemplate; +import com.linkwechat.wecom.domain.query.WeAddGroupMessageQuery; +import com.linkwechat.wecom.domain.vo.WeGroupMessageDetailVo; +import com.linkwechat.wecom.service.IWeGroupMessageTemplateService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.Arrays; +import java.util.List; + +/** + * 群发消息模板Controller + * + * @author ruoyi + * @date 2021-10-27 + */ +@Api(tags = "群发消息管理") +@RestController +@RequestMapping("/wecom/groupmsg/template") +public class WeGroupMessageTemplateController extends BaseController { + + @Autowired + private IWeGroupMessageTemplateService iWeGroupMessageTemplateService; + + /** + * 查询群发消息模板列表 + */ + //@PreAuthorize("@ss.hasPermi('linkwechat:template:list')") + @ApiOperation(value = "查询群发消息模板列表", httpMethod = "GET") + @GetMapping("/list") + public TableDataInfo list(WeGroupMessageTemplate weGroupMessageTemplate) { + startPage(); + List list = iWeGroupMessageTemplateService.queryList(weGroupMessageTemplate); + return getDataTable(list); + } + + + /** + * 获取群发消息模板详细信息 + */ + //@PreAuthorize("@ss.hasPermi('linkwechat:template:query')") + @ApiOperation(value = "获取群发消息模板详细信息", httpMethod = "GET") + @GetMapping(value = "/{id}") + public AjaxResult getGroupMsgTemplateDetail(@PathVariable("id") Long id) { + return AjaxResult.success(iWeGroupMessageTemplateService.getGroupMsgTemplateDetail(id)); + } + + /** + * 新增群发消息模板 + */ + //@PreAuthorize("@ss.hasPermi('linkwechat:template:add')") + @ApiOperation(value = "新增群发消息模板", httpMethod = "POST") + @Log(title = "群发消息模板", businessType = BusinessType.INSERT) + @PostMapping("/add") + public AjaxResult addGroupMsgTemplate(@RequestBody WeAddGroupMessageQuery query) throws Exception { + iWeGroupMessageTemplateService.addGroupMsgTemplate(query); + return AjaxResult.success(); + } + + /** + * 同步消息发送结果 + */ + //@PreAuthorize("@ss.hasPermi('linkwechat:template:remove')") + @ApiOperation(value = "同步消息发送结果", httpMethod = "GET") + @Log(title = "群发消息模板", businessType = BusinessType.OTHER) + @GetMapping("/sync/{ids}") + public AjaxResult sync(@PathVariable Long[] ids) { + iWeGroupMessageTemplateService.syncGroupMsgSendResultByIds(Arrays.asList(ids)); + return AjaxResult.success(); + } + + /** + * 取消定时发送 + */ + //@PreAuthorize("@ss.hasPermi('linkwechat:template:remove')") + @ApiOperation(value = "取消定时发送", httpMethod = "GET") + @Log(title = "群发消息模板", businessType = BusinessType.UPDATE) + @GetMapping("/cancel/{ids}") + public AjaxResult cancel(@PathVariable Long[] ids) { + iWeGroupMessageTemplateService.cancelByIds(Arrays.asList(ids)); + return AjaxResult.success(); + } + + /** + * 群发成员发送任务列表 + */ + //@PreAuthorize("@ss.hasPermi('linkwechat:template:remove')") + @ApiOperation(value = "群发成员发送任务列表", httpMethod = "GET") + @Log(title = "群发消息模板", businessType = BusinessType.SELECT) + @GetMapping("/task/list") + public TableDataInfo groupMsgTaskList(WeGroupMessageTask task) { + startPage(); + List messageTaskList = iWeGroupMessageTemplateService.groupMsgTaskList(task); + return getDataTable(messageTaskList); + } + + /** + * 群发成员发送任务列表 + */ + //@PreAuthorize("@ss.hasPermi('linkwechat:template:remove')") + @ApiOperation(value = "群发成员发送任务列表", httpMethod = "GET") + @Log(title = "群发消息模板", businessType = BusinessType.SELECT) + @GetMapping("/send/result/list") + public TableDataInfo groupMsgSendResultList(WeGroupMessageSendResult sendResult) { + startPage(); + List sendResultList = iWeGroupMessageTemplateService.groupMsgSendResultList(sendResult); + return getDataTable(sendResultList); + } +} diff --git a/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeMaterialController.java b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeMaterialController.java index e9951a3a46df1e433e0ba044bcc1b00f3e4ba867..45dd3719b4029fe80a8083afe524f8466b30b1e5 100644 --- a/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeMaterialController.java +++ b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeMaterialController.java @@ -1,20 +1,36 @@ package com.linkwechat.web.controller.wecom; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.linkwechat.common.annotation.Log; import com.linkwechat.common.core.controller.BaseController; import com.linkwechat.common.core.domain.AjaxResult; import com.linkwechat.common.core.page.TableDataInfo; import com.linkwechat.common.enums.BusinessType; +import com.linkwechat.common.enums.MediaType; import com.linkwechat.wecom.domain.WeMaterial; +import com.linkwechat.wecom.domain.WePoster; +import com.linkwechat.wecom.domain.dto.ResetCategoryDto; +import com.linkwechat.wecom.domain.dto.TemporaryMaterialDto; +import com.linkwechat.wecom.domain.dto.WeMediaDto; import com.linkwechat.wecom.domain.vo.WeMaterialFileVO; import com.linkwechat.wecom.service.IWeMaterialService; +import com.linkwechat.wecom.service.IWePosterService; +import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; +import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Base64; import java.util.List; +import java.util.stream.Collectors; /** * 企业微信素材Controller @@ -22,6 +38,7 @@ import java.util.List; * @author KEWEN * @date 2020-10-08 */ +@Api("企业微信素材管理") @RestController @RequestMapping("/wecom/material") public class WeMaterialController extends BaseController { @@ -30,31 +47,34 @@ public class WeMaterialController extends BaseController { @Autowired private IWeMaterialService materialService; - /** - * 查询素材列表 - */ - @PreAuthorize("@ss.hasPermi('wecom:material:list')") + @Autowired + private IWePosterService wePosterService; + + + // @PreAuthorize("@ss.hasPermi('wecom:material:list')") @GetMapping("/list") - public TableDataInfo list(@RequestParam(value = "categoryId", required = false) String categoryId, @RequestParam(value = "search", required = false) String search) { + @ApiOperation("查询素材列表") + public TableDataInfo list(@RequestParam(value = "categoryId", required = false) String categoryId + , @RequestParam(value = "search", required = false) String search,@RequestParam(value = "mediaType") String mediaType,Integer status) { startPage(); - List list = materialService.findWeMaterials(categoryId, search); - return getDataTable(list); + return getDataTable( + StringUtils.isNotBlank(mediaType) && mediaType.equals(MediaType.POSTER.getType())? + wePosterService.findWePosterToWeMaterial(categoryId,search,status): + materialService.findWeMaterials(categoryId, search,mediaType) + ); } - /** - * 查询素材详细信息 - */ - @PreAuthorize("@ss.hasPermi('wechat:material:query')") + + + // @PreAuthorize("@ss.hasPermi('wechat:material:query')") @GetMapping(value = "/{id}") @ApiOperation("查询素材详细信息") public AjaxResult getInfo(@PathVariable("id") Long id) { return AjaxResult.success(materialService.findWeMaterialById(id)); } - /** - * 添加素材信息 - */ - @PreAuthorize("@ss.hasPermi('wechat:material:add')") + + // @PreAuthorize("@ss.hasPermi('wechat:material:add')") @Log(title = "添加素材信息", businessType = BusinessType.INSERT) @PostMapping @ApiOperation("添加素材信息") @@ -62,10 +82,8 @@ public class WeMaterialController extends BaseController { return toAjax(materialService.insertWeMaterial(material)); } - /** - * 更新素材信息 - */ - @PreAuthorize("@ss.hasPermi('wechat:material:edit')") + + // @PreAuthorize("@ss.hasPermi('wechat:material:edit')") @Log(title = "更新素材信息", businessType = BusinessType.UPDATE) @PutMapping @ApiOperation("更新素材信息") @@ -73,27 +91,95 @@ public class WeMaterialController extends BaseController { return toAjax(materialService.updateWeMaterial(material)); } - /** - * 删除素材信息 - */ - @PreAuthorize("@ss.hasPermi('wechat:material:remove')") + + // @PreAuthorize("@ss.hasPermi('wechat:material:remove')") @Log(title = "删除素材信息", businessType = BusinessType.DELETE) @DeleteMapping("/{ids}") @ApiOperation("删除素材信息") public AjaxResult remove(@PathVariable Long[] ids) { - return toAjax(materialService.deleteWeMaterialByIds(ids)); + materialService.deleteWeMaterialByIds(ids); + + return AjaxResult.success(); } - /** - * 上传素材信息 - */ - @PreAuthorize("@ss.hasPermi('wechat:material:upload')") + + // @PreAuthorize("@ss.hasPermi('wechat:material:upload')") @Log(title = "上传素材信息", businessType = BusinessType.OTHER) @PostMapping("/upload") @ApiOperation("上传素材信息") - public AjaxResult upload(@RequestParam(value = "file") MultipartFile file, @RequestParam(value = "type") String type) { - WeMaterialFileVO weMaterialFileVO = materialService.uploadWeMaterialFile(file, type); + public AjaxResult upload(@RequestParam(value = "file") MultipartFile file, @RequestParam(value = "mediaType") String mediaType) { + WeMaterialFileVO weMaterialFileVO = materialService.uploadWeMaterialFile(file, mediaType); return AjaxResult.success(weMaterialFileVO); } + + // @PreAuthorize("@ss.hasPermi('wechat:material:resetCategory')") + @Log(title = "更换分组", businessType = BusinessType.OTHER) + @PutMapping("/resetCategory") + @ApiOperation("更换分组") + public AjaxResult resetCategory(@RequestBody ResetCategoryDto resetCategoryDto) { + materialService.resetCategory(resetCategoryDto.getCategoryId(), resetCategoryDto.getMaterials()); + return AjaxResult.success(); + } + +// //@PreAuthorize("@ss.hasPermi('wechat:material:temporaryMaterialMediaId')") +// @Log(title = "获取素材media_id", businessType = BusinessType.OTHER) +// @PostMapping("/temporaryMaterialMediaId") +// @ApiOperation("获取素材media_id") +// public AjaxResult temporaryMaterialMediaId(@RequestBody TemporaryMaterialDto temporaryMaterialDto){ +// WeMediaDto weMediaDto = materialService.uploadTemporaryMaterial(temporaryMaterialDto.getUrl(), +// temporaryMaterialDto.getType() +// ,temporaryMaterialDto.getName()); +// return AjaxResult.success(weMediaDto); +// } + + //@PreAuthorize("@ss.hasPermi('wechat:material:temporaryMaterialMediaId')") + @Log(title = "获取素材media_id", businessType = BusinessType.OTHER) + @GetMapping("/temporaryMaterialMediaId") + @ApiOperation("H5端发送获取素材media_id") + public AjaxResult temporaryMaterialMediaId(String url,String type,String name) throws UnsupportedEncodingException { + +// Base64.Encoder encoder = Base64.getEncoder(); +// byte[] textByte = name.getBytes("UTF-8"); +// String encodedText = encoder.encodeToString(textByte); + + WeMediaDto weMediaDto = materialService.uploadTemporaryMaterial(url, + type + , name+"."+url .substring( url .lastIndexOf(".") + 1, url.length())); + return AjaxResult.success(weMediaDto); + } + + + //@PreAuthorize("@ss.hasPermi('wechat:material:temporaryMaterialMediaId')") + @Log(title = "获取素材media_id", businessType = BusinessType.OTHER) + @PostMapping("/temporaryMaterialMediaIdForWeb") + @ApiOperation("web端发送获取素材media_id") + public AjaxResult temporaryMaterialMediaIdForWeb(@RequestBody TemporaryMaterialDto temporaryMaterialDto){ + + WeMediaDto weMediaDto = materialService.uploadTemporaryMaterial(temporaryMaterialDto.getUrl(), + MediaType.of( temporaryMaterialDto.getType()).get().getMediaType() + ,temporaryMaterialDto.getName()); + return AjaxResult.success(weMediaDto); + } + + + + + + + + @Log(title = "上传素材图片", businessType = BusinessType.OTHER) + @PostMapping("/uploadimg") + @ApiOperation("上传素材图片") + public AjaxResult uploadImg(MultipartFile file, HttpServletRequest request){ + System.out.println(request.getServerName()); + WeMediaDto weMediaDto=new WeMediaDto(); +// WeMediaDto weMediaDto = materialService.uploadImg(file); +// weMediaDto.setFileName(file.getResource().getFilename()); weMaterialFileVO.getMaterialUrl()+ + WeMaterialFileVO weMaterialFileVO = materialService.uploadWeMaterialFile(file, MediaType.IMAGE.getType()); + weMediaDto.setFileName(weMaterialFileVO.getMaterialName()); + weMediaDto.setUrl(weMaterialFileVO.getMaterialUrl()+weMaterialFileVO.getMaterialName()); + return AjaxResult.success(weMediaDto); + } + } diff --git a/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeMessagePushController.java b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeMessagePushController.java index 8d3f7d1b0299f4e0225da46fc1ba9b51ca3cfdee..e326e87d55793c28e89a4a1d12cad4ed97b3dd0e 100644 --- a/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeMessagePushController.java +++ b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeMessagePushController.java @@ -21,7 +21,7 @@ import java.util.List; * @date 2020-10-28 */ @RestController -@RequestMapping("/system/push") +@RequestMapping("/wecom/push") public class WeMessagePushController extends BaseController { @Autowired @@ -30,7 +30,7 @@ public class WeMessagePushController extends BaseController { /** * 查询消息发送的列表 */ - @PreAuthorize("@ss.hasPermi('system:push:list')") + // @PreAuthorize("@ss.hasPermi('system:push:list')") @GetMapping("/list") public TableDataInfo list(WeMessagePush weMessagePush) { startPage(); @@ -41,7 +41,7 @@ public class WeMessagePushController extends BaseController { /** * 导出消息发送的列表 */ - @PreAuthorize("@ss.hasPermi('system:push:export')") + // @PreAuthorize("@ss.hasPermi('system:push:export')") @Log(title = "消息发送的", businessType = BusinessType.EXPORT) @GetMapping("/export") public AjaxResult export(WeMessagePush weMessagePush) { @@ -53,7 +53,7 @@ public class WeMessagePushController extends BaseController { /** * 获取消息发送的详细信息 */ - @PreAuthorize("@ss.hasPermi('system:push:query')") + // @PreAuthorize("@ss.hasPermi('system:push:query')") @GetMapping(value = "/{messagePushId}") public AjaxResult getInfo(@PathVariable("messagePushId") Long messagePushId) { return AjaxResult.success(weMessagePushService.selectWeMessagePushById(messagePushId)); @@ -62,17 +62,18 @@ public class WeMessagePushController extends BaseController { /** * 新增消息发送的 */ - @PreAuthorize("@ss.hasPermi('system:push:add')") + // @PreAuthorize("@ss.hasPermi('system:push:add')") @Log(title = "消息发送的", businessType = BusinessType.INSERT) @PostMapping(value = "add") public AjaxResult add(@RequestBody WeMessagePush weMessagePush) { - return toAjax(weMessagePushService.insertWeMessagePush(weMessagePush)); + weMessagePushService.insertWeMessagePush(weMessagePush); + return AjaxResult.success(); } /** * 删除消息发送的 */ - @PreAuthorize("@ss.hasPermi('system:push:remove')") + // @PreAuthorize("@ss.hasPermi('system:push:remove')") @Log(title = "消息发送的", businessType = BusinessType.DELETE) @DeleteMapping("/{messagePushIds}") public AjaxResult remove(@PathVariable Long[] messagePushIds) { diff --git a/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeMomentsController.java b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeMomentsController.java new file mode 100644 index 0000000000000000000000000000000000000000..90f5ca22920fd4c35c8d7426fe8eb2931de5a8b2 --- /dev/null +++ b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeMomentsController.java @@ -0,0 +1,126 @@ +package com.linkwechat.web.controller.wecom; + +import cn.hutool.core.collection.CollectionUtil; +import com.linkwechat.common.constant.WeConstans; +import com.linkwechat.common.core.controller.BaseController; +import com.linkwechat.common.core.domain.AjaxResult; +import com.linkwechat.common.core.page.TableDataInfo; +import com.linkwechat.common.exception.CustomException; +import com.linkwechat.wecom.client.WeMomentsClient; +import com.linkwechat.wecom.constants.SynchRecordConstants; +import com.linkwechat.wecom.domain.WeMoments; +import com.linkwechat.wecom.domain.dto.moments.MomentsCreateResultDto; +import com.linkwechat.wecom.service.IWeMomentsService; +import com.linkwechat.wecom.service.IWeSynchRecordService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import java.util.List; + + +/** + * 朋友圈相关 + */ +@RestController +@RequestMapping("/wecom/moments") +public class WeMomentsController extends BaseController { + + + @Autowired + IWeMomentsService iWeMomentsService; + + @Autowired + IWeSynchRecordService iWeSynchRecordService; + + + @Autowired + WeMomentsClient weMomentsClient; + + + + /** + * 获取朋友圈列表 + * @param weMoments + * @return + */ + @GetMapping("/list") + public TableDataInfo list(WeMoments weMoments) { + startPage(); + List moments = iWeMomentsService.findMoments(weMoments); + TableDataInfo dataTable = getDataTable(moments); + dataTable.setLastSyncTime( + iWeSynchRecordService.findUpdateLatestTime( weMoments.getType().equals(new Integer(0))? + SynchRecordConstants.SYNCH_CUSTOMER_ENTERPRISE_MOMENTS:SynchRecordConstants.SYNCH_CUSTOMER_PERSON_MOMENTS) + );//最近同步时间 + + return dataTable; + } + + + /** + * 获取朋友圈详情 + * @param momentId + * @return + */ + @GetMapping("/findMomentsDetail/{momentId}") + public AjaxResult findMomentsDetail(@PathVariable String momentId){ + + + return AjaxResult.success( + iWeMomentsService.findMomentsDetail(momentId) + ); + } + + /** + * 新增或者编辑朋友圈 + * @return + */ + @PostMapping("/addOrUpdate") + public AjaxResult addOrUpdate(@RequestBody WeMoments weMoments) throws InterruptedException { + + iWeMomentsService.addOrUpdateMoments(weMoments); + + + return AjaxResult.success(); + } + + + /** + * 朋友圈同步 + * @param filterType 0:企业朋友圈;1:个人朋友圈 + * @return + */ + @GetMapping("/synchMoments") + public AjaxResult synchMoments(@RequestParam(defaultValue = "0") Integer filterType){ + + try { + if(filterType.equals(new Integer(0))){ + iWeMomentsService.synchEnterpriseMoments(filterType); + }else if(filterType.equals(new Integer(1))){ + iWeMomentsService.synchPersonMoments(filterType); + } + }catch (CustomException e){ + return AjaxResult.error(e.getMessage()); + } + + + return AjaxResult.success(WeConstans.SYNCH_TIP); + } + + + /** + * 个人朋友圈互动数据同步 + * @param userIds + * @return + */ + @GetMapping("/synchMomentsInteracte/{userIds}") + public AjaxResult synchMomentsInteracte(@PathVariable String[] userIds){ + + iWeMomentsService.synchMomentsInteracte(CollectionUtil.newArrayList(userIds)); + + return AjaxResult.success(WeConstans.SYNCH_TIP); + } + + + + +} diff --git a/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeMsgTlpController.java b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeMsgTlpController.java index 418afd4c21eb6bf59d54a5a34cda232beca68690..a83e3343e39afdb5caf466455bc6efe6b7eec69e 100644 --- a/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeMsgTlpController.java +++ b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeMsgTlpController.java @@ -1,94 +1 @@ -package com.linkwechat.web.controller.wecom; - -import com.linkwechat.common.annotation.Log; -import com.linkwechat.common.core.controller.BaseController; -import com.linkwechat.common.core.domain.AjaxResult; -import com.linkwechat.common.core.page.TableDataInfo; -import com.linkwechat.common.enums.BusinessType; -import com.linkwechat.wecom.domain.WeMsgTlp; -import com.linkwechat.wecom.domain.WeMsgTlpScope; -import com.linkwechat.wecom.service.IWeMsgTlpScopeService; -import com.linkwechat.wecom.service.IWeMsgTlpService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.*; - -import java.util.Arrays; -import java.util.List; - -/** - * 欢迎语模板Controller - * - * @author ruoyi - * @date 2020-10-04 - */ -@RestController -@RequestMapping("/wecom/tlp") -public class WeMsgTlpController extends BaseController -{ - @Autowired - private IWeMsgTlpService weMsgTlpService; - - - @Autowired - private IWeMsgTlpScopeService iWeMsgTlpScopeService; - - /** - * 查询欢迎语模板列表 - */ - @PreAuthorize("@ss.hasPermi('wecom:tlp:list')") - @GetMapping("/list") - public TableDataInfo list(WeMsgTlp weMsgTlp) - { - startPage(); - List list = weMsgTlpService.selectWeMsgTlpList(weMsgTlp); - return getDataTable(list); - } - - - /** - * 获取欢迎语模板详细信息 - */ - @PreAuthorize("@ss.hasPermi('wecom:tlp:query')") - @GetMapping(value = "/scop/{id}") - public AjaxResult getInfo(@PathVariable("id") Long id) - { - - return AjaxResult.success( - iWeMsgTlpScopeService.selectWeMsgTlpScopeList(WeMsgTlpScope.builder().msgTlpId(id).build()) - ); - } - - /** - * 新增欢迎语模板 - */ - @PreAuthorize("@ss.hasPermi('wecom:tlp:add')") - @Log(title = "欢迎语模板", businessType = BusinessType.INSERT) - @PostMapping - public AjaxResult add(@RequestBody WeMsgTlp weMsgTlp) - { - return toAjax(weMsgTlpService.insertWeMsgTlp(weMsgTlp)); - } - - /** - * 修改欢迎语模板 - */ - @PreAuthorize("@ss.hasPermi('wecom:tlp:edit')") - @Log(title = "欢迎语模板", businessType = BusinessType.UPDATE) - @PutMapping - public AjaxResult edit(@RequestBody WeMsgTlp weMsgTlp) - { - return toAjax(weMsgTlpService.updateWeMsgTlp(weMsgTlp)); - } - - /** - * 删除欢迎语模板 - */ - @PreAuthorize("@ss.hasPermi('wecom:tlp:remove')") - @Log(title = "欢迎语模板", businessType = BusinessType.DELETE) - @DeleteMapping("/{ids}") - public AjaxResult remove(@PathVariable Long[] ids) - { - return toAjax(weMsgTlpService.batchRemoveByids(Arrays.asList(ids))); - } -} +package com.linkwechat.web.controller.wecom; import cn.hutool.core.collection.CollectionUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.linkwechat.common.annotation.Log; import com.linkwechat.common.core.controller.BaseController; import com.linkwechat.common.core.domain.AjaxResult; import com.linkwechat.common.core.page.TableDataInfo; import com.linkwechat.common.enums.BusinessType; import com.linkwechat.common.utils.StringUtils; import com.linkwechat.wecom.domain.WeMsgTlp; import com.linkwechat.wecom.service.IWeMsgTlpService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; /** * 欢迎语模板Controller * * @author ruoyi * @date 2020-10-04 */ @RestController @RequestMapping("/wecom/tlp") public class WeMsgTlpController extends BaseController { @Autowired private IWeMsgTlpService weMsgTlpService; /** * 查询欢迎语模板列表 */ // @PreAuthorize("@ss.hasPermi('wecom:tlp:list')") @GetMapping("/list") public TableDataInfo list(WeMsgTlp weMsgTlp) { startPage(); return getDataTable(weMsgTlpService.list( new LambdaQueryWrapper() .like(StringUtils.isNotEmpty(weMsgTlp.getWelcomeMsg()),WeMsgTlp::getWelcomeMsg,weMsgTlp.getWelcomeMsg()) .eq(weMsgTlp.getWelcomeMsgTplType() !=null,WeMsgTlp::getWelcomeMsgTplType,weMsgTlp.getWelcomeMsgTplType()) .like(StringUtils.isNotEmpty(weMsgTlp.getUserIds()),WeMsgTlp::getUserIds,weMsgTlp.getUserIds()) )); } /** * 新增欢迎语模板 */ // @PreAuthorize("@ss.hasPermi('wecom:tlp:add')") @Log(title = "新增欢迎语模板", businessType = BusinessType.INSERT) @PostMapping(value = "/addorUpdate") public AjaxResult addorUpdate(@RequestBody WeMsgTlp weMsgTlp) { weMsgTlpService.addorUpdate(weMsgTlp); return AjaxResult.success(); } /** * 删除欢迎语模板 */ // @PreAuthorize("@ss.hasPermi('wecom:tlp:remove')") @Log(title = "删除欢迎语模板", businessType = BusinessType.DELETE) @DeleteMapping("/remove/{ids}") public AjaxResult remove(@PathVariable Long[] ids) { weMsgTlpService.removeByIds(CollectionUtil.toList(ids)); return AjaxResult.success(); } } \ No newline at end of file diff --git a/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WePageDateContraller.java b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WePageDateContraller.java new file mode 100644 index 0000000000000000000000000000000000000000..92dd9f2b6f650457c7262705e9cedc7c02e5865d --- /dev/null +++ b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WePageDateContraller.java @@ -0,0 +1,59 @@ +package com.linkwechat.web.controller.wecom; + +import com.linkwechat.common.core.domain.AjaxResult; +import com.linkwechat.common.core.redis.RedisCache; +import com.linkwechat.quartz.task.PageHomeDataTask; +import com.linkwechat.wecom.domain.dto.WePageStaticDataDto; +import com.linkwechat.wecom.service.IWeCorpAccountService; +import com.linkwechat.wecom.service.IWeUserService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/** + * @author danmo + * @description 首页统计 + * @date 2021/2/23 15:30 + **/ +@Api(tags = "首页统计") +@Slf4j +@RestController +@RequestMapping("wecom/page/") +public class WePageDateContraller { + @Autowired + private RedisCache redisCache; + @Autowired + private PageHomeDataTask pageHomeDataTask; + + /** + * + */ + @ApiOperation(value = "数据总览controller",httpMethod = "GET") + // @PreAuthorize("@ss.hasPermi('wecom:page:getCorpBasicData')") + @GetMapping("/getCorpBasicData") + public AjaxResult getCorpBasicData(){ + return AjaxResult.success(redisCache.getCacheMap("getCorpBasicData")); + } + + @ApiOperation(value = "实时数据controller",httpMethod = "GET") + // @PreAuthorize("@ss.hasPermi('wecom:page:getCorpRealTimeData')") + @GetMapping("/getCorpRealTimeData") + public AjaxResult getCorpRealTimeData(){ + WePageStaticDataDto wePageStaticDataDto = redisCache.getCacheObject("getCorpRealTimeData"); + return AjaxResult.success(wePageStaticDataDto); + } + + @ApiOperation(value = "实时数据刷新",httpMethod = "GET") + @GetMapping("/refresh") + public AjaxResult refresh(){ + pageHomeDataTask.getPageHomeDataData(); + return AjaxResult.success(); + } +} diff --git a/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WePosterController.java b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WePosterController.java new file mode 100644 index 0000000000000000000000000000000000000000..7fc47529777a13b3bb2ee152231b52ae20bfce13 --- /dev/null +++ b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WePosterController.java @@ -0,0 +1,141 @@ +package com.linkwechat.web.controller.wecom; + +import cn.hutool.core.collection.CollectionUtil; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.linkwechat.common.constant.Constants; +import com.linkwechat.common.core.controller.BaseController; +import com.linkwechat.common.core.domain.AjaxResult; +import com.linkwechat.common.enums.MediaType; +import com.linkwechat.common.utils.SnowFlakeUtil; +import com.linkwechat.common.utils.StringUtils; +import com.linkwechat.wecom.domain.WePoster; +import com.linkwechat.wecom.domain.WePosterSubassembly; +import com.linkwechat.wecom.service.IWePosterFontService; +import com.linkwechat.wecom.service.IWePosterService; +import com.linkwechat.wecom.service.IWePosterSubassemblyService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.CollectionUtils; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * @author ws + */ +@RestController +@RequestMapping(value = "wecom/poster/") +@Api(description = "海报") +public class WePosterController extends BaseController { + + + @Resource + private IWePosterService wePosterService; + + @Resource + private IWePosterSubassemblyService wePosterSubassemblyService; + + @Resource + private IWePosterFontService wePosterFontService; + + @PostMapping(value = "insert") + @ApiOperation("创建海报") + @Transactional(rollbackFor = RuntimeException.class) + public AjaxResult insert(@RequestBody WePoster poster) { + wePosterService.generateSimpleImg(poster); + poster.setMediaType(MediaType.POSTER.getType()); + wePosterService.saveOrUpdate(poster); + if(CollectionUtil.isNotEmpty(poster.getPosterSubassemblyList())) { + poster.getPosterSubassemblyList().forEach(wePosterSubassembly -> { + wePosterSubassembly.setPosterId(poster.getId()); + }); + wePosterSubassemblyService.saveBatch(poster.getPosterSubassemblyList()); + } + return AjaxResult.success("创建成功"); + } + + + @PutMapping(value = "update") + @ApiOperation("修改海报") + // @PreAuthorize("@ss.hasAnyPermi('wecom:poster:update')") + @Transactional(rollbackFor = RuntimeException.class) + public AjaxResult update(@RequestBody WePoster poster) { + if (poster.getId() == null) { + return AjaxResult.error("id为空"); + } + poster.setMediaType(null); + wePosterService.generateSimpleImg(poster); + wePosterService.saveOrUpdate(poster); + List posterSubassemblyList = wePosterSubassemblyService.lambdaQuery().eq(WePosterSubassembly::getPosterId, poster.getId()).eq(WePosterSubassembly::getDelFlag, 0).list(); + Map posterSubassemblyMap = posterSubassemblyList.stream().collect(Collectors.toMap(WePosterSubassembly::getId, p -> p)); + if(!CollectionUtils.isEmpty(poster.getPosterSubassemblyList())) { + List insertList = new ArrayList<>(); + List updateList = new ArrayList<>(); + poster.getPosterSubassemblyList().forEach(wePosterSubassembly -> { + if (wePosterSubassembly.getId() == null) { + wePosterSubassembly.setPosterId(poster.getId()); + insertList.add(wePosterSubassembly); + } else { + posterSubassemblyMap.remove(wePosterSubassembly.getId()); + updateList.add(wePosterSubassembly); + } + }); + if (!CollectionUtils.isEmpty(insertList)) { + wePosterSubassemblyService.saveBatch(insertList); + } + if (!CollectionUtils.isEmpty(updateList)) { + wePosterSubassemblyService.updateBatchById(updateList); + } + } + List deleteList = new ArrayList<>(posterSubassemblyMap.values()); + if (!CollectionUtils.isEmpty(deleteList)) { + wePosterSubassemblyService.update(Wrappers.lambdaUpdate(WePosterSubassembly.class).set(WePosterSubassembly::getDelFlag,1).in(WePosterSubassembly::getId,deleteList.stream().map(WePosterSubassembly::getId).collect(Collectors.toList()))); + } + return AjaxResult.success("修改成功"); + } + + + + @GetMapping(value = "entity/{id}") + // @PreAuthorize("@ss.hasAnyPermi('wecom:poster:entity')") + @ApiOperation("查询海报详情") + public AjaxResult entity(@PathVariable Long id) { + return AjaxResult.success(wePosterService.selectOne(id)); + } + + @GetMapping(value = "page") + @ApiOperation("分页查询海报") + // @PreAuthorize("@ss.hasAnyPermi('wecom:poster:page')") + public AjaxResult page(Long categoryId, String name) { + startPage(); + List fontList = wePosterService.lambdaQuery() + .eq(WePoster::getDelFlag, 0) + .eq(categoryId != null, WePoster::getCategoryId, categoryId) + .like(StringUtils.isNotBlank(name), WePoster::getTitle, name) + .orderByDesc(WePoster::getCreateTime) + .list(); + return AjaxResult.success(getDataTable(fontList)); + } + + @DeleteMapping(value = "delete/{id}") + @ApiOperation(value = "删除海报") + // @PreAuthorize("@ss.hasAnyPermi('wecom:poster:delete')") + @Transactional(rollbackFor = RuntimeException.class) + public AjaxResult deletePosterFont(@PathVariable Long id) { + wePosterService.update( + Wrappers.lambdaUpdate(WePoster.class).set(WePoster::getDelFlag, 1).eq(WePoster::getId, id)); + wePosterSubassemblyService.update( + Wrappers.lambdaUpdate(WePosterSubassembly.class).set(WePosterSubassembly::getDelFlag, 1).eq(WePosterSubassembly::getPosterId, id) + ); + return AjaxResult.success("删除成功"); + } + + +} diff --git a/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WePosterFontController.java b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WePosterFontController.java new file mode 100644 index 0000000000000000000000000000000000000000..040f7edbe9cb5bf66a9add26b03c25dae242ac45 --- /dev/null +++ b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WePosterFontController.java @@ -0,0 +1,86 @@ +package com.linkwechat.web.controller.wecom; + +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.linkwechat.common.core.controller.BaseController; +import com.linkwechat.common.core.domain.AjaxResult; +import com.linkwechat.common.enums.MediaType; +import com.linkwechat.common.utils.SnowFlakeUtil; +import com.linkwechat.wecom.domain.WePosterFont; +import com.linkwechat.wecom.service.IWePosterFontService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * @author ws + */ +@RestController +@RequestMapping(value = "wecom/posterFont/") +@Api(description = "海报字体") +public class WePosterFontController extends BaseController { + + + @Resource + private IWePosterFontService wePosterFontService; + + @PostMapping(value = "posterFont") + @ApiOperation("创建海报字体") + @Transactional(rollbackFor = RuntimeException.class) + public AjaxResult insertPosterFont(@RequestBody WePosterFont posterFont) { + posterFont.setMediaType(MediaType.POSTER_FONT.getType()); + wePosterFontService.save(posterFont); + return AjaxResult.success("创建成功"); + } + + + @PutMapping(value = "posterFont") + @ApiOperation("修改海报字体") + @Transactional(rollbackFor = RuntimeException.class) + public AjaxResult updatePosterFont(@RequestBody WePosterFont posterFont) { + if (posterFont.getId() == null) { + return AjaxResult.error("id为空"); + } + posterFont.setMediaType(null); + wePosterFontService.saveOrUpdate(posterFont); + return AjaxResult.success("修改成功"); + } + + @GetMapping(value = "posterFontList") + @ApiOperation("列表查询海报字体") + public AjaxResult selectPosterFontList() { + List fontList = wePosterFontService.lambdaQuery() + .eq(WePosterFont::getDelFlag, 0) + .orderByDesc(WePosterFont::getOrder) + .orderByDesc(WePosterFont::getCreateTime) + .list(); + return AjaxResult.success(fontList); + } + + @GetMapping(value = "posterFontPage") + @ApiOperation("分页查询海报字体") + public AjaxResult selectPosterFontPage() { + startPage(); + List fontList = wePosterFontService.lambdaQuery() + .eq(WePosterFont::getDelFlag, 0) + .orderByDesc(WePosterFont::getOrder) + .orderByDesc(WePosterFont::getCreateTime) + .list(); + return AjaxResult.success(getDataTable(fontList)); + } + + @DeleteMapping(value = "posterFont/{id}") + @ApiOperation("删除海报字体") + @Transactional(rollbackFor = RuntimeException.class) + public AjaxResult deletePosterFont(@PathVariable Long id) { + wePosterFontService.update( + Wrappers.lambdaUpdate(WePosterFont.class).set(WePosterFont::getDelFlag, 1).eq(WePosterFont::getId, id) + ); + return AjaxResult.success("删除成功"); + } + + +} diff --git a/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeQrCodeController.java b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeQrCodeController.java new file mode 100644 index 0000000000000000000000000000000000000000..a692835599b60ff534c32894e9353ca4c6f596a6 --- /dev/null +++ b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeQrCodeController.java @@ -0,0 +1,143 @@ +package com.linkwechat.web.controller.wecom; + +import cn.hutool.core.collection.CollectionUtil; +import com.github.pagehelper.PageInfo; +import com.linkwechat.common.annotation.Log; +import com.linkwechat.common.core.controller.BaseController; +import com.linkwechat.common.core.domain.AjaxResult; +import com.linkwechat.common.core.page.TableDataInfo; +import com.linkwechat.common.enums.BusinessType; +import com.linkwechat.common.exception.CustomException; +import com.linkwechat.common.utils.StringUtils; +import com.linkwechat.common.utils.file.FileUtils; +import com.linkwechat.wecom.domain.WeEmpleCode; +import com.linkwechat.wecom.domain.query.qr.WeQrAddQuery; +import com.linkwechat.wecom.domain.query.qr.WeQrCodeListQuery; +import com.linkwechat.wecom.domain.vo.qr.WeQrCodeDetailVo; +import com.linkwechat.wecom.domain.vo.qr.WeQrCodeScanCountVo; +import com.linkwechat.wecom.domain.vo.qr.WeQrScopeUserVo; +import com.linkwechat.wecom.domain.vo.qr.WeQrScopeVo; +import com.linkwechat.wecom.service.IWeQrCodeService; +import com.linkwechat.wecom.service.event.WeEventPublisherService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.*; +import java.util.stream.Collectors; + +/** + * @author danmo + * @description 活码管理 + * @date 2021/11/12 18:22 + **/ + +@RestController +@RequestMapping(value = "wecom/qr/") +@Api(tags = "活码管理") +public class WeQrCodeController extends BaseController { + + @Autowired + private IWeQrCodeService weQrCodeService; + + @ApiOperation(value = "新增活码", httpMethod = "POST") + @Log(title = "活码管理", businessType = BusinessType.INSERT) + @PostMapping("/add") + public AjaxResult addQrCode(@RequestBody @Validated WeQrAddQuery weQrAddQuery) { + weQrCodeService.addQrCode(weQrAddQuery); + return AjaxResult.success(); + } + + @ApiOperation(value = "修改活码", httpMethod = "POST") + @Log(title = "活码管理", businessType = BusinessType.UPDATE) + @PutMapping("/update") + public AjaxResult updateQrCode(@RequestBody @Validated WeQrAddQuery weQrAddQuery) { + weQrCodeService.updateQrCode(weQrAddQuery); + return AjaxResult.success(); + } + + + @ApiOperation(value = "获取活码详情", httpMethod = "GET") + @Log(title = "活码管理", businessType = BusinessType.SELECT) + @GetMapping("/get/{id}") + public AjaxResult getQrDetail(@PathVariable("id") Long Id) { + WeQrCodeDetailVo qrDetail = weQrCodeService.getQrDetail(Id); + return AjaxResult.success(qrDetail); + } + + @ApiOperation(value = "获取活码列表", httpMethod = "GET") + @Log(title = "活码管理", businessType = BusinessType.SELECT) + @GetMapping("/list") + public TableDataInfo getQrCodeList(WeQrCodeListQuery qrCodeListQuery) { + startPage(); + PageInfo qrCodeList = weQrCodeService.getQrCodeList(qrCodeListQuery); + return getDataTable(qrCodeList); + } + + @ApiOperation(value = "删除活码", httpMethod = "DELETE") + @Log(title = "活码管理", businessType = BusinessType.SELECT) + @DeleteMapping("/del/{ids}") + public AjaxResult delQrCode(@PathVariable("ids") List ids) { + weQrCodeService.delQrCode(ids); + return AjaxResult.success(); + } + + @ApiOperation(value = "获取活码统计", httpMethod = "GET") + @Log(title = "活码管理", businessType = BusinessType.SELECT) + @GetMapping("/scan/count") + public AjaxResult getWeQrCodeScanCount(WeQrCodeListQuery qrCodeListQuery) { + WeQrCodeScanCountVo weQrCodeScanCount = weQrCodeService.getWeQrCodeScanCount(qrCodeListQuery); + return AjaxResult.success(weQrCodeScanCount); + } + + /** + * 员工活码批量下载 + * + * @param ids 员工活码ids + * @param request 请求 + * @param response 输出 + * @throws Exception + */ + @ApiOperation(value = "员工活码批量下载", httpMethod = "GET") + @Log(title = "活码管理", businessType = BusinessType.OTHER) + @GetMapping("/batch/download") + public void batchDownload(@RequestParam("ids") List ids, HttpServletRequest request, HttpServletResponse response) throws IOException { + List qrCodeList = weQrCodeService.getQrDetailByQrIds(ids); + if(CollectionUtil.isNotEmpty(qrCodeList)){ + List> fileList = qrCodeList.stream().map(item -> { + Map fileMap = new HashMap<>(); + List userVoList = item.getQrUserInfos().stream().map(WeQrScopeVo::getWeQrUserList).flatMap(Collection::stream).collect(Collectors.toList()); + String fileName = userVoList.stream().map(WeQrScopeUserVo::getUserName).collect(Collectors.joining(",")); + fileMap.put("fileName", fileName + "-" + item.getName() + ".jpg"); + fileMap.put("url", item.getQrCode()); + return fileMap; + }).collect(Collectors.toList()); + FileUtils.batchDownloadFile(fileList, response.getOutputStream()); + } + } + + /** + * 员工活码下载 + * + * @param id 员工活码id + * @param request 请求 + * @param response 输出 + * @throws Exception + */ + @ApiOperation(value = "员工活码下载", httpMethod = "GET") + @Log(title = "活码管理", businessType = BusinessType.OTHER) + @GetMapping("/download") + public void download(@RequestParam("id") Long id, HttpServletRequest request, HttpServletResponse response) throws IOException { + WeQrCodeDetailVo qrDetail = weQrCodeService.getQrDetail(id); + if (StringUtils.isEmpty(qrDetail.getQrCode())){ + throw new CustomException("活码不存在"); + }else { + FileUtils.downloadFile(qrDetail.getQrCode(), response.getOutputStream()); + } + } +} diff --git a/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeSensitiveActController.java b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeSensitiveActController.java new file mode 100644 index 0000000000000000000000000000000000000000..2d5d6b582b0d6b8024e7709ca30f4cdf2cb7ba70 --- /dev/null +++ b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeSensitiveActController.java @@ -0,0 +1,128 @@ +package com.linkwechat.web.controller.wecom; + +import com.linkwechat.common.annotation.Log; +import com.linkwechat.common.constant.HttpStatus; +import com.linkwechat.common.core.controller.BaseController; +import com.linkwechat.common.core.domain.AjaxResult; +import com.linkwechat.common.core.page.TableDataInfo; +import com.linkwechat.common.enums.BusinessType; +import com.linkwechat.common.utils.poi.ExcelUtil; +import com.linkwechat.wecom.domain.WeSensitiveAct; +import com.linkwechat.wecom.domain.WeSensitiveActHit; +import com.linkwechat.wecom.service.IWeSensitiveActHitService; +import com.linkwechat.wecom.service.IWeSensitiveActService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 敏感行为管理接口 + * + * @author leejoker <1056650571@qq.com> + * @version 1.0 + * @date 2021/1/12 18:07 + */ +@Api(tags = "敏感行为管理接口") +@RestController +@RequestMapping("/wecom/sensitive/act") +public class WeSensitiveActController extends BaseController { + @Autowired + private IWeSensitiveActService weSensitiveActService; + + @Autowired + private IWeSensitiveActHitService weSensitiveActHitService; + + /** + * 查询敏感行为列表 + */ +// @PreAuthorize("@ss.hasPermi('wecom:sensitiveact:list')") + @ApiOperation(value = "查询敏感行为列表",httpMethod = "GET") + @GetMapping("/list") + public TableDataInfo> list(WeSensitiveAct weSensitiveAct) { + startPage(); + List list = weSensitiveActService.selectWeSensitiveActList(weSensitiveAct); + return getDataTable(list); + } + + /** + * 获取敏感行为详细信息 + */ + // @PreAuthorize("@ss.hasPermi('wecom:sensitiveact:query')") + @ApiOperation(value = "获取敏感行为详细信息",httpMethod = "GET") + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("id") Long id) { + return AjaxResult.success(weSensitiveActService.selectWeSensitiveActById(id)); + } + + /** + * 新增敏感行为设置 + */ + // @PreAuthorize("@ss.hasPermi('wecom:sensitiveact:add')") + @ApiOperation(value = "新增敏感行为设置",httpMethod = "POST") + @Log(title = "新增敏感行为", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@Valid @RequestBody WeSensitiveAct weSensitiveAct) { + return weSensitiveActService.insertWeSensitiveAct(weSensitiveAct) ? AjaxResult.success() : AjaxResult.error(); + } + + /** + * 修改敏感行为 + */ + // @PreAuthorize("@ss.hasPermi('wecom:sensitiveact:edit')") + @ApiOperation(value = "修改敏感行为",httpMethod = "PUT") + @Log(title = "修改敏感行为", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody WeSensitiveAct weSensitiveAct) { + Long id = weSensitiveAct.getId(); + WeSensitiveAct originData = weSensitiveActService.selectWeSensitiveActById(id); + if (originData == null) { + return AjaxResult.error(HttpStatus.NOT_FOUND, "数据不存在"); + } + return weSensitiveActService.updateWeSensitiveAct(weSensitiveAct) ? AjaxResult.success() : AjaxResult.error(); + } + + /** + * 删除敏感行为 + */ + // @PreAuthorize("@ss.hasPermi('wecom:sensitiveact:remove')") + @ApiOperation(value = "删除敏感行为",httpMethod = "DELETE") + @Log(title = "删除敏感行为", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable("ids") String ids) { + String[] id = ids.split(","); + Long[] idArray = new Long[id.length]; + Arrays.stream(id).map(Long::parseLong).collect(Collectors.toList()).toArray(idArray); + return weSensitiveActService.deleteWeSensitiveActByIds(idArray) ? AjaxResult.success() : AjaxResult.error(); + } + + /** + * 敏感行为命中查询 + */ + // @PreAuthorize("@ss.hasPermi('wecom:sensitiveacthit:list')") + @ApiOperation(value = "敏感行为命中查询(这个接口有问题)",httpMethod = "GET") + @GetMapping("/hit/list") + public TableDataInfo> hitList() { + startPage(); + List list = weSensitiveActHitService.list(); + return getDataTable(list); + } + + /** + * 导出敏感行为记录 + */ + // @PreAuthorize("@ss.hasPermi('wecom:sensitiveacthit:export')") + @ApiOperation(value = "导出敏感行为记录",httpMethod = "POST") + @PostMapping("/hit/export") + public AjaxResult export() { + List list = weSensitiveActHitService.list(); + ExcelUtil util = new ExcelUtil<>(WeSensitiveActHit.class); + return util.exportExcel(list, "敏感行为记录"); + } +} diff --git a/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeSensitiveController.java b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeSensitiveController.java new file mode 100644 index 0000000000000000000000000000000000000000..6e1abb47c2fecbe9e034d454010aaab01555943c --- /dev/null +++ b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeSensitiveController.java @@ -0,0 +1,108 @@ +package com.linkwechat.web.controller.wecom; + +import com.linkwechat.common.annotation.Log; +import com.linkwechat.common.constant.HttpStatus; +import com.linkwechat.common.core.controller.BaseController; +import com.linkwechat.common.core.domain.AjaxResult; +import com.linkwechat.common.core.page.TableDataInfo; +import com.linkwechat.common.enums.BusinessType; +import com.linkwechat.wecom.domain.WeSensitive; +import com.linkwechat.wecom.domain.query.WeSensitiveHitQuery; +import com.linkwechat.wecom.domain.vo.WeChatContactSensitiveMsgVO; +import com.linkwechat.wecom.service.IWeSensitiveService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 敏感词Controller + * + * @author ruoyi + * @date 2020-12-29 + */ +@RestController +@RequestMapping("/wecom/sensitive") +@Api(tags = "敏感词管理") +public class WeSensitiveController extends BaseController { + @Autowired + private IWeSensitiveService weSensitiveService; + + /** + * 查询敏感词设置列表 + */ + // @PreAuthorize("@ss.hasPermi('wecom:sensitive:list')") + @GetMapping("/list") + @ApiOperation(value = "查询敏感词列表",httpMethod = "GET") + public TableDataInfo> list(WeSensitive weSensitive) { + startPage(); + List list = weSensitiveService.selectWeSensitiveList(weSensitive); + return getDataTable(list); + } + + /** + * 获取敏感词设置详细信息 + */ + // @PreAuthorize("@ss.hasPermi('wecom:sensitive:query')") + @GetMapping(value = "/{id}") + @ApiOperation(value = "查询敏感词详情",httpMethod = "GET") + public AjaxResult getInfo(@PathVariable("id") Long id) { + return AjaxResult.success(weSensitiveService.selectWeSensitiveById(id)); + } + + /** + * 新增敏感词设置 + */ + // @PreAuthorize("@ss.hasPermi('wecom:sensitive:add')") + @Log(title = "敏感词设置", businessType = BusinessType.INSERT) + @PostMapping + @ApiOperation(value = "添加敏感词",httpMethod = "POST") + public AjaxResult add(@Valid @RequestBody WeSensitive weSensitive) { + return toAjax(weSensitiveService.insertWeSensitive(weSensitive)); + } + + /** + * 修改敏感词设置 + */ + // @PreAuthorize("@ss.hasPermi('wecom:sensitive:edit')") + @Log(title = "敏感词设置", businessType = BusinessType.UPDATE) + @PutMapping + @ApiOperation(value = "修改敏感词",httpMethod = "PUT") + public AjaxResult edit(@Valid @RequestBody WeSensitive weSensitive) { + Long id = weSensitive.getId(); + WeSensitive originData = weSensitiveService.selectWeSensitiveById(id); + if (originData == null) { + return AjaxResult.error(HttpStatus.NOT_FOUND, "数据不存在"); + } + return toAjax(weSensitiveService.updateWeSensitive(weSensitive)); + } + + /** + * 删除敏感词设置 + */ + // @PreAuthorize("@ss.hasPermi('wecom:sensitive:remove')") + @Log(title = "敏感词设置", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + @ApiOperation(value = "删除敏感词",httpMethod = "DELETE") + public AjaxResult remove(@PathVariable("ids") String ids) { + String[] id = ids.split(","); + Long[] idArray = new Long[id.length]; + Arrays.stream(id).map(Long::parseLong).collect(Collectors.toList()).toArray(idArray); + return toAjax(weSensitiveService.destroyWeSensitiveByIds(idArray)); + } + + /** + * 敏感词命中查询 + */ + // @PreAuthorize("@ss.hasPermi('wecom:sensitivehit:list')") + @GetMapping("/hit/list") + @ApiOperation(value = "敏感词命中查询",httpMethod = "GET") + public TableDataInfo> hitList(WeSensitiveHitQuery query) { + return getDataTable(weSensitiveService.getHitSensitiveList(query)); + } +} diff --git a/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeTagGroupController.java b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeTagGroupController.java index 1de2f19b02c6e93bc278fdc5ffacddd9cb5f1ba3..e518964d1933389f9c7e689cac7cbdab02fa2b50 100644 --- a/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeTagGroupController.java +++ b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeTagGroupController.java @@ -1,14 +1,23 @@ package com.linkwechat.web.controller.wecom; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.StrUtil; import com.linkwechat.common.annotation.Log; import com.linkwechat.common.constant.WeConstans; import com.linkwechat.common.core.controller.BaseController; import com.linkwechat.common.core.domain.AjaxResult; import com.linkwechat.common.core.page.TableDataInfo; import com.linkwechat.common.enums.BusinessType; +import com.linkwechat.common.exception.CustomException; +import com.linkwechat.common.utils.Threads; +import com.linkwechat.wecom.constants.SynchRecordConstants; +import com.linkwechat.wecom.domain.WeTag; +import com.linkwechat.wecom.service.IWeSynchRecordService; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; @@ -20,6 +29,8 @@ import org.springframework.web.bind.annotation.RestController; import com.linkwechat.wecom.domain.WeTagGroup; import com.linkwechat.wecom.service.IWeTagGroupService; +import java.util.List; + /** * 标签组Controller * @@ -33,29 +44,60 @@ public class WeTagGroupController extends BaseController @Autowired private IWeTagGroupService weTagGroupService; + @Autowired + private IWeSynchRecordService iWeSynchRecordService; + /** - * 查询标签组列表 + * 查询标签组列表(分页) */ - @PreAuthorize("@ss.hasPermi('customerManage:tag:list')") + // @PreAuthorize("@ss.hasPermi('customerManage:tag:list')") @GetMapping("/list") public TableDataInfo list(WeTagGroup weTagGroup) { startPage(); - return getDataTable( + + TableDataInfo dataTable = getDataTable(weTagGroupService.selectWeTagGroupList(weTagGroup)); + dataTable.setLastSyncTime( + iWeSynchRecordService.findUpdateLatestTime(SynchRecordConstants.SYNCH_CUSTOMER) + );//最近同步时间 + + return dataTable; + } + + + /** + * 查询标签组列表(不分页) + * @param weTagGroup + * @return + */ + @GetMapping("/allList") + public AjaxResult allList(WeTagGroup weTagGroup) + { + return AjaxResult.success( weTagGroupService.selectWeTagGroupList(weTagGroup) ); } - /** * 新增标签组 */ - @PreAuthorize("@ss.hasPermi('customerManage:tag:add')") + // @PreAuthorize("@ss.hasPermi('customerManage:tag:add')") @Log(title = "标签组", businessType = BusinessType.INSERT) @PostMapping public AjaxResult add(@RequestBody WeTagGroup weTagGroup) { + + //校验标签组名称与标签名称是否相同 + if(StrUtil.isNotBlank(weTagGroup.getGourpName())){ + List weTags = weTagGroup.getWeTags(); + if(CollectionUtil.isNotEmpty(weTags)){ + if(weTags.stream().filter(m -> m.getName().equals(weTagGroup.getGourpName())).findAny().isPresent()){ + return AjaxResult.error("标签组名称与标签名不可重复"); + } + + } + } weTagGroupService.insertWeTagGroup(weTagGroup); return AjaxResult.success(); @@ -64,7 +106,7 @@ public class WeTagGroupController extends BaseController /** * 修改标签组 */ - @PreAuthorize("@ss.hasPermi('customerManage:tag:edit')") + // @PreAuthorize("@ss.hasPermi('customerManage:tag:edit')") @Log(title = "标签组", businessType = BusinessType.UPDATE) @PutMapping public AjaxResult edit(@RequestBody WeTagGroup weTagGroup) @@ -76,12 +118,13 @@ public class WeTagGroupController extends BaseController /** * 删除标签组 */ - @PreAuthorize("@ss.hasPermi('customerManage:tag:remove')") + // @PreAuthorize("@ss.hasPermi('customerManage:tag:remove')") @Log(title = "标签组", businessType = BusinessType.DELETE) @DeleteMapping("/{ids}") public AjaxResult remove(@PathVariable String[] ids) { - return toAjax(weTagGroupService.deleteWeTagGroupByIds(ids)); + weTagGroupService.deleteWeTagGroupByIds(ids); + return AjaxResult.success(); } @@ -89,11 +132,16 @@ public class WeTagGroupController extends BaseController * 同步标签 * @return */ - @PreAuthorize("@ss.hasPermi('customerManage:tag:sync')") + // @PreAuthorize("@ss.hasPermi('customerManage:tag:sync')") @GetMapping("/synchWeTags") public AjaxResult synchWeTags(){ - weTagGroupService.synchWeTags(); + try { + weTagGroupService.synchWeTags(); + }catch (CustomException e){ + return AjaxResult.error(e.getMessage()); + } + return AjaxResult.success(WeConstans.SYNCH_TIP); } diff --git a/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeTaskFissionController.java b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeTaskFissionController.java new file mode 100644 index 0000000000000000000000000000000000000000..c050a2372a477425865cd557c84c860a04192925 --- /dev/null +++ b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeTaskFissionController.java @@ -0,0 +1,293 @@ +package com.linkwechat.web.controller.wecom; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.bean.copier.CopyOptions; +import cn.hutool.core.collection.CollectionUtil; +import com.alibaba.fastjson.JSONObject; +//import com.alibaba.nacos.common.utils.CollectionUtils; +import com.google.common.collect.Lists; +import com.linkwechat.common.annotation.Log; +import com.linkwechat.common.config.CosConfig; +import com.linkwechat.common.constant.HttpStatus; +import com.linkwechat.common.core.controller.BaseController; +import com.linkwechat.common.core.domain.AjaxResult; +import com.linkwechat.common.core.page.TableDataInfo; +import com.linkwechat.common.enums.BusinessType; +import com.linkwechat.common.exception.wecom.WeComException; +import com.linkwechat.common.utils.DateUtils; +import com.linkwechat.common.utils.StringUtils; +import com.linkwechat.common.utils.file.FileUploadUtils; +import com.linkwechat.common.utils.poi.ExcelUtil; +import com.linkwechat.framework.web.domain.server.SysFile; +import com.linkwechat.framework.web.service.FileService; +import com.linkwechat.wecom.domain.WeCustomer; +import com.linkwechat.wecom.domain.WeTaskFission; +import com.linkwechat.wecom.domain.dto.WeChatUserDTO; +import com.linkwechat.wecom.domain.dto.WeTaskFissionPosterDTO; +import com.linkwechat.wecom.domain.query.WeTaskFissionStatisticQO; +import com.linkwechat.wecom.domain.vo.WeTaskFissionProgressVO; +import com.linkwechat.wecom.domain.vo.WeTaskFissionStatisticVO; +import com.linkwechat.wecom.domain.vo.WeTaskFissionTotalProgressVO; +import com.linkwechat.wecom.service.IWeTaskFissionService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.apache.commons.lang3.ObjectUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.text.ParseException; +import java.util.Date; +import java.util.List; +import java.util.Objects; + + +/** + * 任务宝Controller + * + * @author leejoker + * @date 2021-01-20 + */ +@Api("任务宝Controller") +@RestController +@RequestMapping("/wecom/fission") +public class WeTaskFissionController extends BaseController { + + @Autowired + private IWeTaskFissionService weTaskFissionService; + + + @Autowired + private FileService fileService; + + /** + * 查询任务宝列表 + */ + @ApiOperation(value = "查询任务宝列表", httpMethod = "GET") + // @PreAuthorize("@ss.hasPermi('wecom:fission:list')") + @GetMapping("/list") + public TableDataInfo> list(WeTaskFission weTaskFission){ + startPage(); + List list = weTaskFissionService.selectWeTaskFissionList(weTaskFission); + return getDataTable(list); + } + + /** + * 查询统计信息 + */ + @ApiOperation(value = "查询统计信息", httpMethod = "GET") + // @PreAuthorize("@ss.hasPermi('wecom:fission:stat')") + @GetMapping("/stat") + public AjaxResult statistics(WeTaskFissionStatisticQO weTaskFissionStatisticQO) throws ParseException { + Date st; + Date et = DateUtils.getNowDate(); + if (weTaskFissionStatisticQO.getSeven()) { + st = DateUtils.addDays(et, -7); + } else if (weTaskFissionStatisticQO.getThirty()) { + st = DateUtils.addDays(et, -30); + } else { + if (StringUtils.isNotBlank(weTaskFissionStatisticQO.getBeginTime()) ^ StringUtils.isNotBlank(weTaskFissionStatisticQO.getEndTime())) { + throw new WeComException("开始或结束时间不能为空"); + } + st = DateUtils.parseDate(weTaskFissionStatisticQO.getBeginTime() + " 00:00:00", "yyyy-MM-dd HH:mm:ss"); + et = DateUtils.parseDate(weTaskFissionStatisticQO.getEndTime() + " 23:59:59", "yyyy-MM-dd HH:mm:ss"); + } + WeTaskFissionStatisticVO vo = weTaskFissionService.taskFissionStatistic(weTaskFissionStatisticQO.getTaskFissionId(), st, et); + return AjaxResult.success(vo); + } + + /** + * 导出任务宝列表 + */ + @ApiOperation(value = "导出任务宝列表", httpMethod = "GET") + // @PreAuthorize("@ss.hasPermi('wecom:fission:export')") + @Log(title = "任务宝", businessType = BusinessType.EXPORT) + @GetMapping("/export") + public AjaxResult export(WeTaskFission weTaskFission) { + List list = weTaskFissionService.selectWeTaskFissionList(weTaskFission); + ExcelUtil util = new ExcelUtil(WeTaskFission.class); + return util.exportExcel(list, "fission"); + } + + /** + * 获取任务宝详细信息 + */ + @ApiOperation(value = "获取任务宝详细信息", httpMethod = "GET") + // @PreAuthorize("@ss.hasPermi('wecom:fission:query')") + @GetMapping(value = "/getInfo/{id}") + public AjaxResult getInfo(@PathVariable("id") Long id) { + return AjaxResult.success(weTaskFissionService.selectWeTaskFissionById(id)); + } + + /** + * 新增任务宝 + */ + @ApiOperation(value = "新增任务宝", httpMethod = "POST") + // @PreAuthorize("@ss.hasPermi('wecom:fission:add')") + @Log(title = "任务宝", businessType = BusinessType.INSERT) + @PostMapping("/add") + public AjaxResult add(@RequestBody WeTaskFission weTaskFission) { + weTaskFissionService.insertWeTaskFission(weTaskFission); + return AjaxResult.success(); + } + + /** + * 编辑任务宝 + */ + @ApiOperation(value = "编辑任务宝", httpMethod = "POST") + // @PreAuthorize("@ss.hasPermi('wecom:fission:edit')") + @Log(title = "任务宝", businessType = BusinessType.INSERT) + @PutMapping("/edit") + public AjaxResult edit(@RequestBody WeTaskFission weTaskFission) { + if (ObjectUtils.isEmpty(weTaskFission.getId())) { + return AjaxResult.error("数据id为空"); + } + WeTaskFission fissionTask = weTaskFissionService.selectWeTaskFissionById(weTaskFission.getId()); + if (ObjectUtils.isEmpty(fissionTask)) { + return AjaxResult.error("数据不存在"); + } + CopyOptions options = CopyOptions.create(); + options.setIgnoreNullValue(true); + BeanUtil.copyProperties(weTaskFission, fissionTask, options); + if (CollectionUtil.isNotEmpty(weTaskFission.getTaskFissionStaffs())) { + fissionTask.setTaskFissionStaffs(weTaskFission.getTaskFissionStaffs()); + } + if (CollectionUtil.isNotEmpty(weTaskFission.getTaskFissionWeGroups())) { + fissionTask.setTaskFissionWeGroups(weTaskFission.getTaskFissionWeGroups()); + } + Long id = weTaskFissionService.updateWeTaskFission(fissionTask); + JSONObject json = new JSONObject(); + json.put("id", id); + return AjaxResult.success(json.toJSONString()); + } + + /** + * 删除任务宝 + */ + @ApiOperation(value = "删除任务宝", httpMethod = "DELETE") + // @PreAuthorize("@ss.hasPermi('wecom:fission:remove')") + @Log(title = "任务宝", businessType = BusinessType.DELETE) + @DeleteMapping("/delete/{ids}") + public AjaxResult remove(@PathVariable Long[] ids) { + return toAjax(weTaskFissionService.deleteWeTaskFissionByIds(ids)); + } + + /** + * 发送裂变任务 + */ + /*@ApiOperation(value = "发送裂变任务", httpMethod = "GET") + @Log(title = "发送裂变任务", businessType = BusinessType.OTHER) + @GetMapping("/send/{id}") + public AjaxResult send(@PathVariable Long id) throws Exception { + weTaskFissionService.sendWeTaskFission(id); + return AjaxResult.success(); + }*/ + + /** + * 添加群裂变完成记录 + */ + @ApiOperation(value = "添加群裂变完成记录", httpMethod = "POST") + // @PreAuthorize("@ss.hasPermi('wecom:fission:complete')") + @Log(title = "添加群裂变完成记录", businessType = BusinessType.OTHER) + @PostMapping("/complete/{id}/records/{recordId}") + public AjaxResult completeRecord(@PathVariable("id") Long id, + @PathVariable("recordId") Long recordId, + @RequestBody WeChatUserDTO weChatUserDTO) { + WeTaskFission taskFission = weTaskFissionService.selectWeTaskFissionById(id); + if (taskFission == null) { + return AjaxResult.error(HttpStatus.NOT_FOUND, "数据不存在"); + } + weTaskFissionService.completeFissionRecord(id, recordId, weChatUserDTO); + return AjaxResult.success("操作成功", taskFission.getFissQrcode()); + } + + /** + * 生成带二维码的海报 + */ + @ApiOperation(value = "生成带二维码的海报", httpMethod = "POST") + // @PreAuthorize("@ss.hasPermi('wecom:fission:poster')") + @Log(title = "生成带二维码的海报", businessType = BusinessType.OTHER) + @PostMapping("/poster") + public AjaxResult posterGenerate(@RequestBody WeTaskFissionPosterDTO weTaskFissionPosterDTO) { + String posterUrl = weTaskFissionService.fissionPosterGenerate(weTaskFissionPosterDTO); + JSONObject json = new JSONObject(); + json.put("posterUrl", posterUrl); + return AjaxResult.success(json); + } + + /** + * 上传兑奖图片 + */ + // @PreAuthorize("@ss.hasPermi('wechat:fission:upload')") + @Log(title = "上传兑奖图片", businessType = BusinessType.OTHER) + @PostMapping("/upload") + @ApiOperation(value = "上传兑奖图片", httpMethod = "POST") + public AjaxResult upload(@RequestParam(value = "file") MultipartFile file) throws Exception { + + SysFile sysFile + = fileService.upload(file); +// String url = FileUploadUtils.upload2Cos(file, cosConfig); + JSONObject json = new JSONObject(); + json.put("rewardImageUrl", sysFile.getImgUrlPrefix()+sysFile.getFileName()); + return AjaxResult.success(json); + } + + + /** + * 根据任务id获取参与任务客户列表 + */ + @ApiOperation(value = "根据任务id获取参与任务客户列表", httpMethod = "GET") + // @PreAuthorize("@ss.hasPermi('wecom:fission:getCustomerListById')") + @Log(title = "根据任务id获取参与任务客户列表", businessType = BusinessType.OTHER) + @GetMapping("/getCustomerListById/{id}") + public AjaxResult> getCustomerListById(@ApiParam("任务id") @PathVariable("id") String id) { + return AjaxResult.success(weTaskFissionService.getCustomerListById(null, id)); + } + + + /** + * 获取客户邀请列表和任务进度 + */ + @ApiOperation(value = "获取客户邀请列表和任务进度", httpMethod = "GET") + // @PreAuthorize("@ss.hasPermi('wecom:fission:getCustomerProgress')") + @Log(title = "获取客户邀请列表和任务进度", businessType = BusinessType.OTHER) + @GetMapping("/{id}/progress/{unionId}") + public AjaxResult getCustomerProgress(@ApiParam("任务id") @PathVariable("id") Long id + , @PathVariable("unionId") @ApiParam("客户id") String unionId) { + WeTaskFission weTaskFission = weTaskFissionService.selectWeTaskFissionById(id); + if (weTaskFission != null) { + return AjaxResult.success(weTaskFissionService.getCustomerTaskProgress(weTaskFission, unionId)); + } else { + throw new WeComException("任务不存在"); + } + } + + /** + * 获取任务所有参与客户的完成情况 + */ + @ApiOperation(value = "获取任务所有参与客户的完成情况", httpMethod = "GET") + // @PreAuthorize("@ss.hasPermi('wecom:fission:getCustomerProgress')") + @Log(title = "获取任务所有参与客户的完成情况", businessType = BusinessType.OTHER) + @GetMapping("/{id}/progress") + public AjaxResult> getAllCustomerProgress(@ApiParam("任务id") @PathVariable("id") Long id) { + WeTaskFission weTaskFission = weTaskFissionService.selectWeTaskFissionById(id); + List list = Lists.newArrayList(); + if (weTaskFission != null) { + List customers = weTaskFissionService.getCustomerListById(null, String.valueOf(id)); + if (StringUtils.isNotEmpty(customers)) { + customers.stream().filter(Objects::nonNull).forEach(customer -> { + WeTaskFissionTotalProgressVO vo = new WeTaskFissionTotalProgressVO(); + vo.setCustomer(customer); + vo.setProgress(weTaskFissionService.getCustomerTaskProgress(weTaskFission, customer.getUnionid())); + list.add(vo); + }); + } + return AjaxResult.success(list); + } else { + throw new WeComException("任务不存在"); + } + } +} diff --git a/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeTaskFissionRecordController.java b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeTaskFissionRecordController.java new file mode 100644 index 0000000000000000000000000000000000000000..06450a8319e900ddb20d1802744328d8edba9bb3 --- /dev/null +++ b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeTaskFissionRecordController.java @@ -0,0 +1,99 @@ +package com.linkwechat.web.controller.wecom; + +import com.linkwechat.common.annotation.Log; +import com.linkwechat.common.core.controller.BaseController; +import com.linkwechat.common.core.domain.AjaxResult; +import com.linkwechat.common.core.page.TableDataInfo; +import com.linkwechat.common.enums.BusinessType; +import com.linkwechat.common.utils.poi.ExcelUtil; +import com.linkwechat.wecom.domain.WeTaskFissionRecord; +import com.linkwechat.wecom.service.IWeTaskFissionRecordService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 裂变任务完成记录Controller + * + * @author leejoker + * @date 2021-01-20 + */ +@Api(description = "裂变任务完成记录Controller") +@RestController +@RequestMapping("/wecom/record") +public class WeTaskFissionRecordController extends BaseController { + @Autowired + private IWeTaskFissionRecordService weTaskFissionRecordService; + + /** + * 查询裂变任务完成记录列表 + */ + @ApiOperation(value = "查询裂变任务完成记录列表",httpMethod = "GET") + // @PreAuthorize("@ss.hasPermi('wecom:record:list')") + @GetMapping("/list") + public TableDataInfo list(WeTaskFissionRecord weTaskFissionRecord) { + startPage(); + List list = weTaskFissionRecordService.selectWeTaskFissionRecordList(weTaskFissionRecord); + return getDataTable(list); + } + + /** + * 导出裂变任务完成记录列表 + */ + @ApiOperation(value = "导出裂变任务完成记录列表",httpMethod = "GET") + // @PreAuthorize("@ss.hasPermi('wecom:record:export')") + @Log(title = "裂变任务完成记录", businessType = BusinessType.EXPORT) + @GetMapping("/export") + public AjaxResult export(WeTaskFissionRecord weTaskFissionRecord) { + List list = weTaskFissionRecordService.selectWeTaskFissionRecordList(weTaskFissionRecord); + ExcelUtil util = new ExcelUtil(WeTaskFissionRecord.class); + return util.exportExcel(list, "record"); + } + + /** + * 获取裂变任务完成记录详细信息 + */ + @ApiOperation(value = "获取裂变任务完成记录详细信息",httpMethod = "GET") + // @PreAuthorize("@ss.hasPermi('wecom:record:query')") + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("id") Long id) { + return AjaxResult.success(weTaskFissionRecordService.selectWeTaskFissionRecordById(id)); + } + + /** + * 新增裂变任务完成记录 + */ + @ApiOperation(value = "新增裂变任务完成记录",httpMethod = "POST") + // @PreAuthorize("@ss.hasPermi('wecom:record:add')") + @Log(title = "裂变任务完成记录", businessType = BusinessType.INSERT) + @PostMapping("/add") + public AjaxResult add(@RequestBody WeTaskFissionRecord weTaskFissionRecord) { + return toAjax(weTaskFissionRecordService.insertWeTaskFissionRecord(weTaskFissionRecord)); + } + + /** + * 修改裂变任务完成记录 + */ + @ApiOperation(value = "修改裂变任务完成记录",httpMethod = "PUT") + // @PreAuthorize("@ss.hasPermi('wecom:record:edit')") + @Log(title = "裂变任务完成记录", businessType = BusinessType.UPDATE) + @PutMapping("/edit") + public AjaxResult edit(@RequestBody WeTaskFissionRecord weTaskFissionRecord) { + return toAjax(weTaskFissionRecordService.updateWeTaskFissionRecord(weTaskFissionRecord)); + } + + /** + * 删除裂变任务完成记录 + */ + @ApiOperation(value = "删除裂变任务完成记录",httpMethod = "DELETE") + // @PreAuthorize("@ss.hasPermi('wecom:record:remove')") + @Log(title = "裂变任务完成记录", businessType = BusinessType.DELETE) + @DeleteMapping("/delete/{ids}") + public AjaxResult remove(@PathVariable Long[] ids) { + return toAjax(weTaskFissionRecordService.deleteWeTaskFissionRecordByIds(ids)); + } +} diff --git a/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeTaskFissionRewardController.java b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeTaskFissionRewardController.java new file mode 100644 index 0000000000000000000000000000000000000000..f08cdb3863ce7deebc27b7cfd3b2ca898daf6d0d --- /dev/null +++ b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeTaskFissionRewardController.java @@ -0,0 +1,114 @@ +package com.linkwechat.web.controller.wecom; + +import com.linkwechat.common.annotation.Log; +import com.linkwechat.common.core.controller.BaseController; +import com.linkwechat.common.core.domain.AjaxResult; +import com.linkwechat.common.core.page.TableDataInfo; +import com.linkwechat.common.enums.BusinessType; +import com.linkwechat.common.utils.poi.ExcelUtil; +import com.linkwechat.wecom.domain.WeTaskFissionReward; +import com.linkwechat.wecom.domain.vo.WeTaskFissionRewardVo; +import com.linkwechat.wecom.service.IWeTaskFissionRewardService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + + +/** + * 任务裂变奖励Controller + * + * @author leejoker + * @date 2021-01-20 + */ +@Api(description = "任务裂变奖励Controller") +@RestController +@RequestMapping("/wecom/reward") +public class WeTaskFissionRewardController extends BaseController { + @Autowired + private IWeTaskFissionRewardService weTaskFissionRewardService; + + /** + * 查询任务裂变奖励列表 + */ + @ApiOperation(value = "查询任务裂变奖励列表",httpMethod = "GET") + // @PreAuthorize("@ss.hasPermi('wecom:reward:list')") + @GetMapping("/list") + public TableDataInfo list(WeTaskFissionReward weTaskFissionReward) { + startPage(); + List list = weTaskFissionRewardService.selectWeTaskFissionRewardList(weTaskFissionReward); + return getDataTable(list); + } + + /** + * 导出任务裂变奖励列表 + */ + @ApiOperation(value = "导出任务裂变奖励列表",httpMethod = "GET") + // @PreAuthorize("@ss.hasPermi('wecom:reward:export')") + @Log(title = "任务裂变奖励", businessType = BusinessType.EXPORT) + @GetMapping("/export") + public AjaxResult export(WeTaskFissionReward weTaskFissionReward) { + List list = weTaskFissionRewardService.selectWeTaskFissionRewardList(weTaskFissionReward); + ExcelUtil util = new ExcelUtil(WeTaskFissionReward.class); + return util.exportExcel(list, "reward"); + } + + /** + * 获取任务裂变奖励详细信息 + */ + @ApiOperation(value = "获取任务裂变奖励详细信息",httpMethod = "GET") + // @PreAuthorize("@ss.hasPermi('wecom:reward:query')") + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("id") Long id) { + return AjaxResult.success(weTaskFissionRewardService.selectWeTaskFissionRewardById(id)); + } + + /** + * 新增任务裂变奖励 + */ + @ApiOperation(value = "新增任务裂变奖励",httpMethod = "POST") + // @PreAuthorize("@ss.hasPermi('wecom:reward:add')") + @Log(title = "任务裂变奖励", businessType = BusinessType.INSERT) + @PostMapping("/add") + public AjaxResult add(@RequestBody WeTaskFissionReward weTaskFissionReward) { + return toAjax(weTaskFissionRewardService.insertWeTaskFissionReward(weTaskFissionReward)); + } + + /** + * 修改任务裂变奖励 + */ + @ApiOperation(value = "修改任务裂变奖励",httpMethod = "PUT") + // @PreAuthorize("@ss.hasPermi('wecom:reward:edit')") + @Log(title = "任务裂变奖励", businessType = BusinessType.UPDATE) + @PutMapping("edit") + public AjaxResult edit(@RequestBody WeTaskFissionReward weTaskFissionReward) { + return toAjax(weTaskFissionRewardService.updateWeTaskFissionReward(weTaskFissionReward)); + } + + /** + * 删除任务裂变奖励 + */ + @ApiOperation(value = "删除任务裂变奖励",httpMethod = "DELETE") + // @PreAuthorize("@ss.hasPermi('wecom:reward:remove')") + @Log(title = "任务裂变奖励", businessType = BusinessType.DELETE) + @DeleteMapping("/delete/{ids}") + public AjaxResult remove(@PathVariable Long[] ids) { + return toAjax(weTaskFissionRewardService.deleteWeTaskFissionRewardByIds(ids)); + } + + + /** + * 根据微信用户id和任务id获取任务裂变奖励详细信息 + */ + @ApiOperation(value = "根据微信用户id和任务id获取任务裂变奖励详细信息",httpMethod = "GET") + // @PreAuthorize("@ss.hasPermi('wecom:getRewardByFissionId:query')") + @GetMapping(value = "/getRewardByFissionId/{fissionId}/{eid}") + public AjaxResult getRewardByFissionId(@ApiParam("任务id") @PathVariable("fissionId") String fissionId + , @PathVariable("eid") @ApiParam("客户id") String eid) { + return AjaxResult.success(weTaskFissionRewardService.getRewardByFissionId(fissionId,eid)); + } +} diff --git a/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeTaskFissionStaffController.java b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeTaskFissionStaffController.java new file mode 100644 index 0000000000000000000000000000000000000000..3aecb3eaf3110acf607f8c8f18b26db4194d4d9c --- /dev/null +++ b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeTaskFissionStaffController.java @@ -0,0 +1,99 @@ +package com.linkwechat.web.controller.wecom; + +import com.linkwechat.common.annotation.Log; +import com.linkwechat.common.core.controller.BaseController; +import com.linkwechat.common.core.domain.AjaxResult; +import com.linkwechat.common.core.page.TableDataInfo; +import com.linkwechat.common.enums.BusinessType; +import com.linkwechat.common.utils.poi.ExcelUtil; +import com.linkwechat.wecom.domain.WeTaskFissionStaff; +import com.linkwechat.wecom.service.IWeTaskFissionStaffService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 裂变任务员工列Controller + * + * @author leejoker + * @date 2021-01-20 + */ +@Api(description = "裂变任务员工列Controller") +@RestController +@RequestMapping("/wecom/staff") +public class WeTaskFissionStaffController extends BaseController { + @Autowired + private IWeTaskFissionStaffService weTaskFissionStaffService; + + /** + * 查询裂变任务员工列列表 + */ + @ApiOperation(value = "查询裂变任务员工列列表",httpMethod = "GET") + // @PreAuthorize("@ss.hasPermi('wecom:staff:list')") + @GetMapping("/list") + public TableDataInfo list(WeTaskFissionStaff weTaskFissionStaff) { + startPage(); + List list = weTaskFissionStaffService.selectWeTaskFissionStaffList(weTaskFissionStaff); + return getDataTable(list); + } + + /** + * 导出裂变任务员工列列表 + */ + @ApiOperation(value = "导出裂变任务员工列列表",httpMethod = "GET") + // @PreAuthorize("@ss.hasPermi('wecom:staff:export')") + @Log(title = "裂变任务员工列", businessType = BusinessType.EXPORT) + @GetMapping("/export") + public AjaxResult export(WeTaskFissionStaff weTaskFissionStaff) { + List list = weTaskFissionStaffService.selectWeTaskFissionStaffList(weTaskFissionStaff); + ExcelUtil util = new ExcelUtil(WeTaskFissionStaff.class); + return util.exportExcel(list, "staff"); + } + + /** + * 获取裂变任务员工列详细信息 + */ + @ApiOperation(value = "获取裂变任务员工列详细信息",httpMethod = "GET") + // @PreAuthorize("@ss.hasPermi('wecom:staff:query')") + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("id") Long id) { + return AjaxResult.success(weTaskFissionStaffService.selectWeTaskFissionStaffById(id)); + } + + /** + * 新增裂变任务员工列 + */ + @ApiOperation(value = "新增裂变任务员工列",httpMethod = "POST") + // @PreAuthorize("@ss.hasPermi('wecom:staff:add')") + @Log(title = "裂变任务员工列", businessType = BusinessType.INSERT) + @PostMapping("/add") + public AjaxResult add(@RequestBody WeTaskFissionStaff weTaskFissionStaff) { + return toAjax(weTaskFissionStaffService.insertWeTaskFissionStaff(weTaskFissionStaff)); + } + + /** + * 修改裂变任务员工列 + */ + @ApiOperation(value = "修改裂变任务员工列",httpMethod = "PUT") + // @PreAuthorize("@ss.hasPermi('wecom:staff:edit')") + @Log(title = "裂变任务员工列", businessType = BusinessType.UPDATE) + @PutMapping("/edit") + public AjaxResult edit(@RequestBody WeTaskFissionStaff weTaskFissionStaff) { + return toAjax(weTaskFissionStaffService.updateWeTaskFissionStaff(weTaskFissionStaff)); + } + + /** + * 删除裂变任务员工列 + */ + @ApiOperation(value = "删除裂变任务员工列",httpMethod = "DELETE") + // @PreAuthorize("@ss.hasPermi('wecom:staff:remove')") + @Log(title = "裂变任务员工列", businessType = BusinessType.DELETE) + @DeleteMapping("/delete/{ids}") + public AjaxResult remove(@PathVariable Long[] ids) { + return toAjax(weTaskFissionStaffService.deleteWeTaskFissionStaffByIds(ids)); + } +} diff --git a/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeTicketController.java b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeTicketController.java new file mode 100644 index 0000000000000000000000000000000000000000..2329864cdf5fa4fc594810d62401003adb6d7ac4 --- /dev/null +++ b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeTicketController.java @@ -0,0 +1,77 @@ +package com.linkwechat.web.controller.wecom; + +import com.linkwechat.common.annotation.Log; +import com.linkwechat.common.constant.WeConstans; +import com.linkwechat.common.core.controller.BaseController; +import com.linkwechat.common.core.domain.AjaxResult; +import com.linkwechat.common.core.redis.RedisCache; +import com.linkwechat.common.enums.BusinessType; +import com.linkwechat.common.utils.StringUtils; +import com.linkwechat.common.utils.wecom.TicketUtils; +import com.linkwechat.wecom.client.WeTicketClient; +import com.linkwechat.wecom.domain.WeH5TicketDto; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.concurrent.TimeUnit; + +/** + * @author danmo + * @description h5 ticket校验接口 + * @date 2021/1/6 11:23 + **/ +@Slf4j +@RequestMapping(value = "/wecom/ticket/") +@RestController +public class WeTicketController extends BaseController { + @Autowired + private RedisCache redisCache; + @Autowired + private WeTicketClient weTicketClient; + + + /** + * 获取企业的jsapi_ticket + * + * @param url JS接口页面的完整URL + * @return + */ + @Log(title = "获取企业的jsapi_ticket", businessType = BusinessType.OTHER) + @GetMapping("/getAppTicket") + public AjaxResult getAppTicket(String url,String agentId) { + String ticketVaule = redisCache.getCacheObject(WeConstans.AppTicketKey+"::"+agentId); + if (StringUtils.isEmpty(ticketVaule)) { + WeH5TicketDto ticketRes = weTicketClient.getJsapiTicket(agentId); + if (ticketRes != null && StringUtils.isNotEmpty(ticketRes.getTicket())) { + redisCache.setCacheObject(WeConstans.AppTicketKey+"::"+agentId, ticketRes.getTicket(), ticketRes.getExpiresIn(), TimeUnit.SECONDS); + } + ticketVaule = ticketRes.getTicket(); + } + return AjaxResult.success(TicketUtils.getSignatureMap(ticketVaule, url)); + } + + /** + * 获取应用的jsapi_ticket + * + * @param url JS接口页面的完整URL + * @return + */ + @Log(title = "获取应用的jsapi_ticket", businessType = BusinessType.OTHER) + @GetMapping("/getAgentTicket") + public AjaxResult getAgentTicket(String url,String agentId) { + String ticketVaule = redisCache.getCacheObject(WeConstans.AgentTicketKey+"::"+agentId); + if (StringUtils.isEmpty(ticketVaule)) { + WeH5TicketDto ticketRes = weTicketClient.getTicket(agentId); + if (ticketRes != null && StringUtils.isNotEmpty(ticketRes.getTicket())) { + redisCache.setCacheObject(WeConstans.AgentTicketKey+"::"+agentId, ticketRes.getTicket(), ticketRes.getExpiresIn(), TimeUnit.SECONDS); + } + ticketVaule = ticketRes.getTicket(); + } + return AjaxResult.success(TicketUtils.getSignatureMap(ticketVaule, url)); + } + + +} diff --git a/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeUserController.java b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeUserController.java index fecfc0ddd0f66a2fa2b63283473aa12984898732..179f16b4530c31e9e10fb1bda9e7ccac5483a0a7 100644 --- a/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeUserController.java +++ b/linkwe-admin/src/main/java/com/linkwechat/web/controller/wecom/WeUserController.java @@ -6,217 +6,242 @@ import com.linkwechat.common.core.controller.BaseController; import com.linkwechat.common.core.domain.AjaxResult; import com.linkwechat.common.core.page.TableDataInfo; import com.linkwechat.common.enums.BusinessType; +import com.linkwechat.common.exception.CustomException; import com.linkwechat.wecom.domain.WeUser; -import com.linkwechat.wecom.domain.vo.WeAllocateCustomersVo; -import com.linkwechat.wecom.domain.vo.WeAllocateGroupsVo; -import com.linkwechat.wecom.domain.vo.WeLeaveUserInfoAllocateVo; -import com.linkwechat.wecom.domain.vo.WeLeaveUserVo; -import com.linkwechat.wecom.service.IWeCustomerService; +import com.linkwechat.wecom.domain.vo.*; import com.linkwechat.wecom.service.IWeUserService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; - import java.util.List; /** * 通讯录相关客户Controller - * + * * @author ruoyi * @date 2020-08-31 */ @RestController @RequestMapping("/wecom/user") -@Api("通讯录人员接口") +@Api(tags = "通讯录人员接口") +@Slf4j public class WeUserController extends BaseController { @Autowired private IWeUserService weUserService; - /** * 查询通讯录相关客户列表 */ - @PreAuthorize("@ss.hasPermi('contacts:organization:query')") + @Log(title = "查询通讯录相关客户列表", businessType = BusinessType.SELECT) @GetMapping("/list") - @ApiOperation("获取通讯录人员列表") - public TableDataInfo list(WeUser weUser) - { + @ApiOperation(value = "获取通讯录人员列表", httpMethod = "GET") + public TableDataInfo> list(WeUser weUser) { startPage(); + return getDataTable(weUserService.getList(weUser)); + } - List list = weUserService.selectWeUserList(weUser); - return getDataTable(list); + + /** + * 获取所有员工接口(不分页) + * @param weUser + * @return + */ + @GetMapping("/findAllWeUser") + public AjaxResult findAllWeUser(WeUser weUser){ + + return AjaxResult.success( + weUserService.getList(weUser) + ); } + /** * 获取通讯录相关客户详细信息 + * + * @return */ - @PreAuthorize("@ss.hasPermi('contacts:organization:view')") + @Log(title = "获取通讯录相关客户详细信息", businessType = BusinessType.SELECT) @GetMapping(value = "/{id}") - public AjaxResult getInfo(@PathVariable("id") Long id) - { - return AjaxResult.success(weUserService.selectWeUserById(id)); + @ApiOperation(value = "获取通讯录相关客户详细信息", httpMethod = "GET") + public AjaxResult getInfo(@PathVariable("id") Long id) { + return AjaxResult.success(weUserService.getById(id)); } /** * 新增通讯录相关客户 */ - @PreAuthorize("@ss.hasPermi('contacts:organization:addMember')") @Log(title = "通讯录相关客户", businessType = BusinessType.INSERT) @PostMapping @ApiOperation("新增通讯录客户") - public AjaxResult add(@Validated @RequestBody WeUser weUser) - { - weUserService.insertWeUser(weUser); + public AjaxResult add(@Validated @RequestBody WeUser weUser) { + weUserService.insert(weUser); return AjaxResult.success(); } /** * 修改通讯录相关客户 */ - @PreAuthorize("@ss.hasPermi('contacts:organization:edit')") @Log(title = "更新通讯录客户", businessType = BusinessType.UPDATE) @PutMapping @ApiOperation("更新通讯录客户") - public AjaxResult edit(@RequestBody WeUser weUser) - { - weUserService.updateWeUser(weUser); + public AjaxResult edit(@RequestBody WeUser weUser) { + weUserService.update(weUser); return AjaxResult.success(); } /** * 启用或者禁止 + * * @param weUser * @return */ - @PreAuthorize("@ss.hasPermi('contacts:organization:forbidden')") @Log(title = "启用禁用用户", businessType = BusinessType.UPDATE) @PutMapping("/startOrStop") @ApiOperation("是否启用(1表示启用成员,0表示禁用成员)") - public AjaxResult startOrStop(@RequestBody WeUser weUser){ - + public AjaxResult startOrStop(@RequestBody WeUser weUser) { weUserService.startOrStop(weUser); - return AjaxResult.success(); } /** * 离职已分配 + * * @param weLeaveUserVo * @return */ - @PreAuthorize("@ss.hasPermi('customerManage:dimission:filter')") - @GetMapping({"/leaveUserAllocateList"}) - public TableDataInfo leaveUserAllocateList(WeLeaveUserVo weLeaveUserVo) { - startPage(); - weLeaveUserVo.setIsActivate(WeConstans.WE_USER_IS_LEAVE); - weLeaveUserVo.setIsAllocate(WeConstans.LEAVE_ALLOCATE_STATE); - List list = this.weUserService.leaveAllocateUserList(weLeaveUserVo); - return getDataTable(list); - } + @ApiOperation("离职已分配") + @Log(title = "离职已分配", businessType = BusinessType.SELECT) + @GetMapping({"/leaveUserAllocateList"}) + public TableDataInfo> leaveUserAllocateList(WeLeaveUserVo weLeaveUserVo) { + startPage(); + weLeaveUserVo.setIsActivate(WeConstans.corpUserEnum.ACTIVE_STATE_FIVE.getKey()); + weLeaveUserVo.setIsAllocate(WeConstans.LEAVE_ALLOCATE_STATE); + List list = this.weUserService.leaveAllocateUserList(weLeaveUserVo); + return getDataTable(list); + } /** * 离职未分配 + * * @param weLeaveUserVo * @return */ - @PreAuthorize("@ss.hasPermi('customerManage:dimission:query')") - @GetMapping({"/leaveUserNoAllocateList"}) - public TableDataInfo leaveUserNoAllocateList(WeLeaveUserVo weLeaveUserVo) { + @ApiOperation("离职未分配") + @Log(title = "离职未分配", businessType = BusinessType.SELECT) + @GetMapping({"/leaveUserNoAllocateList"}) + public TableDataInfo> leaveUserNoAllocateList(WeLeaveUserVo weLeaveUserVo) { startPage(); - weLeaveUserVo.setIsActivate(WeConstans.WE_USER_IS_LEAVE); + weLeaveUserVo.setIsActivate(WeConstans.corpUserEnum.ACTIVE_STATE_FIVE.getKey()); weLeaveUserVo.setIsAllocate(WeConstans.LEAVE_NO_ALLOCATE_STATE); List list = weUserService.leaveNoAllocateUserList(weLeaveUserVo); return getDataTable(list); - } + } /** * 离职分配 + * * @param weLeaveUserInfoAllocateVo * @return */ - @PreAuthorize("@ss.hasPermi('customerManage:dimission:allocate')") - @PutMapping({"/allocateLeaveUserAboutData"}) - public AjaxResult allocateLeaveUserAboutData(@RequestBody WeLeaveUserInfoAllocateVo weLeaveUserInfoAllocateVo) { + @ApiOperation("离职分配") + @Log(title = "离职分配", businessType = BusinessType.UPDATE) + @PutMapping({"/allocateLeaveUserAboutData"}) + public AjaxResult allocateLeaveUserAboutData(@RequestBody WeLeaveUserInfoAllocateVo weLeaveUserInfoAllocateVo) { - weUserService.allocateLeaveUserAboutData(weLeaveUserInfoAllocateVo); + weUserService.allocateLeaveUserAboutData(weLeaveUserInfoAllocateVo); - return AjaxResult.success("离职分配成功"); + return AjaxResult.success("离职分配成功"); } /** - * 同步成员 + * 同步成员 + * * @return */ - @PreAuthorize("@ss.hasPermi('contacts:organization:sync')") + @ApiOperation("同步成员") + @Log(title = "同步成员", businessType = BusinessType.OTHER) @GetMapping({"/synchWeUser"}) - public AjaxResult synchWeUser(){ - - - weUserService.synchWeUser(); - - return AjaxResult.success(WeConstans.SYNCH_TIP); + public AjaxResult synchWeUser() { + try { + weUserService.synchWeUser(); + }catch (CustomException e){ + return AjaxResult.error(e.getMessage()); + } + + return AjaxResult.success(WeConstans.SYNCH_TIP); } - /** * 删除用户 + * * @return */ - @PreAuthorize("@ss.hasPermi('contacts:organization:removeMember')") + @ApiOperation("删除用户") + @Log(title = "删除用户", businessType = BusinessType.DELETE) @DeleteMapping({"/{ids}"}) - public AjaxResult deleteUser(@PathVariable String[] ids){ - - + public AjaxResult deleteUser(@PathVariable String[] ids) { weUserService.deleteUser(ids); - - return AjaxResult.success(); } /** * 获取历史分配记录的成员 + * * @param weAllocateCustomersVo * @return */ - @PreAuthorize("@ss.hasPermi('wecom:user:getAllocateCustomers')") + // @PreAuthorize("@ss.hasPermi('wecom:user:getAllocateCustomers')") + @ApiOperation("获取历史分配记录的成员") + @Log(title = "获取历史分配记录的成员", businessType = BusinessType.SELECT) @GetMapping({"/getAllocateCustomers"}) - public TableDataInfo getAllocateCustomers(WeAllocateCustomersVo weAllocateCustomersVo){ + public TableDataInfo> getAllocateCustomers(WeAllocateCustomersVo weAllocateCustomersVo) { startPage(); List list = weUserService.getAllocateCustomers(weAllocateCustomersVo); return getDataTable(list); } - /** * 获取历史分配记录的群 + * * @param weAllocateGroupsVo * @return */ - @PreAuthorize("@ss.hasPermi('wecom:user:getAllocateGroups')") + // @PreAuthorize("@ss.hasPermi('wecom:user:getAllocateGroups')") + @ApiOperation("获取历史分配记录的群") + @Log(title = "获取历史分配记录的群", businessType = BusinessType.SELECT) @GetMapping({"/getAllocateGroups"}) - public TableDataInfo getAllocateGroups(WeAllocateGroupsVo weAllocateGroupsVo){ + public TableDataInfo> getAllocateGroups(WeAllocateGroupsVo weAllocateGroupsVo) { startPage(); List list = weUserService.getAllocateGroups(weAllocateGroupsVo); return getDataTable(list); } - - - - + /** + * 内部应用获取用户userId + * + * @param code + * @return + */ + @Log(title = "内部应用获取用户userId", businessType = BusinessType.SELECT) + @ApiOperation("内部应用获取用户userId") + @GetMapping("/getUserInfo") + public AjaxResult getUserInfo(String code, String agentId) { + WeUserInfoVo userInfo = weUserService.getUserInfo(code, agentId); + return AjaxResult.success(userInfo); + } } diff --git a/linkwe-admin/src/main/java/com/linkwechat/web/controller/weixin/WxAuthController.java b/linkwe-admin/src/main/java/com/linkwechat/web/controller/weixin/WxAuthController.java new file mode 100644 index 0000000000000000000000000000000000000000..560bc67d1064fbecefe288fecfdba1b7ac4a1440 --- /dev/null +++ b/linkwe-admin/src/main/java/com/linkwechat/web/controller/weixin/WxAuthController.java @@ -0,0 +1,48 @@ +package com.linkwechat.web.controller.weixin; + +import com.linkwechat.common.core.domain.AjaxResult; +import com.linkwechat.web.controller.common.CommonController; +import com.linkwechat.wecom.domain.weixin.dto.WxAuthUserInfoDto; +import com.linkwechat.wecom.domain.weixin.dto.WxTokenDto; +import com.linkwechat.wecom.service.IWxAuthService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author danmo + * @description 微信授权controller + * @date 2021/4/5 18:37 + **/ +@Api("微信授权controller") +@Slf4j +@RestController +@RequestMapping("/weixin/auth") +public class WxAuthController extends CommonController { + + @Autowired + private IWxAuthService wxAuthService; + + /** + * 通过code获取网页授权token + */ + @ApiOperation(value = "通过code获取网页授权token",httpMethod = "GET") + @GetMapping("/getToken") + public AjaxResult getToken(@ApiParam(value = "URL上的code参数",required = true) String code, @ApiParam(value = "用户的唯一标识",required = false) String openId) { + return AjaxResult.success(wxAuthService.getToken(code,openId)); + } + + /** + * 拉取用户信息(需scope为 snsapi_userinfo) + */ + @ApiOperation(value = "拉取用户信息(需scope为 snsapi_userinfo)",httpMethod = "GET") + @GetMapping("/getUserInfo") + public AjaxResult getUserInfo(@ApiParam(value = "用户的唯一标识",required = true) String openId, @ApiParam(value = "语言版本",required = true) String lang) { + return AjaxResult.success(wxAuthService.getUserInfo(openId,lang)); + } +} diff --git a/linkwe-admin/src/main/java/com/linkwechat/web/core/config/ResponseAdvice.java b/linkwe-admin/src/main/java/com/linkwechat/web/core/config/ResponseAdvice.java new file mode 100644 index 0000000000000000000000000000000000000000..a7bc8432011ddff71c3f92140d01d76abd090cc4 --- /dev/null +++ b/linkwe-admin/src/main/java/com/linkwechat/web/core/config/ResponseAdvice.java @@ -0,0 +1,32 @@ +package com.linkwechat.web.core.config; + +import com.linkwechat.common.core.domain.AjaxResult; +import lombok.extern.slf4j.Slf4j; +import org.springframework.core.MethodParameter; +import org.springframework.http.MediaType; +import org.springframework.http.server.ServerHttpRequest; +import org.springframework.http.server.ServerHttpResponse; +import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice; + +import java.util.Objects; + +@RestControllerAdvice(basePackages = "com.linkwechat") +@Slf4j +public class ResponseAdvice implements ResponseBodyAdvice { + @Override + public boolean supports(MethodParameter methodParameter, Class aClass) { + return true; + } + + @Override + public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) { + if (Objects.isNull(o)) { + return AjaxResult.success().build(); + } + if (o instanceof AjaxResult) { + return ((AjaxResult) o).build(); + } + return o; + } +} \ No newline at end of file diff --git a/linkwe-admin/src/main/resources/application-druid.yml b/linkwe-admin/src/main/resources/application-druid.yml deleted file mode 100644 index 72b66ce449880e9ce6c4eecd87fd7f9a4ae63519..0000000000000000000000000000000000000000 --- a/linkwe-admin/src/main/resources/application-druid.yml +++ /dev/null @@ -1,57 +0,0 @@ -# 数据源配置 -spring: - datasource: - type: com.alibaba.druid.pool.DruidDataSource - driverClassName: com.mysql.cj.jdbc.Driver - druid: - # 主库数据源 - master: - url: jdbc:mysql://127.0.0.1:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 - username: root - password: 123456 - # 从库数据源 - slave: - # 从数据源开关/默认关闭 - enabled: false - url: - username: - password: - # 初始连接数 - initialSize: 5 - # 最小连接池数量 - minIdle: 10 - # 最大连接池数量 - maxActive: 20 - # 配置获取连接等待超时的时间 - maxWait: 60000 - # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 - timeBetweenEvictionRunsMillis: 60000 - # 配置一个连接在池中最小生存的时间,单位是毫秒 - minEvictableIdleTimeMillis: 300000 - # 配置一个连接在池中最大生存的时间,单位是毫秒 - maxEvictableIdleTimeMillis: 900000 - # 配置检测连接是否有效 - validationQuery: SELECT 1 FROM DUAL - testWhileIdle: true - testOnBorrow: false - testOnReturn: false - webStatFilter: - enabled: true - statViewServlet: - enabled: true - # 设置白名单,不填则允许所有访问 - allow: - url-pattern: /druid/* - # 控制台管理用户名和密码 - login-username: - login-password: - filter: - stat: - enabled: true - # 慢SQL记录 - log-slow-sql: true - slow-sql-millis: 1000 - merge-sql: true - wall: - config: - multi-statement-allow: true diff --git a/linkwe-admin/src/main/resources/application.yml b/linkwe-admin/src/main/resources/application.yml index 21d9b656237d93aae9aa7e9a1dddfa260f6e4e19..cfea601621ae140e718bd9260ca027e2170448f5 100644 --- a/linkwe-admin/src/main/resources/application.yml +++ b/linkwe-admin/src/main/resources/application.yml @@ -1,26 +1,75 @@ # 项目相关配置 ruoyi: # 名称 - name: RuoYi + name: LinkWeChat # 版本 version: 3.1.0 # 版权年份 - copyrightYear: 2019 + copyrightYear: 2021 + startTenant: false + editPwd: false # 实例演示开关 demoEnabled: true - # 文件路径 示例( Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath) - profile: D:/ruoyi/uploadPath + # 目前只支持腾讯云上传 + file: + startCosUpload: true + #腾讯云对象存储 + cos: + secretId: + secretKey: + region: + bucketName: + cosImgUrlPrefix: # 获取ip地址开关 - addressEnabled: false + addressEnabled: true # 验证码类型 math 数组计算 char 字符验证 captchaType: math # 企业微信用户首次登录系统默认密码 weUserDefaultPwd: 123456 + noSyncWeUser: + - 45DuXiangShangQingXie + #匿名访问的URL + anonUrl: + - /login + - /captchaImage + - /findWxQrLoginInfo + - /wxQrLogin + - /profile/** + - /common/download** + - /common/download/resource** + - /common/download/url** + - /swagger-ui.html + - /swagger-resources/** + - /webjars/** + - /*/api-docs + - /druid/** + - /wecom/callback/** + - /wecom/chat/item/list + - /wecom/chat/collection/list + - /wecom/chat/collection/cancleCollection + - /wecom/chat/collection/addCollection + - /wecom/chat/side/h5List + - /wecom/ticket/** + - /wecom/user/getUserInfo + - /wecom/portrait/** + - /wecom/fission/poster + - /wecom/fission/complete/** + - /wecom/fission/*/progress/* + - /wecom/reward/getRewardByFissionId/** + - /wecom/groupCode/getActualCode/** + - /wecom/community/h5/** + - /weixin/auth/** + - /wecom/material/temporaryMaterialMediaId + - /common/findFile + - /wecom/seas/findEmployeeCustomer + - /wecom/seas/setState + + # 开发环境配置 server: - # 服务器的HTTP端口,默认为8080 - port: 8080 + # 服务器的HTTP端口,默认为8090 + port: 8090 servlet: # 应用的访问路径 context-path: / @@ -34,25 +83,88 @@ server: # 日志配置 logging: - level: - com.ruoyi: debug - org.springframework: warn + path: + log: ./logs +#H5地址路径 +H5: + domainPrefix: http://demo.linkwechat.cn/ + url: http://h5.linkwechat.cn/index.html + fissionUrl: http://demo.linkwechat.cn/taskMobile/index.html?fissionId={}&fissionTargetId={}&posterId={} #任务宝 + fissionGroupUrl: http://demo.linkwechat.cn/taskMobile/fission.html?fissionId={}&recordId={} #群裂变 # Spring配置 spring: # 资源信息 messages: # 国际化资源文件路径 basename: i18n/messages - profiles: - active: druid + datasource: + type: com.alibaba.druid.pool.DruidDataSource + driver-class-name: com.p6spy.engine.spy.P6SpyDriver + druid: + # 主库数据源 + master: + url: jdbc:p6spy:mysql://127.0.0.1:10179/link-wechat-prod?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&rewriteBatchedStatements=true + username: root + password: root + # 从库数据源 + slave: + # 从数据源开关/默认关闭 + enabled: false + url: + username: + password: + # 初始连接数 + initialSize: 5 + # 最小连接池数量 + minIdle: 10 + # 最大连接池数量 + maxActive: 20 + # 配置获取连接等待超时的时间 + maxWait: 60000 + # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 + timeBetweenEvictionRunsMillis: 60000 + # 配置一个连接在池中最小生存的时间,单位是毫秒 + minEvictableIdleTimeMillis: 300000 + # 配置一个连接在池中最大生存的时间,单位是毫秒 + maxEvictableIdleTimeMillis: 900000 + # 配置检测连接是否有效 + validationQuery: SELECT 1 FROM DUAL + testWhileIdle: true + testOnBorrow: false + testOnReturn: false + webStatFilter: + enabled: true + statViewServlet: + enabled: true + # 设置白名单,不填则允许所有访问 + allow: + url-pattern: /druid/* + # 控制台管理用户名和密码 + login-username: + login-password: + filter: + stat: + enabled: true + # 慢SQL记录 + log-slow-sql: true + slow-sql-millis: 1000 + merge-sql: false + wall: + config: + multi-statement-allow: true # 文件上传 servlet: - multipart: - # 单个文件大小 - max-file-size: 10MB - # 设置总上传的文件大小 - max-request-size: 20MB + multipart: + # 单个文件大小 + max-file-size: 10MB + # 设置总上传的文件大小 + max-request-size: 20MB + task: + execution: + pool: + keep-alive: 10s + thread-name-prefix: common-pool- # 服务模块 devtools: restart: @@ -61,11 +173,11 @@ spring: # redis 配置 redis: # 地址 - host: localhost + host: 127.0.0.1 # 端口,默认为6379 port: 6379 # 密码 - password: + password: # 连接超时时间 timeout: 10s lettuce: @@ -78,38 +190,38 @@ spring: max-active: 8 # #连接池最大阻塞等待时间(使用负值表示没有限制) max-wait: -1ms + cluster: + refresh: + #自适应拓扑刷新 + adaptive: true + #定时拓扑刷新 + period: 10 + # token配置 token: - # 令牌自定义标识 - header: Authorization - # 令牌密钥 - secret: abcdefghijklmnopqrstuvwxyz - # 令牌有效期(默认30分钟) - expireTime: 30 + # 令牌自定义标识 + header: Authorization + # 令牌密钥 + secret: abcdefghijklmnopqrstuvwxyz + # 令牌有效期(默认30分钟) + expireTime: 600 mybatis-plus: - mapper-locations: classpath*:mapper/**/*Mapper.xml - type-aliases-package: com.linkwechat.**.domain - type-handlers-package: com.linkwechat.framework.handler.** - configuration: - log-impl: org.apache.ibatis.logging.stdout.StdOutImpl - -## MyBatis配置 -#mybatis: -# # 搜索指定包别名 -# typeAliasesPackage: com.linkwechat.**.domain -# # 配置mapper的扫描,找到所有的mapper.xml映射文件 -# mapperLocations: classpath*:mapper/**/*Mapper.xml -# # 加载全局的配置文件 -# configLocation: classpath:mybatis/mybatis-config.xml + mapper-locations: classpath*:mapper/**/*Mapper.xml + type-aliases-package: com.linkwechat.**.domain + type-handlers-package: com.linkwechat.framework.handler.GenericTypeHandler,com.linkwechat.framework.handler.StringArrayJoinTypeHandler + +mpp: + entityBasePath: com.linkwechat.**.domain + # PageHelper分页插件 -pagehelper: +pagehelper: helperDialect: mysql reasonable: true supportMethodsArguments: true - params: count=countSql + params: count=countSql # Swagger配置 swagger: @@ -119,7 +231,7 @@ swagger: pathMapping: # 防止XSS攻击 -xss: +xss: # 过滤开关 enabled: true # 排除链接(多个用逗号分隔) @@ -127,34 +239,32 @@ xss: # 匹配链接 urlPatterns: /system/*,/monitor/*,/tool/* + # forest配置 forest: - interceptors: com.linkwechat.wecom.interceptor.WeAccessTokenInterceptor backend: httpclient - + max-retry-count: 3 # 请求失败后重试次数,默认为0次不重试 + max-retry-interval: 1000 #重试间隔时间 + connect-timeout: 3000 #链接超时时间 + timeout: 3000 # 请求超时时间 + ## 日志总开关,打开/关闭Forest请求/响应日志(默认为 true) + log-enabled: true + ## 打开/关闭Forest请求日志(默认为 true) + log-request: true + ## 打开/关闭Forest响应状态日志(默认为 true) + log-response-status: true + ## 打开/关闭Forest响应内容日志(默认为 false) + log-response-content: true + variables: + weComServerUrl: https://qyapi.weixin.qq.com/ + weComePrefix: cgi-bin + wxServerUrl: https://api.weixin.qq.com/ + wxPrefix: sns wecome: - serverUrl: https://qyapi.weixin.qq.com/ - weComePrefix: cgi-bin - noAccessTokenUrl: - - /gettoken - - /service/get_provider_token - needContactTokenUrl: - - /externalcontact/get_follow_user_list - - /externalcontact/add_contact_way - - /externalcontact/add_corp_tag - - /externalcontact/get_corp_tag_list - - /externalcontact/del_corp_tag - - /externalcontact/edit_corp_tag - - /externalcontact/list - - /externalcontact/get - - /externalcontact/groupchat/list - - /externalcontact/groupchat/get - - /externalcontact/mark_tag - - /externalcontact/transfer - - /externalcontact/groupchat/transfer - - /externalcontact/get_unassigned_list - fileUplodUrl: /media/upload,/media/uploadimg - needProviderTokenUrl: - - /service/get_login_info + weNeedRetryErrorCodes: -1,42001,42009,40082,40014 + welcome-msg-default: "您好,欢迎关注LinkWechat,如果对您有帮助,麻烦在码云上帮我们点个star,谢谢!" +weixin: + appid: #公众号appid + secret: #公众号密钥 \ No newline at end of file diff --git a/linkwe-admin/src/main/resources/bootstrap.properties b/linkwe-admin/src/main/resources/bootstrap.properties new file mode 100644 index 0000000000000000000000000000000000000000..fc464b1ed62153f1c474920d58f4ae72520fd28a --- /dev/null +++ b/linkwe-admin/src/main/resources/bootstrap.properties @@ -0,0 +1,5 @@ +linkwechat.nacos.host= +linkwechat.nacos.port= +linkwechat.nacos.namespace= +linkwechat.nacos.username= +linkwechat.nacos.password= diff --git a/linkwe-admin/src/main/resources/logback.xml b/linkwe-admin/src/main/resources/logback.xml index 6f6bea288663dac644550f37224301fac2b692d9..c81093e229cd0c0f5b7c4c6cf8b53b40e78a1b09 100644 --- a/linkwe-admin/src/main/resources/logback.xml +++ b/linkwe-admin/src/main/resources/logback.xml @@ -1,7 +1,7 @@ - + @@ -14,11 +14,11 @@ - ${log.path}/sys-info.log + ${LOG_PATH}/sys-info.log - ${log.path}/sys-info.%d{yyyy-MM-dd}.log + ${LOG_PATH}/sys-info.%d{yyyy-MM-dd}.log 60 @@ -36,11 +36,11 @@ - ${log.path}/sys-error.log + ${LOG_PATH}/sys-error.log - ${log.path}/sys-error.%d{yyyy-MM-dd}.log + ${LOG_PATH}/sys-error.%d{yyyy-MM-dd}.log 60 @@ -59,10 +59,10 @@ - ${log.path}/sys-user.log + ${LOG_PATH}/sys-user.log - ${log.path}/sys-user.%d{yyyy-MM-dd}.log + ${LOG_PATH}/sys-user.%d{yyyy-MM-dd}.log 60 diff --git a/linkwe-admin/src/main/resources/mybatis/mybatis-config.xml b/linkwe-admin/src/main/resources/mybatis/mybatis-config.xml index 783df7ad0e8c31f73c14bd7f482bc1d8720ee663..6b653fef3e2cc89649a11187516a015dc83f3770 100644 --- a/linkwe-admin/src/main/resources/mybatis/mybatis-config.xml +++ b/linkwe-admin/src/main/resources/mybatis/mybatis-config.xml @@ -8,12 +8,14 @@ - + + + diff --git a/linkwe-admin/src/main/resources/spy.properties b/linkwe-admin/src/main/resources/spy.properties new file mode 100644 index 0000000000000000000000000000000000000000..993efa7fe2d90ba1deb4ab861b5448b2959001a9 --- /dev/null +++ b/linkwe-admin/src/main/resources/spy.properties @@ -0,0 +1,28 @@ +#3.2.1ʹ +modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory +#3.2.1ʹû߲ +#modulelist=com.p6spy.engine.logging.P6LogFactory,com.p6spy.engine.outage.P6OutageFactory +# Զ־ӡ +logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger +#־̨ +appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger +# ʹ־ϵͳ¼ sql +#appender=com.p6spy.engine.spy.appender.Slf4JLogger +# p6spy driver +deregisterdrivers=true +# ȡJDBC URLǰ׺ +useprefix=true +# ü¼ Log ,ȥĽerror,info,batch,debug,statement,commit,rollback,result,resultset. +excludecategories=info,debug,result,commit,resultset +# ڸʽ +dateformat=yyyy-MM-dd HH:mm:ss +# ʵɶ +#driverlist=org.h2.Driver +# ǷSQL¼ +outagedetection=true +# SQL¼׼ 2 +outagedetectioninterval=2 +#־ +filter=true +#sqlQRTZsql Ÿ +exclude=QRTZ,sys_oper_log \ No newline at end of file diff --git a/linkwe-common/pom.xml b/linkwe-common/pom.xml index 5a3af20d737e17f8632c4cdc284348705f081fee..07d8d05c77b64950e7534718c4144ae59905d1b9 100644 --- a/linkwe-common/pom.xml +++ b/linkwe-common/pom.xml @@ -39,12 +39,6 @@ com.github.pagehelper pagehelper-spring-boot-starter - - - org.mybatis.spring.boot - mybatis-spring-boot-starter - - @@ -69,6 +63,7 @@ com.alibaba fastjson + 1.2.56 @@ -101,6 +96,16 @@ jjwt + + io.vertx + vertx-core + + + + io.vertx + vertx-web-client + + org.springframework.boot @@ -127,7 +132,8 @@ com.dtflys.forest - spring-boot-starter-forest + forest-spring-boot-starter + 1.5.5 @@ -180,6 +186,12 @@ mybatis-plus-boot-starter + + p6spy + p6spy + 3.9.1 + + commons-beanutils @@ -192,8 +204,93 @@ cglib-nodep 3.2.4 + + com.thoughtworks.xstream + xstream + 1.4.11.1 + + + org.dom4j + dom4j + 2.1.3 + + + com.github.binarywang + weixin-java-cp + 4.1.0 + + + + + org.elasticsearch.client + elasticsearch-rest-high-level-client + 7.6.2 + + + org.elasticsearch.client + elasticsearch-rest-client + 7.6.2 + + + org.elasticsearch + elasticsearch + 7.6.2 + + + com.qcloud + cos_api + 5.6.24 + + + + + org.bouncycastle + bcprov-jdk15on + 1.68 + + + org.bouncycastle + bcpg-jdk15on + 1.68 + + + org.bouncycastle + bcpkix-jdk15on + 1.68 + + + + org.springframework.boot + spring-boot-starter-aop + + + + com.github.jsqlparser + jsqlparser + + + + org.springframework + spring-test + + + + + org + jaudiotagger + 2.0.1 + + + + + com.googlecode.mp4parser + isoparser + 1.1.22 + + + \ No newline at end of file diff --git a/linkwe-common/src/main/java/com/linkwechat/common/aop/CustomerTrajectoryAop.java b/linkwe-common/src/main/java/com/linkwechat/common/aop/CustomerTrajectoryAop.java new file mode 100644 index 0000000000000000000000000000000000000000..29557d8b5c1d3eb0d0ff0a14286e075f48a10378 --- /dev/null +++ b/linkwe-common/src/main/java/com/linkwechat/common/aop/CustomerTrajectoryAop.java @@ -0,0 +1,31 @@ +package com.linkwechat.common.aop; + +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.springframework.context.annotation.EnableAspectJAutoProxy; +import org.springframework.stereotype.Component; + +/** + * @description: 客户轨迹记录AOP + * @author: HaoN + * @create: 2021-05-02 22:51 + **/ +@Aspect +@Component +public class CustomerTrajectoryAop { + + @Pointcut("@annotation(com.linkwechat.wecom.annotation.CustomerTrajectoryRecord)") + public void customerTrajectoryPointCut(){} + + + /** + * 记录轨迹 + * @param joinPoint + */ + @Around("customerTrajectoryPointCut()") + public void customerTrajectoryRecord(ProceedingJoinPoint joinPoint){ + + } +} diff --git a/linkwe-common/src/main/java/com/linkwechat/common/config/CosConfig.java b/linkwe-common/src/main/java/com/linkwechat/common/config/CosConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..659fe217891e4ff07e634695fca5fe5d0b30a2cc --- /dev/null +++ b/linkwe-common/src/main/java/com/linkwechat/common/config/CosConfig.java @@ -0,0 +1,25 @@ +package com.linkwechat.common.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * @author Kewen + */ +@Component +//@ConfigurationProperties(prefix = "cos") +@Data +public class CosConfig { + + private String secretId; + + private String secretKey; + + private String region; + + private String bucketName; + + private String cosImgUrlPrefix; + +} diff --git a/linkwe-common/src/main/java/com/linkwechat/common/config/ElasticSearchConfig.java b/linkwe-common/src/main/java/com/linkwechat/common/config/ElasticSearchConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..d5778dc6a92f3bffe81ed99374636c663e07b994 --- /dev/null +++ b/linkwe-common/src/main/java/com/linkwechat/common/config/ElasticSearchConfig.java @@ -0,0 +1,122 @@ +package com.linkwechat.common.config;/* +package com.linkwechat.common.config; + +import org.apache.http.HttpHost; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.CredentialsProvider; +import org.apache.http.impl.client.BasicCredentialsProvider; +import org.elasticsearch.client.RestClient; +import org.elasticsearch.client.RestClientBuilder; +import org.elasticsearch.client.RestHighLevelClient; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import java.util.ArrayList; +import java.util.List; + +*/ +/** + * @author danmo + * @description ElasticSearch 配置 + * @date 2020/12/4 9:59 + **//* + + +@Configuration +public class ElasticSearchConfig { + */ +/** + * 协议 + *//* + + @Value("${elasticsearch.schema:http}") + private String schema; + + */ +/** + * 集群地址,如果有多个用“,”隔开 + *//* + + @Value("${elasticsearch.address}") + private String address; + + @Value("${elasticsearch.userName}") + private String userName; + + @Value("${elasticsearch.password}") + private String password; + */ +/** + * 连接超时时间 + *//* + + @Value("${elasticsearch.connectTimeout:5000}") + private int connectTimeout; + + */ +/** + * Socket 连接超时时间 + *//* + + @Value("${elasticsearch.socketTimeout:10000}") + private int socketTimeout; + + */ +/** + * 获取连接的超时时间 + *//* + + @Value("${elasticsearch.connectionRequestTimeout:5000}") + private int connectionRequestTimeout; + + */ +/** + * 最大连接数 + *//* + + @Value("${elasticsearch.maxConnectNum:100}") + private int maxConnectNum; + + */ +/** + * 最大路由连接数 + *//* + + @Value("${elasticsearch.maxConnectPerRoute:100}") + private int maxConnectPerRoute; + + @Bean + public RestHighLevelClient restHighLevelClient() { + // 拆分地址 + List hostLists = new ArrayList<>(); + String[] hostList = address.split(","); + for (String addr : hostList) { + String host = addr.split(":")[0]; + String port = addr.split(":")[1]; + hostLists.add(new HttpHost(host, Integer.parseInt(port), schema)); + } + final CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); + credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(userName, password)); + // 转换成 HttpHost 数组 + HttpHost[] httpHost = hostLists.toArray(new HttpHost[]{}); + // 构建连接对象 + RestClientBuilder builder = RestClient.builder(httpHost); + // 异步连接延时配置 + builder.setRequestConfigCallback(requestConfigBuilder -> { + requestConfigBuilder.setConnectTimeout(connectTimeout); + requestConfigBuilder.setSocketTimeout(socketTimeout); + requestConfigBuilder.setConnectionRequestTimeout(connectionRequestTimeout); + return requestConfigBuilder; + }); + // 异步连接数配置 + builder.setHttpClientConfigCallback(httpClientBuilder -> { + httpClientBuilder.setMaxConnTotal(maxConnectNum); + httpClientBuilder.setMaxConnPerRoute(maxConnectPerRoute); + httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider); + return httpClientBuilder; + }); + return new RestHighLevelClient(builder); + + } +}*/ diff --git a/linkwe-common/src/main/java/com/linkwechat/common/config/FileConfig.java b/linkwe-common/src/main/java/com/linkwechat/common/config/FileConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..0cec7438722de4d1f9001d52dff64d00f89f5bfe --- /dev/null +++ b/linkwe-common/src/main/java/com/linkwechat/common/config/FileConfig.java @@ -0,0 +1,14 @@ +package com.linkwechat.common.config; + +import lombok.Data; + +@Data +public class FileConfig { + + /**是否开启云存储*/ + private boolean startCosUpload=false; + /**腾讯云存储相关配置*/ + private CosConfig cos; + /**文件前缀*/ + private String imgUrlPrefix; +} diff --git a/linkwe-common/src/main/java/com/linkwechat/common/config/RuoYiConfig.java b/linkwe-common/src/main/java/com/linkwechat/common/config/RuoYiConfig.java index 480e09dc2c873867ccf1a482f87b8dfcf60510a4..eab01578b97bb0fab69ff73b67df1add75661e41 100644 --- a/linkwe-common/src/main/java/com/linkwechat/common/config/RuoYiConfig.java +++ b/linkwe-common/src/main/java/com/linkwechat/common/config/RuoYiConfig.java @@ -1,5 +1,6 @@ package com.linkwechat.common.config; +import com.linkwechat.common.utils.OsUtils; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; @@ -33,6 +34,26 @@ public class RuoYiConfig /** 企业微信账号登录系统默认密码 */ private static String weUserDefaultPwd="123456"; + + private FileConfig file; + + + /**是否开启多租户*/ + private boolean startTenant=false; + + + /**是否可以修改密码*/ + private boolean editPwd=true; + + + /**无需同步的用户*/ + private String[] noSyncWeUser; + + + + /**匿名访问的URL*/ + private String[] anonUrl; + public String getName() { return name; @@ -75,7 +96,11 @@ public class RuoYiConfig public static String getProfile() { - return profile; + if(OsUtils.isWindows()){ + return "D:/linkWeChat/uploadPath"; + + } + return "/Users/robin/work/sr_project/lw"; } public void setProfile(String profile) @@ -109,6 +134,14 @@ public class RuoYiConfig return getProfile() + "/download/"; } + /** + * 获取会话存档素材下载路径 + */ + public static String getDownloadWeWorkPath() + { + return getProfile() + "/download/media_data/{}/{}"; + } + /** * 获取上传路径 */ @@ -124,4 +157,45 @@ public class RuoYiConfig public void setWeUserDefaultPwd(String weUserDefaultPwd) { RuoYiConfig.weUserDefaultPwd = weUserDefaultPwd; } + + public String[] getAnonUrl() { + return anonUrl; + } + + public void setAnonUrl(String[] anonUrl) { + this.anonUrl = anonUrl; + } + + public FileConfig getFile() { + return file; + } + + public void setFile(FileConfig file) { + this.file = file; + } + + public boolean isStartTenant() { + return startTenant; + } + + public void setStartTenant(boolean startTenant) { + this.startTenant = startTenant; + } + + public boolean isEditPwd() { + return editPwd; + } + + public void setEditPwd(boolean editPwd) { + this.editPwd = editPwd; + } + + + public String[] getNoSyncWeUser() { + return noSyncWeUser; + } + + public void setNoSyncWeUser(String[] noSyncWeUser) { + this.noSyncWeUser = noSyncWeUser; + } } diff --git a/linkwe-common/src/main/java/com/linkwechat/common/config/WeComeConfig.java b/linkwe-common/src/main/java/com/linkwechat/common/config/WeComeConfig.java index 1cdc6fb9e88b09305bbcdc2d4be417a7f44ea361..5a848bba73a9069fae21cfdf38d13fdb5d728a7d 100644 --- a/linkwe-common/src/main/java/com/linkwechat/common/config/WeComeConfig.java +++ b/linkwe-common/src/main/java/com/linkwechat/common/config/WeComeConfig.java @@ -4,6 +4,8 @@ import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; +import java.util.List; + /** * @Author: Robin * @Description: 企业微信配置文件相关 @@ -30,4 +32,20 @@ public class WeComeConfig { /** 需要供应商token的url*/ private String[] needProviderTokenUrl; + + /** 会话存档所需token 的url */ + private String[] needChatTokenUrl; + + /** 第三方自建应用得url*/ + private String[] thirdAppUrl; + + /**多租户相关表*/ + private String[] needTenant=new String[]{}; + + /** + * 需要进行重试的企业微信请求错误码 + */ + private List weNeedRetryErrorCodes; + + } diff --git a/linkwe-common/src/main/java/com/linkwechat/common/constant/Constants.java b/linkwe-common/src/main/java/com/linkwechat/common/constant/Constants.java index 1c7d4f913cd8203969f5d211bc78497e5e2efa61..94ad4f0753f3662f1029b821b4fbfc327eb97167 100644 --- a/linkwe-common/src/main/java/com/linkwechat/common/constant/Constants.java +++ b/linkwe-common/src/main/java/com/linkwechat/common/constant/Constants.java @@ -151,9 +151,36 @@ public class Constants public static final String USER_TYPE_WECOME="11"; + /** 企业管理 */ + public static final String USER_TYOE_CORP_ADMIN="22"; + + /** 企业微信用户系统中默认用户 */ public static final String DEFAULT_WECOME_ROLE_KEY="WeCome"; + /** 企业微信用户系统中默认用户 */ + public static final String DEFAULT_WECOME_CORP_ADMIN="CROP_ADMIN_ROLE"; + + /**完成待办*/ + public static final String HANDLE_SUCCESS="3"; + + + + /** + * 正常状态(未删除) + */ + public static final Integer COMMON_STATE = 0; + + + /** + * 删除移除状态 + */ + public static final Integer DELETE_STATE = 1; + + + + + } diff --git a/linkwe-common/src/main/java/com/linkwechat/common/constant/GenConstants.java b/linkwe-common/src/main/java/com/linkwechat/common/constant/GenConstants.java index 06b031ff398e8a3c3486fd4d63c681fecfe6fe7d..03ef1137b79def9b1816c66ba86069b74a015299 100644 --- a/linkwe-common/src/main/java/com/linkwechat/common/constant/GenConstants.java +++ b/linkwe-common/src/main/java/com/linkwechat/common/constant/GenConstants.java @@ -13,6 +13,9 @@ public class GenConstants /** 树表(增删改查) */ public static final String TPL_TREE = "tree"; + /** 主子表(增删改查) */ + public static final String TPL_SUB = "sub"; + /** 树编码字段 */ public static final String TREE_CODE = "treeCode"; @@ -32,6 +35,8 @@ public class GenConstants public static final String[] COLUMNTYPE_STR = { "char", "varchar", "narchar", "varchar2", "tinytext", "text", "mediumtext", "longtext" }; + /** 数据库文本类型 */ + public static final String[] COLUMNTYPE_TEXT = { "tinytext", "text", "mediumtext", "longtext" }; /** 数据库时间类型 */ public static final String[] COLUMNTYPE_TIME = { "datetime", "time", "date", "timestamp" }; @@ -74,6 +79,15 @@ public class GenConstants /** 日期控件 */ public static final String HTML_DATETIME = "datetime"; + /** 图片上传控件 */ + public static final String HTML_IMAGE_UPLOAD = "imageUpload"; + + /** 文件上传控件 */ + public static final String HTML_FILE_UPLOAD = "fileUpload"; + + /** 富文本控件 */ + public static final String HTML_EDITOR = "editor"; + /** 字符串类型 */ public static final String TYPE_STRING = "String"; diff --git a/linkwe-common/src/main/java/com/linkwechat/common/constant/WeConstans.java b/linkwe-common/src/main/java/com/linkwechat/common/constant/WeConstans.java index 6f6259a50446a31489e78f9e7e65bbe63ab68742..1f95336b2013070002281a374a9c419e121ae26e 100644 --- a/linkwe-common/src/main/java/com/linkwechat/common/constant/WeConstans.java +++ b/linkwe-common/src/main/java/com/linkwechat/common/constant/WeConstans.java @@ -1,5 +1,11 @@ package com.linkwechat.common.constant; + +import lombok.Getter; + +import java.util.HashMap; +import java.util.Map; + /** * @description: 企业微信相关常量 * @author: HaoN @@ -7,12 +13,29 @@ package com.linkwechat.common.constant; **/ public class WeConstans { + /** + * 微信授权token + */ + public static final String WX_AUTH_ACCESS_TOKEN = "wx_auth_access_token"; + public static final String WX_AUTH_REFRESH_ACCESS_TOKEN = "wx_auth_refresh_access_token"; + + /** + * 微信通用token + */ + public static final String WX_ACCESS_TOKEN = "wx_access_token"; + /** * 企业微信相关token */ public static final String WE_COMMON_ACCESS_TOKEN = "we_common_access_token"; + /** + * 自建应用token + */ + public static final String WE_THIRD_APP_TOKEN = "we_third_app_token"; + + /** * 获取外部联系人相关 token */ @@ -22,7 +45,29 @@ public class WeConstans { /** * 供应商相关token */ - public static final String WE_PROVIDER_ACCESS_TOKEN = "we_provider_access_token"; + public static final String WE_PROVIDER_ACCESS_TOKEN = "we_provider_access_token"; + + /** + * 会话存档相关token + */ + public static final String WE_CHAT_ACCESS_TOKEN = "we_chat_access_token"; + + /** + * 应用相关token + */ + public static final String WE_AGENT_ACCESS_TOKEN = "we_agent_access_token"; + + + public static final String WE_EMPLE_CODE_KEY = "we_emple_code_key"; + + /** + * 活码前缀 + */ + public static final String WE_QR_CODE_PREFIX = "we_qr"; + /** + * 新客拉群 + */ + public static final String WE_QR_XKLQ_PREFIX = "we_xklq"; /** @@ -82,7 +127,7 @@ public class WeConstans { /** * 已离职 */ - public static final Integer WE_USER_IS_LEAVE = 6; + public static final Integer WE_USER_IS_LEAVE = 5; /** @@ -96,6 +141,16 @@ public class WeConstans { */ public static final Integer WE_ROOT_CATEGORY_ID = 0; + /** + * 实际群活码正在使用中 + */ + public static final Integer WE_GROUP_CODE_ENABLE = 0; + + /** + * 群活码已禁用/达到扫码次数上限 + */ + public static final Integer WE_GROUP_CODE_DISABLE = 2; + /** * 单人活码 @@ -126,6 +181,20 @@ public class WeConstans { */ public static final Integer QR_CODE_EMPLE_CODE_SCENE = 2; + /** + * 客户添加时无需经过确认自动成为好友,是 + */ + public static final Boolean IS_JOIN_CONFIR_MFRIENDS = true; + + /** + * 客户添加时无需经过确认自动成为好友,否 + */ + public static final Boolean NOT_IS_JOIN_CONFIR_MFRIENDS = false; + + /** + * 批量生成的单人码 活动场景 + */ + public static final String ONE_PERSON_CODE_GENERATED_BATCH = "批量生成的单人码"; /** * 微信接口相应端错误字段 @@ -170,5 +239,182 @@ public class WeConstans { public static final String COMMA = ","; + public static final String USER_ID = "userid"; + + public static final String CURSOR = "cursor"; + + public static final String CORPID = "CORP_ID"; + + /** + * 业务id类型1:组织机构id,2:成员id + */ + public static final Integer USE_SCOP_BUSINESSID_TYPE_USER = 2; + public static final Integer USE_SCOP_BUSINESSID_TYPE_ORG = 1; + public static final Integer USE_SCOP_BUSINESSID_TYPE_ALL = 3; + + /** + * 客户流失通知开关 0:关闭 1:开启 + */ + public static final String DEL_FOLLOW_USER_SWITCH_CLOSE = "0"; + public static final String DEL_FOLLOW_USER_SWITCH_OPEN = "1"; + + public static final String CONTACT_SEQ_KEY = "seq"; + + /** + * id类型 0:成员 1:客户,2:机器 + */ + public static final Integer ID_TYPE_USER = 0; + public static final Integer ID_TYPE_EX = 1; + public static final Integer ID_TYPE_MACHINE = 2; + + /** + * 一次拉取的消息条数,最大值1000条,超过1000条会返回错误 + */ + public static final long LIMIT = 1_000L; + + /** + * 敏感词过滤查询用户分片 + */ + public static final Integer SENSITIVE_USER_PIECE = 50; + + /** + * 任务裂变用户活码state前缀 + */ + public static final String FISSION_PREFIX = "fis-"; + + public static final String AppTicketKey = "ticket:AppGet"; + public static final String AgentTicketKey = "ticket:AgentGet"; + + public static final String corpAccountKey = "we:corpAccount:{}"; + + //性别,1表示男性,2表示女性 + //表示所在部门是否为上级,0-否,1-是,顺序与Department字段的部门逐一对应 + //激活状态:1=已激活 2=已禁用 4=未激活 已激活代表已激活企业微信或已关注微工作台(原企业号) 5=成员退出 + public static enum corpUserEnum { + + User_SEX_TYPE_MAN(1, "男性"), + User_SEX_TYPE_WEMAN(2, "女性"), + + IS_DEPARTMENT_SUPERIOR_YES(1, "是"), + IS_DEPARTMENT_SUPERIOR_NO(0, "否"), + + ACTIVE_STATE_ONE(1, "已激活"), + ACTIVE_STATE_TWO(2, "已禁用"), + ACTIVE_STATE_FOUR(4, "未激活"), + ACTIVE_STATE_FIVE(5, "成员退出"); + + private int key; + private String value; + + /** + * 构造方法 + * + * @param key + * @param value + */ + corpUserEnum(int key, String value) { + this.setKey(key); + this.setValue(value); + } + + public int getKey() { + return key; + } + + public void setKey(int key) { + this.key = key; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + } + + @Getter + public enum sendMessageStatusEnum { + NOT_SEND("0", "未发送"), + SEND("1", "已发送"), + NOT_FRIEND_SEND("2", "因客户不是好友导致发送失败"), + RECEIVE_OTHER_MESSAGE("3", "-因客户已经收到其他群发消息导致发送失败"), + ; + + private String status; + private String desc; + + /** + * 构造方法 + * + * @param status + * @param desc + */ + sendMessageStatusEnum(String status, String desc) { + this.status = status; + this.desc = desc; + } + } + + + //public static final String WECOM_FINANCE_INDEX = "finance"; + public static final String WECOM_FINANCE_INDEX = "finance_new"; + + public static final String WECOM_SENSITIVE_HIT_INDEX = "sensitive"; + + /** + * 开启会话存档成员列表 + **/ + public static final String weMsgAuditKey = "wecom_msg_audit:user:ids"; + + + /** + * 第三方应用ID,参数标实 + */ + public static final String THIRD_APP_PARAM_TIP = "agentId"; + + public static final String WECUSTOMERS_KEY = "weCustomer"; + + /** + * 发给客户 + */ + public static final String SEND_MESSAGE_CUSTOMER = "0"; + + /** + * 发给客户群 + */ + public static final String SEND_MESSAGE_GROUP = "1"; + + /** + * 消息范围 1 指定客户 + */ + public static final String SEND_MESSAGE_CUSTOMER_ALL = "0"; + + /** + * 消息范围 1 指定客户 + */ + public static final String SEND_MESSAGE_CUSTOMER_PART = "1"; + + /** + * 会话消息订阅的频道 + */ + public static final String CONVERSATION_MSG_CHANNEL = "CONVERSATION_MSG_CHANNEL"; + + + /** + * 群发消息任务key + */ + public static final String WEGROUPMSGTIMEDTASK_KEY = "weGroupMessageTimedTask"; + /** + * 群发消息任务开关 + */ + public static Boolean WEGROUPMSGTIMEDTASK_SWITCH = true; + + /** + * 老客标签建群企业群发消息模板 + */ + public static final String MSG_TEMPLATE = "你有一个新社群运营任务,请点击此链接查看详情"; } diff --git a/linkwe-common/src/main/java/com/linkwechat/common/core/controller/BaseController.java b/linkwe-common/src/main/java/com/linkwechat/common/core/controller/BaseController.java index a741e2a421d8ca0bc03eb8355967f1275b98147a..7ce09032b927c10d4b75f3fd87ea4fb2e2619d2b 100644 --- a/linkwe-common/src/main/java/com/linkwechat/common/core/controller/BaseController.java +++ b/linkwe-common/src/main/java/com/linkwechat/common/core/controller/BaseController.java @@ -64,7 +64,7 @@ public class BaseController * 响应请求分页数据 */ @SuppressWarnings({ "rawtypes", "unchecked" }) - protected TableDataInfo getDataTable(List list) + protected TableDataInfo getDataTable(List list) { TableDataInfo rspData = new TableDataInfo(); rspData.setCode(HttpStatus.SUCCESS); @@ -74,6 +74,22 @@ public class BaseController return rspData; } + + + /** + * 响应请求分页数据 + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + protected TableDataInfo getDataTable(PageInfo pageInfo) + { + TableDataInfo rspData = new TableDataInfo(); + rspData.setCode(HttpStatus.SUCCESS); + rspData.setMsg("查询成功"); + rspData.setRows(pageInfo.getList()); + rspData.setTotal(pageInfo.getTotal()); + return rspData; + } + /** * 响应返回结果 * diff --git a/linkwe-common/src/main/java/com/linkwechat/common/core/domain/AjaxResult.java b/linkwe-common/src/main/java/com/linkwechat/common/core/domain/AjaxResult.java index bbb2dcd6e07bc94f16cc34e44eaf8e3879e8f499..9c3e0224ca37d45b406707ad85c578e6719e0e3a 100644 --- a/linkwe-common/src/main/java/com/linkwechat/common/core/domain/AjaxResult.java +++ b/linkwe-common/src/main/java/com/linkwechat/common/core/domain/AjaxResult.java @@ -1,149 +1,177 @@ package com.linkwechat.common.core.domain; -import java.util.HashMap; - -import com.linkwechat.common.utils.StringUtils; +import com.alibaba.fastjson.JSONObject; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.linkwechat.common.constant.HttpStatus; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Optional; /** * 操作消息提醒 - * + * * @author ruoyi */ -public class AjaxResult extends HashMap -{ - private static final long serialVersionUID = 1L; +@ApiModel +@Data +public class AjaxResult implements Serializable { + + private static final long serialVersionUID = 7337293201809451832L; + + @JsonIgnore + private HashMap map; - /** 状态码 */ + /** + * 状态码 + */ public static final String CODE_TAG = "code"; - /** 返回内容 */ + @ApiModelProperty("状态码") + private int code; + + /** + * 返回内容 + */ public static final String MSG_TAG = "msg"; - /** 数据对象 */ + @ApiModelProperty("返回内容") + private String msg; + + /** + * 数据对象 + */ public static final String DATA_TAG = "data"; + @ApiModelProperty("数据对象") + private T data; + /** * 初始化一个新创建的 AjaxResult 对象,使其表示一个空消息。 */ - public AjaxResult() - { + public AjaxResult() { + this.map = new HashMap<>(); } /** * 初始化一个新创建的 AjaxResult 对象 - * + * * @param code 状态码 - * @param msg 返回内容 + * @param msg 返回内容 */ - public AjaxResult(int code, String msg) - { - super.put(CODE_TAG, code); - super.put(MSG_TAG, msg); + public AjaxResult(int code, String msg) { + this(); + this.code = code; + this.msg = msg; } /** * 初始化一个新创建的 AjaxResult 对象 - * + * * @param code 状态码 - * @param msg 返回内容 + * @param msg 返回内容 * @param data 数据对象 */ - public AjaxResult(int code, String msg, Object data) - { - super.put(CODE_TAG, code); - super.put(MSG_TAG, msg); - if (StringUtils.isNotNull(data)) - { - super.put(DATA_TAG, data); - } + public AjaxResult(int code, String msg, T data) { + this(); + this.code = code; + this.msg = msg; + this.data = data; } /** * 返回成功消息 - * + * * @return 成功消息 */ - public static AjaxResult success() - { + public static AjaxResult success() { return AjaxResult.success("操作成功"); } /** * 返回成功数据 - * + * * @return 成功消息 */ - public static AjaxResult success(Object data) - { + public static AjaxResult success(T data) { return AjaxResult.success("操作成功", data); } /** * 返回成功消息 - * + * * @param msg 返回内容 * @return 成功消息 */ - public static AjaxResult success(String msg) - { + public static AjaxResult success(String msg) { return AjaxResult.success(msg, null); } /** * 返回成功消息 - * - * @param msg 返回内容 + * + * @param msg 返回内容 * @param data 数据对象 * @return 成功消息 */ - public static AjaxResult success(String msg, Object data) - { - return new AjaxResult(HttpStatus.SUCCESS, msg, data); + public static AjaxResult success(String msg, T data) { + return (AjaxResult) new AjaxResult(HttpStatus.SUCCESS, msg, data); } /** * 返回错误消息 - * + * * @return */ - public static AjaxResult error() - { + public static AjaxResult error() { return AjaxResult.error("操作失败"); } /** * 返回错误消息 - * + * * @param msg 返回内容 * @return 警告消息 */ - public static AjaxResult error(String msg) - { + public static AjaxResult error(String msg) { return AjaxResult.error(msg, null); } /** * 返回错误消息 - * - * @param msg 返回内容 + * + * @param msg 返回内容 * @param data 数据对象 * @return 警告消息 */ - public static AjaxResult error(String msg, Object data) - { + public static AjaxResult error(String msg, Object data) { return new AjaxResult(HttpStatus.ERROR, msg, data); } /** * 返回错误消息 - * + * * @param code 状态码 - * @param msg 返回内容 + * @param msg 返回内容 * @return 警告消息 */ - public static AjaxResult error(int code, String msg) - { + public static AjaxResult error(int code, String msg) { return new AjaxResult(code, msg, null); } + + public void put(String key, Object value) { + this.map.put(key, value); + } + + public JSONObject build() { + JSONObject json = new JSONObject(); + json.put("code", getCode()); + json.put("msg", getMsg()); + json.put("data", getData()); + Optional.ofNullable(getMap()).ifPresent(m -> m.forEach(json::put)); + return json; + } } diff --git a/linkwe-common/src/main/java/com/linkwechat/common/core/domain/BaseEntity.java b/linkwe-common/src/main/java/com/linkwechat/common/core/domain/BaseEntity.java index 9fcefd7c73223c458c983dd420ac1783a6b21b3e..3a5ddbaf352298a1fa9dc034a2414f4111679377 100644 --- a/linkwe-common/src/main/java/com/linkwechat/common/core/domain/BaseEntity.java +++ b/linkwe-common/src/main/java/com/linkwechat/common/core/domain/BaseEntity.java @@ -5,11 +5,19 @@ import java.util.Date; import java.util.HashMap; import java.util.Map; +import com.baomidou.mybatisplus.annotation.FieldFill; import com.baomidou.mybatisplus.annotation.TableField; import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonIgnore; import com.linkwechat.common.utils.DateUtils; import com.linkwechat.common.utils.SecurityUtils; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.experimental.SuperBuilder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; import springfox.documentation.annotations.ApiIgnore; /** @@ -17,41 +25,69 @@ import springfox.documentation.annotations.ApiIgnore; * * @author ruoyi */ +@ApiModel +@Data +@SuperBuilder +@AllArgsConstructor +@NoArgsConstructor public class BaseEntity implements Serializable { private static final long serialVersionUID = 1L; /** 搜索值 */ + @TableField(exist = false) + @ApiModelProperty(hidden = true) private String searchValue; /** 创建者 */ + @ApiModelProperty(hidden = true) + @TableField(fill = FieldFill.INSERT) private String createBy; /** 创建时间 */ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") - private Date createTime=new Date(); + @ApiModelProperty(hidden = true) + @TableField(fill = FieldFill.INSERT) + private Date createTime; /** 更新者 */ + @ApiModelProperty(hidden = true) + @TableField(fill = FieldFill.INSERT_UPDATE) private String updateBy; /** 更新时间 */ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") - private Date updateTime=new Date(); + @ApiModelProperty(hidden = true) + @TableField(fill = FieldFill.INSERT_UPDATE) + private Date updateTime; /** 备注 */ + @TableField(exist = false) + @ApiModelProperty(hidden = true) private String remark; /** 开始时间 */ @JsonIgnore + @TableField(exist = false) + @ApiModelProperty(hidden = true) private String beginTime; /** 结束时间 */ @JsonIgnore + @TableField(exist = false) + @ApiModelProperty(hidden = true) private String endTime; /** 请求参数 */ + @TableField(exist = false) + @ApiModelProperty(hidden = true) private Map params; + + + + + public String getSearchValue() { return searchValue; @@ -150,4 +186,5 @@ public class BaseEntity implements Serializable { this.params = params; } + } diff --git a/linkwe-common/src/main/java/com/linkwechat/common/core/domain/ConversationArchiveQuery.java b/linkwe-common/src/main/java/com/linkwechat/common/core/domain/ConversationArchiveQuery.java new file mode 100644 index 0000000000000000000000000000000000000000..d2b51eebc6fc1096b308a9ebd238fe619592d4e0 --- /dev/null +++ b/linkwe-common/src/main/java/com/linkwechat/common/core/domain/ConversationArchiveQuery.java @@ -0,0 +1,46 @@ +package com.linkwechat.common.core.domain; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * @author danmo + * @description 会话存档接口入参实体 + * @date 2020/12/29 14:23 + **/ +@ApiModel +@Data +public class ConversationArchiveQuery extends BaseEntity { + /** 发送人Id */ + @ApiModelProperty("发送人Id") + private String fromId=""; + + /** 成员名称 */ + @ApiModelProperty("成员名称") + private String userName=""; + + /** 接收人Id */ + @ApiModelProperty("接收人Id") + private String receiveId=""; + + /** 客户姓名 */ + @ApiModelProperty("客户姓名") + private String customerName=""; + + /** 群聊Id */ + @ApiModelProperty("群聊Id") + private String roomId=""; + + /** 消息类型(同企微api文档消息类型) */ + @ApiModelProperty("消息类型(同企微api文档消息类型)") + private String msgType=""; + + /** 关键词 **/ + @ApiModelProperty("关键词") + private String keyWord=""; + + /** 消息动作 */ + @ApiModelProperty("消息动作") + private String action=""; +} diff --git a/linkwe-common/src/main/java/com/linkwechat/common/core/domain/FileVo.java b/linkwe-common/src/main/java/com/linkwechat/common/core/domain/FileVo.java new file mode 100644 index 0000000000000000000000000000000000000000..2f540398d6e006043f085147c248ad1753ef40d3 --- /dev/null +++ b/linkwe-common/src/main/java/com/linkwechat/common/core/domain/FileVo.java @@ -0,0 +1,17 @@ +package com.linkwechat.common.core.domain; + +import lombok.experimental.SuperBuilder; +import lombok.Data; +import lombok.experimental.SuperBuilder; + +/** + * @description: + * @author: HaoN + * @create: 2021-07-13 15:25 + **/ +@Data +@SuperBuilder +public class FileVo { + private String fileName; + private String url; +} diff --git a/linkwe-common/src/main/java/com/linkwechat/common/core/domain/Tree.java b/linkwe-common/src/main/java/com/linkwechat/common/core/domain/Tree.java index 2366bbaa8694340b49ba8ae04a33e0d3a6d71655..38badd111a13c23de2b7aebcc3279fbf6fbc746d 100644 --- a/linkwe-common/src/main/java/com/linkwechat/common/core/domain/Tree.java +++ b/linkwe-common/src/main/java/com/linkwechat/common/core/domain/Tree.java @@ -1,12 +1,14 @@ package com.linkwechat.common.core.domain; import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.util.ArrayList; import java.util.List; +@ApiModel @Data public class Tree { @@ -17,7 +19,13 @@ public class Tree { * 名称 */ @ApiModelProperty(name = "label", value = "名称") - private String label; + private String name; + + /** + * 名称 + */ + @ApiModelProperty("可删除标识 0 可删除 1 不可删除") + private Integer flag; /** * 父的叶子信息 diff --git a/linkwe-common/src/main/java/com/linkwechat/common/core/domain/elastic/ElasticSearchDataVo.java b/linkwe-common/src/main/java/com/linkwechat/common/core/domain/elastic/ElasticSearchDataVo.java new file mode 100644 index 0000000000000000000000000000000000000000..62eab96c7b93a3c1558d93dc08da1e40c2a54787 --- /dev/null +++ b/linkwe-common/src/main/java/com/linkwechat/common/core/domain/elastic/ElasticSearchDataVo.java @@ -0,0 +1,26 @@ +package com.linkwechat.common.core.domain.elastic; + +import com.linkwechat.common.core.domain.elastic.ElasticSearchEntity; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author danmo + * @description http交互Vo对象 + * @date 2020/12/9 14:14 + **/ + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class ElasticSearchDataVo { + /** + * 索引名 + */ + private String idxName; + /** + * 数据存储对象 + */ + private ElasticSearchEntity elasticSearchEntity; +} diff --git a/linkwe-common/src/main/java/com/linkwechat/common/core/domain/elastic/ElasticSearchEntity.java b/linkwe-common/src/main/java/com/linkwechat/common/core/domain/elastic/ElasticSearchEntity.java new file mode 100644 index 0000000000000000000000000000000000000000..a62bd908958e030456921651cb92fbf563a6c3b8 --- /dev/null +++ b/linkwe-common/src/main/java/com/linkwechat/common/core/domain/elastic/ElasticSearchEntity.java @@ -0,0 +1,27 @@ +package com.linkwechat.common.core.domain.elastic; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Map; + +/** + * @author danmo + * @description + * @date 2020/12/9 14:11 + **/ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class ElasticSearchEntity { + /** + * 主键标识,用户ES持久化 + */ + private String id; + + /** + * JSON对象,实际存储数据 + */ + private Map data; +} diff --git a/linkwe-common/src/main/java/com/linkwechat/common/core/domain/elastic/ElasticSearchQueryVo.java b/linkwe-common/src/main/java/com/linkwechat/common/core/domain/elastic/ElasticSearchQueryVo.java new file mode 100644 index 0000000000000000000000000000000000000000..959b4f28eeed6b3d7b413f5202caeabcdade50af --- /dev/null +++ b/linkwe-common/src/main/java/com/linkwechat/common/core/domain/elastic/ElasticSearchQueryVo.java @@ -0,0 +1,30 @@ +package com.linkwechat.common.core.domain.elastic; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Map; + +/** + * @author danmo + * @description + * @date 2020/12/9 14:18 + **/ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class ElasticSearchQueryVo { + /** + * 索引名 + */ + private String idxName; + /** + * 需要反射的实体类型,用于对查询结果的封装 + */ + private String className; + /** + * 具体条件 + */ + private Map> query; +} diff --git a/linkwe-common/src/main/java/com/linkwechat/common/core/domain/entity/SysDept.java b/linkwe-common/src/main/java/com/linkwechat/common/core/domain/entity/SysDept.java index 6f168b1a0bf846662f991d8a71779deba58c3e54..4c3e37df6c8693042724f94237402743414c5df3 100644 --- a/linkwe-common/src/main/java/com/linkwechat/common/core/domain/entity/SysDept.java +++ b/linkwe-common/src/main/java/com/linkwechat/common/core/domain/entity/SysDept.java @@ -5,6 +5,10 @@ import java.util.List; import javax.validation.constraints.Email; import javax.validation.constraints.NotBlank; import javax.validation.constraints.Size; + +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; import com.linkwechat.common.core.domain.BaseEntity; @@ -14,6 +18,9 @@ import com.linkwechat.common.core.domain.BaseEntity; * * @author ruoyi */ +@SuperBuilder +@AllArgsConstructor +@NoArgsConstructor public class SysDept extends BaseEntity { private static final long serialVersionUID = 1L; diff --git a/linkwe-common/src/main/java/com/linkwechat/common/core/domain/entity/SysRole.java b/linkwe-common/src/main/java/com/linkwechat/common/core/domain/entity/SysRole.java index bfe6c4aaffa4025fabe77fa6c180c5fe981008bd..b3d35055d20388225fd84cce5e144e86d5fbec0e 100644 --- a/linkwe-common/src/main/java/com/linkwechat/common/core/domain/entity/SysRole.java +++ b/linkwe-common/src/main/java/com/linkwechat/common/core/domain/entity/SysRole.java @@ -4,7 +4,7 @@ import com.linkwechat.common.annotation.Excel; import com.linkwechat.common.annotation.Excel.ColumnType; import com.linkwechat.common.core.domain.BaseEntity; import lombok.AllArgsConstructor; -import lombok.Builder; +import lombok.experimental.SuperBuilder; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; @@ -16,7 +16,7 @@ import javax.validation.constraints.Size; * * @author ruoyi */ -@Builder +@SuperBuilder @AllArgsConstructor public class SysRole extends BaseEntity { diff --git a/linkwe-common/src/main/java/com/linkwechat/common/core/domain/entity/SysUser.java b/linkwe-common/src/main/java/com/linkwechat/common/core/domain/entity/SysUser.java index b67cfce9a6616f66d7274a2bdc4749f68afa89de..86bb353a22ec7ea7070bf004a5512a5e42461108 100644 --- a/linkwe-common/src/main/java/com/linkwechat/common/core/domain/entity/SysUser.java +++ b/linkwe-common/src/main/java/com/linkwechat/common/core/domain/entity/SysUser.java @@ -8,7 +8,7 @@ import com.linkwechat.common.annotation.Excel.Type; import com.linkwechat.common.annotation.Excels; import com.linkwechat.common.core.domain.BaseEntity; import lombok.AllArgsConstructor; -import lombok.Builder; +import lombok.experimental.SuperBuilder; import lombok.Data; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; @@ -25,7 +25,7 @@ import java.util.List; * @author ruoyi */ @Data -@Builder +@SuperBuilder @AllArgsConstructor public class SysUser extends BaseEntity { @@ -50,6 +50,9 @@ public class SysUser extends BaseEntity /** 用户类型(00系统用户)(11:企业微信用户) */ private String userType; + /**当前微信用户对应微信端的id*/ + private String weUserId; + /** 用户邮箱 */ @Excel(name = "用户邮箱") private String email; @@ -105,6 +108,12 @@ public class SysUser extends BaseEntity /** 是否具有有效得cropId */ private boolean validCropId=false; + + private String companyName; + + + private WeCorpAccount weCorpAccount; + public SysUser() { @@ -313,6 +322,15 @@ public class SysUser extends BaseEntity this.postIds = postIds; } + + public String getCompanyName() { + return companyName; + } + + public void setCompanyName(String companyName) { + this.companyName = companyName; + } + @Override public String toString() { return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) diff --git a/linkwe-common/src/main/java/com/linkwechat/common/core/domain/entity/WeCorpAccount.java b/linkwe-common/src/main/java/com/linkwechat/common/core/domain/entity/WeCorpAccount.java new file mode 100644 index 0000000000000000000000000000000000000000..c6c88bccb59b8062859861398391f80f4885dabe --- /dev/null +++ b/linkwe-common/src/main/java/com/linkwechat/common/core/domain/entity/WeCorpAccount.java @@ -0,0 +1,165 @@ +package com.linkwechat.common.core.domain.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.linkwechat.common.constant.Constants; +import com.linkwechat.common.core.domain.BaseEntity; +import com.linkwechat.common.utils.SnowFlakeUtil; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.experimental.SuperBuilder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotBlank; + +/** + * 企业id相关配置对象 wx_corp_account + * + * @author ruoyi + * @date 2020-08-24 + */ +@Data +@SuperBuilder +@AllArgsConstructor +@NoArgsConstructor +@TableName("we_corp_account") +public class WeCorpAccount extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** $column.columnComment */ + @TableId + private Long id; + + /*********************************************** + *******************企业配置start**************** + **********************************************/ + + /** 企业ID */ + @NotBlank(message = "企业ID不能为空") + private String corpId; + + + /** 企业名称 */ + @NotBlank(message = "企业名称不能为空") + private String companyName; + + /*********************************************** + *******************企业配置end**************** + **********************************************/ + + + + /*********************************************** + *******************通讯录配置start************** + **********************************************/ + + /** 通讯录Secret */ + @NotBlank(message = "通讯录Secret不可为空") + private String corpSecret; + + /*********************************************** + *******************通讯录配置end**************** + **********************************************/ + + + + /*********************************************** + *******************客户联系配置start************* + **********************************************/ + + + @NotBlank(message = "客户联系Secret不可为空") + private String contactSecret; + + + /*********************************************** + *******************客户联系配置end*************** + **********************************************/ + + + + /*********************************************** + *******************应用配置start**************** + **********************************************/ + /**消息应用ID*/ + @NotBlank(message = "消息应用ID不可为空") + private String agentId; + + /**消息应用Secret*/ + @NotBlank(message = "消息应用Secret不可为空") + private String agentSecret; + + + /**会话私钥Secret*/ + private String chatSecret; + + + /**会话存档密钥*/ + private String financePrivateKey; + + /*********************************************** + *******************应用配置end**************** + **********************************************/ + + + /*********************************************** + *******************接收事件服务器start*********** + **********************************************/ + + /**回调url*/ + //private String backOffUrl; + + /**回调token*/ + private String token; + + /**回调EncodingAESKey*/ + private String encodingAesKey; + + + /*********************************************** + *******************接收事件服务器end************* + **********************************************/ + + + /*********************************************** + *******************H5跳转start****************** + **********************************************/ + + /**JS SDK 身份校验url*/ + private String authorizeUrl; + + + /**群sop和老客标签建群,跳转链接*/ + private String sopTagRedirectUrl; + + + /**客户公海,跳转链接*/ + private String seasRedirectUrl; + + + + /*********************************************** + *******************H5跳转end******************* + **********************************************/ + + + + /**客服密钥*/ + private String kfSecret; + + /** 删除标志(0代表存在 1代表删除) */ + private Integer delFlag; + + + /**客户流失通知开关 0:关闭 1:开启*/ + private String customerChurnNoticeSwitch = Constants.NORMAL_CODE; + + + + + + +} diff --git a/linkwe-common/src/main/java/com/linkwechat/common/core/elasticsearch/ElasticSearch.java b/linkwe-common/src/main/java/com/linkwechat/common/core/elasticsearch/ElasticSearch.java new file mode 100644 index 0000000000000000000000000000000000000000..c9dac0b52bfbeacdd1b89192e15b138aa95dd01b --- /dev/null +++ b/linkwe-common/src/main/java/com/linkwechat/common/core/elasticsearch/ElasticSearch.java @@ -0,0 +1,461 @@ +package com.linkwechat.common.core.elasticsearch; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.github.pagehelper.PageInfo; +import com.linkwechat.common.core.domain.elastic.ElasticSearchEntity; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; +import org.elasticsearch.action.bulk.BulkRequest; +import org.elasticsearch.action.delete.DeleteRequest; +import org.elasticsearch.action.index.IndexRequest; +import org.elasticsearch.action.search.SearchRequest; +import org.elasticsearch.action.search.SearchResponse; +import org.elasticsearch.action.support.IndicesOptions; +import org.elasticsearch.action.update.UpdateRequest; +import org.elasticsearch.client.RequestOptions; +import org.elasticsearch.client.RestHighLevelClient; +import org.elasticsearch.client.indices.CreateIndexRequest; +import org.elasticsearch.client.indices.CreateIndexResponse; +import org.elasticsearch.client.indices.GetIndexRequest; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.text.Text; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentFactory; +import org.elasticsearch.common.xcontent.XContentType; +import org.elasticsearch.index.query.QueryBuilder; +import org.elasticsearch.index.reindex.DeleteByQueryRequest; +import org.elasticsearch.search.SearchHit; +import org.elasticsearch.search.builder.SearchSourceBuilder; +import org.elasticsearch.search.fetch.subphase.highlight.HighlightField; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.function.BiConsumer; +import java.util.function.Consumer; + +/** + * @author danmo + * @description es工具类 + * @date 2020/12/9 14:02 + **/ +@Slf4j +@Component +public class ElasticSearch { + + @Autowired + private RestHighLevelClient restHighLevelClient; + + /** + * @param idxName 索引名称 + * @param idxSQL 索引描述 + * @return void + * @throws + * @author danmo + * @See + * @date 2019/10/17 17:30 + * @since + */ + public void createIndex(String idxName, String idxSQL) { + try { + if (!this.indexExist(idxName)) { + //log.error(" idxName={} 已经存在,idxSql={}", idxName, idxSQL); + return; + } + CreateIndexRequest request = new CreateIndexRequest(idxName); + buildSetting(request); + request.mapping(idxSQL, XContentType.JSON); +// request.settings() 手工指定Setting + CreateIndexResponse res = restHighLevelClient.indices().create(request, RequestOptions.DEFAULT); + if (!res.isAcknowledged()) { + throw new RuntimeException("初始化失败"); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * @param idxName 索引名称 + * @param builder 索引描述 + * @return void + * @throws + * @author danmo + * @See + * @date 2019/10/17 17:30 + * @since + */ + public void createIndex2(String idxName, XContentBuilder builder) { + try { + if (!this.indexExist(idxName)) { + //log.error(" idxName={} 已经存在,idxSql={}", idxName, builder); + return; + } + CreateIndexRequest request = new CreateIndexRequest(idxName); + GetIndexRequest getIndexRequest = new GetIndexRequest(idxName); + buildSetting(request); + request.mapping(builder); +// request.settings() 手工指定Setting + boolean exists = restHighLevelClient.indices().exists(getIndexRequest, RequestOptions.DEFAULT); + if (!exists) { + CreateIndexResponse res = restHighLevelClient.indices().create(request, RequestOptions.DEFAULT); + if (!res.isAcknowledged()) { + log.info("初始化失败"); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 断某个index是否存在 + * + * @param idxName index名 + * @return boolean + * @throws + * @author danmo + * @See + * @date 2019/10/17 17:27 + * @since + */ + public boolean indexExist(String idxName) throws Exception { + GetIndexRequest request = new GetIndexRequest(idxName); + request.local(false); + request.humanReadable(true); + request.includeDefaults(false); + request.indicesOptions(IndicesOptions.lenientExpandOpen()); + return restHighLevelClient.indices().exists(request, RequestOptions.DEFAULT); + } + + /** + * 断某个index是否存在 + * + * @param idxName index名 + * @return boolean + * @throws + * @author danmo + * @See + * @date 2019/10/17 17:27 + * @since + */ + public boolean isExistsIndex(String idxName) throws Exception { + return restHighLevelClient.indices().exists(new GetIndexRequest(idxName), RequestOptions.DEFAULT); + } + + /** + * 设置分片 + * + * @param request + * @return void + * @throws + * @author danmo + * @See + * @date 2019/10/17 19:27 + * @since + */ + public void buildSetting(CreateIndexRequest request) { + request.settings(Settings.builder().put("index.number_of_shards", 3) + .put("index.number_of_replicas", 2)); + } + + /** + * @param idxName index + * @param entity 对象 + * @return void + * @throws + * @author danmo + * @See + * @date 2019/10/17 17:27 + * @since + */ + public void insertOrUpdateOne(String idxName, ElasticSearchEntity entity) { + IndexRequest request = new IndexRequest(idxName, "_doc"); + log.info("Data : id={},entity={}", entity.getId(), JSON.toJSONString(entity.getData())); + request.id(entity.getId()); + request.source(entity.getData(), XContentType.JSON); +// request.source(JSON.toJSONString(entity.getData()), XContentType.JSON); + try { + restHighLevelClient.index(request, RequestOptions.DEFAULT); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + + /** + * 批量插入数据 + * + * @param idxName index + * @param list 带插入列表 + * @return void + * @throws + * @author danmo + * @See + * @date 2019/10/17 17:26 + * @since + */ + public void insertBatch(String idxName, List list) { + BulkRequest request = new BulkRequest(); + list.forEach(item -> request.add(new IndexRequest(idxName, "_doc").id(item.getId()) + .source(item.getData(), XContentType.JSON))); + try { + if (!CollectionUtils.isEmpty(request.requests())) { + restHighLevelClient.bulk(request, RequestOptions.DEFAULT); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * 异步批量插入,并执行回调方法 + * + * @param idxName + * @param list + * @param consumer + */ + public void insertBatchAsync(String idxName, List list, BiConsumer consumer, Object param) { + BulkRequest request = new BulkRequest(); + list.parallelStream().forEach(item -> request.add(new IndexRequest(idxName, "_doc").id(item.getId()) + .source(item.getData(), XContentType.JSON))); + try { + if (!CollectionUtils.isEmpty(request.requests())) { + restHighLevelClient.bulkAsync(request, RequestOptions.DEFAULT, getActionListener(consumer, list, param)); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public void insertBatchAsync(String idxName, List list, Consumer> consumer) { + BulkRequest request = new BulkRequest(); + list.forEach(item -> request.add(new IndexRequest(idxName, "_doc").id(item.getString("msgid")) + .source(item, XContentType.JSON))); + try { + if (!CollectionUtils.isEmpty(request.requests())) { + restHighLevelClient.bulkAsync(request, RequestOptions.DEFAULT, getActionListener(consumer, list)); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public void updateBatch(String idxName, List list) { + BulkRequest request = new BulkRequest(); + list.forEach(item -> request.add(new UpdateRequest(idxName, item.getId()).upsert(item.getData(), XContentType.JSON))); + try { + if (!CollectionUtils.isEmpty(request.requests())) { + restHighLevelClient.bulk(request, RequestOptions.DEFAULT); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * 批量删除 + * + * @param idxName index + * @param idList 待删除列表 + * @return void + * @throws + * @author danmo + * @See + * @date 2019/10/17 17:14 + * @since + */ + public void deleteBatch(String idxName, Collection idList) { + BulkRequest request = new BulkRequest(); + idList.forEach(item -> request.add(new DeleteRequest(idxName, "_doc", item.toString()))); + try { + if (!CollectionUtils.isEmpty(request.requests())) { + restHighLevelClient.bulk(request, RequestOptions.DEFAULT); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * @param idxName index + * @param builder 查询参数 + * @param c 结果类对象 + * @return java.util.List + * @throws + * @author danmo + * @See + * @date 2019/10/17 17:14 + * @since + */ + public List search(String idxName, SearchSourceBuilder builder, Class c) { + SearchRequest request = new SearchRequest(idxName); + request.source(builder); + try { + SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT); + long totalHits = response.getHits().getTotalHits().value; + SearchHit[] hits = response.getHits().getHits(); + List res = new ArrayList<>(hits.length); + for (SearchHit hit : hits) { + res.add(JSON.parseObject(hit.getSourceAsString(), c)); + } + return res; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public PageInfo searchPage(String idxName, SearchSourceBuilder builder, int pageNum, int pageSize, Class c) { + SearchRequest request = new SearchRequest(idxName); + request.source(builder); + try { + SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT); + int totalHits = (int) response.getHits().getTotalHits().value; + SearchHit[] hits = response.getHits().getHits(); + List res = new ArrayList<>(hits.length); + for (SearchHit hit : hits) { + //解析高亮字段 + //获取当前命中的对象的高亮的字段 + Map highlightFields = hit.getHighlightFields(); + HighlightField hghlightContent = highlightFields.get("text.content"); + String newName = ""; + if (hghlightContent != null) { + //获取该高亮字段的高亮信息 + Text[] fragments = hghlightContent.getFragments(); + //将前缀、关键词、后缀进行拼接 + for (Text fragment : fragments) { + newName += fragment; + } + } + Map sourceAsMap = hit.getSourceAsMap(); + sourceAsMap.put("content", newName); + res.add(JSON.parseObject(JSONObject.toJSONString(sourceAsMap), c)); + } + // 封装分页 + PageInfo page = new PageInfo<>(); + page.setList(res); + page.setPageNum(pageNum); + page.setPageSize(pageSize); + page.setTotal(totalHits); + page.setPages(totalHits == 0 ? 0 : (totalHits % pageNum == 0 ? totalHits / pageNum : (totalHits / pageNum) + 1)); + page.setHasNextPage(page.getPageNum() < page.getPages()); + return page; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * 删除index + * + * @param idxName + * @return void + * @throws + * @author danmo + * @See + * @date 2019/10/17 17:13 + * @since + */ + public void deleteIndex(String idxName) { + try { + if (!this.indexExist(idxName)) { + //log.error(" idxName={} 已经存在", idxName); + return; + } + restHighLevelClient.indices().delete(new DeleteIndexRequest(idxName), RequestOptions.DEFAULT); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + + /** + * @param idxName + * @param builder + * @return void + * @throws + * @author danmo + * @See + * @date 2019/10/17 17:13 + * @since + */ + public void deleteByQuery(String idxName, QueryBuilder builder) { + DeleteByQueryRequest request = new DeleteByQueryRequest(idxName); + request.setQuery(builder); + //设置批量操作数量,最大为10000 + request.setBatchSize(10000); + request.setConflicts("proceed"); + try { + restHighLevelClient.deleteByQuery(request, RequestOptions.DEFAULT); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public ActionListener getActionListener(Consumer consumer, List list) { + return new ActionListener() { + @Override + public void onResponse(Object o) { + consumer.accept(list); + } + + @Override + public void onFailure(Exception e) { + log.warn("work with es failed, exception={}", ExceptionUtils.getStackTrace(e)); + } + }; + } + + public ActionListener getActionListener(BiConsumer consumer, List list, Object param) { + return new ActionListener() { + @Override + public void onResponse(Object o) { + consumer.accept(list, param); + } + + @Override + public void onFailure(Exception e) { + log.warn("work with es failed, exception={}", ExceptionUtils.getStackTrace(e)); + } + }; + } + + public XContentBuilder getFinanceMapping() throws IOException { + // 创建 会话文本Mapping + XContentBuilder xContentBuilder = XContentFactory.jsonBuilder() + .startObject() + .startObject("properties") + .startObject("msgid") + .field("type", "keyword") + .endObject() + .startObject("seq") + .field("type", "long") + .endObject() + .startObject("action") + .field("type", "keyword") + .endObject() + .startObject("from") + .field("type", "keyword") + .endObject() + .startObject("roomid") + .field("type", "keyword") + .endObject() + .startObject("msgtime") + .field("type", "long") + .endObject() + .startObject("msgtype") + .field("type", "keyword") + .endObject() + .endObject() + .endObject(); + return xContentBuilder; + } +} \ No newline at end of file diff --git a/linkwe-common/src/main/java/com/linkwechat/common/core/page/TableDataInfo.java b/linkwe-common/src/main/java/com/linkwechat/common/core/page/TableDataInfo.java index 853ecb551931bfe380a358666334e6eca01a3bb9..49ab2f56b1982782374e3878c3764f60e4f6f5bf 100644 --- a/linkwe-common/src/main/java/com/linkwechat/common/core/page/TableDataInfo.java +++ b/linkwe-common/src/main/java/com/linkwechat/common/core/page/TableDataInfo.java @@ -1,6 +1,9 @@ package com.linkwechat.common.core.page; +import com.fasterxml.jackson.annotation.JsonFormat; + import java.io.Serializable; +import java.util.Date; import java.util.List; /** @@ -8,7 +11,7 @@ import java.util.List; * * @author ruoyi */ -public class TableDataInfo implements Serializable +public class TableDataInfo implements Serializable { private static final long serialVersionUID = 1L; @@ -16,7 +19,7 @@ public class TableDataInfo implements Serializable private long total; /** 列表数据 */ - private List rows; + private T rows; /** 消息状态码 */ private int code; @@ -24,6 +27,13 @@ public class TableDataInfo implements Serializable /** 消息内容 */ private String msg; + /**最后同步时间*/ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date lastSyncTime; + + /**去重复客户数*/ + private long noRepeatCustomerTotal; + /** * 表格数据对象 */ @@ -37,7 +47,7 @@ public class TableDataInfo implements Serializable * @param list 列表数据 * @param total 总记录数 */ - public TableDataInfo(List list, int total) + public TableDataInfo(T list, int total) { this.rows = list; this.total = total; @@ -53,12 +63,12 @@ public class TableDataInfo implements Serializable this.total = total; } - public List getRows() + public T getRows() { return rows; } - public void setRows(List rows) + public void setRows(T rows) { this.rows = rows; } @@ -82,4 +92,20 @@ public class TableDataInfo implements Serializable { this.msg = msg; } + + public Date getLastSyncTime() { + return lastSyncTime; + } + + public void setLastSyncTime(Date lastSyncTime) { + this.lastSyncTime = lastSyncTime; + } + + public long getNoRepeatCustomerTotal() { + return noRepeatCustomerTotal; + } + + public void setNoRepeatCustomerTotal(long noRepeatCustomerTotal) { + this.noRepeatCustomerTotal = noRepeatCustomerTotal; + } } diff --git a/linkwe-common/src/main/java/com/linkwechat/common/core/redis/RedisCache.java b/linkwe-common/src/main/java/com/linkwechat/common/core/redis/RedisCache.java index 0a0313145192f7d190303723c92ab2e8b640362e..7ccf6d59d56bf0cb946b0acfb94540f49595fc52 100644 --- a/linkwe-common/src/main/java/com/linkwechat/common/core/redis/RedisCache.java +++ b/linkwe-common/src/main/java/com/linkwechat/common/core/redis/RedisCache.java @@ -1,74 +1,71 @@ package com.linkwechat.common.core.redis; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.TimeUnit; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.HashOperations; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.ValueOperations; +import org.springframework.data.redis.core.ZSetOperations; import org.springframework.stereotype.Component; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.TimeUnit; + /** * spring redis 工具类 * * @author ruoyi **/ -@SuppressWarnings(value = { "unchecked", "rawtypes" }) +@SuppressWarnings(value = {"unchecked", "rawtypes"}) @Component -public class RedisCache -{ +public class RedisCache { @Autowired public RedisTemplate redisTemplate; /** * 缓存基本的对象,Integer、String、实体类等 * - * @param key 缓存的键值 + * @param key 缓存的键值 * @param value 缓存的值 */ - public void setCacheObject(final String key, final T value) - { + public void setCacheObject(final String key, final T value) { redisTemplate.opsForValue().set(key, value); } /** * 缓存基本的对象,Integer、String、实体类等 * - * @param key 缓存的键值 - * @param value 缓存的值 - * @param timeout 时间 + * @param key 缓存的键值 + * @param value 缓存的值 + * @param timeout 时间 * @param timeUnit 时间颗粒度 */ - public void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit) - { + public void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit) { redisTemplate.opsForValue().set(key, value, timeout, timeUnit); } /** * 设置有效时间 * - * @param key Redis键 + * @param key Redis键 * @param timeout 超时时间 * @return true=设置成功;false=设置失败 */ - public boolean expire(final String key, final long timeout) - { + public boolean expire(final String key, final long timeout) { return expire(key, timeout, TimeUnit.SECONDS); } /** * 设置有效时间 * - * @param key Redis键 + * @param key Redis键 * @param timeout 超时时间 - * @param unit 时间单位 + * @param unit 时间单位 * @return true=设置成功;false=设置失败 */ - public boolean expire(final String key, final long timeout, final TimeUnit unit) - { + public boolean expire(final String key, final long timeout, final TimeUnit unit) { return redisTemplate.expire(key, timeout, unit); } @@ -78,8 +75,7 @@ public class RedisCache * @param key 缓存键值 * @return 缓存键值对应的数据 */ - public T getCacheObject(final String key) - { + public T getCacheObject(final String key) { ValueOperations operation = redisTemplate.opsForValue(); return operation.get(key); } @@ -89,8 +85,7 @@ public class RedisCache * * @param key */ - public boolean deleteObject(final String key) - { + public boolean deleteObject(final String key) { return redisTemplate.delete(key); } @@ -100,20 +95,18 @@ public class RedisCache * @param collection 多个对象 * @return */ - public long deleteObject(final Collection collection) - { + public long deleteObject(final Collection collection) { return redisTemplate.delete(collection); } /** * 缓存List数据 * - * @param key 缓存的键值 + * @param key 缓存的键值 * @param dataList 待缓存的List数据 * @return 缓存的对象 */ - public long setCacheList(final String key, final List dataList) - { + public long setCacheList(final String key, final List dataList) { Long count = redisTemplate.opsForList().rightPushAll(key, dataList); return count == null ? 0 : count; } @@ -124,20 +117,18 @@ public class RedisCache * @param key 缓存的键值 * @return 缓存键值对应的数据 */ - public List getCacheList(final String key) - { + public List getCacheList(final String key) { return redisTemplate.opsForList().range(key, 0, -1); } /** * 缓存Set * - * @param key 缓存键值 + * @param key 缓存键值 * @param dataSet 缓存的数据 * @return 缓存数据的对象 */ - public long setCacheSet(final String key, final Set dataSet) - { + public long setCacheSet(final String key, final Set dataSet) { Long count = redisTemplate.opsForSet().add(key, dataSet); return count == null ? 0 : count; } @@ -148,8 +139,7 @@ public class RedisCache * @param key * @return */ - public Set getCacheSet(final String key) - { + public Set getCacheSet(final String key) { return redisTemplate.opsForSet().members(key); } @@ -159,8 +149,7 @@ public class RedisCache * @param key * @param dataMap */ - public void setCacheMap(final String key, final Map dataMap) - { + public void setCacheMap(final String key, final Map dataMap) { if (dataMap != null) { redisTemplate.opsForHash().putAll(key, dataMap); } @@ -172,32 +161,29 @@ public class RedisCache * @param key * @return */ - public Map getCacheMap(final String key) - { + public Map getCacheMap(final String key) { return redisTemplate.opsForHash().entries(key); } /** * 往Hash中存入数据 * - * @param key Redis键 - * @param hKey Hash键 + * @param key Redis键 + * @param hKey Hash键 * @param value 值 */ - public void setCacheMapValue(final String key, final String hKey, final T value) - { + public void setCacheMapValue(final String key, final String hKey, final T value) { redisTemplate.opsForHash().put(key, hKey, value); } /** * 获取Hash中的数据 * - * @param key Redis键 + * @param key Redis键 * @param hKey Hash键 * @return Hash中的对象 */ - public T getCacheMapValue(final String key, final String hKey) - { + public T getCacheMapValue(final String key, final String hKey) { HashOperations opsForHash = redisTemplate.opsForHash(); return opsForHash.get(key, hKey); } @@ -205,12 +191,11 @@ public class RedisCache /** * 获取多个Hash中的数据 * - * @param key Redis键 + * @param key Redis键 * @param hKeys Hash键集合 * @return Hash对象集合 */ - public List getMultiCacheMapValue(final String key, final Collection hKeys) - { + public List getMultiCacheMapValue(final String key, final Collection hKeys) { return redisTemplate.opsForHash().multiGet(key, hKeys); } @@ -220,8 +205,162 @@ public class RedisCache * @param pattern 字符串前缀 * @return 对象列表 */ - public Collection keys(final String pattern) - { + public Collection keys(final String pattern) { return redisTemplate.keys(pattern); } + + + /** + * 将给定的消息发布到给定的频道 + * + * @param channel 要发布到的频道 + * @param message 消息内容 + */ + public void convertAndSend(String channel, Object message) { + redisTemplate.convertAndSend(channel, message); + } + + + /** + * 添加一个元素, zset与set最大的区别就是每个元素都有一个score,因此有个排序的辅助功能; + * + * @param key + * @param value + * @param score + */ + public Boolean setCacheZSet(String key, String value, double score) { + return redisTemplate.opsForZSet().add(key, value, score); + } + + /** + * 删除元素 zrem + * + * @param key + * @param start + * @param end + */ + public Long removeRangeCacheZSet(String key, long start, long end) { + return redisTemplate.opsForZSet().removeRange(key, start,end); + } + + /** + * 删除元素 zrem + * + * @param key + * @param value + */ + public long removeCacheZSet(String key, String value) { + return redisTemplate.opsForZSet().remove(key, value); + } + + /** + * score的增加or减少 zincrby + * + * @param key + * @param value + * @param score + */ + public Double incrScoreCacheZSet(String key, String value, double score) { + return redisTemplate.opsForZSet().incrementScore(key, value, score); + } + + /** + * 查询value对应的score zscore + * + * @param key + * @param value + * @return + */ + public Double getCacheZSetScore(String key, String value) { + return redisTemplate.opsForZSet().score(key, value); + } + + + /** + * 判断value在zset中的排名 zrank + * + * @param key + * @param value + * @return + */ + public Long rankCacheZSet(String key, String value) { + return redisTemplate.opsForZSet().rank(key, value); + } + + + /** + * 返回集合的长度 + * + * @param key + * @return + */ + public Long getCacheZSetSize(String key) { + return redisTemplate.opsForZSet().zCard(key); + } + + /** + * 查询集合中指定顺序的值, 0 -1 表示获取全部的集合内容 zrange + * + * 返回有序的集合,score小的在前面 + * + * @param key + * @param start + * @param end + * @return + */ + public Set rangeCacheZSet(String key, int start, int end) { + return redisTemplate.opsForZSet().range(key, start, end); + } + + /** + * 查询集合中指定顺序的值和score,0, -1 表示获取全部的集合内容 + * + * @param key + * @param start + * @param end + * @return + */ + public Set> rangeWithScore(String key, int start, int end) { + return redisTemplate.opsForZSet().rangeWithScores(key, start, end); + } + + /** + * 查询集合中指定顺序的值 zrevrange + * + * 返回有序的集合中,score大的在前面 + * + * @param key + * @param start + * @param end + * @return + */ + public Set revRangeCacheZSet(String key, int start, int end) { + return redisTemplate.opsForZSet().reverseRange(key, start, end); + } + + /** + * 根据score的值,来获取满足条件的集合 zrangebyscore + * + * @param key + * @param min + * @param max + * @return + */ + public Set sortRangeCacheZSet(String key, double min, double max) { + return redisTemplate.opsForZSet().rangeByScore(key, min, max); + } + + /** + * 根据score的值,来获取满足条件的集合 + * + * @param key + * @param min + * @param max + * @return + */ + public Set> sortRangeWithScoresCacheZSet(String key, double min, double max) { + return redisTemplate.opsForZSet().rangeByScoreWithScores(key, min, max); + } + + } diff --git a/linkwe-common/src/main/java/com/linkwechat/common/enums/AllocateCustomerStatus.java b/linkwe-common/src/main/java/com/linkwechat/common/enums/AllocateCustomerStatus.java new file mode 100644 index 0000000000000000000000000000000000000000..70c55a055f85b29fb99ed847da93b6279261cfbb --- /dev/null +++ b/linkwe-common/src/main/java/com/linkwechat/common/enums/AllocateCustomerStatus.java @@ -0,0 +1,40 @@ +package com.linkwechat.common.enums; + +import java.util.stream.Stream; + +/** + * 客户分配的状态 + */ +public enum AllocateCustomerStatus { + JOB_EXTENDS_SUCCESS(0,"成功发起转接"), + JOB_EXTENDS_JTWB(1,"接替完毕"), + JOB_EXTENDS_DDJT(2,"等待接替"), + JOB_EXTENDS_KHJJ(3,"客户拒绝"), + JOB_EXTENDS_DDSX(4,"接替成员客户达到上限"), + JOB_EXTENDS_WJTJL(5,"无接替记录"), + JOB_EXTENDS_BKJC(6,"当前客户已被继承"); + + + private final Integer code; + private final String info; + + AllocateCustomerStatus(Integer code, String info) + { + this.code = code; + this.info = info; + } + + public Integer getCode() { + return code; + } + + public String getInfo() { + return info; + } + + public static AllocateCustomerStatus of(Integer type){ + return Stream.of(values()).filter(s->s.getCode().equals(type)).findFirst().orElseGet(null); + } + + +} diff --git a/linkwe-common/src/main/java/com/linkwechat/common/enums/AllocateGroupStatus.java b/linkwe-common/src/main/java/com/linkwechat/common/enums/AllocateGroupStatus.java new file mode 100644 index 0000000000000000000000000000000000000000..ea5c4006ba3140ef73e5260013c844ae7ac09d1a --- /dev/null +++ b/linkwe-common/src/main/java/com/linkwechat/common/enums/AllocateGroupStatus.java @@ -0,0 +1,35 @@ +package com.linkwechat.common.enums; + +/** + * 群分配状态 + */ +public enum AllocateGroupStatus { + + ALLOCATE_GROUP_STATUS_BJTCG(0,"被接替成功"), + ALLOCATE_GROUP_STATUS_DJT(1,"待接替"), + ALLOCATE_GROUP_STATUS_JTSB(2,"接替失败"), + ALLOCATE_GROUP_STATUS_ZCZT(3,"正常状态"); + + private Integer key; + private String val; + + AllocateGroupStatus(Integer key,String val){ + this.key=key; + this.val=val; + } + public Integer getKey() { + return key; + } + + public void setKey(Integer key) { + this.key = key; + } + + public String getVal() { + return val; + } + + public void setVal(String val) { + this.val = val; + } +} diff --git a/linkwe-common/src/main/java/com/linkwechat/common/enums/BusinessType.java b/linkwe-common/src/main/java/com/linkwechat/common/enums/BusinessType.java index b9f19ce709736e722eeebf3ee6bbeae6e6f628b3..9afb71328ce905a9ba3746ed38e618cb80832589 100644 --- a/linkwe-common/src/main/java/com/linkwechat/common/enums/BusinessType.java +++ b/linkwe-common/src/main/java/com/linkwechat/common/enums/BusinessType.java @@ -2,11 +2,10 @@ package com.linkwechat.common.enums; /** * 业务操作类型 - * + * * @author ruoyi */ -public enum BusinessType -{ +public enum BusinessType { /** * 其它 */ @@ -51,9 +50,14 @@ public enum BusinessType * 生成代码 */ GENCODE, - + /** * 清空数据 */ CLEAN, + + /** + * 查询 + */ + SELECT, } diff --git a/linkwe-common/src/main/java/com/linkwechat/common/enums/CallbackEventUpdateDetail.java b/linkwe-common/src/main/java/com/linkwechat/common/enums/CallbackEventUpdateDetail.java new file mode 100644 index 0000000000000000000000000000000000000000..e1eedafe0a6f6b70145130e461cb05d75683127f --- /dev/null +++ b/linkwe-common/src/main/java/com/linkwechat/common/enums/CallbackEventUpdateDetail.java @@ -0,0 +1,27 @@ +package com.linkwechat.common.enums; + +import lombok.Getter; + +/** + * 客户群变更时间的回调参数 UpdateDetail + * 变更详情。目前有以下几种: + * add_member : 成员入群 + * del_member : 成员退群 + * change_owner : 群主变更 + * change_name : 群名变更 + * change_notice : 群公告变更 + */ +@Getter +public enum CallbackEventUpdateDetail { + ADD_MEMBER("add_member"), + DEL_MEMBER("del_member"), + CHANGE_OWNER("change_owner"), + CHANGE_NAME("change_name"), + CHANGE_NOTICE("change_notice"); + + private final String type; + + CallbackEventUpdateDetail(String type) { + this.type = type; + } +} diff --git a/linkwe-common/src/main/java/com/linkwechat/common/enums/ChatType.java b/linkwe-common/src/main/java/com/linkwechat/common/enums/ChatType.java new file mode 100644 index 0000000000000000000000000000000000000000..eead618a99c17e3937da1743f8d241d169d4d855 --- /dev/null +++ b/linkwe-common/src/main/java/com/linkwechat/common/enums/ChatType.java @@ -0,0 +1,38 @@ +package com.linkwechat.common.enums; + +import lombok.Getter; + +import java.util.stream.Stream; + +/** + * 群发任务的类型,默认为single,表示发送给客户,group表示发送给客户群 + */ +@Getter +public enum ChatType { + + /** + * 发给客户 + */ + SINGLE("single","0"), + + /** + * 发给客户群 + */ + GROUP("group","1") + ; + + private String name; + + private String type; + + + ChatType(String name, String type) { + this.name = name; + this.type = type; + } + + public static ChatType of(String type){ + return Stream.of(values()).filter(s->s.getType().equals(type)).findFirst().orElseGet(null); + } + +} diff --git a/linkwe-common/src/main/java/com/linkwechat/common/enums/CommunityTaskType.java b/linkwe-common/src/main/java/com/linkwechat/common/enums/CommunityTaskType.java new file mode 100644 index 0000000000000000000000000000000000000000..8540bd2fb70b49fbb9bf6337e4abd626ef620f7c --- /dev/null +++ b/linkwe-common/src/main/java/com/linkwechat/common/enums/CommunityTaskType.java @@ -0,0 +1,28 @@ +package com.linkwechat.common.enums; + +import lombok.Getter; + +/** + * H5列表页数据类型 + * @Author Hang + * @Date 2021/3/24 11:02 + */ +@Getter +public enum CommunityTaskType { + + TAG(1, "老客标签建群"), + + SEAS(3, "客户公海"), + + SOP(2, "群sop"); + + + private final String name; + + private final Integer type; + + CommunityTaskType(Integer type, String name) { + this.name = name; + this.type = type; + } +} diff --git a/linkwe-common/src/main/java/com/linkwechat/common/enums/CustomerAddWay.java b/linkwe-common/src/main/java/com/linkwechat/common/enums/CustomerAddWay.java new file mode 100644 index 0000000000000000000000000000000000000000..bb49a0618e6527233401bef687f71b6d6e52d01c --- /dev/null +++ b/linkwe-common/src/main/java/com/linkwechat/common/enums/CustomerAddWay.java @@ -0,0 +1,49 @@ +package com.linkwechat.common.enums; + +import java.util.stream.Stream; + +/** + * 客户添加方式 + */ +public enum CustomerAddWay { + ADD_WAY_WZLY(0,"未知来源"), + ADD_WAY_SMEWM(1,"扫描二维码"), + ADD_WAY_SSSJH(2,"搜索手机号"), + ADD_WAY_MPFX(3,"名片分享"), + ADD_WAY_QL(4,"群聊"), + ADD_WAY_SJTXL(5,"手机通讯录"), + ADD_WAY_WXLXR(6,"微信联系人"), + ADD_WAY_LZWXTJHY(7,"来自微信的添加好友申请"), + ADD_WAY_KFRY(8,"安装第三方应用时自动添加的客服人员"), + ADD_WAY_SSYX(9,"搜索邮箱"), + ADD_WAY_SPHZYTJ(10,"视频号主页添加"), + ADD_WAY_LBCYGX(201,"内部成员共享"), + ADD_WAY_GLYFP(202,"管理员/负责人分配"); + + private Integer key; + + private String val; + CustomerAddWay(Integer key,String val){ + this.key=key; + this.val=val; + } + + public Integer getKey() { + return key; + } + + public void setKey(Integer key) { + this.key = key; + } + + public String getVal() { + return val; + } + + public void setVal(String val) { + this.val = val; + } + public static CustomerAddWay of(Integer type){ + return Stream.of(values()).filter(s->s.getKey().equals(type)).findFirst().orElseGet(null); + } +} diff --git a/linkwe-common/src/main/java/com/linkwechat/common/enums/GroupMessageType.java b/linkwe-common/src/main/java/com/linkwechat/common/enums/GroupMessageType.java new file mode 100644 index 0000000000000000000000000000000000000000..e2ef0e687b41488730982a7224974fc404e59d6e --- /dev/null +++ b/linkwe-common/src/main/java/com/linkwechat/common/enums/GroupMessageType.java @@ -0,0 +1,61 @@ +package com.linkwechat.common.enums; + +import lombok.Getter; + +import java.util.Optional; +import java.util.stream.Stream; + +/** + * 群发消息类型 0 文本消息 1 图片消息 2 链接消息 3 小程序消息 4 图文消息 + */ +@SuppressWarnings("all") +@Getter +public enum GroupMessageType { + + /** + * 文本消息 + */ + TEXT("0", "text"), + /** + * 图片消息 + */ + IMAGE("1", "image"), + /** + * 链接消息 + */ + LINK("2", "link"), + /** + * 小程序消息 + */ + MINIPROGRAM("3", "miniprogram"), + /** + * 图文消息 + */ + TEXT_IMAGE("4", "text_image"), + + /** + * 视频 + */ + VIDEO("5", "video") + + ; + /** + * 媒体类型 + */ + String messageType; + + /** + * 数据值 + */ + String type; + + GroupMessageType(String type, String messageType) { + this.type = type; + this.messageType = messageType; + } + + public static Optional of(String type) { + return Stream.of(values()).filter(s -> s.type.equals(type)).findFirst(); + } + +} diff --git a/linkwe-common/src/main/java/com/linkwechat/common/enums/MediaType.java b/linkwe-common/src/main/java/com/linkwechat/common/enums/MediaType.java index 44d8a052f3ceb71516175a376f83a4a284ef6cdf..5653caea9ebc9922820401ee2b3382782d997cee 100644 --- a/linkwe-common/src/main/java/com/linkwechat/common/enums/MediaType.java +++ b/linkwe-common/src/main/java/com/linkwechat/common/enums/MediaType.java @@ -14,7 +14,36 @@ public enum MediaType { IMAGE("0", "image"), VOICE("1", "voice"), VIDEO("2", "video"), - FILE("3", "file"); + FILE("3", "file"), + /** + * 海报 + */ + POSTER("5", "poster"), + /** + * 海报字体 + */ + POSTER_FONT("6", "poster_font"), + + + /** + * 图文 + */ + IMAGE_TEXT("7","image_text"), + + /** + * 链接 + */ + LINK("8","link"), + + /** + * 小程序 + */ + APPLET("9","applet"), + + /** + * 文字 + */ + TEXT("10","text"); /** * 媒体类型 @@ -22,7 +51,7 @@ public enum MediaType { String mediaType; /** - * 0 图片(image)、1 语音(voice)、2 视频(video),3 普通文件(file) 4 文本 + * 0 图片(image)、1 语音(voice)、2 视频(video),3 普通文件(file) 4 文本 5 海报 6 海报字体 7 图文 8 链接 9 小程序 */ String type; diff --git a/linkwe-common/src/main/java/com/linkwechat/common/enums/MessageType.java b/linkwe-common/src/main/java/com/linkwechat/common/enums/MessageType.java index 426767c65afa902d468b8d956745120b2e82b23a..0b846040273161ac136b726c60ad7209f16a3f38 100644 --- a/linkwe-common/src/main/java/com/linkwechat/common/enums/MessageType.java +++ b/linkwe-common/src/main/java/com/linkwechat/common/enums/MessageType.java @@ -15,53 +15,63 @@ public enum MessageType { /** * 文本消息 */ - TEXT("0", "text"), + TEXT("0", "text", "文本"), /** * 图片消息 */ - IMAGE("1", "image"), + IMAGE("1", "image", "图片"), /** * 语音消息 */ - VOICE("2", "voice"), + VOICE("2", "voice", "语音"), /** * 视频消息 */ - VIDEO("3", "video"), + VIDEO("3", "video", "视频"), /** * 文件消息 */ - FILE("4", "file"), + FILE("4", "file", "文件"), /** * 文本卡片消息 */ - TEXTCARD("5", "textcard"), + TEXTCARD("5", "textcard", "文本卡片"), /** * 图文消息 */ - NEWS("6", "news"), + NEWS("6", "news", "图文"), /** * 图文消息(mpnews) */ - MPNEWS("7", "mpnews"), + MPNEWS("7", "mpnews", "图文"), /** * markdown消息 */ - MARKDOWN("8", "markdown"), + MARKDOWN("8", "markdown", "markdown"), /** * 小程序通知消息 */ - MINIPROGRAM_NOTICE("9", "miniprogram_notice"), + MINIPROGRAM_NOTICE("9", "miniprogram_notice", "小程序"), /** * 任务卡片消息 */ - TASKCARD("10", "taskcard"), + TASKCARD("10", "taskcard", "任务卡片"), + + /** + * 群发图文消息 + */ + LINK("11", "link","链接"), + + /** + * 群发小程序 + */ + MINIPROGRAM("12", "miniprogram", "小程序"), ; /** @@ -69,18 +79,28 @@ public enum MessageType { */ String messageType; + /** + * 媒体名称 + */ + String name; + /** * 数据值 */ String type; - MessageType(String type, String messageType) { + MessageType(String type, String messageType, String name) { this.type = type; this.messageType = messageType; + this.name = name; } public static Optional of(String type) { return Stream.of(values()).filter(s -> s.type.equals(type)).findFirst(); } + public static MessageType messageTypeOf(String messageType) { + return Stream.of(values()).filter(s -> s.messageType.equals(messageType)).findFirst().get(); + } + } diff --git a/linkwe-common/src/main/java/com/linkwechat/common/enums/TaskFissionType.java b/linkwe-common/src/main/java/com/linkwechat/common/enums/TaskFissionType.java new file mode 100644 index 0000000000000000000000000000000000000000..cffa9774efb49a4db71c1cf46cd00dc55e3a7f70 --- /dev/null +++ b/linkwe-common/src/main/java/com/linkwechat/common/enums/TaskFissionType.java @@ -0,0 +1,30 @@ +package com.linkwechat.common.enums; + +import lombok.Getter; + +/** + * @author leejoker <1056650571@qq.com> + * @version 1.0 + * @date 2021/2/9 10:31 + */ +@Getter +public enum TaskFissionType { + /** + * 任务宝 + */ + USER_FISSION(1, "任务宝"), + + /** + * 群裂变 + */ + GROUP_FISSION(2, "群裂变"); + + private String value; + + private Integer code; + + TaskFissionType(Integer code, String value) { + this.code = code; + this.value = value; + } +} diff --git a/linkwe-common/src/main/java/com/linkwechat/common/enums/TaskSendType.java b/linkwe-common/src/main/java/com/linkwechat/common/enums/TaskSendType.java new file mode 100644 index 0000000000000000000000000000000000000000..f0ae063305a0a09c59ec74528f76f1a037b2eb2e --- /dev/null +++ b/linkwe-common/src/main/java/com/linkwechat/common/enums/TaskSendType.java @@ -0,0 +1,30 @@ +package com.linkwechat.common.enums; + +import lombok.Getter; + +/** + * 老客标签建群任务群发类型 + * @Author Hang + * @Date 2021/3/24 9:56 + */ +@Getter +public enum TaskSendType { + /** + * 个人群发 + */ + CROP(0, "企业群发"), + + /** + * 企业群发 + */ + SINGLE(1, "个人群发"); + + private final String name; + + private final Integer type; + + TaskSendType(Integer type, String name) { + this.name = name; + this.type = type; + } +} diff --git a/linkwe-common/src/main/java/com/linkwechat/common/enums/TrackState.java b/linkwe-common/src/main/java/com/linkwechat/common/enums/TrackState.java new file mode 100644 index 0000000000000000000000000000000000000000..9a9db4ea27119904f6dc05eba989a5ab2c732e2a --- /dev/null +++ b/linkwe-common/src/main/java/com/linkwechat/common/enums/TrackState.java @@ -0,0 +1,35 @@ +package com.linkwechat.common.enums; + +public enum TrackState { + //跟踪状态 1:待跟进;2:跟进中;3:已成交;4:无意向;5:已流失 + STATE_DGJ(1,"待跟进"), + STATE_GJZ(2,"跟进中"), + STATE_JCJ(3,"已成交"), + STATE_WYX(4,"无意向"), + STATE_YLS(5,"已流失"); + + private String name; + + private Integer type; + + TrackState(Integer type,String name){ + this.name=name; + this.type=type; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } +} diff --git a/linkwe-common/src/main/java/com/linkwechat/common/enums/TrajectorySceneType.java b/linkwe-common/src/main/java/com/linkwechat/common/enums/TrajectorySceneType.java new file mode 100644 index 0000000000000000000000000000000000000000..fa1db66b003c994e0bd594e83991ef3f7110d1d4 --- /dev/null +++ b/linkwe-common/src/main/java/com/linkwechat/common/enums/TrajectorySceneType.java @@ -0,0 +1,62 @@ +package com.linkwechat.common.enums; + +import java.util.stream.Stream; + +public enum TrajectorySceneType { + + TRAJECTORY_TITLE_TJYG(1,"添加员工","%s通过:%s 方式添加员工:%s"), + TRAJECTORY_TITLE_SCYG(2,"删除员工","%s删除员工%s"), + TRAJECTORY_TITLE_JRQL(3,"加入群聊","{客户名}通过{添加的方式}加入群聊{群名}"), + TRAJECTORY_TITLE_TCQL(4,"退出群聊","{客户名}退出群聊{员工名}"), + TRAJECTORY_TITLE_GXQYBQ(5,"更新企业标签","员工:%s,更新客户标签:%s"), + TRAJECTORY_TITLE_GXGRBQ(6,"更新个人标签","员工:%s,更新个人标签:%s"), + TRAJECTORY_TITLE_BJBQ(7,"编辑信息","员工:%s 编辑了:%s的详细资料"), + TRAJECTORY_TITLE_TJGJ(8,"添加更进","员工%s添加跟进:%s"), + TRAJECTORY_TITLE_DZPYQ(9,"点赞朋友圈","%s点赞了员工%s的朋友圈"), + TRAJECTORY_TITLE_PLPYQ(10,"评论朋友圈","%s评论了员工%s的朋友圈"); + + + private String name; + + private Integer type; + + private String msgTpl; + + + + + TrajectorySceneType( Integer type,String name,String msgTpl) { + this.name = name; + this.type = type; + this.msgTpl=msgTpl; + } + + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public String getMsgTpl() { + return msgTpl; + } + + public void setMsgTpl(String msgTpl) { + this.msgTpl = msgTpl; + } + + public static TrajectorySceneType of(Integer type){ + return Stream.of(values()).filter(s->s.getType().equals(type)).findFirst().orElseGet(null); + } +} diff --git a/linkwe-common/src/main/java/com/linkwechat/common/enums/TrajectoryType.java b/linkwe-common/src/main/java/com/linkwechat/common/enums/TrajectoryType.java new file mode 100644 index 0000000000000000000000000000000000000000..c782f2462346d32109be95afb88804379c1bd946 --- /dev/null +++ b/linkwe-common/src/main/java/com/linkwechat/common/enums/TrajectoryType.java @@ -0,0 +1,49 @@ +package com.linkwechat.common.enums; + +import lombok.Getter; + +import java.util.stream.Stream; + +/** + * 客户轨迹枚举 + */ +@Getter +public enum TrajectoryType { + + + TRAJECTORY_TYPE_XXDT(1,"客户动态"), + TRAJECTORY_TYPE_SJDT(2,"员工动态"), + + TRAJECTORY_TYPE_HDGZ(3,"互动动态"), + + TRAJECTORY_TYPE_DBDT(4,"跟进动态"); + + private String name; + + private Integer type; + + + TrajectoryType( Integer type,String name) { + this.name = name; + this.type = type; + } + + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + +} diff --git a/linkwe-common/src/main/java/com/linkwechat/common/enums/TransferFailReason.java b/linkwe-common/src/main/java/com/linkwechat/common/enums/TransferFailReason.java new file mode 100644 index 0000000000000000000000000000000000000000..3df367fca06d9dc992ff6777ac406f75b0e2bb12 --- /dev/null +++ b/linkwe-common/src/main/java/com/linkwechat/common/enums/TransferFailReason.java @@ -0,0 +1,55 @@ +package com.linkwechat.common.enums; + +import lombok.Getter; + +/** + * @author danmo + * @description 接替失败的原因 + * @date 2021/1/20 0:14 + **/ +@Getter +public enum TransferFailReason { + /** + * 客户拒绝 + */ + CUSTOMER_REFUSED(3,"customer_refused", "客户拒绝"), + + /** + * 接替成员的客户数达到上限 + */ + CUSTOMER_LIMIT_EXCEED(4,"customer_limit_exceed", "接替成员的客户数达到上限"); + + private int num; + + private String name; + + private String reason; + + TransferFailReason(int num, String name, String reason) { + this.num = num; + this.name = name; + this.reason = reason; + } + + public static String getReason(String name){ + TransferFailReason[] values = TransferFailReason.values(); + + for(TransferFailReason transferFailReason:values){ + if(transferFailReason.getName().equals(name)){ + return transferFailReason.getReason(); + } + } + throw new RuntimeException("无对应原因"); + } + + public static int getNum(String name){ + TransferFailReason[] values = TransferFailReason.values(); + + for(TransferFailReason transferFailReason:values){ + if(transferFailReason.getName().equals(name)){ + return transferFailReason.getNum(); + } + } + throw new RuntimeException("无对应类型"); + } +} diff --git a/linkwe-common/src/main/java/com/linkwechat/common/enums/WeEmpleCodeType.java b/linkwe-common/src/main/java/com/linkwechat/common/enums/WeEmpleCodeType.java new file mode 100644 index 0000000000000000000000000000000000000000..979f3b5aee55f00c5496fcaf68b527a4b81365ba --- /dev/null +++ b/linkwe-common/src/main/java/com/linkwechat/common/enums/WeEmpleCodeType.java @@ -0,0 +1,29 @@ +package com.linkwechat.common.enums; + + +/** + * 群活码运用场景: 单人、多人、批量 + */ +public enum WeEmpleCodeType { + + // 员工活码类型:1:单人;2:多人;3:批量; + SINGLE(1, "单人"), + MULTI(2, "多人"), + BATCH(3, "批量"); + + private final Integer type; + private final String info; + + WeEmpleCodeType(Integer type, String info) { + this.type = type; + this.info = info; + } + + public Integer getType() { + return type; + } + + public String getInfo() { + return info; + } +} diff --git a/linkwe-common/src/main/java/com/linkwechat/common/enums/WeErrorCodeEnum.java b/linkwe-common/src/main/java/com/linkwechat/common/enums/WeErrorCodeEnum.java new file mode 100644 index 0000000000000000000000000000000000000000..a8425cb1633e9309a6ab9fac2808fa66c2bace77 --- /dev/null +++ b/linkwe-common/src/main/java/com/linkwechat/common/enums/WeErrorCodeEnum.java @@ -0,0 +1,744 @@ +package com.linkwechat.common.enums; + +import lombok.Getter; +import lombok.NoArgsConstructor; + +/** + * @author danmo + * @description 企业微信全局错误码 + * @date 2021/9/30 11:13 + **/ +@NoArgsConstructor +@Getter +public enum WeErrorCodeEnum { + + ERROR_CODE_OWE_1(-1, "系统繁忙"), + ERROR_CODE_0(0, "请求成功"), + ERROR_CODE_6000(6000, "数据版本冲突"), + ERROR_CODE_40001(40001, "不合法的secret参数"), + ERROR_CODE_40003(40003, "无效的UserID"), + ERROR_CODE_40004(40004, "不合法的媒体文件类型"), + ERROR_CODE_40005(40005, "不合法的type参数"), + ERROR_CODE_40006(40006, "不合法的文件大小"), + ERROR_CODE_40007(40007, "不合法的media_id参数"), + ERROR_CODE_40008(40008, "不合法的msgtype参数"), + ERROR_CODE_40009(40009, "上传图片大小不是有效值"), + ERROR_CODE_40011(40011, "上传视频大小不是有效值"), + ERROR_CODE_40013(40013, "不合法的CorpID"), + ERROR_CODE_40014(40014, "不合法的access_token"), + ERROR_CODE_40016(40016, "不合法的按钮个数"), + ERROR_CODE_40017(40017, "不合法的按钮类型"), + ERROR_CODE_40018(40018, "不合法的按钮名字长度"), + ERROR_CODE_40019(40019, "不合法的按钮KEY长度"), + ERROR_CODE_40020(40020, "不合法的按钮URL长度"), + ERROR_CODE_40022(40022, "不合法的子菜单级数"), + ERROR_CODE_40023(40023, "不合法的子菜单按钮个数"), + ERROR_CODE_40024(40024, "不合法的子菜单按钮类型"), + ERROR_CODE_40025(40025, "不合法的子菜单按钮名字长度"), + ERROR_CODE_40026(40026, "不合法的子菜单按钮KEY长度"), + ERROR_CODE_40027(40027, "不合法的子菜单按钮URL长度"), + ERROR_CODE_40029(40029, "不合法的oauth_code"), + ERROR_CODE_40031(40031, "不合法的UserID列表"), + ERROR_CODE_40032(40032, "不合法的UserID列表长度"), + ERROR_CODE_40033(40033, "不合法的请求字符"), + ERROR_CODE_40035(40035, "不合法的参数"), + ERROR_CODE_40036(40036, "不合法的模板id长度"), + ERROR_CODE_40037(40037, "无效的模板id"), + ERROR_CODE_40039(40039, "不合法的url长度"), + ERROR_CODE_40050(40050, "chatid不存在"), + ERROR_CODE_40054(40054, "不合法的子菜单url域名"), + ERROR_CODE_40055(40055, "不合法的菜单url域名"), + ERROR_CODE_40056(40056, "不合法的agentid"), + ERROR_CODE_40057(40057, "不合法的callbackurl或者callbackurl验证失败"), + ERROR_CODE_40058(40058, "不合法的参数"), + ERROR_CODE_40059(40059, "不合法的上报地理位置标志位"), + ERROR_CODE_40063(40063, "参数为空"), + ERROR_CODE_40066(40066, "不合法的部门列表"), + ERROR_CODE_40068(40068, "不合法的标签ID"), + ERROR_CODE_40070(40070, "指定的标签范围结点全部无效"), + ERROR_CODE_40071(40071, "不合法的标签名字"), + ERROR_CODE_40072(40072, "不合法的标签名字长度"), + ERROR_CODE_40073(40073, "不合法的openid"), + ERROR_CODE_40074(40074, "news消息不支持保密消息类型"), + ERROR_CODE_40077(40077, "不合法的pre_auth_code参数"), + ERROR_CODE_40078(40078, "不合法的auth_code参数"), + ERROR_CODE_40080(40080, "不合法的suite_secret"), + ERROR_CODE_40082(40082, "不合法的suite_token"), + ERROR_CODE_40083(40083, "不合法的suite_id"), + ERROR_CODE_40084(40084, "不合法的permanent_code参数"), + ERROR_CODE_40085(40085, "不合法的的suite_ticket参数"), + ERROR_CODE_40086(40086, "不合法的第三方应用appid"), + ERROR_CODE_40088(40088, "jobid不存在"), + ERROR_CODE_40089(40089, "批量任务的结果已清理"), + ERROR_CODE_40091(40091, "secret不合法"), + ERROR_CODE_40092(40092, "导入文件存在不合法的内容"), + ERROR_CODE_40093(40093, "jsapi签名错误"), + ERROR_CODE_40094(40094, "不合法的URL"), + ERROR_CODE_40096(40096, "不合法的外部联系人userid"), + ERROR_CODE_40097(40097, "该成员尚未离职"), + ERROR_CODE_40098(40098, "成员尚未实名认证"), + ERROR_CODE_40099(40099, "外部联系人的数量已达上限"), + ERROR_CODE_40100(40100, "此用户的外部联系人已经在转移流程中"), + ERROR_CODE_40102(40102, "域名或IP不可与应用市场上架应用重复"), + ERROR_CODE_40123(40123, "上传临时图片素材,图片格式非法"), + ERROR_CODE_40124(40124, "推广活动里的sn禁止绑定"), + ERROR_CODE_40125(40125, "无效的openuserid参数"), + ERROR_CODE_40126(40126, "企业标签个数达到上限,最多为3000个"), + ERROR_CODE_40127(40127, "不支持的uri schema"), + ERROR_CODE_40128(40128, "客户转接过于频繁(90天内只允许转接一次,同一个客户最多只能转接两次)"), + ERROR_CODE_40129(40129, "当前客户正在转接中"), + ERROR_CODE_40130(40130, "原跟进人与接手人一样,不可继承"), + ERROR_CODE_40131(40131, "handover_userid 并不是外部联系人的跟进人"), + ERROR_CODE_41001(41001, "缺少access_token参数"), + ERROR_CODE_41002(41002, "缺少corpid参数"), + ERROR_CODE_41004(41004, "缺少secret参数"), + ERROR_CODE_41006(41006, "缺少media_id参数"), + ERROR_CODE_41008(41008, "缺少auth code参数"), + ERROR_CODE_41009(41009, "缺少userid参数"), + ERROR_CODE_41010(41010, "缺少url参数"), + ERROR_CODE_41011(41011, "缺少agentid参数"), + ERROR_CODE_41016(41016, "缺少title参数"), + ERROR_CODE_41019(41019, "缺少 department 参数"), + ERROR_CODE_41017(41017, "缺少tagid参数"), + ERROR_CODE_41021(41021, "缺少suite_id参数"), + ERROR_CODE_41022(41022, "缺少suite_access_token参数"), + ERROR_CODE_41023(41023, "缺少suite_ticket参数"), + ERROR_CODE_41024(41024, "缺少secret参数"), + ERROR_CODE_41025(41025, "缺少permanent_code参数"), + ERROR_CODE_41033(41033, "缺少 description 参数"), + ERROR_CODE_41035(41035, "缺少外部联系人userid参数"), + ERROR_CODE_41036(41036, "不合法的企业对外简称"), + ERROR_CODE_41037(41037, "缺少「联系我」type参数"), + ERROR_CODE_41038(41038, "缺少「联系我」scene参数"), + ERROR_CODE_41039(41039, "无效的「联系我」type参数"), + ERROR_CODE_41040(41040, "无效的「联系我」scene参数"), + ERROR_CODE_41041(41041, "「联系我」使用人数超过限制"), + ERROR_CODE_41042(41042, "无效的「联系我」style参数"), + ERROR_CODE_41043(41043, "缺少「联系我」config_id参数"), + ERROR_CODE_41044(41044, "无效的「联系我」config_id参数"), + ERROR_CODE_41045(41045, "API添加「联系我」达到数量上限"), + ERROR_CODE_41046(41046, "缺少企业群发消息id"), + ERROR_CODE_41047(41047, "无效的企业群发消息id"), + ERROR_CODE_41048(41048, "无可发送的客户"), + ERROR_CODE_41049(41049, "缺少欢迎语code参数"), + ERROR_CODE_41050(41050, "无效的欢迎语code"), + ERROR_CODE_41051(41051, "客户和服务人员已经开始聊天了"), + ERROR_CODE_41052(41052, "无效的发送时间"), + ERROR_CODE_41053(41053, "客户未同意聊天存档"), + ERROR_CODE_41054(41054, "该用户尚未激活"), + ERROR_CODE_41055(41055, "群欢迎语模板数量达到上限"), + ERROR_CODE_41056(41056, "外部联系人id类型不正确"), + ERROR_CODE_41057(41057, "企业或服务商未绑定微信开发者账号"), + ERROR_CODE_41058(41058, "无此群欢迎语模板的编辑权限"), + ERROR_CODE_41059(41059, "缺少moment_id参数"), + ERROR_CODE_41060(41060, "不合法的moment_id参数"), + ERROR_CODE_41061(41061, "不合法朋友圈发送成员userid,当前朋友圈并非此用户发表"), + ERROR_CODE_41062(41062, "企业创建的朋友圈尚未被成员userid发表"), + ERROR_CODE_41063(41063, "群发消息正在被派发中,请稍后再试"), + ERROR_CODE_41064(41064, "附件大小超过限制"), + ERROR_CODE_41065(41065, "无效的附件类型"), + ERROR_CODE_41066(41066, "用户视频号名称错误"), + ERROR_CODE_41067(41067, "朋友圈moment_id类型错误"), + ERROR_CODE_41068(41068, "聊天敏感词列表超过了限制"), + ERROR_CODE_41069(41069, "聊天敏感词规则总数超过了限制"), + ERROR_CODE_41070(41070, "无效的聊天敏感词规则id"), + ERROR_CODE_41071(41071, "聊天敏感词规则已经被删除"), + ERROR_CODE_41072(41072, "资源附件场景使用错误"), + ERROR_CODE_41073(41073, "商品图册描述不符合标准"), + ERROR_CODE_41074(41074, "商品图册数据已经被删除"), + ERROR_CODE_41075(41075, "无效的商品图册id或者数据不存在"), + ERROR_CODE_41076(41076, "聊天敏感词规则适用范围超过限制"), + ERROR_CODE_41077(41077, "聊天敏感词规则名称不唯一"), + ERROR_CODE_41078(41078, "创建朋友圈正在进行的异步任务总数超过了限制"), + ERROR_CODE_41079(41079, "朋友圈正在被派发中,请稍后再试"), + ERROR_CODE_41102(41102, "缺少菜单名"), + ERROR_CODE_42001(42001, "access_token已过期"), + ERROR_CODE_42007(42007, "pre_auth_code已过期"), + ERROR_CODE_42009(42009, "suite_access_token已过期"), + ERROR_CODE_42012(42012, "jsapi_ticket不可用,一般是没有正确调用接口来创建jsapi_ticket"), + ERROR_CODE_42013(42013, "小程序未登陆或登录态已经过期"), + ERROR_CODE_42014(42014, "任务卡片消息的task_id不合法"), + ERROR_CODE_42015(42015, "更新的消息的应用与发送消息的应用不匹配"), + ERROR_CODE_42016(42016, "更新的task_id不存在"), + ERROR_CODE_42017(42017, "按钮key值不存在"), + ERROR_CODE_42018(42018, "按钮key值不合法"), + ERROR_CODE_42019(42019, "缺少按钮key值不合法"), + ERROR_CODE_42020(42020, "缺少按钮名称"), + ERROR_CODE_42021(42021, "device_access_token 过期"), + ERROR_CODE_42022(42022, "code已经被使用过。只能使用一次"), + ERROR_CODE_42027(42027, "Template_Card.horizontal_content_list.keyname 字段缺失"), + ERROR_CODE_42028(42028, "Template_Card 缺失 Url,card_action、horizontal_content_list、jump_list缺失该字段都可能报此错误"), + ERROR_CODE_42029(42029, "Template_Card 缺失 mediaid,Template_Card.horizontal_content_list.mediaid 字段缺失"), + ERROR_CODE_42030(42030, "Template_Card 缺失 appid,card_action、jump_list 缺失该字段都可能报此错误"), + ERROR_CODE_42031(42031, "Template_Card.CardType 字段不合法"), + ERROR_CODE_42033(42033, "Template_Card.缺失 Title,vertical_content_list、jump_list缺失该字段都可能报此错误"), + ERROR_CODE_42035(42035, "Template_Card.horizontal_content_list 数组长度不合法"), + ERROR_CODE_42036(42036, "Template_Card.vertical_content_list 数组长度不合法"), + ERROR_CODE_42037(42037, "Template_Card.option_list 数组长度不合法"), + ERROR_CODE_42038(42038, "Template_Card.button_list.text 缺失或不合法"), + ERROR_CODE_42039(42039, "Template_Card.button_list.key 缺失或不合法"), + ERROR_CODE_42040(42040, "Template_Card.option_list.id 缺失或不合法"), + ERROR_CODE_42041(42041, "Template_Card.option_list.text 缺失或不合法"), + ERROR_CODE_42042(42042, "Template_Card.jump_list 数组长度不合法"), + ERROR_CODE_42043(42043, "Template_Card.question_Key 缺失或不合法"), + ERROR_CODE_42044(42044, "Template_Card.card_image.url 缺失或不合法"), + ERROR_CODE_42045(42045, "Template_Card.card_action 缺失或不合法"), + ERROR_CODE_42046(42046, "Template_Card.submit_button.key 缺失或不合法"), + ERROR_CODE_42047(42047, "Template_Card.select_list 数组长度不合法"), + ERROR_CODE_42049(42049, "Template_Card.submit_button.text 缺失或不合法"), + ERROR_CODE_43004(43004, "指定的userid未绑定微信或未关注微工作台(原企业号)"), + ERROR_CODE_43009(43009, "企业未验证主体"), + ERROR_CODE_43012(43012, "应用需配置回调url"), + ERROR_CODE_44001(44001, "多媒体文件为空"), + ERROR_CODE_44004(44004, "文本消息content参数为空"), + ERROR_CODE_45001(45001, "多媒体文件大小超过限制"), + ERROR_CODE_45002(45002, "消息内容大小超过限制"), + ERROR_CODE_45004(45004, "应用description参数长度不符合系统限制"), + ERROR_CODE_45007(45007, "语音播放时间超过限制"), + ERROR_CODE_45008(45008, "图文消息的文章数量不符合系统限制"), + ERROR_CODE_45009(45009, "接口调用超过限制"), + ERROR_CODE_45022(45022, "应用name参数长度不符合系统限制"), + ERROR_CODE_45024(45024, "帐号数量超过上限"), + ERROR_CODE_45026(45026, "触发删除用户数的保护"), + ERROR_CODE_45029(45029, "回包大小超过上限"), + ERROR_CODE_45032(45032, "图文消息author参数长度超过限制"), + ERROR_CODE_45033(45033, "接口并发调用超过限制"), + ERROR_CODE_45034(45034, "url必须有协议头"), + ERROR_CODE_46003(46003, "菜单未设置"), + ERROR_CODE_46004(46004, "指定的用户不存在"), + ERROR_CODE_48002(48002, "API接口无权限调用"), + ERROR_CODE_48003(48003, "不合法的suite_id"), + ERROR_CODE_48004(48004, "授权关系无效"), + ERROR_CODE_48005(48005, "API接口已废弃"), + ERROR_CODE_48006(48006, "接口权限被收回"), + ERROR_CODE_49004(49004, "签名不匹配"), + ERROR_CODE_49008(49008, "群已经解散"), + ERROR_CODE_50001(50001, "redirect_url未登记可信域名"), + ERROR_CODE_50002(50002, "成员不在权限范围"), + ERROR_CODE_50003(50003, "应用已禁用"), + ERROR_CODE_50100(50100, "分页查询的游标无效"), + ERROR_CODE_60001(60001, "部门长度不符合限制"), + ERROR_CODE_60003(60003, "部门ID不存在"), + ERROR_CODE_60004(60004, "父部门不存在"), + ERROR_CODE_60005(60005, "部门下存在成员"), + ERROR_CODE_60006(60006, "部门下存在子部门"), + ERROR_CODE_60007(60007, "不允许删除根部门"), + ERROR_CODE_60008(60008, "部门已存在"), + ERROR_CODE_60009(60009, "部门名称含有非法字符"), + ERROR_CODE_60010(60010, "部门存在循环关系"), + ERROR_CODE_60011(60011, "指定的成员/部门/标签参数无权限"), + ERROR_CODE_60012(60012, "不允许删除默认应用"), + ERROR_CODE_60020(60020, "访问ip不在白名单之中"), + ERROR_CODE_60021(60021, "userid不在应用可见范围内"), + ERROR_CODE_60028(60028, "不允许修改第三方应用的主页 URL"), + ERROR_CODE_60102(60102, "UserID已存在"), + ERROR_CODE_60103(60103, "手机号码不合法"), + ERROR_CODE_60104(60104, "手机号码已存在"), + ERROR_CODE_60105(60105, "邮箱不合法"), + ERROR_CODE_60106(60106, "邮箱已存在"), + ERROR_CODE_60107(60107, "微信号不合法"), + ERROR_CODE_60110(60110, "用户所属部门数量超过限制"), + ERROR_CODE_60111(60111, "UserID不存在"), + ERROR_CODE_60112(60112, "成员name参数不合法"), + ERROR_CODE_60123(60123, "无效的部门id"), + ERROR_CODE_60124(60124, "无效的父部门id"), + ERROR_CODE_60125(60125, "非法部门名字"), + ERROR_CODE_60127(60127, "缺少department参数"), + ERROR_CODE_60129(60129, "成员手机和邮箱都为空"), + ERROR_CODE_60132(60132, "is_leader_in_dept和department的元素个数不一致"), + ERROR_CODE_60136(60136, "记录不存在"), + ERROR_CODE_60137(60137, "家长手机号重复"), + ERROR_CODE_60203(60203, "不合法的模版ID"), + ERROR_CODE_60204(60204, "模版状态不可用"), + ERROR_CODE_60205(60205, "模版关键词不匹配"), + ERROR_CODE_60206(60206, "该种类型的消息只支持第三方独立应用使用"), + ERROR_CODE_60207(60207, "第三方独立应用只允许发送模板消息"), + ERROR_CODE_60208(60208, "第三方独立应用不支持指定@all,不支持参数toparty和totag"), + ERROR_CODE_60209(60209, "缺少操作者vid"), + ERROR_CODE_60210(60210, "选择成员列表为空"), + ERROR_CODE_60211(60211, "SelectedTicket为空"), + ERROR_CODE_60214(60214, "仅支持第三方应用调用"), + ERROR_CODE_60215(60215, "传入SelectedTicket数量超过最大限制(10个)"), + ERROR_CODE_60217(60217, "当前操作者无权限,操作者需要授权或者在可见范围内"), + ERROR_CODE_60218(60218, "仅支持成员授权模式的应用可调用"), + ERROR_CODE_60219(60219, "消费SelectedTicket和创建SelectedTicket的应用appid不匹配"), + ERROR_CODE_60220(60220, "缺少corpappid"), + ERROR_CODE_60221(60221, "open_userid对应的服务商不是当前服务商"), + ERROR_CODE_60222(60222, "非法SelectedTicket"), + ERROR_CODE_60223(60223, "非法BundleId"), + ERROR_CODE_60224(60224, "非法PackageName"), + ERROR_CODE_60225(60225, "当前操作者并非SelectedTicket相关人,不能创建群聊"), + ERROR_CODE_60226(60226, "选人数量超过最大限制(2000)"), + ERROR_CODE_60227(60227, "缺少ServiceCorpid"), + ERROR_CODE_60228(60228, "缺少bind_corpid字段"), + ERROR_CODE_60229(60229, "成员或者部门id不正确"), + ERROR_CODE_60230(60230, "缺少shareticket"), + ERROR_CODE_60231(60231, "shareticket非法"), + ERROR_CODE_60233(60233, "shareticket非法"), + ERROR_CODE_60234(60234, "shareticket非法"), + ERROR_CODE_60235(60235, "缺少payment_id字段"), + ERROR_CODE_60236(60236, "缺少trade_no字段"), + ERROR_CODE_60237(60237, "传入的payment_id对应的收款项目不是由当前应用发起的"), + ERROR_CODE_60239(60239, "收款人未实名"), + ERROR_CODE_60240(60240, "收款企业尚未验证或者认证"), + ERROR_CODE_60241(60241, "付款学生或者部门id不正确"), + ERROR_CODE_60242(60242, "shareticket不能跨域名使用"), + ERROR_CODE_60243(60243, "trade_no不合法"), + ERROR_CODE_60244(60244, "shareticket不能跨APP使用"), + ERROR_CODE_65000(65000, "学校已经迁移"), + ERROR_CODE_65001(65001, "无效的关注模式"), + ERROR_CODE_65002(65002, "导入家长信息数量过多"), + ERROR_CODE_65003(65003, "学校尚未迁移"), + ERROR_CODE_65004(65004, "组织架构不存在"), + ERROR_CODE_65005(65005, "无效的同步模式"), + ERROR_CODE_65006(65006, "无效的管理员类型"), + ERROR_CODE_65007(65007, "无效的家校部门类型"), + ERROR_CODE_65008(65008, "无效的入学年份"), + ERROR_CODE_65009(65009, "无效的标准年级类型"), + ERROR_CODE_65010(65010, "此userid并不是学生"), + ERROR_CODE_65011(65011, "家长userid数量超过限制"), + ERROR_CODE_65012(65012, "学生userid数量超过限制"), + ERROR_CODE_65013(65013, "学生已有家长"), + ERROR_CODE_65014(65014, "非学校企业"), + ERROR_CODE_65015(65015, "父部门类型不匹配"), + ERROR_CODE_65018(65018, "家长人数达到上限"), + ERROR_CODE_65022(65022, "家校通迅录无权限"), + ERROR_CODE_65023(65023, "家校通迅录无权限"), + ERROR_CODE_660001(660001, "无效的商户号"), + ERROR_CODE_660002(660002, "无效的企业收款人id"), + ERROR_CODE_660003(660003, "userid不在应用的可见范围"), + ERROR_CODE_660004(660004, "partyid不在应用的可见范围"), + ERROR_CODE_660005(660005, "tagid不在应用的可见范围"), + ERROR_CODE_660006(660006, "找不到该商户号"), + ERROR_CODE_660007(660007, "申请已经存在"), + ERROR_CODE_660008(660008, "商户号已经绑定"), + ERROR_CODE_660009(660009, "商户号主体和商户主体不一致"), + ERROR_CODE_660010(660010, "超过商户号绑定数量限制"), + ERROR_CODE_660011(660011, "商户号未绑定"), + ERROR_CODE_670001(670001, "应用不在共享范围"), + ERROR_CODE_72023(72023, "发票已被其他公众号锁定"), + ERROR_CODE_72024(72024, "发票状态错误"), + ERROR_CODE_72037(72037, "存在发票不属于该用户"), + ERROR_CODE_80001(80001, "可信域名不正确,或者无ICP备案"), + ERROR_CODE_81001(81001, "部门下的结点数超过限制(3W)"), + ERROR_CODE_81002(81002, "部门最多15层"), + ERROR_CODE_81003(81003, "标签下节点个数超过30000个"), + ERROR_CODE_81011(81011, "无权限操作标签"), + ERROR_CODE_81012(81012, "缺失可见范围"), + ERROR_CODE_81013(81013, "UserID、部门ID、标签ID全部非法或无权限"), + ERROR_CODE_81014(81014, "标签添加成员,单次添加user或party过多"), + ERROR_CODE_81015(81015, "邮箱域名需要跟企业邮箱域名一致"), + ERROR_CODE_81016(81016, "logined_userid字段缺失"), + ERROR_CODE_81017(81017, "请求个数超过限制"), + ERROR_CODE_81018(81018, "该服务商可获取名字数量配额不足"), + ERROR_CODE_81019(81019, "items数组成员缺少id字段"), + ERROR_CODE_81020(81020, "items数组成员缺少type字段"), + ERROR_CODE_81021(81021, "items数组成员的type字段不合法"), + ERROR_CODE_82001(82001, "指定的成员/部门/标签全部为空"), + ERROR_CODE_82002(82002, "不合法的PartyID列表长度"), + ERROR_CODE_82003(82003, "不合法的TagID列表长度"), + ERROR_CODE_82004(82004, "不合法的消息内容"), + ERROR_CODE_84014(84014, "成员票据过期"), + ERROR_CODE_84015(84015, "成员票据无效"), + ERROR_CODE_84019(84019, "缺少templateid参数"), + ERROR_CODE_84020(84020, "templateid不存在"), + ERROR_CODE_84021(84021, "缺少register_code参数"), + ERROR_CODE_84022(84022, "无效的register_code参数"), + ERROR_CODE_84023(84023, "不允许调用设置通讯录同步完成接口"), + ERROR_CODE_84024(84024, "无注册信息"), + ERROR_CODE_84025(84025, "不符合的state参数"), + ERROR_CODE_84052(84052, "缺少caller参数"), + ERROR_CODE_84053(84053, "缺少callee参数"), + ERROR_CODE_84054(84054, "缺少auth_corpid参数"), + ERROR_CODE_84055(84055, "超过拨打公费电话频率"), + ERROR_CODE_84056(84056, "被拨打用户安装应用时未授权拨打公费电话权限"), + ERROR_CODE_84057(84057, "公费电话余额不足"), + ERROR_CODE_84058(84058, "caller 呼叫号码不支持"), + ERROR_CODE_84059(84059, "号码非法"), + ERROR_CODE_84060(84060, "callee 呼叫号码不支持"), + ERROR_CODE_84061(84061, "不存在外部联系人的关系"), + ERROR_CODE_84062(84062, "未开启公费电话应用"), + ERROR_CODE_84063(84063, "caller不存在"), + ERROR_CODE_84064(84064, "callee不存在"), + ERROR_CODE_84065(84065, "caller跟callee电话号码一致"), + ERROR_CODE_84066(84066, "服务商拨打次数超过限制"), + ERROR_CODE_84067(84067, "管理员收到的服务商公费电话个数超过限制"), + ERROR_CODE_84069(84069, "拨打方被限制拨打公费电话"), + ERROR_CODE_84070(84070, "不支持的电话号码"), + ERROR_CODE_84071(84071, "不合法的外部联系人授权码"), + ERROR_CODE_84072(84072, "应用未配置客服"), + ERROR_CODE_84073(84073, "客服userid不在应用配置的客服列表中"), + ERROR_CODE_84074(84074, "没有外部联系人权限"), + ERROR_CODE_84075(84075, "不合法或过期的authcode"), + ERROR_CODE_84076(84076, "缺失authcode"), + ERROR_CODE_84077(84077, "订单价格过高,无法受理"), + ERROR_CODE_84078(84078, "购买人数不正确"), + ERROR_CODE_84079(84079, "价格策略不存在"), + ERROR_CODE_84080(84080, "订单不存在"), + ERROR_CODE_84081(84081, "存在未支付订单"), + ERROR_CODE_84082(84082, "存在申请退款中的订单"), + ERROR_CODE_84083(84083, "非服务人员"), + ERROR_CODE_84084(84084, "非跟进用户"), + ERROR_CODE_84085(84085, "应用已下架"), + ERROR_CODE_84086(84086, "订单人数超过可购买最大人数"), + ERROR_CODE_84087(84087, "打开订单支付前禁止关闭订单"), + ERROR_CODE_84088(84088, "禁止关闭已支付的订单"), + ERROR_CODE_84089(84089, "订单已支付"), + ERROR_CODE_84090(84090, "缺失user_ticket"), + ERROR_CODE_84091(84091, "订单价格不可低于下限"), + ERROR_CODE_84092(84092, "无法发起代下单操作"), + ERROR_CODE_84093(84093, "代理关系已占用,无法代下单"), + ERROR_CODE_84094(84094, "该应用未配置代理分润规则,请先联系应用服务商处理"), + ERROR_CODE_84095(84095, "免费试用版,无法扩容"), + ERROR_CODE_84096(84096, "免费试用版,无法续期"), + ERROR_CODE_84097(84097, "当前企业有未处理订单"), + ERROR_CODE_84098(84098, "固定总量,无法扩容"), + ERROR_CODE_84099(84099, "非购买状态,无法扩容"), + ERROR_CODE_84100(84100, "未购买过此应用,无法续期"), + ERROR_CODE_84101(84101, "企业已试用付费版本,无法全新购买"), + ERROR_CODE_84102(84102, "企业当前应用状态已过期,无法扩容"), + ERROR_CODE_84103(84103, "仅可修改未支付订单"), + ERROR_CODE_84104(84104, "订单已支付,无法修改"), + ERROR_CODE_84105(84105, "订单已被取消,无法修改"), + ERROR_CODE_84106(84106, "企业含有该应用的待支付订单,无法代下单"), + ERROR_CODE_84107(84107, "企业含有该应用的退款中订单,无法代下单"), + ERROR_CODE_84108(84108, "企业含有该应用的待生效订单,无法代下单"), + ERROR_CODE_84109(84109, "订单定价不能未0"), + ERROR_CODE_84110(84110, "新安装应用不在试用状态,无法升级为付费版"), + ERROR_CODE_84111(84111, "无足够可用优惠券"), + ERROR_CODE_84112(84112, "无法关闭未支付订单"), + ERROR_CODE_84113(84113, "无付费信息"), + ERROR_CODE_84114(84114, "虚拟版本不支持下单"), + ERROR_CODE_84115(84115, "虚拟版本不支持扩容"), + ERROR_CODE_84116(84116, "虚拟版本不支持续期"), + ERROR_CODE_84117(84117, "在虚拟正式版期内不能扩容"), + ERROR_CODE_84118(84118, "虚拟正式版期内不能变更版本"), + ERROR_CODE_84119(84119, "当前企业未报备,无法进行代下单"), + ERROR_CODE_84120(84120, "当前应用版本已删除"), + ERROR_CODE_84121(84121, "应用版本已删除,无法扩容"), + ERROR_CODE_84122(84122, "应用版本已删除,无法续期"), + ERROR_CODE_84123(84123, "非虚拟版本,无法升级"), + ERROR_CODE_84124(84124, "非行业方案订单,不能添加部分应用版本的订单"), + ERROR_CODE_84125(84125, "购买人数不能少于最少购买人数"), + ERROR_CODE_84126(84126, "购买人数不能多于最大购买人数"), + ERROR_CODE_84127(84127, "无应用管理权限"), + ERROR_CODE_84128(84128, "无该行业方案下全部应用的管理权限"), + ERROR_CODE_84129(84129, "付费策略已被删除,无法下单"), + ERROR_CODE_84130(84130, "订单生效时间不合法"), + ERROR_CODE_84200(84200, "文件转译解析错误"), + ERROR_CODE_85002(85002, "包含不合法的词语"), + ERROR_CODE_85004(85004, "每企业每个月设置的可信域名不可超过20个"), + ERROR_CODE_85005(85005, "可信域名未通过所有权校验"), + ERROR_CODE_86001(86001, "参数 chatid 不合法"), + ERROR_CODE_86003(86003, "参数 chatid 不存在"), + ERROR_CODE_86004(86004, "参数 群名不合法"), + ERROR_CODE_86005(86005, "参数 群主不合法"), + ERROR_CODE_86006(86006, "群成员数过多或过少"), + ERROR_CODE_86007(86007, "不合法的群成员"), + ERROR_CODE_86008(86008, "非法操作非自己创建的群"), + ERROR_CODE_86101(86101, "仅群主才有操作权限"), + ERROR_CODE_86201(86201, "参数 需要chatid"), + ERROR_CODE_86202(86202, "参数 需要群名"), + ERROR_CODE_86203(86203, "参数 需要群主"), + ERROR_CODE_86204(86204, "参数 需要群成员"), + ERROR_CODE_86205(86205, "参数 字符串chatid过长"), + ERROR_CODE_86206(86206, "参数 数字chatid过大"), + ERROR_CODE_86207(86207, "群主不在群成员列表"), + ERROR_CODE_86214(86214, "群发类型不合法"), + ERROR_CODE_86215(86215, "会话ID已经存在"), + ERROR_CODE_86216(86216, "存在非法会话成员ID"), + ERROR_CODE_86217(86217, "会话发送者不在会话成员列表中"), + ERROR_CODE_86220(86220, "指定的会话参数不合法"), + ERROR_CODE_86224(86224, "不是受限群,不允许使用该接口"), + ERROR_CODE_90001(90001, "未认证摇一摇周边"), + ERROR_CODE_90002(90002, "缺少摇一摇周边ticket参数"), + ERROR_CODE_90003(90003, "摇一摇周边ticket参数不合法"), + ERROR_CODE_90100(90100, "非法的对外属性类型"), + ERROR_CODE_90101(90101, "对外属性:文本类型长度不合法"), + ERROR_CODE_90102(90102, "对外属性:网页类型标题长度不合法"), + ERROR_CODE_90103(90103, "对外属性:网页url不合法"), + ERROR_CODE_90104(90104, "对外属性:小程序类型标题长度不合法"), + ERROR_CODE_90105(90105, "对外属性:小程序类型pagepath不合法"), + ERROR_CODE_90106(90106, "对外属性:请求参数不合法"), + ERROR_CODE_90200(90200, "缺少小程序appid参数"), + ERROR_CODE_90201(90201, "小程序通知的content_item个数超过限制"), + ERROR_CODE_90202(90202, "小程序通知中的key长度不合法"), + ERROR_CODE_90203(90203, "小程序通知中的value长度不合法"), + ERROR_CODE_90204(90204, "小程序通知中的page参数不合法"), + ERROR_CODE_90206(90206, "小程序未关联到企业中"), + ERROR_CODE_90207(90207, "不合法的小程序appid"), + ERROR_CODE_90208(90208, "小程序appid不匹配"), + ERROR_CODE_90211(90211, "登录时传入的suiteid不合法"), + ERROR_CODE_90212(90212, "登录时传入的suiteid和使用的小程序绑定的第三方应用不匹配"), + ERROR_CODE_90300(90300, "orderid 不合法"), + ERROR_CODE_90302(90302, "付费应用已过期"), + ERROR_CODE_90303(90303, "付费应用超过最大使用人数"), + ERROR_CODE_90304(90304, "订单中心服务异常,请稍后重试"), + ERROR_CODE_90305(90305, "参数错误,errmsg中有提示具体哪个参数有问题"), + ERROR_CODE_90306(90306, "商户设置不合法,详情请见errmsg"), + ERROR_CODE_90307(90307, "登录态过期"), + ERROR_CODE_90308(90308, "在开启IP鉴权的前提下,识别为无效的请求IP"), + ERROR_CODE_90309(90309, "订单已经存在,请勿重复下单"), + ERROR_CODE_90310(90310, "找不到订单"), + ERROR_CODE_90311(90311, "关单失败, 可能原因:该单并没被拉起支付页面; 已经关单;已经支付;渠道失败;单处于保护状态;等等"), + ERROR_CODE_90312(90312, "退款请求失败, 详情请看errmsg"), + ERROR_CODE_90313(90313, "退款调用频率限制,超过规定的阈值"), + ERROR_CODE_90314(90314, "订单状态错误,可能未支付,或者当前状态操作受限"), + ERROR_CODE_90315(90315, "退款请求失败,主键冲突,请核实退款refund_id是否已使用"), + ERROR_CODE_90316(90316, "退款原因编号不对"), + ERROR_CODE_90317(90317, "尚未注册成为供应商"), + ERROR_CODE_90318(90318, "参数nonce_str 为空或者重复,判定为重放攻击"), + ERROR_CODE_90319(90319, "时间戳为空或者与系统时间间隔太大"), + ERROR_CODE_90320(90320, "订单token无效"), + ERROR_CODE_90321(90321, "订单token已过有效时间"), + ERROR_CODE_90322(90322, "旧套件(包含多个应用的套件)不支持支付系统"), + ERROR_CODE_90323(90323, "单价超过限额"), + ERROR_CODE_90324(90324, "商品数量超过限额"), + ERROR_CODE_90325(90325, "预支单已经存在"), + ERROR_CODE_90326(90326, "预支单单号非法"), + ERROR_CODE_90327(90327, "该预支单已经结算下单"), + ERROR_CODE_90328(90328, "结算下单失败,详情请看errmsg"), + ERROR_CODE_90329(90329, "该订单号已经被预支单占用"), + ERROR_CODE_90330(90330, "创建供应商失败"), + ERROR_CODE_90331(90331, "更新供应商失败"), + ERROR_CODE_90332(90332, "还没签署合同"), + ERROR_CODE_90333(90333, "创建合同失败"), + ERROR_CODE_90338(90338, "已经过了可退款期限"), + ERROR_CODE_90339(90339, "供应商主体名包含非法字符"), + ERROR_CODE_90340(90340, "创建客户失败,可能信息真实性校验失败"), + ERROR_CODE_90341(90341, "退款金额大于付款金额"), + ERROR_CODE_90342(90342, "退款金额超过账户余额"), + ERROR_CODE_90343(90343, "退款单号已经存在"), + ERROR_CODE_90344(90344, "指定的付款渠道无效"), + ERROR_CODE_90345(90345, "超过5w人民币不可指定微信支付渠道"), + ERROR_CODE_90346(90346, "同一单的退款次数超过限制"), + ERROR_CODE_90347(90347, "退款金额不可为0"), + ERROR_CODE_90348(90348, "管理端没配置支付密钥"), + ERROR_CODE_90349(90349, "记录数量太大"), + ERROR_CODE_90350(90350, "银行信息真实性校验失败"), + ERROR_CODE_90351(90351, "应用状态异常"), + ERROR_CODE_90352(90352, "延迟试用期天数超过限制"), + ERROR_CODE_90353(90353, "预支单列表不可为空"), + ERROR_CODE_90354(90354, "预支单列表数量超过限制"), + ERROR_CODE_90355(90355, "关联有退款预支单,不可删除"), + ERROR_CODE_90356(90356, "不能0金额下单"), + ERROR_CODE_90357(90357, "代下单必须指定支付渠道"), + ERROR_CODE_90358(90358, "预支单或代下单,不支持部分退款"), + ERROR_CODE_90359(90359, "预支单与下单者企业不匹配"), + ERROR_CODE_90381(90381, "参数 refunded_credit_orderid 不合法"), + ERROR_CODE_90456(90456, "必须指定组织者"), + ERROR_CODE_90457(90457, "日历ID异常"), + ERROR_CODE_90458(90458, "日历ID列表不能为空"), + ERROR_CODE_90459(90459, "日历已删除"), + ERROR_CODE_90460(90460, "日程已删除"), + ERROR_CODE_90461(90461, "日程ID异常"), + ERROR_CODE_90462(90462, "日程ID列表不能为空"), + ERROR_CODE_90463(90463, "不能变更组织者"), + ERROR_CODE_90464(90464, "参与者数量超过限制"), + ERROR_CODE_90465(90465, "不支持的重复类型"), + ERROR_CODE_90466(90466, "不能操作别的应用创建的日历/日程"), + ERROR_CODE_90467(90467, "星期参数异常"), + ERROR_CODE_90468(90468, "不能变更组织者"), + ERROR_CODE_90469(90469, "每页大小超过限制"), + ERROR_CODE_90470(90470, "页数异常"), + ERROR_CODE_90471(90471, "提醒时间异常"), + ERROR_CODE_90472(90472, "没有日历/日程操作权限"), + ERROR_CODE_90473(90473, "颜色参数异常"), + ERROR_CODE_90474(90474, "组织者不能与参与者重叠"), + ERROR_CODE_90475(90475, "不是组织者的日历"), + ERROR_CODE_90479(90479, "不允许操作用户创建的日程"), + ERROR_CODE_90500(90500, "群主并未离职"), + ERROR_CODE_90501(90501, "该群不是客户群"), + ERROR_CODE_90502(90502, "群主已经离职"), + ERROR_CODE_90503(90503, "满人 & 99个微信成员,没办法踢,要客户端确认"), + ERROR_CODE_90504(90504, "群主没变"), + ERROR_CODE_90507(90507, "离职群正在继承处理中"), + ERROR_CODE_90508(90508, "离职群已经继承"), + ERROR_CODE_90509(90509, "非企业微信客户群"), + ERROR_CODE_90510(90510, "企业一年内无活跃用户"), + ERROR_CODE_90511(90511, "opengid不存在或者无效"), + ERROR_CODE_90603(90603, "事件分类id不合法"), + ERROR_CODE_90604(90604, "网格单元id不合法"), + ERROR_CODE_90606(90606, "该网格单元管理员达到上限,一个网格单元最多有20个管理员"), + ERROR_CODE_90607(90607, "含有成员的网格单元不能被删除"), + ERROR_CODE_90608(90608, "网格单元的名字重复了"), + ERROR_CODE_90609(90609, "网格单元的成员数超过上限"), + ERROR_CODE_90610(90610, "网格单元的成员数超过上限"), + ERROR_CODE_91040(91040, "获取ticket的类型无效"), + ERROR_CODE_92000(92000, "成员不在应用可见范围之内"), + ERROR_CODE_92001(92001, "应用没有敏感信息权限"), + ERROR_CODE_92002(92002, "不允许跨企业调用"), + ERROR_CODE_92003(92003, "不允许跨应用调用"), + ERROR_CODE_92006(92006, "该直播已经开始或取消"), + ERROR_CODE_92007(92007, "该直播回放不能被删除"), + ERROR_CODE_92008(92008, "当前应用没权限操作这个直播"), + ERROR_CODE_93000(93000, "机器人webhookurl不合法或者机器人已经被移除出群"), + ERROR_CODE_93004(93004, "机器人被停用"), + ERROR_CODE_93008(93008, "不在群里"), + ERROR_CODE_94000(94000, "应用未开启工作台自定义模式"), + ERROR_CODE_94001(94001, "不合法的type类型"), + ERROR_CODE_94002(94002, "缺少keydata字段"), + ERROR_CODE_94003(94003, "keydata的items列表长度超出限制"), + ERROR_CODE_94005(94005, "缺少list字段"), + ERROR_CODE_94006(94006, "list的items列表长度超出限制"), + ERROR_CODE_94007(94007, "缺少webview字段"), + ERROR_CODE_94008(94008, "应用未设置自定义工作台模版类型"), + ERROR_CODE_95000(95000, "不合法的open_kfid"), + ERROR_CODE_95001(95001, "发送客服消息次数限制"), + ERROR_CODE_95002(95002, "发送客服消息时间限制"), + ERROR_CODE_95003(95003, "发送客服消息可接待客户咨询数限制"), + ERROR_CODE_95004(95004, "open_kfid不存在"), + ERROR_CODE_95005(95005, "客服帐号数超过限制"), + ERROR_CODE_95006(95006, "不合法的客服帐号名"), + ERROR_CODE_95007(95007, "不合法的msgtoken"), + ERROR_CODE_95008(95008, "菜单消息的菜单项个数超过上限"), + ERROR_CODE_95009(95009, "不合法的菜单消息的菜单项类型"), + ERROR_CODE_95012(95012, "未在企业微信使用微信客服"), + ERROR_CODE_95013(95013, "会话已经结束"), + ERROR_CODE_95014(95014, "用户不是接待人员"), + ERROR_CODE_95015(95015, "管理端已经配置了专属服务"), + ERROR_CODE_95016(95016, "不允许这种状态转移"), + ERROR_CODE_95017(95017, "系统应用权限下,api开关处于关闭状态"), + ERROR_CODE_95018(95018, "发送客服消息时当前会话状态不允许发送"), + ERROR_CODE_301002(301002, "无权限操作指定的应用"), + ERROR_CODE_301005(301005, "不允许删除创建者"), + ERROR_CODE_301012(301012, "参数 position 不合法"), + ERROR_CODE_301013(301013, "参数 telephone 不合法"), + ERROR_CODE_301014(301014, "参数 english_name 不合法"), + ERROR_CODE_301015(301015, "参数 mediaid 不合法"), + ERROR_CODE_301016(301016, "上传语音文件不符合系统要求"), + ERROR_CODE_301017(301017, "上传语音文件仅支持AMR格式"), + ERROR_CODE_301021(301021, "参数 userid 无效"), + ERROR_CODE_301022(301022, "获取打卡数据失败"), + ERROR_CODE_301023(301023, "useridlist非法或超过限额"), + ERROR_CODE_301024(301024, "获取打卡记录时间间隔超限"), + ERROR_CODE_301025(301025, "审批开放接口参数错误"), + ERROR_CODE_301036(301036, "不允许更新该用户的userid"), + ERROR_CODE_301039(301039, "请求参数错误,请检查输入参数"), + ERROR_CODE_301042(301042, "ip白名单限制,请求ip不在设置白名单范围"), + ERROR_CODE_301048(301048, "sdkfileid对应的文件不存在或已过期"), + ERROR_CODE_301052(301052, "会话存档服务已过期"), + ERROR_CODE_301053(301053, "会话存档服务未开启"), + ERROR_CODE_301058(301058, "拉取会话数据请求超过大小限制,可减少limit参数"), + ERROR_CODE_301059(301059, "非内部群,不提供数据"), + ERROR_CODE_301060(301060, "拉取同意情况请求量过大,请减少到100个参数以下"), + ERROR_CODE_301061(301061, "userid或者exteropenid用户不存在"), + ERROR_CODE_302003(302003, "批量导入任务的文件中userid有重复"), + ERROR_CODE_302004(302004, "组织架构不合法(1不是一棵树,2 多个一样的partyid,3 partyid空,4 partyid name 空,5 同一个父节点下有两个子节点 部门名字一样 可能是以上情况,请一一排查)"), + ERROR_CODE_302005(302005, "批量导入系统失败,请重新尝试导入"), + ERROR_CODE_302006(302006, "批量导入任务的文件中partyid有重复"), + ERROR_CODE_302007(302007, "批量导入任务的文件中,同一个部门下有两个子部门名字一样"), + ERROR_CODE_2000002(2000002, "CorpId参数无效"), + ERROR_CODE_600001(600001, "不合法的sn"), + ERROR_CODE_600002(600002, "设备已注册"), + ERROR_CODE_600003(600003, "不合法的硬件activecode"), + ERROR_CODE_600004(600004, "该硬件尚未授权任何企业"), + ERROR_CODE_600005(600005, "硬件Secret无效"), + ERROR_CODE_600007(600007, "缺少硬件sn"), + ERROR_CODE_600008(600008, "缺少nonce参数"), + ERROR_CODE_600009(600009, "缺少timestamp参数"), + ERROR_CODE_600010(600010, "缺少signature参数"), + ERROR_CODE_600011(600011, "签名校验失败"), + ERROR_CODE_600012(600012, "长连接已经注册过设备"), + ERROR_CODE_600013(600013, "缺少activecode参数"), + ERROR_CODE_600014(600014, "设备未网络注册"), + ERROR_CODE_600015(600015, "缺少secret参数"), + ERROR_CODE_600016(600016, "设备未激活"), + ERROR_CODE_600018(600018, "无效的起始结束时间"), + ERROR_CODE_600020(600020, "设备未登录"), + ERROR_CODE_600021(600021, "设备sn已存在"), + ERROR_CODE_600023(600023, "时间戳已失效"), + ERROR_CODE_600024(600024, "固件大小超过5M"), + ERROR_CODE_600025(600025, "固件名为空或者超过20字节"), + ERROR_CODE_600026(600026, "固件信息不存在"), + ERROR_CODE_600027(600027, "非法的固件参数"), + ERROR_CODE_600028(600028, "固件版本已存在"), + ERROR_CODE_600029(600029, "非法的固件版本"), + ERROR_CODE_600030(600030, "缺少固件版本参数"), + ERROR_CODE_600031(600031, "硬件固件不允许升级"), + ERROR_CODE_600032(600032, "无法解析硬件二维码"), + ERROR_CODE_600033(600033, "设备型号id冲突"), + ERROR_CODE_600034(600034, "指纹数据大小超过限制"), + ERROR_CODE_600035(600035, "人脸数据大小超过限制"), + ERROR_CODE_600036(600036, "设备sn冲突"), + ERROR_CODE_600037(600037, "缺失设备型号id"), + ERROR_CODE_600038(600038, "设备型号不存在"), + ERROR_CODE_600039(600039, "不支持的设备类型"), + ERROR_CODE_600040(600040, "打印任务id不存在"), + ERROR_CODE_600041(600041, "无效的offset或limit参数值"), + ERROR_CODE_600042(600042, "无效的设备型号id"), + ERROR_CODE_600043(600043, "门禁规则未设置"), + ERROR_CODE_600044(600044, "门禁规则不合法"), + ERROR_CODE_600045(600045, "设备已订阅企业信息"), + ERROR_CODE_600046(600046, "操作id和用户userid不匹配"), + ERROR_CODE_600047(600047, "secretno的status非法"), + ERROR_CODE_600048(600048, "无效的指纹算法"), + ERROR_CODE_600049(600049, "无效的人脸识别算法"), + ERROR_CODE_600050(600050, "无效的算法长度"), + ERROR_CODE_600051(600051, "设备过期"), + ERROR_CODE_600052(600052, "无效的文件分块"), + ERROR_CODE_600053(600053, "该链接已经激活"), + ERROR_CODE_600054(600054, "该链接已经订阅"), + ERROR_CODE_600055(600055, "无效的用户类型"), + ERROR_CODE_600056(600056, "无效的健康状态"), + ERROR_CODE_600057(600057, "缺少体温参数"), + ERROR_CODE_610001(610001, "永久二维码超过每个员工5000的限制"), + ERROR_CODE_610003(610003, "scene参数不合法"), + ERROR_CODE_610004(610004, "userid不在客户联系配置的使用范围内"), + ERROR_CODE_610014(610014, "无效的unionid"), + ERROR_CODE_610015(610015, "小程序对应的开放平台账号未认证"), + ERROR_CODE_610016(610016, "企业未认证"), + ERROR_CODE_610017(610017, "小程序和企业主体不一致"), + ERROR_CODE_640001(640001, "微盘不存在当前空间"), + ERROR_CODE_640002(640002, "文件不存在"), + ERROR_CODE_640003(640003, "文件已删除"), + ERROR_CODE_640004(640004, "无权限访问"), + ERROR_CODE_640005(640005, "成员不在空间内"), + ERROR_CODE_640006(640006, "超出当前成员拥有的容量"), + ERROR_CODE_640007(640007, "超出微盘的容量"), + ERROR_CODE_640008(640008, "没有空间权限"), + ERROR_CODE_640009(640009, "非法文件名"), + ERROR_CODE_640010(640010, "超出空间的最大成员数"), + ERROR_CODE_640011(640011, "json格式不匹配"), + ERROR_CODE_640012(640012, "非法的userid"), + ERROR_CODE_640013(640013, "非法的departmentid"), + ERROR_CODE_640014(640014, "空间没有有效的管理员"), + ERROR_CODE_640015(640015, "不支持设置预览权限"), + ERROR_CODE_640016(640016, "不支持设置文件水印"), + ERROR_CODE_640017(640017, "微盘管理端未开通API 权限"), + ERROR_CODE_640018(640018, "微盘管理端未设置编辑权限"), + ERROR_CODE_640019(640019, "API 调用次数超出限制"), + ERROR_CODE_640020(640020, "非法的权限类型"), + ERROR_CODE_640021(640021, "非法的fatherid"), + ERROR_CODE_640022(640022, "非法的文件内容的base64"), + ERROR_CODE_640023(640023, "非法的权限范围"), + ERROR_CODE_640024(640024, "非法的fileid"), + ERROR_CODE_640025(640025, "非法的space_name"), + ERROR_CODE_640026(640026, "非法的spaceid"), + ERROR_CODE_640027(640027, "参数错误"), + ERROR_CODE_640028(640028, "空间设置了关闭成员邀请链接"), + ERROR_CODE_640029(640029, "只支持下载普通文件,不支持下载文件夹等其他非文件实体类型"), + ERROR_CODE_844001(844001, "非法的output_file_format"), + ERROR_CODE_60252(60252, "非法的openkfid"), + ERROR_CODE_60251(60251, "缺少openkfid"), + ERROR_CODE_60253(60253, "客服不在接待人员列表中"); + + + private Integer errorCode; + private String errorMsg; + + WeErrorCodeEnum(Integer errorCode, String errorMsg) { + this.errorCode = errorCode; + this.errorMsg = errorMsg; + } + + public static WeErrorCodeEnum parseEnum(int errorCode) { + WeErrorCodeEnum[] errorCodeEnums = WeErrorCodeEnum.values(); + for (WeErrorCodeEnum errorCodeEnum : errorCodeEnums) { + if (errorCodeEnum.getErrorCode() == errorCode) { + return errorCodeEnum; + } + } + return null; + } +} diff --git a/linkwe-common/src/main/java/com/linkwechat/common/enums/WePosterSubassemblyType.java b/linkwe-common/src/main/java/com/linkwechat/common/enums/WePosterSubassemblyType.java new file mode 100644 index 0000000000000000000000000000000000000000..919d5f52d6c54c1bac3de067e724f026c2c3fb98 --- /dev/null +++ b/linkwe-common/src/main/java/com/linkwechat/common/enums/WePosterSubassemblyType.java @@ -0,0 +1,44 @@ +package com.linkwechat.common.enums; + +/** + * 海报组件类型 + * @author ws + */ +public enum WePosterSubassemblyType { + /** + * 自定义文本 + */ + plainText(0,"自定义文本"), + /** + * 图片 + */ + picture(1,"图片"), + /** + * 二维码 + */ + QRCode(2,"二维码"); + + private Integer code; + private String label; + + private WePosterSubassemblyType(Integer code,String label){ + this.code = code; + this.label = label; + } + + public Integer getCode() { + return code; + } + + public void setCode(Integer code) { + this.code = code; + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } +} diff --git a/linkwe-common/src/main/java/com/linkwechat/common/exception/wecom/WeComException.java b/linkwe-common/src/main/java/com/linkwechat/common/exception/wecom/WeComException.java index 674a19928b2d02748b06b9ee28c8325b1c0018cb..34cc961b4d70f62e3c5715fbcd79d5abe6060407 100644 --- a/linkwe-common/src/main/java/com/linkwechat/common/exception/wecom/WeComException.java +++ b/linkwe-common/src/main/java/com/linkwechat/common/exception/wecom/WeComException.java @@ -11,7 +11,7 @@ public class WeComException extends RuntimeException { protected String message; - private Integer code; + private Integer code = -1; public WeComException(String message) { diff --git a/linkwe-common/src/main/java/com/linkwechat/common/utils/DateUtils.java b/linkwe-common/src/main/java/com/linkwechat/common/utils/DateUtils.java index 49806c1dac496e7ec001655ca0ae561e4354a730..f6c5e53a7aeeee148284839fe0e74b2c848d4ec8 100644 --- a/linkwe-common/src/main/java/com/linkwechat/common/utils/DateUtils.java +++ b/linkwe-common/src/main/java/com/linkwechat/common/utils/DateUtils.java @@ -3,12 +3,19 @@ package com.linkwechat.common.utils; import java.lang.management.ManagementFactory; import java.text.ParseException; import java.text.SimpleDateFormat; +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.time.temporal.ChronoUnit; +import java.util.ArrayList; +import java.util.Calendar; import java.util.Date; +import java.util.List; + import org.apache.commons.lang3.time.DateFormatUtils; /** * 时间工具类 - * + * * @author ruoyi */ public class DateUtils extends org.apache.commons.lang3.time.DateUtils @@ -22,15 +29,15 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils public static String YYYYMMDDHHMMSS = "yyyyMMddHHmmss"; public static String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss"; - + private static String[] parsePatterns = { - "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM", + "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM", "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM", "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"}; /** * 获取当前Date型日期 - * + * * @return Date() 当前日期 */ public static Date getNowDate() @@ -40,7 +47,7 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils /** * 获取当前日期, 默认格式为yyyy-MM-dd - * + * * @return String */ public static String getDate() @@ -121,7 +128,7 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils return null; } } - + /** * 获取服务器启动时间 */ @@ -152,4 +159,263 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils // long sec = diff % nd % nh % nm / ns; return day + "天" + hour + "小时" + min + "分钟"; } + + /** + * 计算两个时间差 + */ + public static long diffTime(Date endDate, Date nowDate){ + return endDate.getTime() - nowDate.getTime(); + } + + /** + * 获取时间段内所有日期 + * @param dBegin + * @param dEnd + * @return + */ + public static List findDates(Date dBegin, Date dEnd) + { + List lDate = new ArrayList(); + lDate.add(dBegin); + Calendar calBegin = Calendar.getInstance(); + // 使用给定的 Date 设置此 Calendar 的时间 + calBegin.setTime(dBegin); + Calendar calEnd = Calendar.getInstance(); + // 使用给定的 Date 设置此 Calendar 的时间 + calEnd.setTime(dEnd); + // 测试此日期是否在指定日期之后 + while (dEnd.after(calBegin.getTime())) + { + // 根据日历的规则,为给定的日历字段添加或减去指定的时间量 + calBegin.add(Calendar.DAY_OF_MONTH, 1); + lDate.add(calBegin.getTime()); + } + return lDate; + } + + public static long getMillionSceondsBydate(String date) throws ParseException { + SimpleDateFormat sdf = new SimpleDateFormat(YYYY_MM_DD_HH_MM_SS); + long millionSeconds = sdf.parse(date).getTime();//毫秒 + return millionSeconds; + } + + + + + public static int getAge(Date birthDay) throws Exception { + Calendar cal = Calendar.getInstance(); + if (cal.before(birthDay)) { //出生日期晚于当前时间,无法计算 + throw new IllegalArgumentException( + "The birthDay is before Now.It's unbelievable!"); + } + int yearNow = cal.get(Calendar.YEAR); //当前年份 + int monthNow = cal.get(Calendar.MONTH); //当前月份 + int dayOfMonthNow = cal.get(Calendar.DAY_OF_MONTH); //当前日期 + cal.setTime(birthDay); + int yearBirth = cal.get(Calendar.YEAR); + int monthBirth = cal.get(Calendar.MONTH); + int dayOfMonthBirth = cal.get(Calendar.DAY_OF_MONTH); + int age = yearNow - yearBirth; //计算整岁数 + if (monthNow <= monthBirth) { + if (monthNow == monthBirth) { + if (dayOfMonthNow < dayOfMonthBirth) age--;//当前日期在生日之前,年龄减一 + }else{ + age--;//当前月份在生日之前,年龄减一 + } } + return age; + + } + + + /** + * 获取当前时间的时间戳 + */ + public static int getCurrentTimeIntValue() { + return (int) (System.currentTimeMillis() / 1000); + } + + + /** + * 获取days天后的当前时间 时间戳 + */ + public static int addDaysTimeStamp(int days) { + Calendar cal = Calendar.getInstance(); + cal.setTime(new Date()); + cal.add(Calendar.DATE, days); + return (int) (cal.getTimeInMillis() / 1000); + } + + /** + * 获取今日零点的时间戳 + */ + public static int getStartTimeStamp() { + Calendar todayStart = Calendar.getInstance(); + todayStart.set(Calendar.HOUR_OF_DAY, 0); + todayStart.set(Calendar.MINUTE, 0); + todayStart.set(Calendar.SECOND, 0); + todayStart.set(Calendar.MILLISECOND, 0); + long time = todayStart.getTimeInMillis()/1000; + return (int)time; + } + + /** + * 获取今日23:59:59的时间戳 + */ + public static int getEndTimeStamp() { + Calendar todayEnd = Calendar.getInstance(); + todayEnd.set(Calendar.HOUR_OF_DAY, 23); + todayEnd.set(Calendar.MINUTE, 59); + todayEnd.set(Calendar.SECOND, 59); + todayEnd.set(Calendar.MILLISECOND, 999); + long time = todayEnd.getTimeInMillis() / 1000; + return (int) time; + } + + /** + * 获取指定时间零点的时间戳 + */ + public static int getStartTimeStamp(Date date) { + Calendar todayStart = Calendar.getInstance(); + todayStart.setTime(date); + todayStart.set(Calendar.HOUR_OF_DAY, 0); + todayStart.set(Calendar.MINUTE, 0); + todayStart.set(Calendar.SECOND, 0); + todayStart.set(Calendar.MILLISECOND, 0); + long time = todayStart.getTimeInMillis()/1000; + return (int)time; + } + + /** + * 获取指定时间23:59:59的时间戳 + */ + public static int getEndTimeStamp(Date date) { + Calendar todayEnd = Calendar.getInstance(); + todayEnd.setTime(date); + todayEnd.set(Calendar.HOUR_OF_DAY, 23); + todayEnd.set(Calendar.MINUTE, 59); + todayEnd.set(Calendar.SECOND, 59); + todayEnd.set(Calendar.MILLISECOND, 999); + long time = todayEnd.getTimeInMillis() / 1000; + return (int) time; + } + + /** + * 获取昨天零点的时间(字符串) + */ + public static String getYesterDayStartTimeStamp() { + SimpleDateFormat sdfYMD = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + Calendar calendar = Calendar.getInstance(); + calendar.set(Calendar.SECOND,0); //这是将【秒】设置为0 + calendar.set(Calendar.MINUTE,0); //这是将【分】设置为0 + calendar.set(Calendar.HOUR_OF_DAY,0); //这是将【时】设置为0 + calendar.add(Calendar.DATE,-1); //当前日期加一 + String yesterday = sdfYMD.format(calendar.getTime()); //获取昨天的时间 如2021-02-25 00:00:00 + return yesterday; + } + + /** + * 获取昨天零点的时间戳 + */ + public static Integer getBeforeStartTime(){ + Calendar todayStart = Calendar.getInstance(); + todayStart.set(Calendar.HOUR_OF_DAY, 0); + todayStart.set(Calendar.MINUTE, 0); + todayStart.set(Calendar.SECOND, 0); + todayStart.set(Calendar.MILLISECOND, 0); + long time = todayStart.getTimeInMillis()/1000; + return (int)time-86400; + } + + /** + * 获取昨天23:59:59的时间(字符串) + */ + public static String getYesterDayEndTimeStamp() { + SimpleDateFormat sdfYMD = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + Calendar calendar = Calendar.getInstance(); + calendar.set(Calendar.SECOND,59); //这是将当天的【秒】设置为0 + calendar.set(Calendar.MINUTE,59); //这是将当天的【分】设置为0 + calendar.set(Calendar.HOUR_OF_DAY,23); //这是将当天的【时】设置为0 + calendar.add(Calendar.DATE,-1); //当前日期加一 + String yesterday = sdfYMD.format(calendar.getTime()); //获取第二天的时间 2021-02-25 00:00:00 + return yesterday; + } + + + + /** + * 获取明天零点的时间戳 + */ + public static Integer getAfterStartime() + { + Calendar todayStart = Calendar.getInstance(); + todayStart.set(Calendar.HOUR_OF_DAY, 0); + todayStart.set(Calendar.MINUTE, 0); + todayStart.set(Calendar.SECOND, 0); + todayStart.set(Calendar.MILLISECOND, 0); + long time = todayStart.getTimeInMillis()/1000; + return (int)time+86400; + } + + /** + * 将昨天凌晨时间转换为Date类型(下面设置成这样 new simpleDateFormat("yyyy-MM-dd HH:mm:ss") 数据中对应的字段类型就是DateTime)   * 这个方法中调用了上面的getYesterDayStartTimeStamp()方法哦 + */ + public static Date getDateTime() + { + Date dateTime = null; + String yesterDayStartTimeStamp = getYesterDayStartTimeStamp(); + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + try + { + dateTime = formatter.parse(yesterDayStartTimeStamp); + } + catch (ParseException e) + { + e.printStackTrace(); + } + //Sun May 09 00:00:00 CST 2021 + return dateTime; + } + + + /** + * 当前时间向推几小时 + * @param ihour 小时 + * @return String + */ + public static String getBeforeByHourTime(int ihour){ + String returnstr = ""; + Calendar calendar = Calendar.getInstance(); + calendar.set(Calendar.HOUR_OF_DAY, calendar.get(Calendar.HOUR_OF_DAY) - ihour); + SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + returnstr = df.format(calendar.getTime()); + return returnstr; + } + + + /** + * 当前时间向推N天 + * @param day 小时 + * @return String + */ + public static String getBeforeByDayTime(int day){ + LocalDateTime now = LocalDateTime.now(); + now = now.minus(-day, ChronoUnit.DAYS); + + + return now.toString(); + } + + /** + * 当前时间向推N天 + * 获取时间戳 + * @param day 小时 + * @return String + */ + public static Long getBeforeByDayLongTime(int day){ + LocalDateTime now = LocalDateTime.now(); + now = now.minus(-day, ChronoUnit.DAYS); + + + return now.toEpochSecond(ZoneOffset.of("+8")); + } } diff --git a/linkwe-common/src/main/java/com/linkwechat/common/utils/OsUtils.java b/linkwe-common/src/main/java/com/linkwechat/common/utils/OsUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..598598fed8b7ac681cb9e9b16f168e3e1e426e8c --- /dev/null +++ b/linkwe-common/src/main/java/com/linkwechat/common/utils/OsUtils.java @@ -0,0 +1,14 @@ +package com.linkwechat.common.utils; + + +/** + * 操作系统相关判断 + */ +public class OsUtils { + + public static boolean isWindows() { + String osName = System.getProperties().getProperty("os.name"); + System.out.println("current system is " + osName); + return osName.toUpperCase().indexOf("WINDOWS") != -1; + } +} diff --git a/linkwe-common/src/main/java/com/linkwechat/common/utils/QREncode.java b/linkwe-common/src/main/java/com/linkwechat/common/utils/QREncode.java index 571fa32a20471341fad49ebf67fc3760142e0825..0bc6018c74d2dbfb6b62abb56b906f5a09ce3970 100644 --- a/linkwe-common/src/main/java/com/linkwechat/common/utils/QREncode.java +++ b/linkwe-common/src/main/java/com/linkwechat/common/utils/QREncode.java @@ -1,66 +1,212 @@ package com.linkwechat.common.utils; +import java.awt.*; +import java.awt.geom.RoundRectangle2D; import java.awt.image.BufferedImage; -import java.io.File; -import java.io.IOException; -import java.io.OutputStream; +import java.io.*; +import java.net.URL; +import java.util.HashMap; import java.util.Hashtable; import javax.imageio.ImageIO; +import javax.servlet.ServletOutputStream; import com.google.zxing.BarcodeFormat; import com.google.zxing.EncodeHintType; import com.google.zxing.MultiFormatWriter; +import com.google.zxing.WriterException; import com.google.zxing.common.BitMatrix; +import com.google.zxing.qrcode.QRCodeWriter; +import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; +import com.linkwechat.common.constant.Constants; +import org.springframework.mock.web.MockMultipartFile; +import org.springframework.web.multipart.MultipartFile; public class QREncode { - - private static final int BLACK = 0xFF000000; - private static final int WHITE = 0xFFFFFFFF; - - private QREncode() {} - - - public static BufferedImage toBufferedImage(BitMatrix matrix) { - int width = matrix.getWidth(); - int height = matrix.getHeight(); - BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); - for (int x = 0; x < width; x++) { - for (int y = 0; y < height; y++) { - image.setRGB(x, y, matrix.get(x, y) ? BLACK : WHITE); - } - } - return image; - } - - - public static void writeToFile(BitMatrix matrix, String format, File file) - throws IOException { - BufferedImage image = toBufferedImage(matrix); - if (!ImageIO.write(image, format, file)) { - throw new IOException("Could not write an image of format " + format + " to " + file); - } - } - - - public static void writeToStream(BitMatrix matrix, String format, OutputStream stream) - throws IOException { - BufferedImage image = toBufferedImage(matrix); - if (!ImageIO.write(image, format, stream)) { - throw new IOException("Could not write an image of format " + format); - } - } - @SuppressWarnings({ "unchecked", "rawtypes" }) -public static void main(String[] args) throws Exception { - String text = "http://open.weixin.qq.com/qr/code/?username=LinkWeChat2021"; - int width = 300; - int height = 300; - String format = "png"; - Hashtable hints = new Hashtable(); - hints.put(EncodeHintType.CHARACTER_SET, "utf-8"); - BitMatrix bitMatrix = new MultiFormatWriter().encode(text, - BarcodeFormat.QR_CODE, width, height, hints); - File outputFile = new File("d:"+File.separator+"qr.png"); - QREncode.writeToFile(bitMatrix, format, outputFile); - } + + private static final int BLACK = 0xFF000000; + private static final int WHITE = 0xFFFFFFFF; + /** + * 默认宽度 + */ + private static final Integer WIDTH = 140; + /** + * 默认高度 + */ + private static final Integer HEIGHT = 140; + + /** + * LOGO 默认宽度 + */ + private static final Integer LOGO_WIDTH = 22; + /** + * LOGO 默认高度 + */ + private static final Integer LOGO_HEIGHT = 22; + + /** + * 图片格式 + */ + private static final String IMAGE_FORMAT = "png"; + + + private QREncode() { + } + + + public static BufferedImage toBufferedImage(BitMatrix matrix) { + int width = matrix.getWidth(); + int height = matrix.getHeight(); + BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); + for (int x = 0; x < width; x++) { + for (int y = 0; y < height; y++) { + image.setRGB(x, y, matrix.get(x, y) ? BLACK : WHITE); + } + } + return image; + } + + public static void writeToFile(BitMatrix matrix, String format, File file) + throws IOException { + BufferedImage image = toBufferedImage(matrix); + if (!ImageIO.write(image, format, file)) { + throw new IOException("Could not write an image of format " + format + " to " + file); + } + } + + public static void writeToStream(BitMatrix matrix, String format, OutputStream stream) + throws IOException { + BufferedImage image = toBufferedImage(matrix); + if (!ImageIO.write(image, format, stream)) { + throw new IOException("Could not write an image of format " + format); + } + } + + /** + * 生成带头像的二维码 + * + * @param content 内容 + * @param logoUrl logo在线地址 + * @return + */ + public static BufferedImage crateQRCode(String content, String logoUrl) { + if (StringUtils.isNotBlank(content)) { + ServletOutputStream stream = null; + HashMap hints = new HashMap<>(4); + // 指定字符编码为utf-8 + hints.put(EncodeHintType.CHARACTER_SET, Constants.UTF8); + // 指定二维码的纠错等级为中级 + hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M); + // 设置图片的边距 + hints.put(EncodeHintType.MARGIN, 2); + try { + QRCodeWriter writer = new QRCodeWriter(); + BitMatrix bitMatrix = writer.encode(content, BarcodeFormat.QR_CODE, WIDTH, HEIGHT, hints); + BufferedImage bufferedImage = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB); + for (int x = 0; x < WIDTH; x++) { + for (int y = 0; y < HEIGHT; y++) { + bufferedImage.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF); + } + } + if (StringUtils.isNotBlank(logoUrl)) { + insertLogo(bufferedImage, logoUrl); + } + return bufferedImage; + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (stream != null) { + try { + stream.flush(); + stream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } + return null; + } + + /** + * 二维码插入logo + * + * @param source 二维码 + * @param logoUrl logo 在线地址 + * @throws Exception + */ + private static void insertLogo(BufferedImage source, String logoUrl) throws Exception { + // logo 源可为 File/InputStream/URL + Image src = ImageIO.read(new URL(logoUrl)); + // 插入LOGO + Graphics2D graph = source.createGraphics(); + int x = (WIDTH - LOGO_WIDTH) / 2; + int y = (HEIGHT - LOGO_HEIGHT) / 2; + graph.drawImage(src, x, y, LOGO_WIDTH, LOGO_HEIGHT, null); + Shape shape = new RoundRectangle2D.Float(x, y, LOGO_WIDTH, LOGO_HEIGHT, 6, 6); + graph.setStroke(new BasicStroke(3f)); + graph.draw(shape); + graph.dispose(); + } + + /** + * 生成带二维码并生成流文件进行传输 + * + * @param content 内容 + * @param output 输出流 + * @throws Exception + */ + public void getQRCode(String content, OutputStream output) throws Exception { + BufferedImage image = crateQRCode(content, null); + if (StringUtils.isNotNull(image)) { + ImageIO.write(image, IMAGE_FORMAT, output); + } + } + + /** + * 生成带logo的二维码并生成流文件进行传输 + * + * @param content 内容 + * @param logoUrl logo资源 + * @param output 输出流 + * @throws Exception + */ + public void getQRCode(String content, String logoUrl, OutputStream output) throws Exception { + BufferedImage image = crateQRCode(content, logoUrl); + if (StringUtils.isNotNull(image)) { + ImageIO.write(image, IMAGE_FORMAT, output); + } + } + + public static InputStream writeToInputStream(BufferedImage bufferedImage) throws IOException { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + try { + ImageIO.write(bufferedImage, IMAGE_FORMAT, os); + return new ByteArrayInputStream(os.toByteArray()); + } catch (Exception e) { + throw new IOException(e.getMessage(), e); + } + } + + public static MultipartFile getQRCodeMultipartFile(String content, String logoUrl) throws IOException { + BufferedImage bufferedImage = crateQRCode(content, logoUrl); + //读取图片转换为 BufferedImage + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ImageIO.write( bufferedImage, "jpg", baos ); + //转换为MultipartFile + return new MockMultipartFile("groupQrCode","groupQrCode.jpg","text/plain", baos.toByteArray()); + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + public static void main(String[] args) throws Exception { + String text = "http://open.weixin.qq.com/qr/code/?username=LinkWeChat2021"; + int width = 300; + int height = 300; + String format = "png"; + Hashtable hints = new Hashtable<>(); + hints.put(EncodeHintType.CHARACTER_SET, Constants.UTF8); + BitMatrix bitMatrix = new MultiFormatWriter().encode(text, BarcodeFormat.QR_CODE, width, height, hints); + File outputFile = new File("d:" + File.separator + "qr.png"); + QREncode.writeToFile(bitMatrix, format, outputFile); + } } diff --git a/linkwe-common/src/main/java/com/linkwechat/common/utils/StringUtils.java b/linkwe-common/src/main/java/com/linkwechat/common/utils/StringUtils.java index e9e6c6eb3152848a566ec51cfec48e733cb8b0dd..65021301c9c2dd015e4581d0e1e65aec4c20a233 100644 --- a/linkwe-common/src/main/java/com/linkwechat/common/utils/StringUtils.java +++ b/linkwe-common/src/main/java/com/linkwechat/common/utils/StringUtils.java @@ -490,6 +490,23 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils } + /** + * 企微用户客户机器判断 + * @param str + * @return + */ + public static int weCustomTypeJudgment(String str){ + if (isNotEmpty(str)){ + if (str.startsWith("wo") || str.startsWith("wm")){ + return 1; + } + if (str.startsWith("wb")){ + return 2; + } + } + return 0; + } + public static void main(String[] args) { Integer[] arrays = { 1,2,3,4,5,6,7 }; String join = join(arrays, ","); diff --git a/linkwe-common/src/main/java/com/linkwechat/common/utils/Threads.java b/linkwe-common/src/main/java/com/linkwechat/common/utils/Threads.java index ec9257dc92c75467dccfe0603ccab9afc16f4f89..fcfbf8ad6f39c9e528b4813d8e00a44f3fa8be54 100644 --- a/linkwe-common/src/main/java/com/linkwechat/common/utils/Threads.java +++ b/linkwe-common/src/main/java/com/linkwechat/common/utils/Threads.java @@ -1,10 +1,8 @@ package com.linkwechat.common.utils; -import java.util.concurrent.CancellationException; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; +import java.util.concurrent.*; + +import com.google.common.util.concurrent.ThreadFactoryBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -17,6 +15,23 @@ public class Threads { private static final Logger logger = LoggerFactory.getLogger(Threads.class); + private static final int CORE_POOL_SIZE = Runtime.getRuntime().availableProcessors(); + + private static final ThreadFactory NAMED_THREAD_FACTORY = new ThreadFactoryBuilder().setNameFormat("common-pool-%d").build(); + /** + * 创建线程池 + */ + public static final ThreadPoolExecutor SINGLE_THREAD_POOL = new ThreadPoolExecutor(CORE_POOL_SIZE, CORE_POOL_SIZE + 1, 10l, TimeUnit.SECONDS, + new SynchronousQueue<>(), NAMED_THREAD_FACTORY, (r, executor) -> { + try { + executor.getQueue().put(r); + } catch (InterruptedException e) { + e.printStackTrace(); + } + }); + + + /** * sleep等待,单位为毫秒 */ diff --git a/linkwe-common/src/main/java/com/linkwechat/common/utils/ValidateUtils.java b/linkwe-common/src/main/java/com/linkwechat/common/utils/ValidateUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..b495a30e0b69e6a153ed1e2ca2f89f72235305fe --- /dev/null +++ b/linkwe-common/src/main/java/com/linkwechat/common/utils/ValidateUtils.java @@ -0,0 +1,19 @@ +package com.linkwechat.common.utils; + +import java.util.regex.Pattern; + +public class ValidateUtils { + + private static final String REGEX_MOBILE ="((\\+86|0086)?\\s*)((134[0-8]\\d{7})|(((13([0-3]|[5-9]))|(14[5-9])|15([0-3]|[5-9])|(16(2|[5-7]))|17([0-3]|[5-8])|18[0-9]|19(1|[8-9]))\\d{8})|(14(0|1|4)0\\d{7})|(1740([0-5]|[6-9]|[10-12])\\d{7}))"; + + /** + * 判断是否是手机号 + * @param tel 手机号 + * @return boolean true:是 false:否 + */ + public static boolean isMobile(String tel) { + if (StringUtils.isEmpty(tel)){ return false;} + return Pattern.matches(REGEX_MOBILE, tel); + } + +} diff --git a/linkwe-common/src/main/java/com/linkwechat/common/utils/file/FileUploadUtils.java b/linkwe-common/src/main/java/com/linkwechat/common/utils/file/FileUploadUtils.java index 8560f5c7033147a25e9dee379833a08052d7afb3..4698eb15909ff2192293ea752ecfc0ae0af27f8e 100644 --- a/linkwe-common/src/main/java/com/linkwechat/common/utils/file/FileUploadUtils.java +++ b/linkwe-common/src/main/java/com/linkwechat/common/utils/file/FileUploadUtils.java @@ -2,7 +2,11 @@ package com.linkwechat.common.utils.file; import java.io.File; import java.io.IOException; +import java.io.InputStream; +import cn.hutool.core.io.FileUtil; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.linkwechat.common.config.CosConfig; import com.linkwechat.common.config.RuoYiConfig; import com.linkwechat.common.constant.Constants; import com.linkwechat.common.exception.file.FileNameLengthLimitExceededException; @@ -11,6 +15,15 @@ import com.linkwechat.common.exception.file.InvalidExtensionException; import com.linkwechat.common.utils.DateUtils; import com.linkwechat.common.utils.StringUtils; import com.linkwechat.common.utils.uuid.IdUtils; +import com.qcloud.cos.COSClient; +import com.qcloud.cos.ClientConfig; +import com.qcloud.cos.auth.BasicCOSCredentials; +import com.qcloud.cos.auth.COSCredentials; +import com.qcloud.cos.model.ObjectMetadata; +import com.qcloud.cos.model.PutObjectRequest; +import com.qcloud.cos.model.PutObjectResult; +import com.qcloud.cos.region.Region; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.FilenameUtils; import org.springframework.web.multipart.MultipartFile; @@ -19,8 +32,8 @@ import org.springframework.web.multipart.MultipartFile; * * @author ruoyi */ -public class FileUploadUtils -{ +@Slf4j +public class FileUploadUtils { /** * 默认大小 50M */ @@ -36,16 +49,16 @@ public class FileUploadUtils */ private static String defaultBaseDir = RuoYiConfig.getProfile(); - public static void setDefaultBaseDir(String defaultBaseDir) - { + public static void setDefaultBaseDir(String defaultBaseDir) { FileUploadUtils.defaultBaseDir = defaultBaseDir; } - public static String getDefaultBaseDir() - { + public static String getDefaultBaseDir() { return defaultBaseDir; } + + /** * 以默认配置进行文件上传 * @@ -53,14 +66,34 @@ public class FileUploadUtils * @return 文件名称 * @throws Exception */ - public static final String upload(MultipartFile file) throws IOException - { - try - { + public static final String upload(MultipartFile file) throws IOException { + try { return upload(getDefaultBaseDir(), file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION); + } catch (Exception e) { + throw new IOException(e.getMessage(), e); } - catch (Exception e) - { + } + + public static final String upload(InputStream inputStream,String fileName) throws IOException { + try { + return upload(getDefaultBaseDir(), inputStream, fileName); + } catch (Exception e) { + throw new IOException(e.getMessage(), e); + } + } + + + /** + * 以默认配置进行文件上传 + * + * @param file 上传的文件 + * @return 文件名称 + * @throws Exception + */ + public static final String uploadFile(MultipartFile file) throws IOException { + try { + return uploadFile(getDefaultBaseDir(), file); + } catch (Exception e) { throw new IOException(e.getMessage(), e); } } @@ -69,18 +102,14 @@ public class FileUploadUtils * 根据文件路径上传 * * @param baseDir 相对应用的基目录 - * @param file 上传的文件 + * @param file 上传的文件 * @return 文件名称 * @throws IOException */ - public static final String upload(String baseDir, MultipartFile file) throws IOException - { - try - { + public static final String upload(String baseDir, MultipartFile file) throws IOException { + try { return upload(baseDir, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION); - } - catch (Exception e) - { + } catch (Exception e) { throw new IOException(e.getMessage(), e); } } @@ -88,27 +117,144 @@ public class FileUploadUtils /** * 文件上传 * - * @param baseDir 相对应用的基目录 - * @param file 上传的文件 + * @param baseDir 相对应用的基目录 + * @param file 上传的文件 * @param allowedExtension 上传文件类型 * @return 返回上传成功的文件名 - * @throws FileSizeLimitExceededException 如果超出最大大小 + * @throws FileSizeLimitExceededException 如果超出最大大小 * @throws FileNameLengthLimitExceededException 文件名太长 - * @throws IOException 比如读写文件出错时 - * @throws InvalidExtensionException 文件校验异常 + * @throws IOException 比如读写文件出错时 + * @throws InvalidExtensionException 文件校验异常 */ public static final String upload(String baseDir, MultipartFile file, String[] allowedExtension) throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException, - InvalidExtensionException - { + InvalidExtensionException { int fileNamelength = file.getOriginalFilename().length(); - if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH) - { + if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH) { + throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH); + } + + assertAllowed(file, allowedExtension); + + String fileName = extractFilename(file); + + File desc = getAbsoluteFile(baseDir, fileName); + file.transferTo(desc); + String pathFileName = getPathFileName(baseDir, fileName); + return pathFileName; + } + + public static final String upload(String baseDir, InputStream inputStream, String fileName) throws IOException { + File desc = getAbsoluteFile(baseDir, fileName); + File file = FileUtil.writeFromStream(inputStream, desc); + return file.getAbsolutePath(); + } + + /** + * 上传到腾讯对象云存储中 + * + * @param file 上传的文件 + * @return 访问路径 + * @throws IOException + */ + public static final String upload2Cos(MultipartFile file , CosConfig cosConfig) throws IOException { + try { + return upload2Cos( file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION,cosConfig); + } catch (Exception e) { + throw new IOException(e.getMessage(), e); + } + } + + /** + * 通过流进行文件上传 + * @param in 流 + * @throws IOException + */ + public static String upload2Cos(InputStream in, String fileExtension, CosConfig cosConfig) throws IOException { + try { + return upload2Cos( in, fileExtension, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION, cosConfig); + } catch (Exception e) { + throw new IOException(e.getMessage(), e); + } + } + + + /** + * 文件上传 + * + * @param file 上传的文件 + * @param allowedExtension 上传文件类型 + * @return 返回上传成功的文件名 + * @throws FileSizeLimitExceededException 如果超出最大大小 + * @throws FileNameLengthLimitExceededException 文件名太长 + * @throws IOException 比如读写文件出错时 + * @throws InvalidExtensionException 文件校验异常 + */ + public static final String upload2Cos( MultipartFile file, String[] allowedExtension, CosConfig cosConfig) + throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException, + InvalidExtensionException { + int fileNamelength = file.getOriginalFilename().length(); + if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH) { throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH); } assertAllowed(file, allowedExtension); + String fileName = extractFilename(file); + // 1 初始化用户身份信息(secretId, secretKey)。 + COSCredentials cred = new BasicCOSCredentials(cosConfig.getSecretId(), cosConfig.getSecretKey()); + // 2 设置 bucket 的区域, COS 地域的简称请参照 https://cloud.tencent.com/document/product/436/6224 + // clientConfig 中包含了设置 region, https(默认 http), 超时, 代理等 set 方法, 使用可参见源码或者常见问题 Java SDK 部分。 + Region region = new Region(cosConfig.getRegion()); + ClientConfig clientConfig = new ClientConfig(region); + // 3 生成 cos 客户端。 + COSClient cosClient = new COSClient(cred, clientConfig); + + // 指定要上传到 COS 上对象键 + ObjectMetadata objectMetadata = new ObjectMetadata(); + InputStream inputStream = file.getInputStream(); + PutObjectRequest putObjectRequest = new PutObjectRequest(cosConfig.getBucketName(), fileName,file.getInputStream(),objectMetadata); + PutObjectResult putObjectResult = cosClient.putObject(putObjectRequest); + log.info("{}",cosConfig.getCosImgUrlPrefix()+fileName); + log.info("腾讯cos上传信息:{}",new ObjectMapper().writeValueAsString(putObjectResult)); + cosClient.shutdown(); + + return fileName; + } + + /** + * 将流中的文件传到腾讯云 + * @param inputStream 输入流 + * @param fileExtension 被写入流的文件的后缀名 + * @param allowedExtension 允许的后缀名 + * @throws FileSizeLimitExceededException 文件大小超过上限 + * @throws InvalidExtensionException 文件后缀名非法 + */ + public static String upload2Cos(InputStream inputStream, String fileExtension, String[] allowedExtension, CosConfig cosConfig) throws FileSizeLimitExceededException, InvalidExtensionException { + String fileName = DateUtils.datePath() + "/" + IdUtils.fastUUID() + "." + fileExtension; + if (!isAllowedExtension(fileExtension, allowedExtension)) + { + throw new InvalidExtensionException.InvalidImageExtensionException(allowedExtension, fileExtension, fileName); + } + COSCredentials cred = new BasicCOSCredentials(cosConfig.getSecretId(), cosConfig.getSecretKey()); + Region region = new Region(cosConfig.getRegion()); + ClientConfig clientConfig = new ClientConfig(region); + COSClient cosClient = new COSClient(cred, clientConfig); + ObjectMetadata objectMetadata = new ObjectMetadata(); + PutObjectRequest putObjectRequest = new PutObjectRequest(cosConfig.getBucketName(), fileName ,inputStream ,objectMetadata); + cosClient.putObject(putObjectRequest); + cosClient.shutdown(); + return fileName; + } + + + public static final String uploadFile(String baseDir, MultipartFile file) + throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException { + int fileNamelength = file.getOriginalFilename().length(); + if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH) { + throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH); + } + String fileName = extractFilename(file); File desc = getAbsoluteFile(baseDir, fileName); @@ -120,34 +266,34 @@ public class FileUploadUtils /** * 编码文件名 */ - public static final String extractFilename(MultipartFile file) - { + public static final String extractFilename(MultipartFile file) { String fileName = file.getOriginalFilename(); String extension = getExtension(file); fileName = DateUtils.datePath() + "/" + IdUtils.fastUUID() + "." + extension; return fileName; } - private static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException - { + private static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException { File desc = new File(uploadDir + File.separator + fileName); - if (!desc.getParentFile().exists()) - { + if (!desc.getParentFile().exists()) { desc.getParentFile().mkdirs(); } - if (!desc.exists()) - { + if (!desc.exists()) { desc.createNewFile(); } return desc; } - private static final String getPathFileName(String uploadDir, String fileName) throws IOException - { + public static final String getPathFileName(String uploadDir, String fileName) throws IOException { int dirLastIndex = RuoYiConfig.getProfile().length() + 1; String currentDir = StringUtils.substring(uploadDir, dirLastIndex); - String pathFileName = Constants.RESOURCE_PREFIX + "/" + currentDir + "/" + fileName; + String pathFileName; + if(org.apache.commons.lang3.StringUtils.isBlank(currentDir)){ + pathFileName = Constants.RESOURCE_PREFIX + "/" +fileName; + }else { + pathFileName = Constants.RESOURCE_PREFIX + "/" + currentDir + "/" + fileName; + } return pathFileName; } @@ -160,35 +306,25 @@ public class FileUploadUtils * @throws InvalidExtensionException */ public static final void assertAllowed(MultipartFile file, String[] allowedExtension) - throws FileSizeLimitExceededException, InvalidExtensionException - { + throws FileSizeLimitExceededException, InvalidExtensionException { long size = file.getSize(); - if (DEFAULT_MAX_SIZE != -1 && size > DEFAULT_MAX_SIZE) - { + if (DEFAULT_MAX_SIZE != -1 && size > DEFAULT_MAX_SIZE) { throw new FileSizeLimitExceededException(DEFAULT_MAX_SIZE / 1024 / 1024); } String fileName = file.getOriginalFilename(); String extension = getExtension(file); - if (allowedExtension != null && !isAllowedExtension(extension, allowedExtension)) - { - if (allowedExtension == MimeTypeUtils.IMAGE_EXTENSION) - { + if (allowedExtension != null && !isAllowedExtension(extension, allowedExtension)) { + if (allowedExtension == MimeTypeUtils.IMAGE_EXTENSION) { throw new InvalidExtensionException.InvalidImageExtensionException(allowedExtension, extension, fileName); - } - else if (allowedExtension == MimeTypeUtils.FLASH_EXTENSION) - { + } else if (allowedExtension == MimeTypeUtils.FLASH_EXTENSION) { throw new InvalidExtensionException.InvalidFlashExtensionException(allowedExtension, extension, fileName); - } - else if (allowedExtension == MimeTypeUtils.MEDIA_EXTENSION) - { + } else if (allowedExtension == MimeTypeUtils.MEDIA_EXTENSION) { throw new InvalidExtensionException.InvalidMediaExtensionException(allowedExtension, extension, fileName); - } - else - { + } else { throw new InvalidExtensionException(allowedExtension, extension, fileName); } } @@ -202,12 +338,9 @@ public class FileUploadUtils * @param allowedExtension * @return */ - public static final boolean isAllowedExtension(String extension, String[] allowedExtension) - { - for (String str : allowedExtension) - { - if (str.equalsIgnoreCase(extension)) - { + public static final boolean isAllowedExtension(String extension, String[] allowedExtension) { + for (String str : allowedExtension) { + if (str.equalsIgnoreCase(extension)) { return true; } } @@ -220,11 +353,9 @@ public class FileUploadUtils * @param file 表单文件 * @return 后缀名 */ - public static final String getExtension(MultipartFile file) - { + public static final String getExtension(MultipartFile file) { String extension = FilenameUtils.getExtension(file.getOriginalFilename()); - if (StringUtils.isEmpty(extension)) - { + if (StringUtils.isEmpty(extension)) { extension = MimeTypeUtils.getExtension(file.getContentType()); } return extension; diff --git a/linkwe-common/src/main/java/com/linkwechat/common/utils/file/FileUtil.java b/linkwe-common/src/main/java/com/linkwechat/common/utils/file/FileUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..c8829c0690c0147c91e9c46c2110422c4ec986bb --- /dev/null +++ b/linkwe-common/src/main/java/com/linkwechat/common/utils/file/FileUtil.java @@ -0,0 +1,90 @@ +package com.linkwechat.common.utils.file; + + +import com.alibaba.fastjson.JSONObject; +import com.linkwechat.common.config.RuoYiConfig; +import com.linkwechat.common.utils.OsUtils; +import com.linkwechat.common.utils.spring.SpringUtils; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import java.io.File; +import java.io.IOException; + + +/** + * 文件服务 + */ +@Slf4j +public class FileUtil { + + + private static RuoYiConfig ruoYiConfig = SpringUtils.getBean(RuoYiConfig.class); + + + private static final String WINDOWSFILEPATH="D:/linkWeChat/uploadPath"; + + + private static final String LINUXFILEPATH="/linkWeChat/uploadPath"; + + /** + * 文件上传 + * @param file + * @return + * @throws IOException + */ + public static JSONObject upload(MultipartFile file) throws Exception { + + try { + FileUploadUtils.assertAllowed(file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION); + String fileName=""; + String imgUrlPrefix=""; + if(ruoYiConfig.getFile().isStartCosUpload()){//开启云上传 + //开启云上传开关则云上传,不然上传本地 + fileName = FileUploadUtils.upload2Cos(file, ruoYiConfig.getFile().getCos()); + imgUrlPrefix = ruoYiConfig.getFile().getCos().getCosImgUrlPrefix(); + }else {//本地上传 + File osFile=OsUtils.isWindows()?new File(WINDOWSFILEPATH):new File(LINUXFILEPATH); + if(!osFile.exists()){ + osFile.mkdirs(); + } + fileName = FileUploadUtils.upload(osFile.getPath(), file); + imgUrlPrefix = ruoYiConfig.getFile().getImgUrlPrefix(); + } + JSONObject reust = new JSONObject(); + reust.put("fileName",fileName); + reust.put("imgUrlPrefix",imgUrlPrefix); + return reust; + + }catch (Exception e){ + throw e; + } + + } + + + /** + * 获取图片(本地,或者网络图片) + * @param fileName + * @param rp + */ + public void findImage(String fileName, HttpServletResponse rp){ + try { + String fileDownUrl=""; + rp.setContentType("image/png"); + if(ruoYiConfig.getFile().isStartCosUpload()) {//开启云上传 + fileDownUrl= ruoYiConfig.getFile().getCos().getCosImgUrlPrefix(); + FileUtils.downloadFile(fileDownUrl+fileName,rp.getOutputStream()); + }else{ + fileDownUrl=OsUtils.isWindows()?WINDOWSFILEPATH+"/"+fileName:LINUXFILEPATH+"/"+fileName; + FileUtils.writeBytes(fileDownUrl,rp.getOutputStream()); + } + }catch (Exception e){ + log.error("图片获取异常:"+e.getMessage()); + + } + } + + +} diff --git a/linkwe-common/src/main/java/com/linkwechat/common/utils/file/FileUtils.java b/linkwe-common/src/main/java/com/linkwechat/common/utils/file/FileUtils.java index 606e96436b80ca0ac6b85f0161a805f8f0c011b2..ffc1f946d9241d093e11fbf773fda1a22e13ac3a 100644 --- a/linkwe-common/src/main/java/com/linkwechat/common/utils/file/FileUtils.java +++ b/linkwe-common/src/main/java/com/linkwechat/common/utils/file/FileUtils.java @@ -1,17 +1,26 @@ package com.linkwechat.common.utils.file; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.OutputStream; -import java.io.UnsupportedEncodingException; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.ObjectUtil; +import com.linkwechat.common.utils.StringUtils; +import org.springframework.web.multipart.MultipartFile; + +import java.io.*; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLConnection; import java.net.URLEncoder; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; import javax.servlet.http.HttpServletRequest; /** * 文件处理工具类 - * + * * @author ruoyi */ public class FileUtils extends org.apache.commons.io.FileUtils @@ -20,7 +29,7 @@ public class FileUtils extends org.apache.commons.io.FileUtils /** * 输出指定文件的byte数组 - * + * * @param filePath 文件路径 * @param os 输出流 * @return @@ -75,11 +84,119 @@ public class FileUtils extends org.apache.commons.io.FileUtils } /** - * 删除文件 - * - * @param filePath 文件 - * @return + * 批量下载文件,打包为zip。 + * @param fileList 文件列表,每个元素应包含fileName、url,前者即为文件名,后者为下载所需链接 + * @param os 输出流 + */ + public static void batchDownloadFile(List> fileList, OutputStream os) { + try { + Map fileNameCountMap = fileList.stream().collect(Collectors + .toMap(item -> item.get("fileName"), item -> 0, (key, value) -> key)); + ZipOutputStream zos = new ZipOutputStream(os); + for (Map fileInfo: fileList) { + String fileName = fileInfo.get("fileName"); + String url = fileInfo.get("url"); + if(fileNameCountMap.containsKey(fileName)){ + Integer count = fileNameCountMap.get(fileName); + if(count > 0){ + String tempName = FileUtil.getPrefix(fileName) + "(" + count + ")"; + fileName = fileName.replaceAll(FileUtil.getPrefix(fileName),tempName); + } + fileNameCountMap.put(fileName,count+1); + } + // 跳过不包含指定键位的对象 + if (StringUtils.isEmpty(url) || StringUtils.isEmpty(fileName)){ + continue; + } + URL _url = new URL(url); + zos.putNextEntry(new ZipEntry(fileName)); + InputStream fis = _url.openConnection().getInputStream(); + byte[] buffer = new byte[1024]; + int r = 0; + while ((r = fis.read(buffer)) != -1) { + zos.write(buffer, 0, r); + } + fis.close(); + } + //关闭zip输出流 + zos.flush(); + zos.close(); + } catch (IOException e) { + e.printStackTrace(); + } + + } + + /** + * + * @param urlPath 下载路径 + * @param os 输出流 + * @return 返回下载文件 + * @throws Exception */ + public static void downloadFile(String urlPath,OutputStream os){ + InputStream inputStream = null; + try { + URL url = new URL(urlPath); + // 连接类的父类,抽象类 + URLConnection urlConnection = url.openConnection(); + // http的连接类 + HttpURLConnection httpURLConnection = (HttpURLConnection) urlConnection; + // 设定请求的方法,默认是GET(对于知识库的附件服务器必须是GET,如果是POST会返回405。流程附件迁移功能里面必须是POST,有所区分。) + httpURLConnection.setRequestMethod("GET"); + // 设置字符编码 + httpURLConnection.setRequestProperty("Charset", "UTF-8"); + // 打开到此 URL 引用的资源的通信链接(如果尚未建立这样的连接)。 + httpURLConnection.getResponseCode(); + + inputStream = httpURLConnection.getInputStream(); + + byte[] b = new byte[1024]; + int length; + while ((length = inputStream.read(b)) > 0) + { + os.write(b, 0, length); + } + inputStream.close(); + os.close(); + } catch (IOException e) { + e.printStackTrace(); + }catch (Exception e){ + e.printStackTrace(); + }finally + { + if (os != null) + { + try + { + os.close(); + } + catch (IOException e1) + { + e1.printStackTrace(); + } + } + if (inputStream != null) + { + try + { + inputStream.close(); + } + catch (IOException e1) + { + e1.printStackTrace(); + } + } + } + } + + + /** + * 删除文件 + * + * @param filePath 文件 + * @return + */ public static boolean deleteFile(String filePath) { boolean flag = false; @@ -139,4 +256,30 @@ public class FileUtils extends org.apache.commons.io.FileUtils } return filename; } + + + /** + * MultipartFile 转化为file + * @param multiFile + * @return + */ + public static File MultipartFileToFile(MultipartFile multiFile) { + // 获取文件名 + String fileName = multiFile.getOriginalFilename(); + // 获取文件后缀 + String prefix = fileName.substring(fileName.lastIndexOf(".")); + // 若需要防止生成的临时文件重复,可以在文件名后添加随机码 + + try { + File file = File.createTempFile(fileName, prefix); + multiFile.transferTo(file); + return file; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + + } diff --git a/linkwe-common/src/main/java/com/linkwechat/common/utils/file/MimeTypeUtils.java b/linkwe-common/src/main/java/com/linkwechat/common/utils/file/MimeTypeUtils.java index a932d5314dd6be7f4965b3d1ea2c66ce8a360100..34a7a985ee43577481dc650ce06e02520012e1f6 100644 --- a/linkwe-common/src/main/java/com/linkwechat/common/utils/file/MimeTypeUtils.java +++ b/linkwe-common/src/main/java/com/linkwechat/common/utils/file/MimeTypeUtils.java @@ -32,7 +32,7 @@ public class MimeTypeUtils // 压缩文件 "rar", "zip", "gz", "bz2", // pdf - "pdf" }; + "pdf" ,"wav","amr","mp4","mp3"}; public static String getExtension(String prefix) { diff --git a/linkwe-common/src/main/java/com/linkwechat/common/utils/img/ImageUtils.java b/linkwe-common/src/main/java/com/linkwechat/common/utils/img/ImageUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..6a111e3d87dddd5d10a44d8099c80bf934e12dae --- /dev/null +++ b/linkwe-common/src/main/java/com/linkwechat/common/utils/img/ImageUtils.java @@ -0,0 +1,778 @@ +package com.linkwechat.common.utils.img; + + +import com.qcloud.cos.utils.IOUtils; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.fileupload.FileItem; +import org.apache.commons.fileupload.disk.DiskFileItem; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.multipart.commons.CommonsMultipartFile; + +import javax.imageio.ImageIO; +import javax.swing.*; + +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.*; +import java.math.BigDecimal; +import java.net.URL; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; +import java.util.stream.Stream; + +@Slf4j +public class ImageUtils { + + private final static JLabel J_LABEL = new JLabel(); + + + + + public static byte[] changeImageSize(InputStream inputStream, Integer size) { + try { + BufferedImage oldBufferedImage = ImageIO.read(inputStream); + int oldWidth = oldBufferedImage.getWidth(); + int oldHeight = oldBufferedImage.getHeight(); + int newWidth = 0; + int newHeight = 0; + if (size >= 0) { + newWidth = oldWidth * size; + newHeight = oldHeight * size; + } else { + size = -size; + newWidth = oldWidth / size; + newHeight = oldHeight / size; + } + BufferedImage newBufferedImage = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_ARGB); + Graphics2D newGraphics2D = newBufferedImage.createGraphics(); + newGraphics2D.setBackground(Color.WHITE); + newGraphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + newGraphics2D.drawImage(oldBufferedImage, 0, 0, newWidth, newHeight, null); + oldBufferedImage.flush(); + OutputStream outputStream = new ByteArrayOutputStream(); + ImageIO.write(newBufferedImage, "jpg", outputStream); + newBufferedImage.flush(); + byte[] bytes = ((ByteArrayOutputStream) outputStream).toByteArray(); + outputStream.flush(); + outputStream.close(); + return bytes; + + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + /** + * 切割图片 + * + * @param inputStream + * @param x + * @param y + * @param width + * @param height + * @return + */ + public static byte[] cropImage(InputStream inputStream, int x, int y, int width, int height) { + BufferedImage bufferedImage = null; + byte bytes[] = null; + try { + bufferedImage = ImageIO.read(inputStream); + bytes = cropImage(bufferedImage, x, y, width, height); + } catch (Exception e) { + e.printStackTrace(); + } finally { + bufferedImage.flush(); + try { + inputStream.close(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + inputStream = null; + } + } + return bytes; + } + + + public static byte[] cropImage(BufferedImage bufferedImage, int x, int y, int width, int height) { + //BufferedImage newBufferedImage = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB); + BufferedImage copyBufferedImage = bufferedImage.getSubimage(x, y, width, height); + /*Graphics2D graphics2D = newBufferedImage.createGraphics(); + graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON); + graphics2D.drawImage(copyBufferedImage,0,0,width,height,null); + copyBufferedImage.flush();*/ + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + byte[] bytes = null; + try { + ImageIO.write(copyBufferedImage, "jpg", outputStream); + bytes = outputStream.toByteArray(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + outputStream.flush(); + outputStream.close(); + } catch (Exception e) { + e.printStackTrace(); + outputStream = null; + } + //newBufferedImage.flush(); + + } + return bytes; + + } + + + public static void inciseImage(InputStream inputStream, Integer direction, Integer directionValue, String fileName, String path) { + try { + BufferedImage bufferedImage = ImageIO.read(inputStream); + int width = bufferedImage.getWidth(); + int height = bufferedImage.getHeight(); + if (direction == 1) { + int directionNum = height / directionValue; + if (directionNum == 0) { + return; + } + int i = 0; + for (i = 0; i < directionNum; i++) { + byte[] bytes = cropImage(bufferedImage, 0, i * directionValue, width, directionValue); + byteToFile(bytes, fileName + "-" + i, "jpg", path); + } + int directionSurplus = height % directionValue; + if (directionSurplus > 0) { + byte[] bytes = cropImage(bufferedImage, 0, height - directionSurplus, width, directionSurplus); + byteToFile(bytes, fileName + "-" + (i + 1), "jpg", path); + } + } else if (direction == 2) { + int directionNum = width / directionValue; + if (directionNum == 0) { + return; + } + int i = 0; + for (; i < directionNum; i++) { + byte[] bytes = cropImage(bufferedImage, i * directionValue, 0, directionValue, height); + byteToFile(bytes, fileName + "-" + i, "jpg", path); + } + int directionSurplus = width % directionValue; + if (directionSurplus > 0) { + byte[] bytes = cropImage(bufferedImage, height - directionSurplus, 0, directionSurplus, height); + byteToFile(bytes, fileName + "-" + (i + 1), "jpg", path); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + + public static BufferedImage filePathToBufferedImage(String filePath) throws Exception { + File file = new File(filePath); + if (!file.isFile()) { + throw new FileNotFoundException("文件路径为目录"); + } + if (!file.exists()) { + throw new FileNotFoundException("文件不存在"); + } + BufferedImage bufferedImage = ImageIO.read(file); + return bufferedImage; + } + + + /** + * 复制 + * + * @param bufferedImage + * @param bufferedImageType + * @return + */ + public static BufferedImage copyBufferedImage(BufferedImage bufferedImage, Integer bufferedImageType) { + BufferedImage newBufferedImage = new BufferedImage(bufferedImage.getWidth(), bufferedImage.getHeight(), bufferedImageType); + Graphics2D graphics2D = newBufferedImage.createGraphics(); + graphics2D.drawImage(bufferedImage, null, 0, 0); + return newBufferedImage; + } + + /** + * 设置透明度 + * @param bufferedImage + * @param alpha + * @param bufferedImageType + * @return + */ + public static BufferedImage setBufferedImageAlpha(BufferedImage bufferedImage,Integer alpha,Integer bufferedImageType){ + if(alpha < 0 || alpha > 255){ + throw new RuntimeException("范围错误[0,255]"); + } + int width = bufferedImage.getWidth(); + int height = bufferedImage.getHeight(); + BufferedImage newBufferedImage = new BufferedImage(width,height, bufferedImageType); + int argb; + int oa; + int a; + int rgb; + for(int y = 0; y < height; y++){ + for(int x = 0; x < width; x++){ + argb = bufferedImage.getRGB(x,y); + rgb = argb & 0x00FFFFFF; + oa = argb >>> 24; + a = oa == 0?0:alpha<<24; + argb = a^rgb; + newBufferedImage.setRGB(x,y,argb); + } + } + return newBufferedImage; + } + + + /** + * 放大缩小 + * @param bufferedImage + * @param enlargementTimes + * @return + */ + public static BufferedImage enlargementBufferedImage(BufferedImage bufferedImage, double enlargementTimes, Integer bufferedImageType) { + int newWidth = (int) (bufferedImage.getWidth() * enlargementTimes); + int newHeight = (int) (bufferedImage.getHeight() * enlargementTimes); + BufferedImage newBufferedImage = new BufferedImage(newWidth, newHeight, bufferedImageType); + Graphics2D graphics2D = newBufferedImage.createGraphics(); + graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + graphics2D.drawImage(bufferedImage, 0, 0, newWidth, newHeight, null); + return newBufferedImage; + } + + /** + * 将图片改为固定尺寸 + * + * @param bufferedImage + * @param bufferedImageType + * @param width + * @param height + * @return + */ + public static BufferedImage fixedDimensionBufferedImage(BufferedImage bufferedImage, Integer bufferedImageType, Integer width, Integer height) { + BufferedImage newBufferedImage = new BufferedImage(width, height, bufferedImageType); + Graphics2D graphics2D = newBufferedImage.createGraphics(); + graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + graphics2D.drawImage(bufferedImage, 0, 0, width, height, null); + return newBufferedImage; + } + + + /** + * 合并两个图层 + * + * @param backBufferedImage + * @param frontBufferedImage + * @param pointX + * @param pointY + * @return + */ + public static BufferedImage mergeBufferedImage(BufferedImage backBufferedImage, BufferedImage frontBufferedImage, Integer pointX, Integer pointY) { + Graphics2D graphics2D = backBufferedImage.createGraphics(); + graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + graphics2D.drawImage(frontBufferedImage, pointX, pointY, frontBufferedImage.getWidth(), frontBufferedImage.getHeight(), null); + return backBufferedImage; + } + + /** + * 在图层上写字 + * + * @param bufferedImage + * @param str + * @param pointX + * @param pointY + * @param font + * @param color + * @return + */ + public static BufferedImage writeFontBufferedImage(BufferedImage bufferedImage, String str, Integer pointX, Integer pointY, Font font, Color color) { + Graphics2D graphics2D = bufferedImage.createGraphics(); + /*graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + graphics2D.setColor(color); + graphics2D.setFont(font); + graphics2D.drawString(str, pointX, pointY);*/ + writeFontBufferedImage(graphics2D,str,pointX,pointY,font,color); + return bufferedImage; + } + + public static void writeFontBufferedImage(Graphics2D graphics2D, String str, Integer pointX, Integer pointY, Font font, Color color) { + graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + graphics2D.setColor(color); + graphics2D.setFont(font); + graphics2D.drawString(str, pointX, pointY); + } + + + /** + * byte数组转成文件 + * + * @param bytes + * @param fileName + * @param fileType + * @param filePath + */ + public static void byteToFile(byte bytes[], String fileName, String fileType, String filePath) { + File fileFloder = new File(filePath); + if (!fileFloder.exists()) { + fileFloder.mkdirs(); + } + fileFloder = null; + ///fileName = WsStringUtils.stringTrim(fileName); + filePath = filePath + fileName + "." + fileType; + File file = new File(filePath); + FileOutputStream fileOutputStream = null; + FileChannel fileChannel = null; + try { + if (!file.exists()) { + file.createNewFile(); + } + fileOutputStream = new FileOutputStream(file); + fileChannel = fileOutputStream.getChannel(); + ByteBuffer byteBuffer = ByteBuffer.wrap(bytes); + fileChannel.write(byteBuffer); + byteBuffer.clear(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + if (fileChannel != null) { + fileChannel.close(); + } + if (fileOutputStream != null) { + fileOutputStream.flush(); + fileOutputStream.close(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + + } + + /** + * 为图片打马赛克 + * @param bufferedImage + * @param pointX + * @param pointY + * @param width + * @param height + * @param level + * @return + */ + public static BufferedImage createMosaic(BufferedImage bufferedImage, Integer pointX, Integer pointY, Integer width, Integer height, Integer level) { + int bufferImageWidth = bufferedImage.getWidth(); + int bufferImageHeight = bufferedImage.getHeight(); + Integer x = pointX; + Integer y = pointY; + int chunkWidth = width / level; + int chunkHeight = height / level; + chunkWidth = chunkWidth == 0 ? 1 : chunkWidth; + chunkHeight = chunkHeight == 0 ? 1 : chunkHeight; + + x -= chunkWidth; + y -= chunkHeight; + Random random = new Random(); + Graphics2D graphics2D = bufferedImage.createGraphics(); + /*Rectangle rectangle = new Rectangle(); + rectangle.setRect(pointX,pointY,chunkWidth,chunkHeight);*/ + while (x < pointX + width) { + x += chunkWidth; + while (y < pointY + height) { + y += chunkHeight; + Integer randomX = random.nextInt(chunkWidth); + Integer randomY = random.nextInt(chunkWidth); + int modificationX = 0; + int modificationY = 0; + if (x + randomX >= bufferImageWidth) { + modificationX = (x + randomX) - bufferImageWidth + 1; + } + if (y + randomY >= bufferImageHeight) { + modificationY = (y + randomY) - bufferImageHeight + 1; + } + + System.out.println("(" + (x + randomX - modificationX) + "," + (y + randomY - modificationY) + ")(" + x + "," + y + ")"); + + int rgb = bufferedImage.getRGB(x + randomX - modificationX, y + randomY - modificationY); + int a = rgb >>> 24; + int r = (rgb << 8) >>> 24; + int g = (rgb << 16) >>> 24; + int b = (rgb << 24) >>> 24; + //System.out.println("a:"+a+" r:"+r+" g:"+g+" b:"+b); + Color color = new Color(r, g, b); + graphics2D.setColor(color); + graphics2D.fillRect(x, y, chunkWidth, chunkHeight); + + + } + y = pointY - chunkHeight; + } + return bufferedImage; + } + + + /** + * bufferedImage转成byte数组 + * + * @param bufferedImage + * @param type + * @return + */ + public static byte[] bufferedImageToByteArray(BufferedImage bufferedImage, String type) { + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + byte[] bytes = null; + try { + ImageIO.write(bufferedImage, type, byteArrayOutputStream); + bytes = byteArrayOutputStream.toByteArray(); + bufferedImage.flush(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + byteArrayOutputStream.flush(); + byteArrayOutputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + return bytes; + + } + + /** + * 把字符串拆成行 + * @param context 文本内容 + * @param fontMetrics + * @param pointX 开始点的x轴坐标 + * @param pointY 开始点的y轴坐标 + * @param width 文本域宽度 + * @param height 文本域高度 + * @param wordSpace 字间距 + * @param lineSpace 行间距 + * @param horizontalType 1 右对齐 2 居中 3 左对齐 + * @return + */ + public static List splitContext(String context,FontMetrics fontMetrics,int pointX,int pointY,int width,int height,int wordSpace,int lineSpace,Integer horizontalType,Integer verticalType){ + context = new String(context.getBytes(StandardCharsets.UTF_8)); + Font font = fontMetrics.getFont(); + char[] chars = context.toCharArray(); + List returnLineList = new ArrayList<>(); + StringBuilder sb = new StringBuilder(); + //当前的行宽度 + int currentLineWidth = 0; + //当前的高度 + int currentHeight = font.getSize(); + //字体宽度 + int charSize = 0; + List charTextList = new ArrayList<>(); + for(char c:chars){ + charSize = fontMetrics.charWidth(c); + currentLineWidth += charSize; + if(currentLineWidth >= width){ + returnLineList.add(new LineText(pointX,width,currentHeight,sb.toString(),currentLineWidth - charSize - wordSpace,charTextList,horizontalType)); + currentHeight += font.getSize(); + currentHeight += lineSpace; + currentLineWidth = charSize; + charTextList = new ArrayList<>(); + sb = new StringBuilder(); + } + charTextList.add(new CharText(currentLineWidth - charSize,currentHeight,c)); + currentLineWidth += wordSpace; + sb.append(c); + if(currentHeight > height){ + sb = new StringBuilder(); + break; + } + } + if(sb.length() > 0){ + returnLineList.add(new LineText(pointX,width,currentHeight,sb.toString(),currentLineWidth - wordSpace,charTextList,horizontalType)); + } + if(verticalType.equals(2)){ + int allHeight = returnLineList.size()* font.getSize() + lineSpace * returnLineList.size() - 1; + pointY = (height - allHeight)/2 + pointY; + }else if (verticalType.equals(3)){ + int allHeight = returnLineList.size()* font.getSize() + lineSpace * returnLineList.size() - 1; + pointY = pointY + height - allHeight; + } + int finalPointY = pointY; + returnLineList.forEach(lineText -> { + lineText.setPointY(finalPointY + lineText.getPointY()); + lineText.getCharTextList().forEach(charText -> { + charText.setPointY(lineText.getPointY()); + }); + }); + return returnLineList; + + } + + /** + * 旋转图片 + * @param bufferedImage + * @param angle + * @return + */ + public static BufferedImage rotateImage(BufferedImage bufferedImage,double angle){ + Rectangle rectangle = getRotateRectangle(bufferedImage.getWidth(),bufferedImage.getHeight(),angle); + BufferedImage image = new BufferedImage((int) rectangle.getWidth(),(int) rectangle.getHeight(), BufferedImage.TYPE_4BYTE_ABGR); + Graphics2D graphics2D = image.createGraphics(); + graphics2D.translate((rectangle.getWidth() - bufferedImage.getWidth()) / 2,(rectangle.getHeight() - bufferedImage.getHeight()) / 2); + graphics2D.rotate(Math.toRadians(angle), BigDecimal.valueOf(bufferedImage.getWidth()/2).doubleValue(),BigDecimal.valueOf(bufferedImage.getHeight()/2).doubleValue()); + graphics2D.drawImage(bufferedImage,null,0,0); + return image; + } + + + public static Rectangle getRotateRectangle(double width,double height,double angle){ + if (angle >= 90) { + if((int) angle / 90 % 2 == 1){ + double temp = height; + height = width; + width = temp; + } + angle = angle % 90; + } + double j1Angle = Math.atan(height / width); + angle = Math.toRadians(angle); + double r = Math.sqrt(Math.pow(width,2)+Math.pow(height,2)) / 2; + double newWidth = Math.cos(j1Angle - angle) * r * 2; + double newHeight = Math.sin(j1Angle + angle) * r * 2; + newHeight = Math.abs(newHeight); + newWidth = Math.abs(newWidth); + return new Rectangle(0,0,(int) newWidth,(int) newHeight); + } + + + /** + * 解析16进制颜色 + * @param value + * @return + */ + public static Color getColor(String value){ + if(!value.startsWith("#")){ + throw new RuntimeException("格式错误"); + } + return new Color(Integer.parseInt(value.substring(1,3),16),Integer.parseInt(value.substring(3,5),16),Integer.parseInt(value.substring(5,7),16)); + } + + public static Color getColor(String value,Integer alpha){ + if(alpha == null){ + return getColor(value); + } + if(!value.startsWith("#")){ + throw new RuntimeException("格式错误"); + } + return new Color(Integer.parseInt(value.substring(1,3),16),Integer.parseInt(value.substring(3,5),16),Integer.parseInt(value.substring(5,7),16),alpha); + } + + + public static FontMetrics getFontMetrics(Font font){ + return J_LABEL.getFontMetrics(font); + } + + public static class LineText{ + + private Integer pointX; + + private Integer pointY; + + private String text; + + private Integer length; + + private List charTextList; + + public LineText(Integer pointX,Integer width,Integer pointY,String text,Integer length,List charTextList,Integer type){ + this.text = text; + this.length = length; + this.pointY = pointY; + if(type.equals(1)){ + this.pointX = pointX; + }else if(type.equals(2)){ + this.pointX = pointX+(width - length)/2; + }else if(type.equals(3)){ + this.pointX = pointX + width - length; + }else { + throw new RuntimeException("不支持的类型"); + } + charTextList.forEach(charText -> { + charText.setPointX(this.pointX + charText.getPointX()); + }); + this.charTextList = charTextList; + } + + public Integer getPointX() { + return pointX; + } + + public void setPointX(Integer pointX) { + this.pointX = pointX; + } + + public Integer getPointY() { + return pointY; + } + + public void setPointY(Integer pointY) { + this.pointY = pointY; + } + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } + + public Integer getLength() { + return length; + } + + public void setLength(Integer length) { + this.length = length; + } + + public List getCharTextList() { + return charTextList; + } + + public void setCharTextList(List charTextList) { + this.charTextList = charTextList; + } + } + + public static class CharText{ + + private Integer pointX; + + private Integer pointY; + + private Character value; + + public CharText(Integer pointX,Integer pointY,Character value){ + this.pointX = pointX; + this.pointY = pointY; + this.value = value; + } + + + public Integer getPointX() { + return pointX; + } + + public void setPointX(Integer pointX) { + this.pointX = pointX; + } + + public Integer getPointY() { + return pointY; + } + + public void setPointY(Integer pointY) { + this.pointY = pointY; + } + + public Character getValue() { + return value; + } + + public void setValue(Character value) { + this.value = value; + } + } + + /** + * 根据url 拉取文件 + * @param url + * @return + * @throws Exception + */ + public static File getFile(String url) throws Exception { + //对本地文件命名 + String fileName = url.substring(url.lastIndexOf("."),url.length()); + File file = null; + + URL urlfile; + InputStream inStream = null; + OutputStream os = null; + try { + file = File.createTempFile("fwj_url", fileName); + //下载 + urlfile = new URL(url); + inStream = urlfile.openStream(); + os = new FileOutputStream(file); + + int bytesRead = 0; + byte[] buffer = new byte[8192]; + while ((bytesRead = inStream.read(buffer, 0, 8192)) != -1) { + os.write(buffer, 0, bytesRead); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + if (null != os) { + os.close(); + } + if (null != inStream) { + inStream.close(); + } + + } catch (Exception e) { + e.printStackTrace(); + } + } + + return file; + } + + + /** + * 根据url获取图片并转换为multipartFile类型 + * @param url + * @return + */ + public static MultipartFile getMultipartFile(String url) { + FileInputStream inputStream = null; + OutputStream outputStream = null; + try { + File file = getFile(url); + System.out.println(file.toPath()); + FileItem fileItem = new DiskFileItem("formFieldName",//form表单文件控件的名字随便起 + Files.probeContentType(file.toPath()),//文件类型 + false, //是否是表单字段 + file.getName(),//原始文件名 + (int) file.length(),//Interger的最大值可以存储两部1G的电影 + file.getParentFile());//文件会在哪个目录创建 + //为DiskFileItem的OutputStream赋值 + inputStream = new FileInputStream(file); + outputStream = fileItem.getOutputStream(); + IOUtils.copy(inputStream, outputStream); + return new CommonsMultipartFile(fileItem); + } catch (Exception e) { + log.error("文件类型转换失败" + e.getMessage()); + return null; + } finally { + try { + if (null != inputStream) { + inputStream.close(); + } + + if (null != outputStream) { + outputStream.close(); + } + } catch (IOException e) { + log.error(">>文件流关闭失败" + e.getMessage()); + } + } + + } +} + diff --git a/linkwe-common/src/main/java/com/linkwechat/common/utils/img/NetFileUtils.java b/linkwe-common/src/main/java/com/linkwechat/common/utils/img/NetFileUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..d3d1901e661f9cfd4578123026e7b5c2fd2bb7eb --- /dev/null +++ b/linkwe-common/src/main/java/com/linkwechat/common/utils/img/NetFileUtils.java @@ -0,0 +1,166 @@ +package com.linkwechat.common.utils.img; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.vertx.core.Vertx; +import io.vertx.core.buffer.Buffer; +import io.vertx.ext.web.client.WebClient; +import org.springframework.web.multipart.MultipartFile; + +import java.awt.*; +import java.io.*; +import java.nio.channels.Channels; +import java.nio.channels.FileChannel; +import java.nio.channels.ReadableByteChannel; +import java.util.concurrent.Callable; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +/** + * @author ws + */ +public class NetFileUtils { + + private static final Vertx vertx = Vertx.vertx(); + + private static final WebClient webClient = WebClient.create(vertx); + + public static FileCallable getNetFile(String urlPath){ + FileCallable fileCallable = new FileCallable(); + + webClient.getAbs(urlPath).timeout(1000L*60L*10L).send().onSuccess(response -> { + if(response.statusCode() == 200 || response.statusCode() == 302){ + Buffer buffer = response.body(); + buffer.getByteBuf(); + byte[] bytes = buffer.getBytes(); + fileCallable.setFile(bytes); + }else { + fileCallable.error(); + } + }).onFailure(throwable -> { + fileCallable.error(); + throwable.printStackTrace(); + }); + return fileCallable; + + + } + + public static ByteArrayOutputStream getByteArrayOutputStream(FileCallable fileCallable,boolean clearBuf){ + try { + ByteBuf byteBuf = fileCallable.call(); + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + int byteLength = 1024; + byte[] bytes = new byte[byteLength]; + int length = 0; + while ((length = byteBuf.readableBytes()) > 0){ + byteBuf.readBytes(bytes, 0, Math.min(length, byteLength)); + byteArrayOutputStream.write(bytes,0, Math.min(length, byteLength)); + } + if(!clearBuf){ + byteBuf.resetReaderIndex(); + }else { + byteBuf.clear(); + } + return byteArrayOutputStream; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + + } + + public static class FileCallable implements Callable{ + + private final CountDownLatch countDownLatch = new CountDownLatch(1); + + private volatile ByteBuf byteBuf; + + /** + * Computes a result, or throws an exception if unable to do so. + * + * @return computed result + * @throws Exception if unable to compute a result + */ + @Override + public ByteBuf call() throws Exception { + boolean k = countDownLatch.await(10,TimeUnit.MINUTES); + if(k && byteBuf != null){ + return byteBuf; + }else { + throw new RuntimeException("获取失败"); + } + + } + + public void setFile(byte[] bytes){ + ByteBuf byteBuf = Unpooled.directBuffer(); + byteBuf.writeBytes(bytes); + this.byteBuf = byteBuf; + countDownLatch.countDown(); + } + + public void error(){ + countDownLatch.countDown(); + } + } + + public static class StreamMultipartFile implements MultipartFile{ + + private final String filename; + + private final byte[] bytes; + + public StreamMultipartFile(String filename,byte[] bytes){ + this.filename = filename; + this.bytes = bytes; + } + + @Override + public String getName() { + return filename; + } + + @Override + public String getOriginalFilename() { + return filename; + } + + @Override + public String getContentType() { + return null; + } + + @Override + public boolean isEmpty() { + return bytes==null || bytes.length == 0; + } + + @Override + public long getSize() { + return bytes.length; + } + + @Override + public byte[] getBytes() throws IOException { + return this.bytes; + } + + @Override + public InputStream getInputStream() throws IOException { + return new ByteArrayInputStream(bytes); + } + + @Override + public void transferTo(File file) throws IOException, IllegalStateException { + FileOutputStream fileOutputStream = new FileOutputStream(file); + FileChannel fileChannel = fileOutputStream.getChannel(); + ReadableByteChannel channel = Channels.newChannel(new ByteArrayInputStream(bytes)); + fileChannel.transferFrom(channel,0,bytes.length); + fileChannel.close(); + channel.close(); + fileOutputStream.close(); + } + } + +} diff --git a/linkwe-common/src/main/java/com/linkwechat/common/utils/poi/ExcelUtil.java b/linkwe-common/src/main/java/com/linkwechat/common/utils/poi/ExcelUtil.java index a78aa0efe7f0ea0d340ed403467a64ccd95acae0..a30bef0ecf1b4a2ca9eee68bfd7f003ec5da0335 100644 --- a/linkwe-common/src/main/java/com/linkwechat/common/utils/poi/ExcelUtil.java +++ b/linkwe-common/src/main/java/com/linkwechat/common/utils/poi/ExcelUtil.java @@ -9,17 +9,11 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; import java.math.BigDecimal; import java.text.DecimalFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Comparator; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; +import java.util.*; import java.util.stream.Collectors; import com.linkwechat.common.utils.StringUtils; +import org.apache.commons.io.IOUtils; import org.apache.poi.hssf.usermodel.HSSFDateUtil; import org.apache.poi.ss.usermodel.BorderStyle; import org.apache.poi.ss.usermodel.Cell; @@ -54,6 +48,12 @@ import com.linkwechat.common.exception.CustomException; import com.linkwechat.common.utils.DateUtils; import com.linkwechat.common.utils.DictUtils; import com.linkwechat.common.utils.reflect.ReflectUtils; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.ResourceLoader; + +import javax.annotation.Resource; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletResponse; /** * Excel相关处理 @@ -732,7 +732,8 @@ public class ExcelUtil */ public String encodingFilename(String filename) { - filename = UUID.randomUUID().toString() + "_" + filename + ".xlsx"; +// filename = UUID.randomUUID().toString() + "_" + filename + ".xlsx"; + filename = filename + ".xlsx"; return filename; } @@ -933,4 +934,26 @@ public class ExcelUtil } return val; } + + public static void downloadExcel(HttpServletResponse httpServletResponse,String fileName) throws Exception { + + InputStream inputStream = new ClassPathResource("/excel/seas.xlsx").getInputStream(); + + //设置响应类型 + httpServletResponse.setContentType("multipart/form-data;charset=utf-8"); + httpServletResponse.addHeader("Content-Disposition", + " attachment;filename=" + new String(fileName.getBytes(), "iso-8859-1")); + + if(Objects.nonNull(inputStream)){ + try(ServletOutputStream servletOutputStream = httpServletResponse.getOutputStream()){ + IOUtils.copy(inputStream, servletOutputStream); + httpServletResponse.flushBuffer(); + }catch (Exception e){ + log.error("模版下载失败"+fileName+":"+e.getMessage()); + } + } + + + } + } \ No newline at end of file diff --git a/linkwe-common/src/main/java/com/linkwechat/common/utils/wecom/ByteGroup.java b/linkwe-common/src/main/java/com/linkwechat/common/utils/wecom/ByteGroup.java new file mode 100644 index 0000000000000000000000000000000000000000..728349b28858e611d41f40d02399bc6dcce18060 --- /dev/null +++ b/linkwe-common/src/main/java/com/linkwechat/common/utils/wecom/ByteGroup.java @@ -0,0 +1,26 @@ +package com.linkwechat.common.utils.wecom; + +import java.util.ArrayList; + +public class ByteGroup { + ArrayList byteContainer = new ArrayList<>(); + + public byte[] toBytes() { + byte[] bytes = new byte[this.byteContainer.size()]; + for (int i = 0; i < this.byteContainer.size(); i++) { + bytes[i] = this.byteContainer.get(i); + } + return bytes; + } + + public ByteGroup addBytes(byte[] bytes) { + for (byte b : bytes) { + this.byteContainer.add(b); + } + return this; + } + + public int size() { + return this.byteContainer.size(); + } +} diff --git a/linkwe-common/src/main/java/com/linkwechat/common/utils/wecom/PKCS7Encoder.java b/linkwe-common/src/main/java/com/linkwechat/common/utils/wecom/PKCS7Encoder.java new file mode 100644 index 0000000000000000000000000000000000000000..7a1f1454a38896ad003d183068f2fdd0e18d7fb1 --- /dev/null +++ b/linkwe-common/src/main/java/com/linkwechat/common/utils/wecom/PKCS7Encoder.java @@ -0,0 +1,65 @@ +/* + * 对公众平台发送给公众账号的消息加解密示例代码. + * + * @copyright Copyright (c) 1998-2014 Tencent Inc. + */ + +package com.linkwechat.common.utils.wecom; + +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; + +/** + * 提供基于PKCS7算法的加解. + * + * @author tencent + */ +public class PKCS7Encoder { + private static final Charset CHARSET = StandardCharsets.UTF_8; + private static final int BLOCK_SIZE = 32; + + /** + * 获得对明文进行补位填充的字节. + * + * @param count 需要进行填充补位操作的明文字节个数 + * @return 补齐用的字节数组 + */ + public static byte[] encode(int count) { + // 计算需要填充的位数 + int amountToPad = BLOCK_SIZE - (count % BLOCK_SIZE); + // 获得补位所用的字符 + char padChr = chr(amountToPad); + StringBuilder tmp = new StringBuilder(); + for (int index = 0; index < amountToPad; index++) { + tmp.append(padChr); + } + return tmp.toString().getBytes(CHARSET); + } + + /** + * 删除解密后明文的补位字符. + * + * @param decrypted 解密后的明文 + * @return 删除补位字符后的明文 + */ + public static byte[] decode(byte[] decrypted) { + int pad = decrypted[decrypted.length - 1]; + if (pad < 1 || pad > 32) { + pad = 0; + } + return Arrays.copyOfRange(decrypted, 0, decrypted.length - pad); + } + + /** + * 将数字转化成ASCII码对应的字符,用于对明文进行补码. + * + * @param a 需要转化的数字 + * @return 转化得到的字符 + */ + private static char chr(int a) { + byte target = (byte) (a & 0xFF); + return (char) target; + } + +} diff --git a/linkwe-common/src/main/java/com/linkwechat/common/utils/wecom/RSAUtil.java b/linkwe-common/src/main/java/com/linkwechat/common/utils/wecom/RSAUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..46cbad4ef369fafaf233dc8c7d1aba50b0a1a5ba --- /dev/null +++ b/linkwe-common/src/main/java/com/linkwechat/common/utils/wecom/RSAUtil.java @@ -0,0 +1,73 @@ +package com.linkwechat.common.utils.wecom; + +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.openssl.PEMKeyPair; +import org.bouncycastle.openssl.PEMParser; +import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import java.io.IOException; +import java.io.Reader; +import java.io.StringReader; +import java.nio.charset.StandardCharsets; +import java.security.*; +import java.util.Base64; + +/** + * @author danmo + * @description + * @date 2020/12/7 23:37 + **/ +public class RSAUtil { + static{ + try{ + Security.addProvider(new BouncyCastleProvider()); + }catch(Exception e){ + e.printStackTrace(); + } + } + /** + * RSA pkcs1 2048bit 解密工具, + * 获取私钥PrivateKey + * + * @param privKeyPEM 2048bit pkcs1格式,base64编码后的RSA字符串 + * @return PrivateKey, 用于解密 decryptRSA + * @throws IOException 异常 + */ + public static PrivateKey getPrivateKey(String privKeyPEM) throws IOException { + PrivateKey privateKey = null; + Reader privateKeyReader = new StringReader(privKeyPEM); + PEMParser privatePemParser = new PEMParser(privateKeyReader); + Object privateObject = privatePemParser.readObject(); + if (privateObject instanceof PEMKeyPair) { + PEMKeyPair pemKeyPair = (PEMKeyPair) privateObject; + JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC"); + privateKey = converter.getPrivateKey(pemKeyPair.getPrivateKeyInfo()); + } + return privateKey; + } + + /** + * RSA pkcs1 2048bit 解密工具, + * + * @param str 被解密的字符串 + * @param privateKey 私钥对象 从 getPrivateKey 获取 + * @return 解密后数据 + * @throws NoSuchPaddingException 异常 + * @throws NoSuchAlgorithmException 异常 + * @throws InvalidKeyException 异常 + * @throws BadPaddingException 异常 + * @throws IllegalBlockSizeException 异常 + */ + public static String decryptRSA(String str, PrivateKey privateKey) throws NoSuchPaddingException, + NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, NoSuchProviderException { + Security.addProvider(new BouncyCastleProvider()); + Cipher rsa = Cipher.getInstance("RSA/ECB/PKCS1Padding", "BC"); + rsa.init(Cipher.DECRYPT_MODE, privateKey); + byte[] utf8 = rsa.doFinal(Base64.getDecoder().decode(str)); + return new String(utf8, StandardCharsets.UTF_8); + } +} diff --git a/linkwe-common/src/main/java/com/linkwechat/common/utils/wecom/SHA1.java b/linkwe-common/src/main/java/com/linkwechat/common/utils/wecom/SHA1.java new file mode 100644 index 0000000000000000000000000000000000000000..9174d03013c55260871e51dc2e68f4bffdbf64d1 --- /dev/null +++ b/linkwe-common/src/main/java/com/linkwechat/common/utils/wecom/SHA1.java @@ -0,0 +1,86 @@ +package com.linkwechat.common.utils.wecom; + +import com.linkwechat.common.exception.wecom.WeComException; +import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.lang3.StringUtils; + +import java.security.MessageDigest; +import java.util.Arrays; + +/** + * + * @author Daniel Qian + * @date 14/10/19 + */ +public class SHA1 { + + /** + * 串接arr参数,生成sha1 digest. + */ + public static String gen(String... arr) { + if (StringUtils.isAnyEmpty(arr)) { + throw new IllegalArgumentException("非法请求参数,有部分参数为空 : " + Arrays.toString(arr)); + } + + Arrays.sort(arr); + StringBuilder sb = new StringBuilder(); + for (String a : arr) { + sb.append(a); + } + return DigestUtils.sha1Hex(sb.toString()); + } + + /** + * 用&串接arr参数,生成sha1 digest. + */ + public static String genWithAmple(String... arr) { + if (StringUtils.isAnyEmpty(arr)) { + throw new IllegalArgumentException("非法请求参数,有部分参数为空 : " + Arrays.toString(arr)); + } + + Arrays.sort(arr); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < arr.length; i++) { + String a = arr[i]; + sb.append(a); + if (i != arr.length - 1) { + sb.append('&'); + } + } + return DigestUtils.sha1Hex(sb.toString()); + } + + + public static String getSHA1(String token, String timestamp, String nonce, String encrypt) throws WeComException { + try { + String[] array = new String[]{token, timestamp, nonce, encrypt}; + StringBuffer sb = new StringBuffer(); + Arrays.sort(array); + + for(int i = 0; i < 4; ++i) { + sb.append(array[i]); + } + + String str = sb.toString(); + MessageDigest md = MessageDigest.getInstance("SHA-1"); + md.update(str.getBytes()); + byte[] digest = md.digest(); + StringBuffer hexstr = new StringBuffer(); + String shaHex = ""; + + for(int i = 0; i < digest.length; ++i) { + shaHex = Integer.toHexString(digest[i] & 255); + if (shaHex.length() < 2) { + hexstr.append(0); + } + + hexstr.append(shaHex); + } + + return hexstr.toString(); + } catch (Exception var12) { + var12.printStackTrace(); + throw new WeComException("sha加密生成签名失败"); + } + } +} diff --git a/linkwe-common/src/main/java/com/linkwechat/common/utils/wecom/TicketUtils.java b/linkwe-common/src/main/java/com/linkwechat/common/utils/wecom/TicketUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..f17e1a643adb2087a71e193ca3dfe9cc3b5edc9f --- /dev/null +++ b/linkwe-common/src/main/java/com/linkwechat/common/utils/wecom/TicketUtils.java @@ -0,0 +1,35 @@ +package com.linkwechat.common.utils.wecom; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.lang3.RandomStringUtils; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author danmo + * @description + * @date 2021/1/6 12:00 + **/ +@Slf4j +public class TicketUtils { + + public static Map getSignatureMap(String ticketVaule, String url) { + String nonceStr = RandomStringUtils.randomAlphanumeric(10); + Long timestamp = System.currentTimeMillis() / 1000; + StringBuilder strBuild = new StringBuilder(); + strBuild.append("jsapi_ticket=").append(ticketVaule) + .append("&noncestr=").append(nonceStr) + .append("×tamp=").append(timestamp) + .append("&url=").append(url); + log.info("H5加密串:{}",strBuild.toString()); + String signature = DigestUtils.sha1Hex(strBuild.toString()); + return new HashMap(16) {{ + put("nonceStr", nonceStr); + put("timestamp", timestamp); + put("signature", signature); + }}; + } + +} diff --git a/linkwe-common/src/main/java/com/linkwechat/common/utils/wecom/WxCryptUtil.java b/linkwe-common/src/main/java/com/linkwechat/common/utils/wecom/WxCryptUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..00f55cf05cef1d599c43dc72a872be6b35b27245 --- /dev/null +++ b/linkwe-common/src/main/java/com/linkwechat/common/utils/wecom/WxCryptUtil.java @@ -0,0 +1,308 @@ +package com.linkwechat.common.utils.wecom; + +import com.google.common.base.CharMatcher; +import com.google.common.io.BaseEncoding; +import com.linkwechat.common.exception.wecom.WeComException; +import org.apache.commons.codec.binary.Base64; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.xml.sax.InputSource; + +import javax.crypto.Cipher; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import java.io.StringReader; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Random; + +/** + *
+ * 对公众平台发送给公众账号的消息加解密示例代码.
+ * Copyright (c) 1998-2014 Tencent Inc.
+ * 针对org.apache.commons.codec.binary.Base64,
+ * 需要导入架包commons-codec-1.9(或commons-codec-1.8等其他版本)
+ * 官方下载地址:http://commons.apache.org/proper/commons-codec/download_codec.cgi
+ * 
+ * + * @author Tencent + */ +public class WxCryptUtil { + + private static final Base64 BASE64 = new Base64(); + private static final Charset CHARSET = StandardCharsets.UTF_8; + + private static final ThreadLocal BUILDER_LOCAL = new ThreadLocal() { + @Override + protected DocumentBuilder initialValue() { + try { + final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setExpandEntityReferences(false); + factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); + return factory.newDocumentBuilder(); + } catch (ParserConfigurationException exc) { + throw new IllegalArgumentException(exc); + } + } + }; + + protected byte[] aesKey; + protected String token; + protected String appidOrCorpid; + + public WxCryptUtil() { + } + + /** + * 构造函数. + * + * @param token 公众平台上,开发者设置的token + * @param encodingAesKey 公众平台上,开发者设置的EncodingAESKey + * @param appidOrCorpid 公众平台appid/corpid + */ + public WxCryptUtil(String token, String encodingAesKey, String appidOrCorpid) { + this.token = token; + this.appidOrCorpid = appidOrCorpid; + this.aesKey = BaseEncoding.base64().decode(CharMatcher.whitespace().removeFrom(encodingAesKey)); + } + + private static String extractEncryptPart(String xml) { + try { + DocumentBuilder db = BUILDER_LOCAL.get(); + Document document = db.parse(new InputSource(new StringReader(xml))); + + Element root = document.getDocumentElement(); + return root.getElementsByTagName("Encrypt").item(0).getTextContent(); + } catch (Exception e) { + throw new WeComException(e.getMessage()); + } + } + + /** + * 将一个数字转换成生成4个字节的网络字节序bytes数组. + */ + private static byte[] number2BytesInNetworkOrder(int number) { + byte[] orderBytes = new byte[4]; + orderBytes[3] = (byte) (number & 0xFF); + orderBytes[2] = (byte) (number >> 8 & 0xFF); + orderBytes[1] = (byte) (number >> 16 & 0xFF); + orderBytes[0] = (byte) (number >> 24 & 0xFF); + return orderBytes; + } + + /** + * 4个字节的网络字节序bytes数组还原成一个数字. + */ + private static int bytesNetworkOrder2Number(byte[] bytesInNetworkOrder) { + int sourceNumber = 0; + for (int i = 0; i < 4; i++) { + sourceNumber <<= 8; + sourceNumber |= bytesInNetworkOrder[i] & 0xff; + } + return sourceNumber; + } + + /** + * 随机生成16位字符串. + */ + private static String genRandomStr() { + String base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + Random random = new Random(); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < 16; i++) { + int number = random.nextInt(base.length()); + sb.append(base.charAt(number)); + } + return sb.toString(); + } + + /** + * 生成xml消息. + * + * @param encrypt 加密后的消息密文 + * @param signature 安全签名 + * @param timestamp 时间戳 + * @param nonce 随机字符串 + * @return 生成的xml字符串 + */ + private static String generateXml(String encrypt, String signature, String timestamp, String nonce) { + String format = "\n" + "\n" + + "\n" + + "%3$s\n" + "\n" + + ""; + return String.format(format, encrypt, signature, timestamp, nonce); + } + + /** + * 发送文字消息格式封装 + * + * @param content + * @return + */ + public static String getTextRespData(String content) { + return ""; + } + + public static String getReqData(String toUserName, String encrypt, String agentId) { + return ""; + } + + /** + * 将公众平台回复用户的消息加密打包. + *
    + *
  1. 对要发送的消息进行AES-CBC加密
  2. + *
  3. 生成安全签名
  4. + *
  5. 将消息密文和安全签名打包成xml格式
  6. + *
+ * + * @param plainText 公众平台待回复用户的消息,xml格式的字符串 + * @return 加密后的可以直接回复用户的密文,包括msg_signature, timestamp, nonce, encrypt的xml格式的字符串 + */ + public String encrypt(String plainText) { + // 加密 + String encryptedXml = encrypt(genRandomStr(), plainText); + + // 生成安全签名 + String timeStamp = Long.toString(System.currentTimeMillis() / 1000L); + String nonce = genRandomStr(); + + String signature = SHA1.gen(this.token, timeStamp, nonce, encryptedXml); + return generateXml(encryptedXml, signature, timeStamp, nonce); + } + + /** + * 对明文进行加密. + * + * @param plainText 需要加密的明文 + * @return 加密后base64编码的字符串 + */ + protected String encrypt(String randomStr, String plainText) { + ByteGroup byteCollector = new ByteGroup(); + byte[] randomStringBytes = randomStr.getBytes(CHARSET); + byte[] plainTextBytes = plainText.getBytes(CHARSET); + byte[] bytesOfSizeInNetworkOrder = number2BytesInNetworkOrder(plainTextBytes.length); + byte[] appIdBytes = this.appidOrCorpid.getBytes(CHARSET); + + // randomStr + networkBytesOrder + text + appid + byteCollector.addBytes(randomStringBytes); + byteCollector.addBytes(bytesOfSizeInNetworkOrder); + byteCollector.addBytes(plainTextBytes); + byteCollector.addBytes(appIdBytes); + + // ... + pad: 使用自定义的填充方式对明文进行补位填充 + byte[] padBytes = PKCS7Encoder.encode(byteCollector.size()); + byteCollector.addBytes(padBytes); + + // 获得最终的字节流, 未加密 + byte[] unencrypted = byteCollector.toBytes(); + + try { + // 设置加密模式为AES的CBC模式 + Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); + SecretKeySpec keySpec = new SecretKeySpec(this.aesKey, "AES"); + IvParameterSpec iv = new IvParameterSpec(this.aesKey, 0, 16); + cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv); + + // 加密 + byte[] encrypted = cipher.doFinal(unencrypted); + + // 使用BASE64对加密后的字符串进行编码 + return BASE64.encodeToString(encrypted); + } catch (Exception e) { + throw new WeComException(e.getMessage()); + } + } + + /** + * 检验消息的真实性,并且获取解密后的明文. + *
    + *
  1. 利用收到的密文生成安全签名,进行签名验证
  2. + *
  3. 若验证通过,则提取xml中的加密消息
  4. + *
  5. 对消息进行解密
  6. + *
+ * + * @param msgSignature 签名串,对应URL参数的msg_signature + * @param timeStamp 时间戳,对应URL参数的timestamp + * @param nonce 随机串,对应URL参数的nonce + * @param encryptedXml 密文,对应POST请求的数据 + * @return 解密后的原文 + */ + public String decrypt(String msgSignature, String timeStamp, String nonce, String encryptedXml) { + // 密钥,公众账号的app corpSecret + // 提取密文 + String cipherText = extractEncryptPart(encryptedXml); + + // 验证安全签名 + String signature = SHA1.gen(this.token, timeStamp, nonce, cipherText); + if (!signature.equals(msgSignature)) { + throw new WeComException("加密消息签名校验失败"); + } + + // 解密 + return decrypt(cipherText); + } + + /** + * 对密文进行解密. + * + * @param cipherText 需要解密的密文 + * @return 解密得到的明文 + */ + public String decrypt(String cipherText) { + byte[] original; + try { + // 设置解密模式为AES的CBC模式 + Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); + SecretKeySpec keySpec = new SecretKeySpec(this.aesKey, "AES"); + IvParameterSpec iv = new IvParameterSpec(Arrays.copyOfRange(this.aesKey, 0, 16)); + cipher.init(Cipher.DECRYPT_MODE, keySpec, iv); + + // 使用BASE64对密文进行解码 + byte[] encrypted = Base64.decodeBase64(cipherText); + + // 解密 + original = cipher.doFinal(encrypted); + } catch (Exception e) { + throw new WeComException(e.getMessage()); + } + + String xmlContent; + String fromAppid; + try { + // 去除补位字符 + byte[] bytes = PKCS7Encoder.decode(original); + + // 分离16位随机字符串,网络字节序和AppId + byte[] networkOrder = Arrays.copyOfRange(bytes, 16, 20); + + int xmlLength = bytesNetworkOrder2Number(networkOrder); + + xmlContent = new String(Arrays.copyOfRange(bytes, 20, 20 + xmlLength), CHARSET); + fromAppid = new String(Arrays.copyOfRange(bytes, 20 + xmlLength, bytes.length), CHARSET); + } catch (Exception e) { + throw new WeComException(e.getMessage()); + } + + // appid不相同的情况 暂时忽略这段判断 +// if (!fromAppid.equals(this.appidOrCorpid)) { +// throw new WxRuntimeException("AppID不正确,请核实!"); +// } + + return xmlContent; + + } + + public String verifyURL(String msgSignature, String timeStamp, String nonce, String echoStr) throws WeComException { + String signature = SHA1.getSHA1(this.token, timeStamp, nonce, echoStr); + if (!signature.equals(msgSignature)) { + throw new WeComException("签名验证错误"); + } else { + return this.decrypt(echoStr); + } + } +} diff --git a/linkwe-common/src/main/java/com/tencent/wework/Finance.java b/linkwe-common/src/main/java/com/tencent/wework/Finance.java new file mode 100644 index 0000000000000000000000000000000000000000..aea17197f08257f89c25be30564994a0018caa12 --- /dev/null +++ b/linkwe-common/src/main/java/com/tencent/wework/Finance.java @@ -0,0 +1,129 @@ +package com.tencent.wework; + + +import com.linkwechat.common.utils.OsUtils; + +public class Finance { + public native static long NewSdk(); + + /** + * 初始化函数 + * Return值=0表示该API调用成功 + * + * @param /[in] sdk NewSdk返回的sdk指针 + * @param /[in] corpid 调用企业的企业id,例如:wwd08c8exxxx5ab44d,可以在企业微信管理端--我的企业--企业信息查看 + * @param /[in] secret 聊天内容存档的Secret,可以在企业微信管理端--管理工具--聊天内容存档查看 + * @return 返回是否初始化成功 + * 0 - 成功 + * !=0 - 失败 + */ + public native static int Init(long sdk, String corpid, String secret); + + /** + * 拉取聊天记录函数 + * Return值=0表示该API调用成功 + * + * @param /[in] sdk NewSdk返回的sdk指针 + * @param /[in] seq 从指定的seq开始拉取消息,注意的是返回的消息从seq+1开始返回,seq为之前接口返回的最大seq值。首次使用请使用seq:0 + * @param /[in] limit 一次拉取的消息条数,最大值1000条,超过1000条会返回错误 + * @param /[in] proxy 使用代理的请求,需要传入代理的链接。如:socks5://10.0.0.1:8081 或者 http://10.0.0.1:8081 + * @param /[in] passwd 代理账号密码,需要传入代理的账号密码。如 user_name:passwd_123 + * @param /[in] timeout 超时时间,单位秒 + * @param /[out] chatDatas 返回本次拉取消息的数据,slice结构体.内容包括errcode/errmsg,以及每条消息内容。 + * @return 返回是否调用成功 + * 0 - 成功 + * !=0 - 失败 + */ + public native static int GetChatData(long sdk, long seq, long limit, String proxy, String passwd, long timeout, long chatData); + + /** + * 拉取媒体消息函数 + * Return值=0表示该API调用成功 + * + * @param /[in] sdk NewSdk返回的sdk指针 + * @param /[in] sdkFileid 从GetChatData返回的聊天消息中,媒体消息包括的sdkfileid + * @param /[in] proxy 使用代理的请求,需要传入代理的链接。如:socks5://10.0.0.1:8081 或者 http://10.0.0.1:8081 + * @param /[in] passwd 代理账号密码,需要传入代理的账号密码。如 user_name:passwd_123 + * @param /[in] timeout 超时时间,单位秒 + * @param /[in] indexbuf 媒体消息分片拉取,需要填入每次拉取的索引信息。首次不需要填写,默认拉取512k,后续每次调用只需要将上次调用返回的outindexbuf填入即可。 + * @param /[out] media_data 返回本次拉取的媒体数据.MediaData结构体.内容包括data(数据内容)/outindexbuf(下次索引)/is_finish(拉取完成标记) + * @return 返回是否调用成功 + * 0 - 成功 + * !=0 - 失败 + */ + public native static int GetMediaData(long sdk, String indexbuf, String sdkField, String proxy, String passwd, long timeout, long mediaData); + + /** + * @param /[in] encrypt_key, getchatdata返回的encrypt_key + * @param /[in] encrypt_msg, getchatdata返回的content + * @param /[out] msg, 解密的消息明文 + * @return 返回是否调用成功 + * 0 - 成功 + * !=0 - 失败 + * @brief 解析密文 + */ + public native static int DecryptData(long sdk, String encrypt_key, String encrypt_msg, long msg); + + public native static void DestroySdk(long sdk); + + public native static long NewSlice(); + + /** + * @return + * @brief 释放slice,和NewSlice成对使用 + */ + public native static void FreeSlice(long slice); + + /** + * @return 内容 + * @brief 获取slice内容 + */ + public native static String GetContentFromSlice(long slice); + + /** + * @return 内容 + * @brief 获取slice内容长度 + */ + public native static int GetSliceLen(long slice); + + public native static long NewMediaData(); + + public native static void FreeMediaData(long mediaData); + + /** + * @return outindex + * @brief 获取mediadata outindex + */ + public native static String GetOutIndexBuf(long mediaData); + + /** + * @return data + * @brief 获取mediadata data数据 + */ + public native static byte[] GetData(long mediaData); + + public native static int GetIndexLen(long mediaData); + + public native static int GetDataLen(long mediaData); + + /** + * @return 1完成、0未完成 + * @brief 判断mediadata是否结束 + */ + public native static int IsMediaDataFinish(long mediaData); + + static { + if (OsUtils.isWindows()) { + System.loadLibrary("libeay32"); + System.loadLibrary("libprotobuf"); + System.loadLibrary("ssleay32"); + System.loadLibrary("libcurl"); + System.loadLibrary("WeWorkFinanceSdk"); + } else { + System.load("/app/projects/libWeWorkFinanceSdk_Java.so"); + } + + } + + +} \ No newline at end of file diff --git a/linkwe-common/src/main/java/com/tencent/wework/FinanceService.java b/linkwe-common/src/main/java/com/tencent/wework/FinanceService.java new file mode 100644 index 0000000000000000000000000000000000000000..aff19f2498239a463e87b9a0b4eed08ab28c8974 --- /dev/null +++ b/linkwe-common/src/main/java/com/tencent/wework/FinanceService.java @@ -0,0 +1,323 @@ +package com.tencent.wework; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.io.FileUtil; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.linkwechat.common.config.RuoYiConfig; +import com.linkwechat.common.utils.DateUtils; +import com.linkwechat.common.utils.StringUtils; +import com.linkwechat.common.utils.file.FileUploadUtils; +import com.linkwechat.common.utils.spring.SpringUtils; +import com.linkwechat.common.utils.uuid.IdUtils; +import com.linkwechat.common.utils.wecom.RSAUtil; +import lombok.extern.slf4j.Slf4j; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.security.PrivateKey; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Consumer; + +/** + * @author danmo + * @description + * @date 2020/12/2 16:01 + **/ +@Slf4j +public class FinanceService{ + + /** + * NewSdk返回的sdk指针 + */ + private long sdk = 0; + /** + * 超时时间,单位秒 + */ + private final long timeout = 5 * 60; + + /** + * 企业id + */ + private String corpId; + + /** + * 会话存档密钥 + */ + private String secret; + + /** + * 会话私钥 + */ + private String privateKey; + + /** + * 代理 + */ + private String proxy; + + /** + * 代理密码 + */ + private String passwd; + + /** + * 一次拉取的消息条数,最大值1000条,超过1000条会返回错误 + */ + private final long LIMIT = 1_000L; + + private RuoYiConfig ruoYiConfig; + + public FinanceService(String corpId, String secret, String privateKey){ + this(corpId,secret,privateKey,"",""); + } + /** + * 构造器 + * @param corpId 企业id + * @param secret 会话存档密钥 + * @param privateKey 会话私钥 + */ + public FinanceService(String corpId, String secret, String privateKey, String proxy, String passwd){ + this.corpId = corpId; + this.secret = secret; + this.privateKey = privateKey; + this.proxy = proxy; + this.passwd = passwd; + ruoYiConfig = SpringUtils.getBean(RuoYiConfig.class); + //初始化 + initSDK(); + } + + /** + * 初始化 + */ + private void initSDK() { + if (0 == sdk) { + sdk = Finance.NewSdk(); + Finance.Init(sdk, corpId, secret); + } + } + + /** + * 拉取聊天记录 + * + * @param seq 消息的seq值,标识消息的序号 + */ + public void getChatData(long seq, Consumer consumer) { + long slice = Finance.NewSlice(); + int ret = Finance.GetChatData(sdk, seq, LIMIT, proxy, passwd, timeout, slice); + if (ret != 0) { + log.info("getChatData ret " + ret); + return; + } + String content = Finance.GetContentFromSlice(slice); + JSONArray chatDataArr = JSONObject.parseObject(content).getJSONArray("chatdata"); + log.info("开始执行数据解析:------------"); + AtomicLong LocalSEQ = new AtomicLong(); + if (CollectionUtil.isNotEmpty(chatDataArr)) { + chatDataArr.stream().map(data -> (JSONObject) data).forEach(data -> { + LocalSEQ.set(data.getLong("seq")); + JSONObject jsonObject = decryptChatRecord(sdk, data.getString("encrypt_random_key"), data.getString("encrypt_chat_msg")); + if (jsonObject != null) { + jsonObject.put("seq", LocalSEQ.get()); + consumer.accept(jsonObject); + } + }); + log.info("数据解析完成:------------"); + } + Finance.FreeSlice(slice); + } + + /** + * @param sdk 初始化时候获取到的值 + * @param encryptRandomKey 企业微信返回的随机密钥 + * @param encryptChatMsg 企业微信返回的单条记录的密文消息 + * @return JSONObject 返回不同格式的聊天数据,格式有二十来种 + * 详情请看官网 https://open.work.weixin.qq.com/api/doc/90000/90135/91774#%E6%B6%88%E6%81%AF%E6%A0%BC%E5%BC%8F + */ + private JSONObject decryptChatRecord(Long sdk, String encryptRandomKey, String encryptChatMsg) { + Long msg = null; + try { + //获取私钥 + PrivateKey privateKeyObj = RSAUtil.getPrivateKey(privateKey); + String str = RSAUtil.decryptRSA(encryptRandomKey, privateKeyObj); + //初始化参数slice + msg = Finance.NewSlice(); + + //解密 + Finance.DecryptData(sdk, str, encryptChatMsg, msg); + String jsonDataStr = Finance.GetContentFromSlice(msg); + JSONObject realJsonData = JSONObject.parseObject(jsonDataStr); + String msgType = realJsonData.getString("msgtype"); + if (StringUtils.isNotEmpty(msgType)) { + getSwitchType(realJsonData, msgType); + } + log.info("数据解析:------------" + realJsonData.toJSONString()); + return realJsonData; + } catch (Exception e) { + log.error("解析密文失败"); + return null; + } finally { + if (msg != null) { + //释放参数slice + Finance.FreeSlice(msg); + } + } + } + + private void getSwitchType(JSONObject realJsonData, String msgType) { + switch (msgType) { + case "image": + setMediaImageData(realJsonData, msgType); + break; + case "voice": + setMediaVoiceData(realJsonData, msgType); + break; + case "video": + setMediaVideoData(realJsonData, msgType); + break; + case "emotion": + setMediaEmotionData(realJsonData, msgType); + break; + case "file": + setMediaFileData(realJsonData, msgType); + break; + case "mixed": + setMediaMixedData(realJsonData, msgType); + break; + case "meeting_voice_call": + case "voip_doc_share": + setMediaMeetingVoiceCallData(realJsonData, msgType); + break; + default: + break; + } + } + + private void setMediaMeetingVoiceCallData(JSONObject realJsonData, String msgType) { + JSONObject meetingVoiceCall = Optional.ofNullable(realJsonData.getJSONObject(msgType)) + .orElse(realJsonData.getJSONObject("content")); + String fileName = meetingVoiceCall.getString("filename"); + getPath(realJsonData, msgType, fileName); + } + + private void setMediaMixedData(JSONObject realJsonData, String msgType) { + JSONObject mixedData = realJsonData.getJSONObject(msgType); + JSONArray items = mixedData.getJSONArray("item"); + items.stream().map(item -> (JSONObject) item).forEach(item -> { + getSwitchType(item, item.getString("type")); + }); + } + + private void setMediaFileData(JSONObject realJsonData, String msgType) { + JSONObject emotionData = Optional.ofNullable(realJsonData.getJSONObject(msgType)) + .orElse(realJsonData.getJSONObject("content")); + String filename = emotionData.getString("filename"); + //String fileext = emotionData.getString("fileext"); + //String fileName = filename+"."+fileext; + getPath(realJsonData, msgType, filename); + } + + + private void setMediaImageData(JSONObject realJsonData, String msgType) { + String fileName = IdUtils.simpleUUID() + ".jpg"; + getPath(realJsonData, msgType, fileName); + } + + private void setMediaVoiceData(JSONObject realJsonData, String msgType) { + String fileName = IdUtils.simpleUUID() + ".amr"; + getPath(realJsonData, msgType, fileName); + } + + private void setMediaVideoData(JSONObject realJsonData, String msgType) { + String fileName = IdUtils.simpleUUID() + ".mp4"; + getPath(realJsonData, msgType, fileName); + } + + private void setMediaEmotionData(JSONObject realJsonData, String msgType) { + String fileName = ""; + JSONObject emotionData = realJsonData.getJSONObject(msgType); + Integer type = emotionData.getInteger("type"); + switch (type) { + case 1: + fileName = IdUtils.simpleUUID() + ".gif"; + break; + case 2: + fileName = IdUtils.simpleUUID() + ".png"; + break; + default: + break; + } + getPath(realJsonData, msgType, fileName); + } + + private void getPath(JSONObject realJsonData, String msgType, String fileName) { + String filePath = getFilePath(msgType); + JSONObject data = Optional.ofNullable(realJsonData.getJSONObject(msgType)) + .orElse(realJsonData.getJSONObject("content")); + String sdkfileid = data.getString("sdkfileid"); + try { + getMediaData(sdkfileid, filePath, fileName); + if(ruoYiConfig.getFile().isStartCosUpload()) { + //开启云上传开关则云上传,不然上传本地 + InputStream inputStream = new FileInputStream(new File(filePath,fileName)); + String fileFullName = FileUploadUtils.upload2Cos(inputStream, FileUtil.getSuffix(fileName), ruoYiConfig.getFile().getCos()); + String imgUrlPrefix = ruoYiConfig.getFile().getCos().getCosImgUrlPrefix(); + data.put("attachment", imgUrlPrefix + fileFullName); + }else { + data.put("attachment", filePath + "/" + fileName); + } + } catch (Exception e) { + e.printStackTrace(); + } + if (realJsonData.containsKey("content")) { + realJsonData.put("content", data); + } else { + realJsonData.put(msgType, data); + } + + } + + private String getFilePath(String msgType) { + return RuoYiConfig.getProfile() + "/" + msgType + "/" + DateUtils.getDate(); + } + + private void getMediaData(String sdkFileId, String filePath, String fileName) { + String indexbuf = ""; + while (true) { + long mediaData = Finance.NewMediaData(); + int ret = Finance.GetMediaData(sdk, indexbuf, sdkFileId, proxy, passwd, timeout, mediaData); + log.info("getMediaData ret:" + ret); + if (ret != 0) { + return; + } + try { + File f = new File(filePath); + if (!f.exists()) { + f.mkdirs(); + } + File file = new File(filePath, fileName); + if (!file.isDirectory()) { + file.createNewFile(); + } + FileOutputStream outputStream = new FileOutputStream(file, true); + outputStream.write(Finance.GetData(mediaData)); + outputStream.close(); + } catch (Exception e) { + e.printStackTrace(); + } + if (Finance.IsMediaDataFinish(mediaData) == 1) { + Finance.FreeMediaData(mediaData); + break; + } else { + indexbuf = Finance.GetOutIndexBuf(mediaData); + Finance.FreeMediaData(mediaData); + } + } + } +} diff --git a/linkwe-framework/pom.xml b/linkwe-framework/pom.xml index 54e9a4d1cb5bd931bc9d36b4dcc1ad0c43f995a6..e8880b14294b1f4126a4db77136912dc9a6d5777 100644 --- a/linkwe-framework/pom.xml +++ b/linkwe-framework/pom.xml @@ -56,11 +56,13 @@ net.java.dev.jna jna + 5.6.0 net.java.dev.jna jna-platform + 5.6.0 @@ -75,6 +77,15 @@ linkwe-wecom + + io.vertx + vertx-core + + + + io.vertx + vertx-web-client + diff --git a/linkwe-framework/src/main/java/com/linkwechat/framework/aspectj/LogAspect.java b/linkwe-framework/src/main/java/com/linkwechat/framework/aspectj/LogAspect.java index 6006aeee0f5e85ffcb8713598d54114353ad7a39..f4875a813b6189f4e569cf50d33f13dab91e61af 100644 --- a/linkwe-framework/src/main/java/com/linkwechat/framework/aspectj/LogAspect.java +++ b/linkwe-framework/src/main/java/com/linkwechat/framework/aspectj/LogAspect.java @@ -5,6 +5,7 @@ import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import com.linkwechat.common.enums.BusinessType; import com.linkwechat.framework.manager.AsyncManager; import com.linkwechat.framework.web.service.TokenService; import org.aspectj.lang.JoinPoint; @@ -92,8 +93,12 @@ public class LogAspect String ip = IpUtils.getIpAddr(ServletUtils.getRequest()); operLog.setOperIp(ip); // 返回参数 - operLog.setJsonResult(JSON.toJSONString(jsonResult)); - + String jsonResultStr = JSON.toJSONString(jsonResult); + if (jsonResultStr.length() > 2000){ + operLog.setJsonResult(jsonResultStr.substring(0,2000)); + }else { + operLog.setJsonResult(jsonResultStr); + } operLog.setOperUrl(ServletUtils.getRequest().getRequestURI()); if (loginUser != null) { diff --git a/linkwe-framework/src/main/java/com/linkwechat/framework/config/JsonSerializerManage.java b/linkwe-framework/src/main/java/com/linkwechat/framework/config/JsonSerializerManage.java index 58ee9b095e2bedf64369d3fae87a860edda7f002..b2fe47b4e48a80df08f8ae80ef211861333e6137 100644 --- a/linkwe-framework/src/main/java/com/linkwechat/framework/config/JsonSerializerManage.java +++ b/linkwe-framework/src/main/java/com/linkwechat/framework/config/JsonSerializerManage.java @@ -19,7 +19,7 @@ public class JsonSerializerManage { @Bean public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) { ObjectMapper objectMapper = builder.createXmlMapper(false).build(); - objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); +// objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); SimpleModule module = new SimpleModule(); module.addSerializer(Long.class, ToStringSerializer.instance); module.addSerializer(Long.TYPE, ToStringSerializer.instance); diff --git a/linkwe-framework/src/main/java/com/linkwechat/framework/config/MyBatisPlusConfig.java b/linkwe-framework/src/main/java/com/linkwechat/framework/config/MyBatisPlusConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..2d4d71f33d23192488912dc39e3b10125a1fd36f --- /dev/null +++ b/linkwe-framework/src/main/java/com/linkwechat/framework/config/MyBatisPlusConfig.java @@ -0,0 +1,84 @@ +package com.linkwechat.framework.config; + + +import com.github.pagehelper.PageInterceptor; +import com.linkwechat.common.config.RuoYiConfig; +import com.linkwechat.common.config.WeComeConfig; + +import org.apache.ibatis.plugin.Interceptor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + + + +/** + * Mybatis支持*匹配扫描包 + * + * @author ruoyi + */ +@Configuration +public class MyBatisPlusConfig { + @Autowired + WeComeConfig weComeConfig; + @Autowired + RuoYiConfig ruoYiConfig; + + + @Bean + public Interceptor[] plugins() { + + return new Interceptor[]{new PageInterceptor()}; + +// if(ruoYiConfig.isStartTenant()){ //多租户相关 +// MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); +// interceptor.addInnerInterceptor(new TenantLineInnerInterceptor( +// new TenantLineHandler() { +// // 获取租户 ID 值表达式,只支持单个 ID 值 +// @Override +// public Expression getTenantId() { +// +// try { +// WeCorpAccount weCorpAccount +// = SecurityUtils.getLoginUser().getUser().getWeCorpAccount(); +// if(null != weCorpAccount){ +// return new StringValue(weCorpAccount.getCorpId()); +// } +// }catch (Exception e){ +// return null; +// } +// +// return null; +// } +// // 这是 default 方法,默认返回 false 表示所有表都需要拼多租户条件, +// // 这里设置 role表不需要该条件 +// @Override +// public boolean ignoreTable(String tableName) { +// +// if(this.getTenantId()==null){ +// return true; +// } +// +// +// if (Arrays.asList(weComeConfig.getNeedTenant()) +// .contains(tableName)){ +// return false; +// } +// return true; +// } +// +// @Override +// public String getTenantIdColumn() { +// +// return "corp_id"; +// } +// })); +// return new Interceptor[]{interceptor,new PageInterceptor() +// }; +// +// }else{ +// return new Interceptor[]{new PageInterceptor()}; +// } + + } +} \ No newline at end of file diff --git a/linkwe-framework/src/main/java/com/linkwechat/framework/config/RedisConfig.java b/linkwe-framework/src/main/java/com/linkwechat/framework/config/RedisConfig.java index d11f9250b3f2890f1f6358fe98ea8ce5287b8799..ad2a5fc69edcc92100536503ec19a03ddbee9e1a 100644 --- a/linkwe-framework/src/main/java/com/linkwechat/framework/config/RedisConfig.java +++ b/linkwe-framework/src/main/java/com/linkwechat/framework/config/RedisConfig.java @@ -1,11 +1,22 @@ package com.linkwechat.framework.config; +import com.linkwechat.common.constant.WeConstans; +import com.linkwechat.framework.listener.ChatMsgCheckListener; +import com.linkwechat.framework.listener.ChatMsgListener; +import com.linkwechat.framework.listener.EmpleCodeExpiredListener; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.CachingConfigurerSupport; import org.springframework.cache.annotation.EnableCaching; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.MessageListener; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.listener.ChannelTopic; +import org.springframework.data.redis.listener.PatternTopic; +import org.springframework.data.redis.listener.RedisMessageListenerContainer; +import org.springframework.data.redis.listener.Topic; +import org.springframework.data.redis.listener.adapter.MessageListenerAdapter; import org.springframework.data.redis.serializer.StringRedisSerializer; import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.PropertyAccessor; @@ -20,6 +31,10 @@ import com.fasterxml.jackson.databind.ObjectMapper; @EnableCaching public class RedisConfig extends CachingConfigurerSupport { + + @Autowired + private RedisConnectionFactory redisConnectionFactory; + @Bean @SuppressWarnings(value = { "unchecked", "rawtypes" }) public RedisTemplate redisTemplate(RedisConnectionFactory connectionFactory) @@ -40,4 +55,34 @@ public class RedisConfig extends CachingConfigurerSupport template.afterPropertiesSet(); return template; } + + + + @Bean + public RedisMessageListenerContainer redisMessageListenerContainer(MessageListenerAdapter chatMsgAdapter, + MessageListenerAdapter chatMsgCheckAdapter) { + RedisMessageListenerContainer redisMessageListenerContainer = new RedisMessageListenerContainer(); + redisMessageListenerContainer.setConnectionFactory(redisConnectionFactory); + //定义监听渠道 + Topic msgChannel = new ChannelTopic(WeConstans.CONVERSATION_MSG_CHANNEL); + //定义监听器监听的Redis的消息 + redisMessageListenerContainer.addMessageListener(chatMsgAdapter,msgChannel); + redisMessageListenerContainer.addMessageListener(chatMsgCheckAdapter,msgChannel); + return redisMessageListenerContainer; + } + + @Bean + public EmpleCodeExpiredListener codeExpiredListener() { + return new EmpleCodeExpiredListener(this.redisMessageListenerContainer(null,null)); + } + + @Bean + MessageListenerAdapter chatMsgAdapter(ChatMsgListener receiver){ + return new MessageListenerAdapter(receiver); + } + + @Bean + MessageListenerAdapter chatMsgCheckAdapter(ChatMsgCheckListener receiver){ + return new MessageListenerAdapter(receiver); + } } diff --git a/linkwe-framework/src/main/java/com/linkwechat/framework/config/ResourcesConfig.java b/linkwe-framework/src/main/java/com/linkwechat/framework/config/ResourcesConfig.java index 1a34d891105ce1e8635651b60e267c9087e1a570..b7e1c47c24ab750537cb96d85b164a9f5e029cb4 100644 --- a/linkwe-framework/src/main/java/com/linkwechat/framework/config/ResourcesConfig.java +++ b/linkwe-framework/src/main/java/com/linkwechat/framework/config/ResourcesConfig.java @@ -24,6 +24,8 @@ public class ResourcesConfig implements WebMvcConfigurer @Autowired private RepeatSubmitInterceptor repeatSubmitInterceptor; + + @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { @@ -66,4 +68,5 @@ public class ResourcesConfig implements WebMvcConfigurer + } \ No newline at end of file diff --git a/linkwe-framework/src/main/java/com/linkwechat/framework/config/SecurityConfig.java b/linkwe-framework/src/main/java/com/linkwechat/framework/config/SecurityConfig.java index 4a94b8c776344209dcc65e699f71118cada2d778..6897670edc1944fa6827cfc4bf6a4a7278d8960b 100644 --- a/linkwe-framework/src/main/java/com/linkwechat/framework/config/SecurityConfig.java +++ b/linkwe-framework/src/main/java/com/linkwechat/framework/config/SecurityConfig.java @@ -1,7 +1,10 @@ package com.linkwechat.framework.config; +import com.linkwechat.common.config.RuoYiConfig; +import com.linkwechat.framework.security.filter.JwtAuthenticationTokenFilter; import com.linkwechat.framework.security.handle.AuthenticationEntryPointImpl; import com.linkwechat.framework.security.handle.LogoutSuccessHandlerImpl; +import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.http.HttpMethod; @@ -16,22 +19,20 @@ import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.authentication.logout.LogoutFilter; import org.springframework.web.filter.CorsFilter; -import com.linkwechat.framework.security.filter.JwtAuthenticationTokenFilter; /** * spring security配置 - * + * * @author ruoyi */ @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true) -public class SecurityConfig extends WebSecurityConfigurerAdapter -{ +public class SecurityConfig extends WebSecurityConfigurerAdapter { /** * 自定义用户认证逻辑 */ @Autowired private UserDetailsService userDetailsService; - + /** * 认证失败处理类 */ @@ -55,7 +56,12 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter */ @Autowired private CorsFilter corsFilter; - + + + @Autowired + private RuoYiConfig ruoYiConfig; + + /** * 解决 无法直接注入 AuthenticationManager * @@ -64,8 +70,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter */ @Bean @Override - public AuthenticationManager authenticationManagerBean() throws Exception - { + public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } @@ -85,8 +90,12 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter * authenticated | 用户登录后可访问 */ @Override - protected void configure(HttpSecurity httpSecurity) throws Exception - { + protected void configure(HttpSecurity httpSecurity) throws Exception { + + System.out.println( + StringUtils.join(ruoYiConfig.getAnonUrl(),",") + ); + httpSecurity // CSRF禁用,因为不使用session .csrf().disable() @@ -96,8 +105,9 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and() // 过滤请求 .authorizeRequests() - // 对于登录login 验证码captchaImage 允许匿名访问 - .antMatchers("/login", "/captchaImage","/findWxQrLoginInfo","/wxQrLogin").anonymous() + + .antMatchers(ruoYiConfig.getAnonUrl()).anonymous() + .antMatchers( HttpMethod.GET, "/*.html", @@ -105,14 +115,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter "/**/*.css", "/**/*.js" ).permitAll() - .antMatchers("/profile/**").anonymous() - .antMatchers("/common/download**").anonymous() - .antMatchers("/common/download/resource**").anonymous() - .antMatchers("/swagger-ui.html").anonymous() - .antMatchers("/swagger-resources/**").anonymous() - .antMatchers("/webjars/**").anonymous() - .antMatchers("/*/api-docs").anonymous() - .antMatchers("/druid/**").anonymous() + // 除上面外的所有请求全部需要鉴权认证 .anyRequest().authenticated() .and() @@ -123,15 +126,16 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter // 添加CORS filter httpSecurity.addFilterBefore(corsFilter, JwtAuthenticationTokenFilter.class); httpSecurity.addFilterBefore(corsFilter, LogoutFilter.class); + + String join = StringUtils.join(ruoYiConfig.getAnonUrl(), ","); } - + /** * 强散列哈希加密实现 */ @Bean - public BCryptPasswordEncoder bCryptPasswordEncoder() - { + public BCryptPasswordEncoder bCryptPasswordEncoder() { return new BCryptPasswordEncoder(); } @@ -139,8 +143,9 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter * 身份认证接口 */ @Override - protected void configure(AuthenticationManagerBuilder auth) throws Exception - { + protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder()); } + + } diff --git a/linkwe-framework/src/main/java/com/linkwechat/framework/config/WebMvcConfig.java b/linkwe-framework/src/main/java/com/linkwechat/framework/config/WebMvcConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..0a4b3c9ad05bebda52ae3e6fa45b6684eefd0a7d --- /dev/null +++ b/linkwe-framework/src/main/java/com/linkwechat/framework/config/WebMvcConfig.java @@ -0,0 +1,23 @@ +package com.linkwechat.framework.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.CorsRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; + +/** + * @description: + * @author: HaoN + * @create: 2021-06-01 17:07 + **/ +@Configuration +public class WebMvcConfig extends WebMvcConfigurerAdapter { + + @Override + public void addCorsMappings(CorsRegistry registry) { + registry.addMapping("/**") + .allowedOrigins("*") + .allowedMethods("POST", "GET", "PUT", "OPTIONS", "DELETE") + .maxAge(3600) + .allowCredentials(true); + } +} \ No newline at end of file diff --git a/linkwe-framework/src/main/java/com/linkwechat/framework/handler/GenericTypeHandler.java b/linkwe-framework/src/main/java/com/linkwechat/framework/handler/GenericTypeHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..98b575ea292f2c051d17615cb76e28e0a1fd4687 --- /dev/null +++ b/linkwe-framework/src/main/java/com/linkwechat/framework/handler/GenericTypeHandler.java @@ -0,0 +1,88 @@ +package com.linkwechat.framework.handler; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.linkwechat.wecom.domain.dto.message.CustomerMessagePushDto; +import org.apache.ibatis.type.BaseTypeHandler; +import org.apache.ibatis.type.JdbcType; +import org.apache.ibatis.type.MappedJdbcTypes; +import org.apache.ibatis.type.MappedTypes; + +import java.sql.CallableStatement; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; + +/** + * 用以mysql中json格式的字段,进行转换的自定义转换器,转换为实体类的T类型 属性 + * @param + */ +@SuppressWarnings("all") +@MappedTypes(value = {JSONObject.class, CustomerMessagePushDto.class}) +@MappedJdbcTypes(value = {JdbcType.VARCHAR}, includeNullJdbcType = true) +public class GenericTypeHandler extends BaseTypeHandler { + + private Class clazz; + + public GenericTypeHandler(Class clazz) { + if (clazz == null) { + throw new IllegalArgumentException("Type argument cannot be null"); + } + this.clazz = clazz; + } + + /** + * 设置非空参数 + * @param ps + * @param i + * @param parameter + * @param jdbcType + * @throws SQLException + */ + @Override + public void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException { + ps.setString(i, JSON.toJSONString(parameter)); + } + + /** + * 根据列名,获取可以为空的结果 + * @param rs + * @param columnName + * @return + * @throws SQLException + */ + @Override + public T getNullableResult(ResultSet rs, String columnName) throws SQLException { + String sqlJson = rs.getString(columnName); + if (null != sqlJson) { + return JSONObject.parseObject(sqlJson, clazz); + } + return null; + } + + /** + * 根据列索引,获取可以为空的结果 + * @param rs + * @param columnIndex + * @return + * @throws SQLException + */ + @Override + public T getNullableResult(ResultSet rs, int columnIndex) throws SQLException { + String sqlJson = rs.getString(columnIndex); + if (null != sqlJson) { + return JSONObject.parseObject(sqlJson, clazz); + } + return null; + } + + @Override + public T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { + String sqlJson = cs.getString(columnIndex); + if (null != sqlJson) { + return JSONObject.parseObject(sqlJson, clazz); + } + return null; + } + +} \ No newline at end of file diff --git a/linkwe-framework/src/main/java/com/linkwechat/framework/handler/ListTypeHandler.java b/linkwe-framework/src/main/java/com/linkwechat/framework/handler/ListTypeHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..953e0eb88031ae5c0d262aadf2136862b6f85d13 --- /dev/null +++ b/linkwe-framework/src/main/java/com/linkwechat/framework/handler/ListTypeHandler.java @@ -0,0 +1,87 @@ +package com.linkwechat.framework.handler; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.linkwechat.common.utils.StringUtils; +import com.linkwechat.wecom.domain.WeCustomerList; +import com.linkwechat.wecom.domain.WeGroup; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.ibatis.type.*; + +import java.sql.*; +import java.util.ArrayList; +import java.util.List; + + +/** + * 处理jsonArray字符串为pojoList + * @param + */ +//支持的java对象 +@SuppressWarnings("all") +@Slf4j +@MappedTypes(value = {WeGroup.class, WeCustomerList.class}) +@MappedJdbcTypes({JdbcType.VARCHAR}) +public class ListTypeHandler implements TypeHandler> { + + private List getListByJsonArrayString(String content,String filedName) { + + if (StringUtils.isEmpty(content)) { + return new ArrayList<>(); + } + + if(filedName!=null && "customers_info".equals(filedName)){ + return JSONObject.parseArray(content, WeCustomerList.class); + } + + if(filedName!=null && "groups_info".equals(filedName)){ + return JSONObject.parseArray(content, WeGroup.class); + } + + return null; + } + + /** + * 用于定义在Mybatis设置参数时该如何把Java类型的参数转换为对应的数据库类型 + * + *
+     * PreparedStatement pstmt = con.prepareStatement("UPDATE EMPLOYEES
+     * SET SALARY = ? WHERE ID = ?");
+     * pstmt.setBigDecimal(1, 153833.00)
+     * pstmt.setInt(2, 110592)
+     * 
+ * + * @param preparedStatement An object that represents a precompiled SQL statement + * @param i 当前参数的位置 + * @param t 当前参数的Java对象 + * @param jdbcType 当前参数的数据库类型 + * @throws SQLException + */ + @Override + public void setParameter(PreparedStatement preparedStatement, int i, List t, JdbcType jdbcType) throws SQLException { + if (CollectionUtils.isEmpty(t)) { + preparedStatement.setString(i, null); + } else { + preparedStatement.setString(i, JSON.toJSONString(t).replaceAll("[\ud800\udc00-\udbff\udfff\ud800-\udfff]", "")); + } + } + + @Override + public List getResult(ResultSet resultSet, String s) throws SQLException { + log.info("序列化集合字段:{}",s); + return getListByJsonArrayString(resultSet.getString(s),s); + } + + @Override + public List getResult(ResultSet resultSet, int i) throws SQLException { + return getListByJsonArrayString(resultSet.getString(i),null); + } + + @Override + public List getResult(CallableStatement callableStatement, int i) throws SQLException { + return getListByJsonArrayString(callableStatement.getString(i),null); + } + + +} \ No newline at end of file diff --git a/linkwe-framework/src/main/java/com/linkwechat/framework/handler/WeMetaObjectHandler.java b/linkwe-framework/src/main/java/com/linkwechat/framework/handler/WeMetaObjectHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..41fb07b997039e28f408a7e10fa900e4262d90aa --- /dev/null +++ b/linkwe-framework/src/main/java/com/linkwechat/framework/handler/WeMetaObjectHandler.java @@ -0,0 +1,56 @@ +package com.linkwechat.framework.handler; + +import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; +import com.linkwechat.common.exception.CustomException; +import com.linkwechat.common.utils.SecurityUtils; +import com.linkwechat.common.utils.StringUtils; +import lombok.extern.slf4j.Slf4j; +import org.apache.ibatis.reflection.MetaObject; +import org.springframework.stereotype.Component; + +import java.util.Date; + +/** + * @author danmo + * @description 填充器 + * @date 2021/6/19 21:42 + **/ +@Slf4j +@Component +public class WeMetaObjectHandler implements MetaObjectHandler { + private static final String CREATE_TIME = "createTime"; + private static final String CREATE_BY = "createBy"; + private static final String UPDATE_TIME = "updateTime"; + private static final String UPDATE_BY = "updateBy"; + + @Override + public void insertFill(MetaObject metaObject) { + //创建时间 + this.setFieldValByName(CREATE_TIME, new Date(), metaObject); + this.setFieldValByName(UPDATE_TIME, new Date(), metaObject); + //创建人 + String userName = getUserName(); + this.setFieldValByName(CREATE_BY, userName, metaObject); + this.setFieldValByName(UPDATE_BY, userName, metaObject); + + } + + @Override + public void updateFill(MetaObject metaObject) { + //更新时间 + this.setFieldValByName(UPDATE_TIME, new Date(), metaObject); + //更新人 + this.setFieldValByName(UPDATE_BY, getUserName(), metaObject); + } + + private String getUserName() { + + String userName; + try { + userName = SecurityUtils.getUsername(); + } catch (CustomException e){ + userName = "admin"; + } + return userName; + } +} diff --git a/linkwe-framework/src/main/java/com/linkwechat/framework/listener/ChatMsgCheckListener.java b/linkwe-framework/src/main/java/com/linkwechat/framework/listener/ChatMsgCheckListener.java new file mode 100644 index 0000000000000000000000000000000000000000..c302c2f664310038985e736a1c5806ce864eb456 --- /dev/null +++ b/linkwe-framework/src/main/java/com/linkwechat/framework/listener/ChatMsgCheckListener.java @@ -0,0 +1,151 @@ +package com.linkwechat.framework.listener; + +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.linkwechat.common.core.domain.entity.WeCorpAccount; +import com.linkwechat.common.enums.MessageType; +import com.linkwechat.common.utils.StringUtils; +import com.linkwechat.common.utils.Threads; +import com.linkwechat.wecom.client.WeMessagePushClient; +import com.linkwechat.wecom.domain.WeChatContactMsg; +import com.linkwechat.wecom.domain.WeChatContactSensitiveMsg; +import com.linkwechat.wecom.domain.WeSensitive; +import com.linkwechat.wecom.domain.dto.WeMessagePushDto; +import com.linkwechat.wecom.domain.dto.message.TextMessageDto; +import com.linkwechat.wecom.mapper.WeChatContactSensitiveMsgMapper; +import com.linkwechat.wecom.mapper.WeSensitiveMapper; +import com.linkwechat.wecom.service.IWeChatContactMsgService; +import com.linkwechat.wecom.service.IWeCorpAccountService; +import com.linkwechat.wecom.service.IWeSensitiveActHitService; +import com.linkwechat.wecom.service.IWeSensitiveService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.connection.Message; +import org.springframework.data.redis.connection.MessageListener; +import org.springframework.stereotype.Component; + +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; + +/** + * @author danmo + * @description 会话存档会话审核订阅者 + * @date 2021/7/27 23:11 + **/ +@Slf4j +@Component +public class ChatMsgCheckListener implements MessageListener { + + @Autowired + private IWeSensitiveService weSensitiveService; + @Autowired + private WeSensitiveMapper weSensitiveMapper; + @Autowired + private IWeChatContactMsgService weChatContactMsgService; + @Autowired + private WeChatContactSensitiveMsgMapper weChatContactSensitiveMsgMapper; + @Autowired + private IWeCorpAccountService weCorpAccountService; + @Autowired + private WeMessagePushClient weMessagePushClient; + @Autowired + private IWeSensitiveActHitService weSensitiveActHitService; + + @Override + public void onMessage(Message message, byte[] pattern) { + + JSONObject jsonObject = JSONObject.parseObject(new String(message.getBody())); + log.info(">>》》》 订阅消息,会话审核订阅者:message:{}", jsonObject.toJSONString()); + + Threads.SINGLE_THREAD_POOL.submit(() -> msgContextHandle(jsonObject)); + } + + private void msgContextHandle(JSONObject jsonObject) { + String msgType = jsonObject.getString("msgtype"); + if ("external_redpacket".equals(msgType) + || "redpacket".equals(msgType) + || "card".equals(msgType)) { + weSensitiveActHitService.hitWeSensitiveAct(jsonObject); + } else { + handleSensitiveHit(jsonObject); + } + } + + private void handleSensitiveHit(JSONObject jsonObject) { + String fromId = jsonObject.getString("from"); + String msgId = jsonObject.getString("msgid"); + String msgtype = jsonObject.getString("msgtype"); + StringBuilder objectString = new StringBuilder(jsonObject.getString(msgtype)); + if("external_redpacket".equals(msgtype)){ + objectString.append(jsonObject.getString("redpacket")); + }else if("docmsg".equals(msgtype)){ + objectString.append(jsonObject.getString("doc")); + }else if("markdown".equals(msgtype) + || "news".equals(msgtype)){ + objectString.append(jsonObject.getString("info")); + } + log.info("执行敏感词命中过滤,time=[{}]", System.currentTimeMillis()); + //获取所有的敏感词规则 + List allSensitiveRules = weSensitiveMapper.selectWeSensitiveList(new WeSensitive()); + //根据规则过滤命中 + if (CollectionUtils.isNotEmpty(allSensitiveRules)) { + String finalContent = objectString.toString(); + allSensitiveRules.forEach(weSensitive -> { + List patternWords = Arrays.asList(weSensitive.getPatternWords().split(",")); + List users = weSensitiveService.getScopeUsers(weSensitive.getAuditUserScope()); + //log.info("handleSensitiveHit: >>>>>>>>>>>>>>>>>>>>>>finalContent:{}, patternWords:{},users:{},from:{}", finalContent, JSONObject.toJSONString(patternWords), JSONObject.toJSONString(users), fromId); + if (StringUtils.isNotBlank(finalContent) + && !CollectionUtils.isEmpty(users) + && users.stream().anyMatch(fromId::equals)) { + WeChatContactSensitiveMsg wccsm = hitSensitive(patternWords, fromId, finalContent); + //log.info("handleSensitiveHit: >>>>>>>>>>>>>>>>>>>>>> wccsm:{}",JSONObject.toJSONString(wccsm)); + if (wccsm != null) { + wccsm.setMsgId(msgId); + wccsm.setFromId(fromId); + wccsm.setMsgTime(new Date(jsonObject.getLong("msgtime"))); + int result = weChatContactSensitiveMsgMapper.insert(wccsm); + if (result > 0) { + sendMessage(wccsm, weSensitive); + } + } + } + }); + } + } + + private WeChatContactSensitiveMsg hitSensitive(List patternWords, String user, String content) { + WeChatContactSensitiveMsg weChatContactSensitiveMsg = new WeChatContactSensitiveMsg(); + String patternWordStr = patternWords.stream().filter(content.trim()::contains).collect(Collectors.joining(",")); + //log.info("hitSensitive: >>>>>>>>>>>>>>>>>>>>>> patternWordStr:{}",patternWordStr); + if (StringUtils.isNotEmpty(patternWordStr)) { + weChatContactSensitiveMsg.setContent(content); + weChatContactSensitiveMsg.setSendStatus(0); + weChatContactSensitiveMsg.setPatternWords(patternWordStr); + return weChatContactSensitiveMsg; + } + return null; + } + + private void sendMessage(WeChatContactSensitiveMsg wccsm, Object weSensitiveObj) { + WeSensitive weSensitive = (WeSensitive) weSensitiveObj; + if (weSensitive.getAlertFlag().equals(1)) { + //发送消息通知给相应的审计人 + WeCorpAccount weCorpAccount = weCorpAccountService.findValidWeCorpAccount(); + String auditUserId = weSensitive.getAuditUserId(); + String content = "有消息触发敏感词,请登录系统及时处理!"; + TextMessageDto textMessageDto = new TextMessageDto(); + textMessageDto.setContent(content); + WeMessagePushDto pushDto = new WeMessagePushDto(); + pushDto.setTouser(auditUserId); + pushDto.setMsgtype(MessageType.TEXT.getMessageType()); + pushDto.setText(textMessageDto); + pushDto.setAgentid(Integer.parseInt(weCorpAccount.getAgentId())); + weMessagePushClient.sendMessageToUser(pushDto, weCorpAccount.getAgentId()); + wccsm.setSendStatus(1); + weChatContactSensitiveMsgMapper.updateById(wccsm); + } + } +} diff --git a/linkwe-framework/src/main/java/com/linkwechat/framework/listener/ChatMsgListener.java b/linkwe-framework/src/main/java/com/linkwechat/framework/listener/ChatMsgListener.java new file mode 100644 index 0000000000000000000000000000000000000000..de791a4a4943450335d716694f3531c5752689ab --- /dev/null +++ b/linkwe-framework/src/main/java/com/linkwechat/framework/listener/ChatMsgListener.java @@ -0,0 +1,73 @@ +package com.linkwechat.framework.listener; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollectionUtil; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.linkwechat.common.utils.StringUtils; +import com.linkwechat.common.utils.Threads; +import com.linkwechat.wecom.domain.WeChatContactMsg; +import com.linkwechat.wecom.service.IWeChatContactMsgService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.connection.Message; +import org.springframework.data.redis.connection.MessageListener; +import org.springframework.stereotype.Component; + +import java.util.Date; +import java.util.concurrent.Future; + +/** + * @author danmo + * @description 会话存档订阅者 + * @date 2021/7/27 23:11 + **/ +@Slf4j +@Component +public class ChatMsgListener implements MessageListener { + + @Autowired + private IWeChatContactMsgService weChatContactMsgService; + + @Override + public void onMessage(Message message, byte[] pattern) { + JSONObject jsonObject = JSONObject.parseObject(new String(message.getBody())); + log.info(">> 订阅消息,会话存档消息:{}", jsonObject.toJSONString()); + + Threads.SINGLE_THREAD_POOL.submit(() -> msgContextHandle(jsonObject)); + } + + + private void msgContextHandle(JSONObject jsonObject){ + WeChatContactMsg weChatContactMsg = new WeChatContactMsg(); + weChatContactMsg.setMsgId(jsonObject.getString("msgid")); + weChatContactMsg.setFromId(jsonObject.getString("from")); + weChatContactMsg.setToList(CollectionUtil.join(jsonObject.getJSONArray("tolist"), ",")); + weChatContactMsg.setAction(jsonObject.getString("action")); + weChatContactMsg.setRoomId(jsonObject.getString("roomid")); + weChatContactMsg.setMsgType(jsonObject.getString("msgtype")); + weChatContactMsg.setMsgTime(new Date(jsonObject.getLong("msgtime"))); + weChatContactMsg.setSeq(jsonObject.getLong("seq")); + String objectString = jsonObject.getString(jsonObject.getString("msgtype")); + if(StringUtils.isNotEmpty(objectString)){ + weChatContactMsg.setContact(objectString); + }else if("external_redpacket".equals(weChatContactMsg.getMsgType())){ + weChatContactMsg.setContact(jsonObject.getString("redpacket")); + }else if("docmsg".equals(weChatContactMsg.getMsgType())){ + weChatContactMsg.setContact(jsonObject.getString("doc")); + }else if("markdown".equals(weChatContactMsg.getMsgType()) + || "news".equals(weChatContactMsg.getMsgType())){ + weChatContactMsg.setContact(jsonObject.getString("info")); + } + if(!weChatContactMsg.getMsgId().contains("external")){ + weChatContactMsg.setIsExternal(1); + } + LambdaQueryWrapper wrapper = new LambdaQueryWrapper() + .eq(WeChatContactMsg::getMsgId, weChatContactMsg.getMsgId()) + .eq(WeChatContactMsg::getFromId, weChatContactMsg.getFromId()); + if(!weChatContactMsgService.update(weChatContactMsg,wrapper)){ + weChatContactMsgService.save(weChatContactMsg); + } + } +} diff --git a/linkwe-framework/src/main/java/com/linkwechat/framework/listener/EmpleCodeExpiredListener.java b/linkwe-framework/src/main/java/com/linkwechat/framework/listener/EmpleCodeExpiredListener.java new file mode 100644 index 0000000000000000000000000000000000000000..99101b471867a35ff7272f2d2e822640e4100e7a --- /dev/null +++ b/linkwe-framework/src/main/java/com/linkwechat/framework/listener/EmpleCodeExpiredListener.java @@ -0,0 +1,34 @@ +package com.linkwechat.framework.listener; + + +import com.linkwechat.common.constant.WeConstans; +import com.linkwechat.wecom.client.WeExternalContactClient; +import com.linkwechat.wecom.domain.WeEmpleCode; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.connection.Message; +import org.springframework.data.redis.listener.KeyExpirationEventMessageListener; +import org.springframework.data.redis.listener.RedisMessageListenerContainer; + +import java.nio.charset.StandardCharsets; + +/** + * @author danmo + * @description redis 键值过期监听 + * @date 2021/2/8 17:24 + **/ +public class EmpleCodeExpiredListener extends KeyExpirationEventMessageListener { + @Autowired + private WeExternalContactClient weExternalContactClient; + + public EmpleCodeExpiredListener(RedisMessageListenerContainer listenerContainer) { + super(listenerContainer); + } + + @Override + public void onMessage(Message message, byte[] pattern) { + System.out.println("过期key:" + message.toString()); + if(message.toString().contains(WeConstans.WE_EMPLE_CODE_KEY)){ + //weExternalContactClient.delContactWay(message.toString().split(":")[1]); + } + } +} diff --git a/linkwe-framework/src/main/java/com/linkwechat/framework/manager/ShutdownManager.java b/linkwe-framework/src/main/java/com/linkwechat/framework/manager/ShutdownManager.java index 2a74c3c87477d9df6302f1afaccc797738bd5b57..8b8f71e2265680422d0fbcf99861ca69c9f3ddef 100644 --- a/linkwe-framework/src/main/java/com/linkwechat/framework/manager/ShutdownManager.java +++ b/linkwe-framework/src/main/java/com/linkwechat/framework/manager/ShutdownManager.java @@ -1,5 +1,6 @@ package com.linkwechat.framework.manager; +import com.linkwechat.common.utils.Threads; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; @@ -28,8 +29,11 @@ public class ShutdownManager { try { + logger.info("====关闭后台线程池===="); + Threads.shutdownAndAwaitTermination(Threads.SINGLE_THREAD_POOL); logger.info("====关闭后台任务任务线程池===="); AsyncManager.me().shutdown(); + } catch (Exception e) { diff --git a/linkwe-framework/src/main/java/com/linkwechat/framework/security/filter/JwtAuthenticationTokenFilter.java b/linkwe-framework/src/main/java/com/linkwechat/framework/security/filter/JwtAuthenticationTokenFilter.java index cb0c13d7b19b9924c7a3b75e5b83c96b51d1e301..a927f84a9048d6b6a212f589653f41f4d5ca067b 100644 --- a/linkwe-framework/src/main/java/com/linkwechat/framework/security/filter/JwtAuthenticationTokenFilter.java +++ b/linkwe-framework/src/main/java/com/linkwechat/framework/security/filter/JwtAuthenticationTokenFilter.java @@ -1,6 +1,7 @@ package com.linkwechat.framework.security.filter; import java.io.IOException; +import java.util.Enumeration; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; @@ -33,6 +34,7 @@ public class JwtAuthenticationTokenFilter extends OncePerRequestFilter throws ServletException, IOException { LoginUser loginUser = tokenService.getLoginUser(request); + if (StringUtils.isNotNull(loginUser) && StringUtils.isNull(SecurityUtils.getAuthentication())) { tokenService.verifyToken(loginUser); diff --git a/linkwe-framework/src/main/java/com/linkwechat/framework/web/domain/server/SysFile.java b/linkwe-framework/src/main/java/com/linkwechat/framework/web/domain/server/SysFile.java index 067c1cb717e9b7496df0a6419b2bba148ade3082..6c24bf27a60e9a0c3f513b978dfb8d92a5204113 100644 --- a/linkwe-framework/src/main/java/com/linkwechat/framework/web/domain/server/SysFile.java +++ b/linkwe-framework/src/main/java/com/linkwechat/framework/web/domain/server/SysFile.java @@ -1,10 +1,19 @@ package com.linkwechat.framework.web.domain.server; +import lombok.AllArgsConstructor; +import lombok.experimental.SuperBuilder; +import lombok.Data; +import lombok.NoArgsConstructor; + /** * 系统文件相关信息 * * @author ruoyi */ +@Data +@SuperBuilder +@AllArgsConstructor +@NoArgsConstructor public class SysFile { /** @@ -42,73 +51,23 @@ public class SysFile */ private double usage; - public String getDirName() - { - return dirName; - } - - public void setDirName(String dirName) - { - this.dirName = dirName; - } - - public String getSysTypeName() - { - return sysTypeName; - } - - public void setSysTypeName(String sysTypeName) - { - this.sysTypeName = sysTypeName; - } - - public String getTypeName() - { - return typeName; - } - - public void setTypeName(String typeName) - { - this.typeName = typeName; - } - - public String getTotal() - { - return total; - } - - public void setTotal(String total) - { - this.total = total; - } - - public String getFree() - { - return free; - } - - public void setFree(String free) - { - this.free = free; - } - - public String getUsed() - { - return used; - } - - public void setUsed(String used) - { - this.used = used; - } - - public double getUsage() - { - return usage; - } - - public void setUsage(double usage) - { - this.usage = usage; - } + + /** + * 文件名 + */ + private String fileName; + + + /** + * 文件前缀 + */ + private String imgUrlPrefix; + + + /** + * 语音或者视频时长 + */ + private Long timeLong; + + } diff --git a/linkwe-framework/src/main/java/com/linkwechat/framework/web/service/FileService.java b/linkwe-framework/src/main/java/com/linkwechat/framework/web/service/FileService.java new file mode 100644 index 0000000000000000000000000000000000000000..f6bb27842469dccdc2d1fed4f4342e3d05a54cac --- /dev/null +++ b/linkwe-framework/src/main/java/com/linkwechat/framework/web/service/FileService.java @@ -0,0 +1,108 @@ +package com.linkwechat.framework.web.service; + + +import com.linkwechat.common.annotation.Log; +import com.linkwechat.common.config.RuoYiConfig; +import com.linkwechat.common.exception.file.InvalidExtensionException; +import com.linkwechat.common.utils.OsUtils; +import com.linkwechat.common.utils.file.FileUploadUtils; +import com.linkwechat.common.utils.file.FileUtils; +import com.linkwechat.common.utils.file.MimeTypeUtils; +import com.linkwechat.framework.web.domain.server.SysFile; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import java.io.File; +import java.io.IOException; + + +/** + * 文件服务 + */ +@Component +@Slf4j +public class FileService { + + + @Autowired + private RuoYiConfig ruoYiConfig; + + + private static final String WINDOWSFILEPATH="D:/linkWeChat/uploadPath"; + + + private static final String LINUXFILEPATH="/linkWeChat/uploadPath"; + + + + /** + * 文件上传 + * @param file + * @return + * @throws IOException + */ + public SysFile upload(MultipartFile file) throws IOException, InvalidExtensionException { + + try { + FileUploadUtils.assertAllowed(file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION); + String fileName=""; + String imgUrlPrefix=""; + if(ruoYiConfig.getFile().isStartCosUpload()){//开启云上传 + //开启云上传开关则云上传,不然上传本地 + fileName = FileUploadUtils.upload2Cos(file, ruoYiConfig.getFile().getCos()); + imgUrlPrefix = ruoYiConfig.getFile().getCos().getCosImgUrlPrefix(); + }else {//本地上传 + File osFile=OsUtils.isWindows()?new File(WINDOWSFILEPATH):new File(LINUXFILEPATH); + if(!osFile.exists()){ + osFile.mkdirs(); + } + fileName = FileUploadUtils.upload(osFile.getPath(), file); + imgUrlPrefix = ruoYiConfig.getFile().getImgUrlPrefix(); + } + + return SysFile.builder() + .fileName(fileName) + .imgUrlPrefix(imgUrlPrefix) +// .timeLong( +// FileUploadUtils.isAllowedExtension(FileUploadUtils.getExtension(file), +// MimeTypeUtils.MEDIA_EXTENSION +// )?FileUtils.getVideoOrVoice(file):new Long(0) +// ) + .build(); + + }catch (Exception e){ + + throw e; + + } + + } + + + /** + * 获取图片(本地,或者网络图片) + * @param fileName + * @param rp + */ + public void findImage(String fileName, HttpServletResponse rp){ + try { + String fileDownUrl=""; + rp.setContentType("image/png"); + if(ruoYiConfig.getFile().isStartCosUpload()) {//开启云上传 + fileDownUrl= ruoYiConfig.getFile().getCos().getCosImgUrlPrefix(); + FileUtils.downloadFile(fileDownUrl+fileName,rp.getOutputStream()); + }else{ + fileDownUrl=OsUtils.isWindows()?WINDOWSFILEPATH+"/"+fileName:LINUXFILEPATH+"/"+fileName; + FileUtils.writeBytes(fileDownUrl,rp.getOutputStream()); + } + }catch (Exception e){ + log.error("图片获取异常:"+e.getMessage()); + + } + } + + +} diff --git a/linkwe-framework/src/main/java/com/linkwechat/framework/web/service/TokenService.java b/linkwe-framework/src/main/java/com/linkwechat/framework/web/service/TokenService.java index 18833e7b7118ed963da0d25f5bf8c7b9f2213324..7972c0cf2918d05b96c99da03dbb35cf046f4b9f 100644 --- a/linkwe-framework/src/main/java/com/linkwechat/framework/web/service/TokenService.java +++ b/linkwe-framework/src/main/java/com/linkwechat/framework/web/service/TokenService.java @@ -1,10 +1,13 @@ package com.linkwechat.framework.web.service; +import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit; import javax.servlet.http.HttpServletRequest; + +import com.linkwechat.common.config.RuoYiConfig; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @@ -41,6 +44,9 @@ public class TokenService @Value("${token.expireTime}") private int expireTime; + @Autowired + private RuoYiConfig ruoYiConfig; + protected static final long MILLIS_SECOND = 1000; protected static final long MILLIS_MINUTE = 60 * MILLIS_SECOND; @@ -208,11 +214,19 @@ public class TokenService */ private String getToken(HttpServletRequest request) { - String token = request.getHeader(header); - if (StringUtils.isNotEmpty(token) && token.startsWith(Constants.TOKEN_PREFIX)) - { - token = token.replace(Constants.TOKEN_PREFIX, ""); + String token = ""; + //移除匿名接口中请求头的token + if(!Arrays.asList(ruoYiConfig.getAnonUrl()).contains(request.getRequestURI())){ +// request.removeAttribute(header); +// request. + token = request.getHeader(header); + if (StringUtils.isNotEmpty(token) && token.startsWith(Constants.TOKEN_PREFIX)) + { + token = token.replace(Constants.TOKEN_PREFIX, ""); + } } + + return token; } diff --git a/linkwe-framework/src/main/java/com/linkwechat/framework/web/service/UserDetailsServiceImpl.java b/linkwe-framework/src/main/java/com/linkwechat/framework/web/service/UserDetailsServiceImpl.java index 04881ebf4bcaf7408325db18e7ea2e8d461cf9a7..58f1dd6fdaeb68c035a78d0445f92cb4c5042e1b 100644 --- a/linkwe-framework/src/main/java/com/linkwechat/framework/web/service/UserDetailsServiceImpl.java +++ b/linkwe-framework/src/main/java/com/linkwechat/framework/web/service/UserDetailsServiceImpl.java @@ -1,18 +1,19 @@ package com.linkwechat.framework.web.service; -import cn.hutool.core.util.ArrayUtil; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.linkwechat.common.config.RuoYiConfig; import com.linkwechat.common.constant.Constants; -import com.linkwechat.common.core.domain.entity.SysRole; import com.linkwechat.common.core.domain.entity.SysUser; +import com.linkwechat.common.core.domain.entity.WeCorpAccount; import com.linkwechat.common.core.domain.model.LoginUser; import com.linkwechat.common.enums.UserStatus; import com.linkwechat.common.exception.BaseException; -import com.linkwechat.common.utils.SecurityUtils; import com.linkwechat.common.utils.StringUtils; -import com.linkwechat.system.mapper.SysRoleMapper; +import com.linkwechat.system.service.ISysRoleService; import com.linkwechat.system.service.ISysUserService; import com.linkwechat.wecom.domain.WeUser; +import com.linkwechat.wecom.service.IWeCorpAccountService; import com.linkwechat.wecom.service.IWeUserService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -22,8 +23,6 @@ import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; -import java.util.stream.Collectors; - /** * 用户验证处理 * @@ -40,15 +39,24 @@ public class UserDetailsServiceImpl implements UserDetailsService @Autowired private SysPermissionService permissionService; + @Autowired - private IWeUserService iWeUserService; + private IWeCorpAccountService iWeCorpAccountService; + + + @Autowired + private ISysRoleService iSysRoleService; @Autowired private RuoYiConfig ruoYiConfig; + @Autowired - private SysRoleMapper roleMapper; + private IWeUserService iWeUserService; + + + @Override @@ -57,32 +65,66 @@ public class UserDetailsServiceImpl implements UserDetailsService SysUser user = userService.selectUserByUserName(username); if (StringUtils.isNull(user)) { + //we_user表中去查询,如果该表为空则提示用户不存在,如果不为空,则将用户记录注册到系统用户表中 - WeUser weUser - = iWeUserService.getById(username); + WeUser weUser=iWeUserService.getOne(new LambdaQueryWrapper() + .eq(WeUser::getMobile,username) + .ne(WeUser::getIsActivate,new Integer(6))); if(null == weUser){ - log.info("登录用户:{} 不存在.", username); - throw new UsernameNotFoundException("登录用户:" + username + " 不存在"); + throw new BaseException("对不起,您的账号:" + username + " 不存在"); } - - //注册到we_user表中 - user=SysUser.builder() - .userName(weUser.getUserId()) - .nickName(weUser.getName()) - .userType(Constants.USER_TYPE_WECOME) - .email(weUser.getEmail()) - .phonenumber(weUser.getMobile()) - .sex(weUser.getGender().toString()) - .avatar(weUser.getAvatarMediaid()) - .roleIds(ArrayUtil.toArray(roleMapper.selectRoleList(SysRole.builder() - .roleKey(Constants.DEFAULT_WECOME_ROLE_KEY) - .build()).stream().map(SysRole::getRoleId).collect(Collectors.toList()), Long.class)) - .password(SecurityUtils.encryptPassword(ruoYiConfig.getWeUserDefaultPwd())) - .build(); - - userService.insertUser( - user - ); +// if(StrUtil.isBlank(weUser.getMobile())){ +// throw new BaseException("请填写当前企业员工的手机号:" + username + " 然后再登录"); +// } + +// //查询企业管理相关账号 +// WeCorpAccount weCorpByAccount = iWeCorpAccountService.getOne(new LambdaQueryWrapper().eq(WeCorpAccount::getCorpAccount, username) +// .eq(WeCorpAccount::getDelFlag, Constants.NORMAL_CODE)); +// if(null != weCorpByAccount){ +// //注册到we_user表中 +// user=SysUser.builder() +// .userName(weCorpByAccount.getCorpAccount()) +// .nickName(weCorpByAccount.getCompanyName()) +// .userType(Constants.USER_TYOE_CORP_ADMIN) +// .roleIds(ArrayUtil.toArray(iSysRoleService.selectRoleList(SysRole.builder() +// .roleKey(Constants.DEFAULT_WECOME_CORP_ADMIN) +// .build()).stream().map(SysRole::getRoleId).collect(Collectors.toList()), Long.class)) +// .password(SecurityUtils.encryptPassword(ruoYiConfig.getWeUserDefaultPwd())) +// .build(); +// } else{ +// //we_user表中去查询,如果该表为空则提示用户不存在,如果不为空,则将用户记录注册到系统用户表中 +// WeUser weUser=iWeUserService.getOne(new LambdaQueryWrapper() +// .eq(WeUser::getMobile,username) +// .ne(WeUser::getIsActivate,new Integer(6))); +// if(null == weUser){ +// throw new BaseException("对不起,您的账号:" + username + " 不存在"); +// } +// if(StrUtil.isBlank(weUser.getMobile())){ +// throw new BaseException("请填写当前企业员工的手机号:" + username + " 然后再登录"); +// } +// //注册到we_user表中 +// user=SysUser.builder() +// .userName(username) +// .nickName(weUser.getName()) +// .userType(Constants.USER_TYPE_WECOME) +// .email(weUser.getEmail()) +// .phonenumber(weUser.getMobile()) +// .sex(weUser.getGender() ==0 ? "1": weUser.getGender() .toString()) +// .avatar(weUser.getHeadImageUrl()) +// .weUserId(weUser.getUserId()) +// .roleIds(ArrayUtil.toArray(iSysRoleService.selectRoleList(SysRole.builder() +// .roleKey(Constants.DEFAULT_WECOME_ROLE_KEY) +// .build()).stream().map(SysRole::getRoleId).collect(Collectors.toList()), Long.class)) +// .password(SecurityUtils.encryptPassword(ruoYiConfig.getWeUserDefaultPwd())) +// .build(); +// +// } +// +// if(user != null){ +// userService.insertUser( +// user +// ); +// } } else if (UserStatus.DELETED.getCode().equals(user.getDelFlag())) { @@ -96,6 +138,15 @@ public class UserDetailsServiceImpl implements UserDetailsService } +// //当前登录用户为企业管理,设置corpId和密钥相关 +// if(Constants.USER_TYOE_CORP_ADMIN.equals(user.getUserType())){ +// user.setWeCorpAccount( +// iWeCorpAccountService.getOne(new LambdaQueryWrapper().eq(WeCorpAccount::getCorpAccount, username) +// .eq(WeCorpAccount::getDelFlag, Constants.NORMAL_CODE)) +// ); +// } + + return createLoginUser(user); } diff --git a/linkwe-generator/src/main/java/com/linkwechat/generator/domain/GenTable.java b/linkwe-generator/src/main/java/com/linkwechat/generator/domain/GenTable.java index 238f0c1454f72db701835de782de513c7d119166..d06734f3c878df3439d625f795f133b2584eacb8 100644 --- a/linkwe-generator/src/main/java/com/linkwechat/generator/domain/GenTable.java +++ b/linkwe-generator/src/main/java/com/linkwechat/generator/domain/GenTable.java @@ -1,12 +1,13 @@ package com.linkwechat.generator.domain; -import java.util.List; -import javax.validation.Valid; -import javax.validation.constraints.NotBlank; -import org.apache.commons.lang3.ArrayUtils; import com.linkwechat.common.constant.GenConstants; import com.linkwechat.common.core.domain.BaseEntity; import com.linkwechat.common.utils.StringUtils; +import org.apache.commons.lang3.ArrayUtils; + +import javax.validation.Valid; +import javax.validation.constraints.NotBlank; +import java.util.List; /** * 业务表 gen_table @@ -28,11 +29,17 @@ public class GenTable extends BaseEntity @NotBlank(message = "表描述不能为空") private String tableComment; + /** 关联父表的表名 */ + private String subTableName; + + /** 本表关联父表的外键名 */ + private String subTableFkName; + /** 实体类名称(首字母大写) */ @NotBlank(message = "实体类名称不能为空") private String className; - /** 使用的模板(crud单表操作 tree树表操作) */ + /** 使用的模板(crud单表操作 tree树表操作 sub主子表操作) */ private String tplCategory; /** 生成包路径 */ @@ -64,6 +71,9 @@ public class GenTable extends BaseEntity /** 主键信息 */ private GenTableColumn pkColumn; + /** 子表信息 */ + private GenTable subTable; + /** 表列信息 */ @Valid private List columns; @@ -116,6 +126,26 @@ public class GenTable extends BaseEntity this.tableComment = tableComment; } + public String getSubTableName() + { + return subTableName; + } + + public void setSubTableName(String subTableName) + { + this.subTableName = subTableName; + } + + public String getSubTableFkName() + { + return subTableFkName; + } + + public void setSubTableFkName(String subTableFkName) + { + this.subTableFkName = subTableFkName; + } + public String getClassName() { return className; @@ -216,6 +246,16 @@ public class GenTable extends BaseEntity this.pkColumn = pkColumn; } + public GenTable getSubTable() + { + return subTable; + } + + public void setSubTable(GenTable subTable) + { + this.subTable = subTable; + } + public List getColumns() { return columns; @@ -286,6 +326,16 @@ public class GenTable extends BaseEntity this.parentMenuName = parentMenuName; } + public boolean isSub() + { + return isSub(this.tplCategory); + } + + public static boolean isSub(String tplCategory) + { + return tplCategory != null && StringUtils.equals(GenConstants.TPL_SUB, tplCategory); + } + public boolean isTree() { return isTree(this.tplCategory); diff --git a/linkwe-generator/src/main/java/com/linkwechat/generator/util/GenUtils.java b/linkwe-generator/src/main/java/com/linkwechat/generator/util/GenUtils.java index 0b8fda991a670e2e8c277f0e5f01100e52aa2292..bc620d3fd1857c9a026ff9094929224c4574bb41 100644 --- a/linkwe-generator/src/main/java/com/linkwechat/generator/util/GenUtils.java +++ b/linkwe-generator/src/main/java/com/linkwechat/generator/util/GenUtils.java @@ -1,12 +1,13 @@ package com.linkwechat.generator.util; -import java.util.Arrays; -import org.apache.commons.lang3.RegExUtils; import com.linkwechat.common.constant.GenConstants; import com.linkwechat.common.utils.StringUtils; import com.linkwechat.generator.config.GenConfig; import com.linkwechat.generator.domain.GenTable; import com.linkwechat.generator.domain.GenTableColumn; +import org.apache.commons.lang3.RegExUtils; + +import java.util.Arrays; /** * 代码生成器 工具类 @@ -40,13 +41,14 @@ public class GenUtils column.setCreateBy(table.getCreateBy()); // 设置java字段名 column.setJavaField(StringUtils.toCamelCase(columnName)); + // 设置默认类型 + column.setJavaType(GenConstants.TYPE_STRING); - if (arraysContains(GenConstants.COLUMNTYPE_STR, dataType)) + if (arraysContains(GenConstants.COLUMNTYPE_STR, dataType) || arraysContains(GenConstants.COLUMNTYPE_TEXT, dataType)) { - column.setJavaType(GenConstants.TYPE_STRING); // 字符串长度超过500设置为文本域 Integer columnLength = getColumnLength(column.getColumnType()); - String htmlType = columnLength >= 500 ? GenConstants.HTML_TEXTAREA : GenConstants.HTML_INPUT; + String htmlType = columnLength >= 500 || arraysContains(GenConstants.COLUMNTYPE_TEXT, dataType) ? GenConstants.HTML_TEXTAREA : GenConstants.HTML_INPUT; column.setHtmlType(htmlType); } else if (arraysContains(GenConstants.COLUMNTYPE_TIME, dataType)) @@ -111,6 +113,21 @@ public class GenUtils { column.setHtmlType(GenConstants.HTML_SELECT); } + // 图片字段设置图片上传控件 + else if (StringUtils.endsWithIgnoreCase(columnName, "image")) + { + column.setHtmlType(GenConstants.HTML_IMAGE_UPLOAD); + } + // 文件字段设置文件上传控件 + else if (StringUtils.endsWithIgnoreCase(columnName, "file")) + { + column.setHtmlType(GenConstants.HTML_FILE_UPLOAD); + } + // 内容字段设置富文本控件 + else if (StringUtils.endsWithIgnoreCase(columnName, "content")) + { + column.setHtmlType(GenConstants.HTML_EDITOR); + } } /** diff --git a/linkwe-generator/src/main/java/com/linkwechat/generator/util/VelocityUtils.java b/linkwe-generator/src/main/java/com/linkwechat/generator/util/VelocityUtils.java index 65b6c3f5d993e33857fc629473f66900937989e3..830c2e8543e305809447ef1aa9a58eac43053592 100644 --- a/linkwe-generator/src/main/java/com/linkwechat/generator/util/VelocityUtils.java +++ b/linkwe-generator/src/main/java/com/linkwechat/generator/util/VelocityUtils.java @@ -63,6 +63,10 @@ public class VelocityUtils { setTreeVelocityContext(velocityContext, genTable); } + if (GenConstants.TPL_SUB.equals(tplCategory)) + { + setSubVelocityContext(velocityContext, genTable); + } return velocityContext; } @@ -96,6 +100,24 @@ public class VelocityUtils } } + public static void setSubVelocityContext(VelocityContext context, GenTable genTable) + { + GenTable subTable = genTable.getSubTable(); + String subTableName = genTable.getSubTableName(); + String subTableFkName = genTable.getSubTableFkName(); + String subClassName = genTable.getSubTable().getClassName(); + String subTableFkClassName = StringUtils.convertToCamelCase(subTableFkName); + + context.put("subTable", subTable); + context.put("subTableName", subTableName); + context.put("subTableFkName", subTableFkName); + context.put("subTableFkClassName", subTableFkClassName); + context.put("subTableFkclassName", StringUtils.uncapitalize(subTableFkClassName)); + context.put("subClassName", subClassName); + context.put("subclassName", StringUtils.uncapitalize(subClassName)); + context.put("subImportList", getImportList(genTable.getSubTable())); + } + /** * 获取模板信息 * @@ -199,6 +221,37 @@ public class VelocityUtils return basePackage; } + + /** + * 根据列类型获取导入包 + * + * @param genTable 业务表对象 + * @return 返回需要导入的包列表 + */ + public static HashSet getImportList(GenTable genTable) + { + List columns = genTable.getColumns(); + GenTable subGenTable = genTable.getSubTable(); + HashSet importList = new HashSet(); + if (StringUtils.isNotNull(subGenTable)) + { + importList.add("java.util.List"); + } + for (GenTableColumn column : columns) + { + if (!column.isSuperColumn() && GenConstants.TYPE_DATE.equals(column.getJavaType())) + { + importList.add("java.util.Date"); + importList.add("com.fasterxml.jackson.annotation.JsonFormat"); + } + else if (!column.isSuperColumn() && GenConstants.TYPE_BIGDECIMAL.equals(column.getJavaType())) + { + importList.add("java.math.BigDecimal"); + } + } + return importList; + } + /** * 根据列类型获取导入包 * diff --git a/linkwe-generator/src/main/resources/generator.yml b/linkwe-generator/src/main/resources/generator.yml index 5bd3dd67b84fc8de893ebad2946f90ba41d27154..e88aedba6a3a5f3e50e60506e0da41dcbae7d70a 100644 --- a/linkwe-generator/src/main/resources/generator.yml +++ b/linkwe-generator/src/main/resources/generator.yml @@ -3,7 +3,7 @@ gen: # 作者 author: ruoyi # 默认生成包路径 system 需改成自己的模块名称 如 system monitor tool - packageName: com.ruoyi.system + packageName: com.linkwechat # 自动去除表前缀,默认是false autoRemovePre: false # 表前缀(生成类名不会包含表前缀,多个用逗号分隔) diff --git a/linkwe-generator/src/main/resources/mapper/generator/GenTableColumnMapper.xml b/linkwe-generator/src/main/resources/mapper/generator/GenTableColumnMapper.xml index eeda40dc2413165a2a3377988bff114ffd8373a9..12788eda49d98b8a0b0b360c976150753279aeb2 100644 --- a/linkwe-generator/src/main/resources/mapper/generator/GenTableColumnMapper.xml +++ b/linkwe-generator/src/main/resources/mapper/generator/GenTableColumnMapper.xml @@ -116,5 +116,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" #{tableId} + + + delete from gen_table_column where column_id in + + #{item.columnId} + + \ No newline at end of file diff --git a/linkwe-generator/src/main/resources/vm/java/controller.java.vm b/linkwe-generator/src/main/resources/vm/java/controller.java.vm index 6a2275c5148a8585a60c79537726a91b1a961c16..aced3bd4adfb9186131654a1f358f9608850c062 100644 --- a/linkwe-generator/src/main/resources/vm/java/controller.java.vm +++ b/linkwe-generator/src/main/resources/vm/java/controller.java.vm @@ -1,6 +1,9 @@ -package ${packageName}.controller; +package ${packageName}.web.controller.wecom; import java.util.List; +import java.util.Arrays; + +import lombok.RequiredArgsConstructor; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; @@ -11,15 +14,15 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import Log; -import BaseController; -import AjaxResult; -import BusinessType; +import com.ruoyi.common.annotation.Log; +import com.ruoyi.common.core.controller.BaseController; +import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.enums.BusinessType; import ${packageName}.domain.${ClassName}; import ${packageName}.service.I${ClassName}Service; -import ExcelUtil; -#if($table.crud) -import TableDataInfo; +import com.ruoyi.common.utils.poi.ExcelUtil; +#if($table.crud || $table.sub) +import com.ruoyi.common.core.page.TableDataInfo; #elseif($table.tree) #end @@ -29,29 +32,27 @@ import TableDataInfo; * @author ${author} * @date ${datetime} */ +@RequiredArgsConstructor(onConstructor_ = @Autowired) @RestController -@RequestMapping("/${moduleName}/${businessName}") -public class ${ClassName}Controller extends BaseController -{ - @Autowired - private I${ClassName}Service ${className}Service; +@RequestMapping("/${moduleName}/${businessName}" ) +public class ${ClassName}Controller extends BaseController { + + private final I${ClassName}Service i${ClassName}Service; /** * 查询${functionName}列表 */ @PreAuthorize("@ss.hasPermi('${permissionPrefix}:list')") @GetMapping("/list") -#if($table.crud) - public TableDataInfo list(${ClassName} ${className}) - { +#if($table.crud || $table.sub) + public TableDataInfo list(${ClassName} ${className}) { startPage(); - List<${ClassName}> list = ${className}Service.select${ClassName}List(${className}); + List<${ClassName}> list = i${ClassName}Service.queryList(${className}); return getDataTable(list); } #elseif($table.tree) - public AjaxResult list(${ClassName} ${className}) - { - List<${ClassName}> list = ${className}Service.select${ClassName}List(${className}); + public AjaxResult list(${ClassName} ${className}) { + List<${ClassName}> list = i${ClassName}Service.queryList(${className}); return AjaxResult.success(list); } #end @@ -59,56 +60,51 @@ public class ${ClassName}Controller extends BaseController /** * 导出${functionName}列表 */ - @PreAuthorize("@ss.hasPermi('${permissionPrefix}:export')") - @Log(title = "${functionName}", businessType = BusinessType.EXPORT) - @GetMapping("/export") - public AjaxResult export(${ClassName} ${className}) - { - List<${ClassName}> list = ${className}Service.select${ClassName}List(${className}); + @PreAuthorize("@ss.hasPermi('${permissionPrefix}:export')" ) + @Log(title = "${functionName}" , businessType = BusinessType.EXPORT) + @GetMapping("/export" ) + public AjaxResult export(${ClassName} ${className}) { + List<${ClassName}> list = i${ClassName}Service.queryList(${className}); ExcelUtil<${ClassName}> util = new ExcelUtil<${ClassName}>(${ClassName}.class); - return util.exportExcel(list, "${businessName}"); + return util.exportExcel(list, "${businessName}" ); } /** * 获取${functionName}详细信息 */ - @PreAuthorize("@ss.hasPermi('${permissionPrefix}:query')") - @GetMapping(value = "/{${pkColumn.javaField}}") - public AjaxResult getInfo(@PathVariable("${pkColumn.javaField}") ${pkColumn.javaType} ${pkColumn.javaField}) - { - return AjaxResult.success(${className}Service.select${ClassName}ById(${pkColumn.javaField})); + @PreAuthorize("@ss.hasPermi('${permissionPrefix}:query')" ) + @GetMapping(value = "/{${pkColumn.javaField}}" ) + public AjaxResult getInfo(@PathVariable("${pkColumn.javaField}" ) ${pkColumn.javaType} ${pkColumn.javaField}) { + return AjaxResult.success(i${ClassName}Service.getById(${pkColumn.javaField})); } /** * 新增${functionName} */ - @PreAuthorize("@ss.hasPermi('${permissionPrefix}:add')") - @Log(title = "${functionName}", businessType = BusinessType.INSERT) + @PreAuthorize("@ss.hasPermi('${permissionPrefix}:add')" ) + @Log(title = "${functionName}" , businessType = BusinessType.INSERT) @PostMapping - public AjaxResult add(@RequestBody ${ClassName} ${className}) - { - return toAjax(${className}Service.insert${ClassName}(${className})); + public AjaxResult add(@RequestBody ${ClassName} ${className}) { + return toAjax(i${ClassName}Service.save(${className}) ? 1 : 0); } /** * 修改${functionName} */ - @PreAuthorize("@ss.hasPermi('${permissionPrefix}:edit')") - @Log(title = "${functionName}", businessType = BusinessType.UPDATE) + @PreAuthorize("@ss.hasPermi('${permissionPrefix}:edit')" ) + @Log(title = "${functionName}" , businessType = BusinessType.UPDATE) @PutMapping - public AjaxResult edit(@RequestBody ${ClassName} ${className}) - { - return toAjax(${className}Service.update${ClassName}(${className})); + public AjaxResult edit(@RequestBody ${ClassName} ${className}) { + return toAjax(i${ClassName}Service.updateById(${className}) ? 1 : 0); } /** * 删除${functionName} */ - @PreAuthorize("@ss.hasPermi('${permissionPrefix}:remove')") - @Log(title = "${functionName}", businessType = BusinessType.DELETE) - @DeleteMapping("/{${pkColumn.javaField}s}") - public AjaxResult remove(@PathVariable ${pkColumn.javaType}[] ${pkColumn.javaField}s) - { - return toAjax(${className}Service.delete${ClassName}ByIds(${pkColumn.javaField}s)); + @PreAuthorize("@ss.hasPermi('${permissionPrefix}:remove')" ) + @Log(title = "${functionName}" , businessType = BusinessType.DELETE) + @DeleteMapping("/{${pkColumn.javaField}s}" ) + public AjaxResult remove(@PathVariable ${pkColumn.javaType}[] ${pkColumn.javaField}s) { + return toAjax(i${ClassName}Service.removeByIds(Arrays.asList(${pkColumn.javaField}s)) ? 1 : 0); } } diff --git a/linkwe-generator/src/main/resources/vm/java/domain.java.vm b/linkwe-generator/src/main/resources/vm/java/domain.java.vm index c5f22514b484830d079f74b51360cd15769e573e..41df89801e94d754a119fed5059b6b1e6522929c 100644 --- a/linkwe-generator/src/main/resources/vm/java/domain.java.vm +++ b/linkwe-generator/src/main/resources/vm/java/domain.java.vm @@ -1,16 +1,19 @@ -package ${packageName}.domain; +package ${packageName}.wecom.domain; -#foreach ($import in $importList) -import ${import}; -#end -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; -import Excel; -#if($table.crud) -import BaseEntity; -#elseif($table.tree) -import TreeEntity; -#end +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; +import com.ruoyi.common.annotation.Excel; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import java.io.Serializable; +import java.util.Date; +import java.util.Map; +import java.util.HashMap; +import java.math.BigDecimal; /** * ${functionName}对象 ${tableName} @@ -18,17 +21,16 @@ import TreeEntity; * @author ${author} * @date ${datetime} */ -#if($table.crud) -#set($Entity="BaseEntity") -#elseif($table.tree) -#set($Entity="TreeEntity") -#end -public class ${ClassName} extends ${Entity} -{ - private static final long serialVersionUID = 1L; +@Data +@NoArgsConstructor +@Accessors(chain = true) +@TableName("${tableName}") +public class ${ClassName} implements Serializable { + +private static final long serialVersionUID=1L; #foreach ($column in $columns) -#if(!$table.isSuperColumn($column.javaField)) + /** $column.columnComment */ #if($column.list) #set($parentheseIndex=$column.columnComment.indexOf("(")) @@ -38,48 +40,22 @@ public class ${ClassName} extends ${Entity} #set($comment=$column.columnComment) #end #if($parentheseIndex != -1) - @Excel(name = "${comment}", readConverterExp = "$column.readConverterExp()") + @Excel(name = "${comment}" , readConverterExp = "$column.readConverterExp()") #elseif($column.javaType == 'Date') - @JsonFormat(pattern = "yyyy-MM-dd") - @Excel(name = "${comment}", width = 30, dateFormat = "yyyy-MM-dd") + @Excel(name = "${comment}" , width = 30, dateFormat = "yyyy-MM-dd") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") #else @Excel(name = "${comment}") #end #end +#if($column.isPk==1) + @TableId(value = "$column.columnName") private $column.javaType $column.javaField; - -#end -#end -#foreach ($column in $columns) -#if(!$table.isSuperColumn($column.javaField)) -#if($column.javaField.length() > 2 && $column.javaField.substring(1,2).matches("[A-Z]")) -#set($AttrName=$column.javaField) #else -#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) -#end - public void set${AttrName}($column.javaType $column.javaField) - { - this.$column.javaField = $column.javaField; - } - - public $column.javaType get${AttrName}() - { - return $column.javaField; - } + private $column.javaType $column.javaField; #end #end - @Override - public String toString() { - return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) -#foreach ($column in $columns) -#if($column.javaField.length() > 2 && $column.javaField.substring(1,2).matches("[A-Z]")) -#set($AttrName=$column.javaField) -#else -#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) -#end - .append("${column.javaField}", get${AttrName}()) -#end - .toString(); - } + @TableField(exist = false) + private Map params = new HashMap<>(); } diff --git a/linkwe-generator/src/main/resources/vm/java/mapper.java.vm b/linkwe-generator/src/main/resources/vm/java/mapper.java.vm index 172eb59253046c85c0a83688003f9e9353ffec05..91c0661c234f3b3fbb5f9b9b0222eb0d648c6bc9 100644 --- a/linkwe-generator/src/main/resources/vm/java/mapper.java.vm +++ b/linkwe-generator/src/main/resources/vm/java/mapper.java.vm @@ -1,61 +1,14 @@ -package ${packageName}.mapper; +package ${packageName}.wecom.mapper; -import java.util.List; import ${packageName}.domain.${ClassName}; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; /** * ${functionName}Mapper接口 - * + * * @author ${author} * @date ${datetime} */ -public interface ${ClassName}Mapper -{ - /** - * 查询${functionName} - * - * @param ${pkColumn.javaField} ${functionName}ID - * @return ${functionName} - */ - public ${ClassName} select${ClassName}ById(${pkColumn.javaType} ${pkColumn.javaField}); +public interface ${ClassName}Mapper extends BaseMapper<${ClassName}> { - /** - * 查询${functionName}列表 - * - * @param ${className} ${functionName} - * @return ${functionName}集合 - */ - public List<${ClassName}> select${ClassName}List(${ClassName} ${className}); - - /** - * 新增${functionName} - * - * @param ${className} ${functionName} - * @return 结果 - */ - public int insert${ClassName}(${ClassName} ${className}); - - /** - * 修改${functionName} - * - * @param ${className} ${functionName} - * @return 结果 - */ - public int update${ClassName}(${ClassName} ${className}); - - /** - * 删除${functionName} - * - * @param ${pkColumn.javaField} ${functionName}ID - * @return 结果 - */ - public int delete${ClassName}ById(${pkColumn.javaType} ${pkColumn.javaField}); - - /** - * 批量删除${functionName} - * - * @param ${pkColumn.javaField}s 需要删除的数据ID - * @return 结果 - */ - public int delete${ClassName}ByIds(${pkColumn.javaType}[] ${pkColumn.javaField}s); } diff --git a/linkwe-generator/src/main/resources/vm/java/service.java.vm b/linkwe-generator/src/main/resources/vm/java/service.java.vm index 1217d53cf4e63765d42a1c05752301def103b2d7..a55b6cccb4224ff6bb7d4303242c6e36f6409880 100644 --- a/linkwe-generator/src/main/resources/vm/java/service.java.vm +++ b/linkwe-generator/src/main/resources/vm/java/service.java.vm @@ -1,61 +1,19 @@ -package ${packageName}.service; +package ${packageName}.wecom.service; -import java.util.List; import ${packageName}.domain.${ClassName}; +import com.baomidou.mybatisplus.extension.service.IService; +import java.util.List; /** * ${functionName}Service接口 - * + * * @author ${author} * @date ${datetime} */ -public interface I${ClassName}Service -{ - /** - * 查询${functionName} - * - * @param ${pkColumn.javaField} ${functionName}ID - * @return ${functionName} - */ - public ${ClassName} select${ClassName}ById(${pkColumn.javaType} ${pkColumn.javaField}); - - /** - * 查询${functionName}列表 - * - * @param ${className} ${functionName} - * @return ${functionName}集合 - */ - public List<${ClassName}> select${ClassName}List(${ClassName} ${className}); - - /** - * 新增${functionName} - * - * @param ${className} ${functionName} - * @return 结果 - */ - public int insert${ClassName}(${ClassName} ${className}); - - /** - * 修改${functionName} - * - * @param ${className} ${functionName} - * @return 结果 - */ - public int update${ClassName}(${ClassName} ${className}); - - /** - * 批量删除${functionName} - * - * @param ${pkColumn.javaField}s 需要删除的${functionName}ID - * @return 结果 - */ - public int delete${ClassName}ByIds(${pkColumn.javaType}[] ${pkColumn.javaField}s); +public interface I${ClassName}Service extends IService<${ClassName}> { /** - * 删除${functionName}信息 - * - * @param ${pkColumn.javaField} ${functionName}ID - * @return 结果 + * 查询列表 */ - public int delete${ClassName}ById(${pkColumn.javaType} ${pkColumn.javaField}); + List<${ClassName}> queryList(${ClassName} ${className}); } diff --git a/linkwe-generator/src/main/resources/vm/java/serviceImpl.java.vm b/linkwe-generator/src/main/resources/vm/java/serviceImpl.java.vm index 4b3a180ac95374c5a810d3523753d09c63c8a8a2..a2dbf84526afcf441482ff34e76cba15ca23b78c 100644 --- a/linkwe-generator/src/main/resources/vm/java/serviceImpl.java.vm +++ b/linkwe-generator/src/main/resources/vm/java/serviceImpl.java.vm @@ -1,109 +1,114 @@ -package ${packageName}.service.impl; +package ${packageName}.wecom.service.impl; -import java.util.List; -#foreach ($column in $columns) -#if($column.javaField == 'createTime' || $column.javaField == 'updateTime') -import DateUtils; -#break -#end -#end -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import org.apache.commons.lang3.StringUtils; import ${packageName}.mapper.${ClassName}Mapper; import ${packageName}.domain.${ClassName}; import ${packageName}.service.I${ClassName}Service; +import java.util.List; +import java.util.Map; + /** * ${functionName}Service业务层处理 - * + * * @author ${author} * @date ${datetime} */ @Service -public class ${ClassName}ServiceImpl implements I${ClassName}Service -{ - @Autowired - private ${ClassName}Mapper ${className}Mapper; +public class ${ClassName}ServiceImpl extends ServiceImpl<${ClassName}Mapper, ${ClassName}> implements I${ClassName}Service { - /** - * 查询${functionName} - * - * @param ${pkColumn.javaField} ${functionName}ID - * @return ${functionName} - */ @Override - public ${ClassName} select${ClassName}ById(${pkColumn.javaType} ${pkColumn.javaField}) - { - return ${className}Mapper.select${ClassName}ById(${pkColumn.javaField}); - } - - /** - * 查询${functionName}列表 - * - * @param ${className} ${functionName} - * @return ${functionName} - */ - @Override - public List<${ClassName}> select${ClassName}List(${ClassName} ${className}) - { - return ${className}Mapper.select${ClassName}List(${className}); - } - - /** - * 新增${functionName} - * - * @param ${className} ${functionName} - * @return 结果 - */ - @Override - public int insert${ClassName}(${ClassName} ${className}) - { -#foreach ($column in $columns) -#if($column.javaField == 'createTime') - ${className}.setCreateTime(DateUtils.getNowDate()); + public List<${ClassName}> queryList(${ClassName} ${className}) { + LambdaQueryWrapper<${ClassName}> lqw = Wrappers.lambdaQuery(); +#foreach($column in $columns) +#set($queryType=$column.queryType) +#set($javaField=$column.javaField) +#set($javaType=$column.javaType) +#set($columnName=$column.columnName) +#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) +#if($column.query) +#if($column.queryType == "EQ") +#if($javaType == 'String') + if (StringUtils.isNotBlank(${className}.get$AttrName())){ + lqw.eq(${ClassName}::get$AttrName ,${className}.get$AttrName()); + } +#else + if (${className}.get$AttrName() != null){ + lqw.eq(${ClassName}::get$AttrName ,${className}.get$AttrName()); + } #end +#elseif($queryType == "NE") +#if($javaType == 'String') + if (StringUtils.isNotBlank(${className}.get$AttrName())){ + lqw.ne(${ClassName}::get$AttrName ,${className}.get$AttrName()); + } +#else + if (${className}.get$AttrName() != null){ + lqw.ne(${ClassName}::get$AttrName ,${className}.get$AttrName()); + } #end - return ${className}Mapper.insert${ClassName}(${className}); - } - - /** - * 修改${functionName} - * - * @param ${className} ${functionName} - * @return 结果 - */ - @Override - public int update${ClassName}(${ClassName} ${className}) - { -#foreach ($column in $columns) -#if($column.javaField == 'updateTime') - ${className}.setUpdateTime(DateUtils.getNowDate()); +#elseif($queryType == "GT") +#if($javaType == 'String') + if (StringUtils.isNotBlank(${className}.get$AttrName())){ + lqw.gt(${ClassName}::get$AttrName ,${className}.get$AttrName()); + } +#else + if (${className}.get$AttrName() != null){ + lqw.gt(${ClassName}::get$AttrName ,${className}.get$AttrName()); + } #end +#elseif($queryType == "GTE") +#if($javaType == 'String') + if (StringUtils.isNotBlank(${className}.get$AttrName())){ + lqw.ge(${ClassName}::get$AttrName ,${className}.get$AttrName()); + } +#else + if (${className}.get$AttrName() != null){ + lqw.ge(${ClassName}::get$AttrName ,${className}.get$AttrName()); + } #end - return ${className}Mapper.update${ClassName}(${className}); - } - - /** - * 批量删除${functionName} - * - * @param ${pkColumn.javaField}s 需要删除的${functionName}ID - * @return 结果 - */ - @Override - public int delete${ClassName}ByIds(${pkColumn.javaType}[] ${pkColumn.javaField}s) - { - return ${className}Mapper.delete${ClassName}ByIds(${pkColumn.javaField}s); - } - - /** - * 删除${functionName}信息 - * - * @param ${pkColumn.javaField} ${functionName}ID - * @return 结果 - */ - @Override - public int delete${ClassName}ById(${pkColumn.javaType} ${pkColumn.javaField}) - { - return ${className}Mapper.delete${ClassName}ById(${pkColumn.javaField}); +#elseif($queryType == "LT") +#if($javaType == 'String') + if (StringUtils.isNotBlank(${className}.get$AttrName())){ + lqw.lt(${ClassName}::get$AttrName ,${className}.get$AttrName()); + } +#else + if (${className}.get$AttrName() != null){ + lqw.lt(${ClassName}::get$AttrName ,${className}.get$AttrName()); + } +#end +#elseif($queryType == "LTE") +#if($javaType == 'String') + if (StringUtils.isNotBlank(${className}.get$AttrName())){ + lqw.le(${ClassName}::get$AttrName ,${className}.get$AttrName()); + } +#else + if (${className}.get$AttrName() != null){ + lqw.le(${ClassName}::get$AttrName ,${className}.get$AttrName()); + } +#end +#elseif($queryType == "LIKE") +#if($javaType == 'String') + if (StringUtils.isNotBlank(${className}.get$AttrName())){ + lqw.like(${ClassName}::get$AttrName ,${className}.get$AttrName()); + } +#else + if (${className}.get$AttrName() != null){ + lqw.like(${ClassName}::get$AttrName ,${className}.get$AttrName()); + } +#end +#elseif($queryType == "BETWEEN") + Map params = ${className}.getParams(); + if (params.get("begin$AttrName") != null && params.get("end$AttrName") != null) { + lqw.between(${ClassName}::get$AttrName ,params.get("begin$AttrName"),params.get("end$AttrName")); + } +#end +#end +#end + return this.list(lqw); } } diff --git a/linkwe-generator/src/main/resources/vm/java/sub-domain.java.vm b/linkwe-generator/src/main/resources/vm/java/sub-domain.java.vm new file mode 100644 index 0000000000000000000000000000000000000000..e35cae25c5f0e5a332eaa8598db26c5f05d809a8 --- /dev/null +++ b/linkwe-generator/src/main/resources/vm/java/sub-domain.java.vm @@ -0,0 +1,76 @@ +package ${packageName}.wecom.domain; + +#foreach ($import in $subImportList) +import ${import}; +#end +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import com.ruoyi.common.annotation.Excel; +import com.ruoyi.common.core.domain.BaseEntity; + +/** + * ${subTable.functionName}对象 ${subTableName} + * + * @author ${author} + * @date ${datetime} + */ +public class ${subClassName} extends BaseEntity +{ + private static final long serialVersionUID = 1L; + +#foreach ($column in $subTable.columns) +#if(!$table.isSuperColumn($column.javaField)) + /** $column.columnComment */ +#if($column.list) +#set($parentheseIndex=$column.columnComment.indexOf("(")) +#if($parentheseIndex != -1) +#set($comment=$column.columnComment.substring(0, $parentheseIndex)) +#else +#set($comment=$column.columnComment) +#end +#if($parentheseIndex != -1) + @Excel(name = "${comment}", readConverterExp = "$column.readConverterExp()") +#elseif($column.javaType == 'Date') + @JsonFormat(pattern = "yyyy-MM-dd") + @Excel(name = "${comment}", width = 30, dateFormat = "yyyy-MM-dd") +#else + @Excel(name = "${comment}") +#end +#end + private $column.javaType $column.javaField; + +#end +#end +#foreach ($column in $subTable.columns) +#if(!$table.isSuperColumn($column.javaField)) +#if($column.javaField.length() > 2 && $column.javaField.substring(1,2).matches("[A-Z]")) +#set($AttrName=$column.javaField) +#else +#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) +#end + public void set${AttrName}($column.javaType $column.javaField) + { + this.$column.javaField = $column.javaField; + } + + public $column.javaType get${AttrName}() + { + return $column.javaField; + } +#end +#end + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) +#foreach ($column in $subTable.columns) +#if($column.javaField.length() > 2 && $column.javaField.substring(1,2).matches("[A-Z]")) +#set($AttrName=$column.javaField) +#else +#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) +#end + .append("${column.javaField}", get${AttrName}()) +#end + .toString(); + } +} diff --git a/linkwe-generator/src/main/resources/vm/sql/sql.vm b/linkwe-generator/src/main/resources/vm/sql/sql.vm index bfd71945e258122920299fb2e99bc482e96230fe..057558350ca33f70499732c336a93e0e2d14060d 100644 --- a/linkwe-generator/src/main/resources/vm/sql/sql.vm +++ b/linkwe-generator/src/main/resources/vm/sql/sql.vm @@ -1,22 +1,22 @@ -- 菜单 SQL -insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) -values('${functionName}', '${parentMenuId}', '1', '${businessName}', '${moduleName}/${businessName}/index', 1, 'C', '0', '0', '${permissionPrefix}:list', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '${functionName}菜单'); +insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) +values('${functionName}', '${parentMenuId}', '1', '${businessName}', '${moduleName}/${businessName}/index', 1, 0, 'C', '0', '0', '${permissionPrefix}:list', '#', 'admin', sysdate(), '', null, '${functionName}菜单'); -- 按钮父菜单ID SELECT @parentId := LAST_INSERT_ID(); -- 按钮 SQL -insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) -values('${functionName}查询', @parentId, '1', '#', '', 1, 'F', '0', '0', '${permissionPrefix}:query', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', ''); +insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) +values('${functionName}查询', @parentId, '1', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:query', '#', 'admin', sysdate(), '', null, ''); -insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) -values('${functionName}新增', @parentId, '2', '#', '', 1, 'F', '0', '0', '${permissionPrefix}:add', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', ''); +insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) +values('${functionName}新增', @parentId, '2', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:add', '#', 'admin', sysdate(), '', null, ''); -insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) -values('${functionName}修改', @parentId, '3', '#', '', 1, 'F', '0', '0', '${permissionPrefix}:edit', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', ''); +insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) +values('${functionName}修改', @parentId, '3', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:edit', '#', 'admin', sysdate(), '', null, ''); -insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) -values('${functionName}删除', @parentId, '4', '#', '', 1, 'F', '0', '0', '${permissionPrefix}:remove', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', ''); +insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) +values('${functionName}删除', @parentId, '4', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:remove', '#', 'admin', sysdate(), '', null, ''); -insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) -values('${functionName}导出', @parentId, '5', '#', '', 1, 'F', '0', '0', '${permissionPrefix}:export', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', ''); \ No newline at end of file +insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) +values('${functionName}导出', @parentId, '5', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:export', '#', 'admin', sysdate(), '', null, ''); \ No newline at end of file diff --git a/linkwe-generator/src/main/resources/vm/vue/index-tree.vue.vm b/linkwe-generator/src/main/resources/vm/vue/index-tree.vue.vm index f487eb15134d054fb387ed73e78d36a96b766ee6..bc244c913ff1b907e86c9e7c0a294134f19856fe 100644 --- a/linkwe-generator/src/main/resources/vm/vue/index-tree.vue.vm +++ b/linkwe-generator/src/main/resources/vm/vue/index-tree.vue.vm @@ -38,20 +38,33 @@ -#elseif($column.htmlType == "datetime") +#elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN") - +#elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN") + + + #end #end #end - 搜索 + 搜索 重置 @@ -60,6 +73,7 @@ +#elseif($column.htmlType == "imageUpload") + + + +#elseif($column.htmlType == "fileUpload") + + + +#elseif($column.htmlType == "editor") + + + #elseif($column.htmlType == "select" && "" != $dictType) @@ -193,10 +219,10 @@ #elseif($column.htmlType == "datetime") - @@ -221,10 +247,48 @@ import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName}, export${BusinessName} } from "@/api/${moduleName}/${businessName}"; import Treeselect from "@riophae/vue-treeselect"; import "@riophae/vue-treeselect/dist/vue-treeselect.css"; +#foreach($column in $columns) +#if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == "imageUpload") +import ImageUpload from '@/components/ImageUpload'; +#break +#end +#end +#foreach($column in $columns) +#if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == "fileUpload") +import FileUpload from '@/components/FileUpload'; +#break +#end +#end +#foreach($column in $columns) +#if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == "editor") +import Editor from '@/components/Editor'; +#break +#end +#end export default { name: "${BusinessName}", - components: { Treeselect }, + components: { +#foreach($column in $columns) +#if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == "imageUpload") + ImageUpload, +#break +#end +#end +#foreach($column in $columns) +#if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == "fileUpload") + FileUpload, +#break +#end +#end +#foreach($column in $columns) +#if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == "editor") + Editor, +#break +#end +#end + Treeselect + }, data() { return { // 遮罩层 @@ -249,6 +313,10 @@ export default { #if(${column.dictType} != '') // $comment字典 ${column.javaField}Options: [], +#elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN") +#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) + // $comment时间范围 + daterange${AttrName}: [], #end #end // 查询参数 @@ -273,7 +341,7 @@ export default { #set($comment=$column.columnComment) #end $column.javaField: [ - { required: true, message: "$comment不能为空", trigger: "#if($column.htmlType == "select")"change"#else"blur"#end" } + { required: true, message: "$comment不能为空", trigger: #if($column.htmlType == "select")"change"#else"blur"#end } ]#if($velocityCount != $columns.size()),#end #end @@ -295,6 +363,21 @@ export default { /** 查询${functionName}列表 */ getList() { this.loading = true; +#foreach ($column in $columns) +#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN") + this.queryParams.params = {}; +#break +#end +#end +#foreach ($column in $columns) +#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN") +#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) + if (null != this.daterange${AttrName} && '' != this.daterange${AttrName}) { + this.queryParams.params["begin${AttrName}"] = this.daterange${AttrName}[0]; + this.queryParams.params["end${AttrName}"] = this.daterange${AttrName}[1]; + } +#end +#end list${BusinessName}(this.queryParams).then(response => { this.${businessName}List = this.handleTree(response.data, "${treeCode}", "${treeParentCode}"); this.loading = false; @@ -363,6 +446,12 @@ export default { }, /** 重置按钮操作 */ resetQuery() { +#foreach ($column in $columns) +#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN") +#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) + this.daterange${AttrName} = []; +#end +#end this.resetForm("queryForm"); this.handleQuery(); }, @@ -402,19 +491,15 @@ export default { #end if (this.form.${pkColumn.javaField} != null) { update${BusinessName}(this.form).then(response => { - if (response.code === 200) { - this.msgSuccess("修改成功"); - this.open = false; - this.getList(); - } + this.msgSuccess("修改成功"); + this.open = false; + this.getList(); }); } else { add${BusinessName}(this.form).then(response => { - if (response.code === 200) { - this.msgSuccess("新增成功"); - this.open = false; - this.getList(); - } + this.msgSuccess("新增成功"); + this.open = false; + this.getList(); }); } } @@ -431,7 +516,7 @@ export default { }).then(() => { this.getList(); this.msgSuccess("删除成功"); - }).catch(function() {}); + }) } } }; diff --git a/linkwe-generator/src/main/resources/vm/vue/index.vue.vm b/linkwe-generator/src/main/resources/vm/vue/index.vue.vm index d688b7d1c8fdb51b57e8181a8a9a3c161b87bcff..c6b6573e39be710cf862e0fa0d9be884d49dd7e7 100644 --- a/linkwe-generator/src/main/resources/vm/vue/index.vue.vm +++ b/linkwe-generator/src/main/resources/vm/vue/index.vue.vm @@ -38,20 +38,33 @@ -#elseif($column.htmlType == "datetime") +#elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN") - +#elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN") + + + #end #end #end - 搜索 + 搜索 重置 @@ -60,6 +73,7 @@ 导出 - + @@ -109,7 +126,7 @@ #set($comment=$column.columnComment) #end #if($column.pk) - + #elseif($column.list && $column.htmlType == "datetime")