Browse Source

初始化

yingp 6 years ago
commit
27ff234866
100 changed files with 6437 additions and 0 deletions
  1. 33 0
      .gitignore
  2. 56 0
      README.md
  3. 20 0
      apis/README.md
  4. 5 0
      apis/account-api/build.gradle
  5. 125 0
      apis/account-api/src/main/java/com/usoftchina/uu/account/api/AccountApi.java
  6. 44 0
      apis/account-api/src/main/java/com/usoftchina/uu/account/api/CompanyApi.java
  7. 33 0
      apis/account-api/src/main/java/com/usoftchina/uu/account/api/DeviceInfoApi.java
  8. 34 0
      apis/account-api/src/main/java/com/usoftchina/uu/account/api/TokenApi.java
  9. 24 0
      apis/account-api/src/main/java/com/usoftchina/uu/account/context/AccountHolder.java
  10. 24 0
      apis/account-api/src/main/java/com/usoftchina/uu/account/context/CompanyHolder.java
  11. 24 0
      apis/account-api/src/main/java/com/usoftchina/uu/account/context/DeviceInfoHolder.java
  12. 24 0
      apis/account-api/src/main/java/com/usoftchina/uu/account/context/TokenHolder.java
  13. 130 0
      apis/account-api/src/main/java/com/usoftchina/uu/account/dto/AccountDTO.java
  14. 46 0
      apis/account-api/src/main/java/com/usoftchina/uu/account/dto/CompanyDTO.java
  15. 150 0
      apis/account-api/src/main/java/com/usoftchina/uu/account/dto/DeviceInfoDTO.java
  16. 81 0
      apis/account-api/src/main/java/com/usoftchina/uu/account/dto/TokenDTO.java
  17. 80 0
      apis/account-api/src/main/java/com/usoftchina/uu/account/util/ImageUtils.java
  18. 3 0
      apis/app-api/build.gradle
  19. 205 0
      apis/app-api/src/main/java/com/usoftchina/uu/app/api/AppConfigApi.java
  20. 50 0
      apis/app-api/src/main/java/com/usoftchina/uu/app/api/AppGroupApi.java
  21. 146 0
      apis/app-api/src/main/java/com/usoftchina/uu/app/dto/AppConfigDTO.java
  22. 56 0
      apis/app-api/src/main/java/com/usoftchina/uu/app/dto/AppGroupDTO.java
  23. 38 0
      apis/app-api/src/main/java/com/usoftchina/uu/app/dto/CompanyAppConfigDTO.java
  24. 54 0
      apis/app-api/src/main/java/com/usoftchina/uu/app/dto/CompanyAppGroupDTO.java
  25. 3 0
      apis/home-api/build.gradle
  26. 193 0
      apis/home-api/src/main/java/com/usoftchina/uu/home/api/HomeConfigApi.java
  27. 20 0
      apis/home-api/src/main/java/com/usoftchina/uu/home/dto/CompanyHomeConfigDTO.java
  28. 161 0
      apis/home-api/src/main/java/com/usoftchina/uu/home/dto/HomeConfigDTO.java
  29. 4 0
      apis/message-api/build.gradle
  30. 84 0
      apis/message-api/src/main/java/com/usoftchina/uu/message/api/MessageApi.java
  31. 203 0
      apis/message-api/src/main/java/com/usoftchina/uu/message/api/MessageConfigApi.java
  32. 38 0
      apis/message-api/src/main/java/com/usoftchina/uu/message/dto/CompanyMessageConfigDTO.java
  33. 174 0
      apis/message-api/src/main/java/com/usoftchina/uu/message/dto/MessageConfigDTO.java
  34. 76 0
      apis/message-api/src/main/java/com/usoftchina/uu/message/dto/MessageDTO.java
  35. 68 0
      apis/message-api/src/main/java/com/usoftchina/uu/message/dto/SendMessageDTO.java
  36. 42 0
      apis/message-api/src/main/java/com/usoftchina/uu/message/dto/UnreadMessageCountDTO.java
  37. 21 0
      apis/mobile-grpc-api/README.md
  38. 51 0
      apis/mobile-grpc-api/build-android.gradle
  39. 32 0
      apis/mobile-grpc-api/build-default.gradle
  40. 4 0
      apis/mobile-grpc-api/build.gradle
  41. 193 0
      apis/mobile-grpc-api/src/main/proto/account.proto
  42. 24 0
      apis/mobile-grpc-api/src/main/proto/app.proto
  43. 170 0
      apis/mobile-grpc-api/src/main/proto/base.proto
  44. 24 0
      apis/mobile-grpc-api/src/main/proto/home.proto
  45. 78 0
      apis/mobile-grpc-api/src/main/proto/message.proto
  46. 31 0
      apis/open-grpc-api/build.gradle
  47. 46 0
      apis/open-grpc-api/src/main/proto/account.proto
  48. 69 0
      apis/open-grpc-api/src/main/proto/app.proto
  49. 116 0
      apis/open-grpc-api/src/main/proto/base.proto
  50. 79 0
      apis/open-grpc-api/src/main/proto/message.proto
  51. 65 0
      build.gradle
  52. 54 0
      db/account-schema.sql
  53. 27 0
      db/app-schema.sql
  54. 20 0
      db/home-schema.sql
  55. 67 0
      db/message-schema.sql
  56. 11 0
      external/README.md
  57. 4 0
      external/baidu-push-feign-client/build.gradle
  58. 86 0
      external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/auth/feign/BaiduSignatureInterceptor.java
  59. 58 0
      external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/base/BaiduResult.java
  60. 33 0
      external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/config/BaiduFeignConfig.java
  61. 69 0
      external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/config/BaiduPushProperties.java
  62. 22 0
      external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/exception/BaiduException.java
  63. 42 0
      external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/exception/BaiduExceptionCode.java
  64. 38 0
      external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/exception/feign/BaiduFeignErrorDecoder.java
  65. 109 0
      external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/push/api/BaiduPushApi.java
  66. 185 0
      external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/push/dto/AndroidNotification.java
  67. 83 0
      external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/push/dto/BaiduBatchPushRequest.java
  68. 40 0
      external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/push/dto/BaiduBatchPushResponse.java
  69. 23 0
      external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/push/dto/BaiduCancelTimerRequest.java
  70. 83 0
      external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/push/dto/BaiduPushAllRequest.java
  71. 53 0
      external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/push/dto/BaiduPushAllResponse.java
  72. 137 0
      external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/push/dto/BaiduPushSingleRequest.java
  73. 46 0
      external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/push/dto/BaiduPushSingleResponse.java
  74. 107 0
      external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/push/dto/BaiduPushTagRequest.java
  75. 53 0
      external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/push/dto/BaiduPushTagResponse.java
  76. 45 0
      external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/push/dto/BaiduQueryTimerRequest.java
  77. 42 0
      external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/push/dto/BaiduQueryTimerResponse.java
  78. 38 0
      external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/push/dto/BaiduQueryTopicRequest.java
  79. 42 0
      external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/push/dto/BaiduQueryTopicResponse.java
  80. 79 0
      external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/push/dto/BaiduTimer.java
  81. 79 0
      external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/push/dto/BaiduTopic.java
  82. 117 0
      external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/push/dto/IosNotification.java
  83. 36 0
      external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/push/dto/Notification.java
  84. 68 0
      external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/report/api/BaiduReportApi.java
  85. 20 0
      external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/report/dto/BaiduMsgReportRequest.java
  86. 41 0
      external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/report/dto/BaiduMsgReportResponse.java
  87. 68 0
      external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/report/dto/BaiduMsgStatus.java
  88. 116 0
      external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/report/dto/BaiduStatisticDeviceResponse.java
  89. 23 0
      external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/report/dto/BaiduStatisticTopicRequest.java
  90. 64 0
      external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/report/dto/BaiduStatisticTopicResponse.java
  91. 83 0
      external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/report/dto/BaiduTimerMsgReportRequest.java
  92. 39 0
      external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/report/dto/BaiduTimerMsgReportResponse.java
  93. 53 0
      external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/report/dto/BaiduTimerMsgStatus.java
  94. 83 0
      external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/report/dto/BaiduTopicMsgReportRequest.java
  95. 39 0
      external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/report/dto/BaiduTopicMsgReportResponse.java
  96. 53 0
      external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/report/dto/BaiduTopicMsgStatus.java
  97. 79 0
      external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/tag/api/BaiduTagApi.java
  98. 38 0
      external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/tag/dto/BaiduAddDevicesToTagRequest.java
  99. 65 0
      external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/tag/dto/BaiduAddDevicesToTagResponse.java
  100. 23 0
      external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/tag/dto/BaiduCreateTagRequest.java

+ 33 - 0
.gitignore

@@ -0,0 +1,33 @@
+.git
+logs
+rebel.xml
+target
+!.mvn/wrapper/maven-wrapper.jar
+### VSCODE ###
+.vscode
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+
+### IntelliJ IDEA ###
+.gradle
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+nbproject/private/
+build/
+nbbuild/
+dist/
+node_modules/
+nbdist/
+.nb-gradle/
+generatorConfig.xml
+
+*.log:

+ 56 - 0
README.md

@@ -0,0 +1,56 @@
+## UU互联
+
+### 项目结构
+
+```
+├─uu-platform
+│  │  
+│  ├─apis-------------------------------------接口定义
+│  ├─db---------------------------------------数据库脚本
+│  ├─external---------------------------------第三方对接
+│  ├─fronted----------------------------------前端
+│  ├─runtime----------------------------------服务运行
+│  ├─services---------------------------------服务实现
+│  ├─shared-----------------------------------公共模块
+│  │
+```
+
+### 开发环境配置
+
+| 工具/环境      |  版本  |
+| --------   | :----:  |
+| gradle |  5.4  |
+| idea |  2019.3  |
+| java |  1.8  |
+
+### 本地构建
+
+```
+gradle build -x test
+```
+
+### 测试运行环境
+
+> 服务器
+
+| IP      |  账号  |  密码  |  环境  |  资源  |
+| --------   | :----:  | :----: | :------:  | :------:  |
+| 10.1.81.81 |  root  | select123*** |  CentOS7, Tigase, MySQL  | Cpu: 8, Mem: 16G, Disk: 60G |
+| 10.1.81.82 |  root  | select123*** |  CentOS7, MySQL  | Cpu: 8, Mem: 16G, Disk: 60G |
+| 10.1.81.83 |  root  | select123*** |  CentOS7, Docker  | Cpu: 8, Mem: 16G, Disk: 60G |
+
+> 数据库
+
+| 数据库      | 类型   | 地址   |  账号  |  密码  |  说明  |
+| --------   | :-----: | :-----:  | :----:  | :----: | :------  |
+| uu_base | mysql | 10.1.81.82:3306 |  root  | select111*** |  基础库  |
+
+> 中间件
+
+| 类型 | 地址 | 账号 | 密码 | 说明 |
+| ---- | :----: | :----: | :----: | ---- |
+| redis | 10.1.81.82:6379 | | | 内存数据库 |
+
+> 部署
+
+* [jenkins](http://10.1.81.61:8080/job/uu/view/test) **账号** admin **密码** select123***

+ 20 - 0
apis/README.md

@@ -0,0 +1,20 @@
+## 接口定义
+
+### 开发说明
+
+* 第一阶段定义基本java接口,以standalone架构开发
+* 第二阶段定义grpc接口,并实现基于gateway的grpc服务转发与基于eureka的grpc服务发现,以微服务架构重构
+
+### 项目结构
+
+```
+├─apis
+│  │  
+│  ├─account-api------------------------------账户模块接口
+│  ├─app-api----------------------------------应用模块接口
+│  ├─home-api---------------------------------个人主页模块接口
+│  ├─message-api------------------------------消息模块接口
+│  ├─mobile-grpc-api--------------------------提供给移动端调用grpc接口
+│  ├─open-grpc-api----------------------------开放给第三方调用grpc接口
+│  │
+```

+ 5 - 0
apis/account-api/build.gradle

@@ -0,0 +1,5 @@
+dependencies {
+    compile 'org.apache.commons:commons-lang3'
+    compile "$alibabaThreadLocal"
+    compile project(':shared:core')
+}

+ 125 - 0
apis/account-api/src/main/java/com/usoftchina/uu/account/api/AccountApi.java

@@ -0,0 +1,125 @@
+package com.usoftchina.uu.account.api;
+
+import com.usoftchina.uu.account.dto.AccountDTO;
+
+/**
+ * @author yingp
+ * @date 2019/4/17
+ */
+public interface AccountApi {
+    /**
+     * 注册
+     *
+     * @param accountDTO
+     * @param password
+     * @return
+     */
+    boolean register(AccountDTO accountDTO, String password);
+
+    /**
+     * 注册或者更新
+     * <pre>
+     *     如果存在则更新,否则注册
+     * </pre>
+     *
+     * @param accountDTO
+     * @param password
+     * @return
+     */
+    boolean registerOrUpdate(AccountDTO accountDTO, String password);
+
+    /**
+     * 更新
+     *
+     * @param accountDTO
+     * @return
+     */
+    boolean update(AccountDTO accountDTO);
+
+    /**
+     * 按account.id查找
+     *
+     * @param id
+     * @return
+     */
+    AccountDTO findByPrimaryKey(Long id);
+
+    /**
+     * 按手机号查找
+     *
+     * @param mobile
+     * @return
+     */
+    AccountDTO findByMobile(String mobile);
+
+    /**
+     * 按account.id删除
+     *
+     * @param id
+     * @return
+     */
+    boolean removeByPrimaryKey(Long id);
+
+    /**
+     * 绑定公司
+     *
+     * @param accountId
+     * @param companyId
+     * @return
+     */
+    boolean bindCompany(Long accountId, Long companyId);
+
+    /**
+     * 是否绑定了公司
+     *
+     * @param accountId
+     * @param companyId
+     * @return
+     */
+    boolean hasBindCompany(Long accountId, Long companyId);
+
+    /**
+     * 解除绑定公司
+     *
+     * @param accountId
+     * @param companyId
+     * @return
+     */
+    boolean unbindCompany(Long accountId, Long companyId);
+
+    /**
+     * 修改密码
+     *
+     * @param id
+     * @param password
+     * @return
+     */
+    boolean updatePasswordByPrimaryKey(Long id, String password);
+
+    /**
+     * 修改密码
+     *
+     * @param mobile
+     * @param password
+     * @return
+     */
+    boolean updatePasswordByMobile(String mobile, String password);
+
+    /**
+     * 校验密码
+     *
+     * @param id
+     * @param password
+     * @return
+     */
+    boolean checkPasswordByPrimaryKey(Long id, String password);
+
+    /**
+     * 校验密码
+     *
+     * @param mobile
+     * @param password
+     * @return
+     */
+    boolean checkPasswordByMobile(String mobile, String password);
+}

+ 44 - 0
apis/account-api/src/main/java/com/usoftchina/uu/account/api/CompanyApi.java

@@ -0,0 +1,44 @@
+package com.usoftchina.uu.account.api;
+
+import com.usoftchina.uu.account.dto.CompanyDTO;
+
+import java.util.List;
+
+/**
+ * @author yingp
+ * @date 2019/4/18
+ */
+public interface CompanyApi {
+
+    /**
+     * 按个人查找绑定的企业
+     *
+     * @param accountId
+     * @return
+     */
+    List<CompanyDTO> findByAccountId(Long accountId);
+
+    /**
+     * 保存
+     *
+     * @param companyDTO
+     * @return
+     */
+    boolean save(CompanyDTO companyDTO);
+
+    /**
+     * 查找
+     *
+     * @param id
+     * @return
+     */
+    CompanyDTO findByPrimaryKey(Long id);
+
+    /**
+     * 删除
+     *
+     * @param id
+     * @return
+     */
+    boolean removeByPrimaryKey(Long id);
+}

+ 33 - 0
apis/account-api/src/main/java/com/usoftchina/uu/account/api/DeviceInfoApi.java

@@ -0,0 +1,33 @@
+package com.usoftchina.uu.account.api;
+
+import com.usoftchina.uu.account.dto.DeviceInfoDTO;
+
+/**
+ * @author yingp
+ * @date 2019/4/17
+ */
+public interface DeviceInfoApi {
+    /**
+     * 保存设备信息
+     *
+     * @param deviceInfoDTO
+     * @return
+     */
+    DeviceInfoDTO save(DeviceInfoDTO deviceInfoDTO);
+
+    /**
+     * 按accountId删除
+     *
+     * @param accountId
+     * @return
+     */
+    boolean removeByAccountId(Long accountId);
+
+    /**
+     * 按accountId查找
+     *
+     * @param accountId
+     * @return
+     */
+    DeviceInfoDTO findByAccountId(Long accountId);
+}

+ 34 - 0
apis/account-api/src/main/java/com/usoftchina/uu/account/api/TokenApi.java

@@ -0,0 +1,34 @@
+package com.usoftchina.uu.account.api;
+
+import com.usoftchina.uu.account.dto.TokenDTO;
+
+/**
+ * @author yingp
+ * @date 2019/4/18
+ */
+public interface TokenApi {
+
+    /**
+     * 查找
+     *
+     * @param id
+     * @return
+     */
+    TokenDTO findByPrimaryKey(String id);
+
+    /**
+     * 保存
+     *
+     * @param tokenDTO
+     * @return
+     */
+    boolean save(TokenDTO tokenDTO);
+
+    /**
+     * 删除
+     *
+     * @param id
+     * @return
+     */
+    boolean removeByPrimaryKey(String id);
+}

+ 24 - 0
apis/account-api/src/main/java/com/usoftchina/uu/account/context/AccountHolder.java

@@ -0,0 +1,24 @@
+package com.usoftchina.uu.account.context;
+
+import com.alibaba.ttl.TransmittableThreadLocal;
+import com.usoftchina.uu.account.dto.AccountDTO;
+
+/**
+ * @author yingp
+ * @date 2019/4/18
+ */
+public class AccountHolder {
+    private static final ThreadLocal<AccountDTO> threadLocal = new TransmittableThreadLocal<>();
+
+    public static void set(AccountDTO accountDTO) {
+        threadLocal.set(accountDTO);
+    }
+
+    public static AccountDTO get() {
+        return threadLocal.get();
+    }
+
+    public static void clear() {
+        threadLocal.remove();
+    }
+}

+ 24 - 0
apis/account-api/src/main/java/com/usoftchina/uu/account/context/CompanyHolder.java

@@ -0,0 +1,24 @@
+package com.usoftchina.uu.account.context;
+
+import com.alibaba.ttl.TransmittableThreadLocal;
+import com.usoftchina.uu.account.dto.CompanyDTO;
+
+/**
+ * @author yingp
+ * @date 2019/4/18
+ */
+public class CompanyHolder {
+    private static final ThreadLocal<CompanyDTO> threadLocal = new TransmittableThreadLocal<>();
+
+    public static void set(CompanyDTO companyDTO) {
+        threadLocal.set(companyDTO);
+    }
+
+    public static CompanyDTO get() {
+        return threadLocal.get();
+    }
+
+    public static void clear() {
+        threadLocal.remove();
+    }
+}

+ 24 - 0
apis/account-api/src/main/java/com/usoftchina/uu/account/context/DeviceInfoHolder.java

@@ -0,0 +1,24 @@
+package com.usoftchina.uu.account.context;
+
+import com.alibaba.ttl.TransmittableThreadLocal;
+import com.usoftchina.uu.account.dto.DeviceInfoDTO;
+
+/**
+ * @author yingp
+ * @date 2019/4/18
+ */
+public class DeviceInfoHolder {
+    private static final ThreadLocal<DeviceInfoDTO> threadLocal = new TransmittableThreadLocal<>();
+
+    public static void set(DeviceInfoDTO deviceInfoDTO) {
+        threadLocal.set(deviceInfoDTO);
+    }
+
+    public static DeviceInfoDTO get() {
+        return threadLocal.get();
+    }
+
+    public static void clear() {
+        threadLocal.remove();
+    }
+}

+ 24 - 0
apis/account-api/src/main/java/com/usoftchina/uu/account/context/TokenHolder.java

@@ -0,0 +1,24 @@
+package com.usoftchina.uu.account.context;
+
+import com.alibaba.ttl.TransmittableThreadLocal;
+import com.usoftchina.uu.account.dto.TokenDTO;
+
+/**
+ * @author yingp
+ * @date 2019/4/18
+ */
+public class TokenHolder {
+    private static final ThreadLocal<TokenDTO> threadLocal = new TransmittableThreadLocal<>();
+
+    public static void set(TokenDTO tokenDTO) {
+        threadLocal.set(tokenDTO);
+    }
+
+    public static TokenDTO get() {
+        return threadLocal.get();
+    }
+
+    public static void clear() {
+        threadLocal.remove();
+    }
+}

+ 130 - 0
apis/account-api/src/main/java/com/usoftchina/uu/account/dto/AccountDTO.java

@@ -0,0 +1,130 @@
+package com.usoftchina.uu.account.dto;
+
+/**
+ * 个人账户
+ *
+ * @author yingp
+ * @date 2019/4/16
+ */
+public class AccountDTO {
+    private Long id;
+    /**
+     * 真实姓名(考虑是企业应用,非社交类型,不需要昵称)
+     */
+    private String realname;
+    /**
+     * 手机号
+     */
+    private String mobile;
+    /**
+     * 邮箱
+     */
+    private String email;
+    /**
+     * 头像
+     */
+    private String avatarUrl;
+    /**
+     * 性别
+     */
+    private Integer sex;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getRealname() {
+        return realname;
+    }
+
+    public void setRealname(String realname) {
+        this.realname = realname;
+    }
+
+    public String getMobile() {
+        return mobile;
+    }
+
+    public void setMobile(String mobile) {
+        this.mobile = mobile;
+    }
+
+    public String getEmail() {
+        return email;
+    }
+
+    public void setEmail(String email) {
+        this.email = email;
+    }
+
+    public String getAvatarUrl() {
+        return avatarUrl;
+    }
+
+    public void setAvatarUrl(String avatarUrl) {
+        this.avatarUrl = avatarUrl;
+    }
+
+    public Integer getSex() {
+        return sex;
+    }
+
+    public void setSex(Integer sex) {
+        this.sex = sex;
+    }
+
+    public boolean isNew() {
+        return null == getId() || getId() <= 0;
+    }
+
+    @Override
+    public String toString() {
+        return "AccountDTO{" +
+                "id=" + id +
+                ", realname='" + realname + '\'' +
+                ", mobile='" + mobile + '\'' +
+                ", email='" + email + '\'' +
+                ", avatarUrl='" + avatarUrl + '\'' +
+                ", sex=" + sex +
+                '}';
+    }
+
+    public enum Sex {
+        /**
+         * 女
+         */
+        FEMALE(0),
+        /**
+         * 男
+         */
+        MALE(1);
+
+        private final int value;
+
+        Sex (int value) {
+            this.value = value;
+        }
+
+        public int getValue() {
+            return value;
+        }
+
+        public static Sex of(String name) {
+            String nameUpper = name.toUpperCase();
+            boolean isFemale = nameUpper.equals("F") || nameUpper.equals(FEMALE.name()) || nameUpper.equals("女");
+            return isFemale ? FEMALE : MALE;
+        }
+
+        public static Sex valueOf(int value) {
+            return FEMALE.value == value ? FEMALE : MALE;
+        }
+
+        public static boolean isFemale(int value) {
+            return valueOf(value) == FEMALE;
+        }
+    }
+}

+ 46 - 0
apis/account-api/src/main/java/com/usoftchina/uu/account/dto/CompanyDTO.java

@@ -0,0 +1,46 @@
+package com.usoftchina.uu.account.dto;
+
+/**
+ * 公司
+ *
+ * @author yingp
+ * @date 2019/4/16
+ */
+public class CompanyDTO {
+    private Long id;
+    private String name;
+    private String secretKey;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getSecretKey() {
+        return secretKey;
+    }
+
+    public void setSecretKey(String secretKey) {
+        this.secretKey = secretKey;
+    }
+
+    @Override
+    public String toString() {
+        return "CompanyDTO{" +
+                "id=" + id +
+                ", name='" + name + '\'' +
+                ", secretKey='" + secretKey + '\'' +
+                '}';
+    }
+}

+ 150 - 0
apis/account-api/src/main/java/com/usoftchina/uu/account/dto/DeviceInfoDTO.java

@@ -0,0 +1,150 @@
+package com.usoftchina.uu.account.dto;
+
+import com.usoftchina.uu.base.DeviceOS;
+
+/**
+ * 设备信息
+ *
+ * @author yingp
+ * @date 2019/4/17
+ */
+public class DeviceInfoDTO {
+    private Long accountId;
+    /**
+     * 客户端发行版本,例如1.0.0
+     */
+    private String version;
+    /**
+     * 设备型号
+     */
+    private String model;
+    /**
+     * 系统
+     * @see DeviceOS
+     */
+    private Integer os;
+    /**
+     * 系统版本,例如7.1
+     */
+    private String osVersion;
+    /**
+     * 经度
+     */
+    private Double longitude;
+    /**
+     * 纬度
+     */
+    private Double latitude;
+    /**
+     * 位置
+     */
+    private String location;
+    /**
+     * 语言
+     */
+    private String lang;
+    /**
+     * 消息通道ID
+     */
+    private String channelId;
+
+    public Long getAccountId() {
+        return accountId;
+    }
+
+    public void setAccountId(Long accountId) {
+        this.accountId = accountId;
+    }
+
+    public String getVersion() {
+        return version;
+    }
+
+    public void setVersion(String version) {
+        this.version = version;
+    }
+
+    public String getModel() {
+        return model;
+    }
+
+    public void setModel(String model) {
+        this.model = model;
+    }
+
+    public Integer getOs() {
+        return os;
+    }
+
+    public void setOs(Integer os) {
+        this.os = os;
+    }
+
+    public String getOsVersion() {
+        return osVersion;
+    }
+
+    public void setOsVersion(String osVersion) {
+        this.osVersion = osVersion;
+    }
+
+    public Double getLongitude() {
+        return longitude;
+    }
+
+    public void setLongitude(Double longitude) {
+        this.longitude = longitude;
+    }
+
+    public Double getLatitude() {
+        return latitude;
+    }
+
+    public void setLatitude(Double latitude) {
+        this.latitude = latitude;
+    }
+
+    public String getLocation() {
+        return location;
+    }
+
+    public void setLocation(String location) {
+        this.location = location;
+    }
+
+    public String getLang() {
+        return lang;
+    }
+
+    public void setLang(String lang) {
+        this.lang = lang;
+    }
+
+    public String getChannelId() {
+        return channelId;
+    }
+
+    public void setChannelId(String channelId) {
+        this.channelId = channelId;
+    }
+
+    @Override
+    public String toString() {
+        return "DeviceInfoDTO{" +
+                "accountId=" + accountId +
+                ", version='" + version + '\'' +
+                ", model='" + model + '\'' +
+                ", os=" + os +
+                ", osVersion='" + osVersion + '\'' +
+                ", longitude=" + longitude +
+                ", latitude=" + latitude +
+                ", location='" + location + '\'' +
+                ", lang='" + lang + '\'' +
+                ", channelId='" + channelId + '\'' +
+                '}';
+    }
+
+    public DeviceOS os() {
+        return DeviceOS.of(os);
+    }
+}

+ 81 - 0
apis/account-api/src/main/java/com/usoftchina/uu/account/dto/TokenDTO.java

@@ -0,0 +1,81 @@
+package com.usoftchina.uu.account.dto;
+
+import org.apache.commons.lang3.RandomStringUtils;
+
+/**
+ * @author yingp
+ * @date 2019/4/18
+ */
+public class TokenDTO {
+    /**
+     * 30天
+     */
+    public static final int EXPIRE_30_DAYS = 2592000;
+    private String id;
+    private Long accountId;
+    private Long companyId;
+    private Integer expire;
+    private Long timestamp;
+
+    public TokenDTO() {
+    }
+
+    public TokenDTO(Long accountId, Long companyId) {
+        this.id = RandomStringUtils.randomAlphanumeric(32);
+        this.accountId = accountId;
+        this.companyId = companyId;
+        this.timestamp = System.currentTimeMillis();
+        this.expire = EXPIRE_30_DAYS;
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public Long getAccountId() {
+        return accountId;
+    }
+
+    public void setAccountId(Long accountId) {
+        this.accountId = accountId;
+    }
+
+    public Integer getExpire() {
+        return expire;
+    }
+
+    public void setExpire(Integer expire) {
+        this.expire = expire;
+    }
+
+    public Long getTimestamp() {
+        return timestamp;
+    }
+
+    public void setTimestamp(Long timestamp) {
+        this.timestamp = timestamp;
+    }
+
+    public Long getCompanyId() {
+        return companyId;
+    }
+
+    public void setCompanyId(Long companyId) {
+        this.companyId = companyId;
+    }
+
+    @Override
+    public String toString() {
+        return "TokenDTO{" +
+                "id='" + id + '\'' +
+                ", accountId=" + accountId +
+                ", companyId=" + companyId +
+                ", expire=" + expire +
+                ", timestamp=" + timestamp +
+                '}';
+    }
+}

+ 80 - 0
apis/account-api/src/main/java/com/usoftchina/uu/account/util/ImageUtils.java

@@ -0,0 +1,80 @@
+package com.usoftchina.uu.account.util;
+
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Random;
+
+/**
+ * @author yingp
+ * @date 2019/4/18
+ */
+public class ImageUtils {
+
+    /**
+     * 干扰线数量
+     */
+    private static final int LINES = 5;
+    /**
+     * 宽度
+     */
+    private static final int WIDTH = 80;
+    /**
+     * 高度
+     */
+    private static final int HEIGHT = 40;
+    /**
+     * 字体大小
+     */
+    private static final int FONT_SIZE = 30;
+    /**
+     * 字体
+     */
+    private static final Font FONT = new Font(null, Font.BOLD + Font.ITALIC, FONT_SIZE);
+
+    /**
+     * 生成用于校验的图片
+     *
+     * @param code
+     * @return
+     */
+    public static byte[] createValidImage(String code) throws IOException{
+        BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
+        Graphics graphic = image.getGraphics();
+        graphic.setColor(Color.LIGHT_GRAY);
+        graphic.fillRect(0, 0, WIDTH, HEIGHT);
+        for (int i = 0, len = code.length(); i < len; i++) {
+            graphic.setColor(getRandomColor());
+            graphic.setFont(FONT);
+            graphic.drawString(String.valueOf(code.charAt(i)), i * WIDTH / len, HEIGHT * 2 / 3);
+        }
+        // 干扰线
+        Random random = new Random();
+        for (int i = 0; i < LINES; i++) {
+            graphic.setColor(getRandomColor());
+            graphic.drawLine(random.nextInt(WIDTH), random.nextInt(HEIGHT),
+                    random.nextInt(WIDTH), random.nextInt(HEIGHT));
+        }
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        try {
+            ImageIO.write(image, "jpeg", out);
+            return out.toByteArray();
+        } finally {
+            try {
+                out.close();
+            } catch (Exception e) {
+            }
+        }
+    }
+
+    /**
+     * 随机取色
+     */
+    private static Color getRandomColor() {
+        Random random = new Random();
+        Color color = new Color(random.nextInt(256), random.nextInt(256), random.nextInt(256));
+        return color;
+    }
+}

+ 3 - 0
apis/app-api/build.gradle

@@ -0,0 +1,3 @@
+dependencies {
+    compile project(':shared:core')
+}

+ 205 - 0
apis/app-api/src/main/java/com/usoftchina/uu/app/api/AppConfigApi.java

@@ -0,0 +1,205 @@
+package com.usoftchina.uu.app.api;
+
+import com.usoftchina.uu.app.dto.AppConfigDTO;
+import com.usoftchina.uu.app.dto.AppGroupDTO;
+import com.usoftchina.uu.app.dto.CompanyAppGroupDTO;
+import com.usoftchina.uu.base.CompanyRelate;
+import com.usoftchina.uu.base.Platform;
+
+import java.util.List;
+
+/**
+ * @author yingp
+ * @date 2019/4/18
+ */
+public interface AppConfigApi {
+    /**
+     * 保存
+     *
+     * @param appConfigDTO
+     * @return
+     */
+    boolean save(AppConfigDTO appConfigDTO);
+
+    /**
+     * 批量保存
+     *
+     * @param appConfigDTOList
+     * @return
+     */
+    boolean save(List<AppConfigDTO> appConfigDTOList);
+
+    /**
+     * 删除
+     *
+     * @param id
+     * @return
+     */
+    boolean removeByPrimaryKey(Integer id);
+
+    /**
+     * 更新
+     *
+     * @param appConfigDTO
+     * @return
+     */
+    boolean updateByPrimaryKey(AppConfigDTO appConfigDTO);
+
+    /**
+     * 批量更新
+     *
+     * @param appConfigDTOList
+     * @return
+     */
+    boolean updateByPrimaryKey(List<AppConfigDTO> appConfigDTOList);
+
+    /**
+     * 批量新增或更新
+     *
+     * @param appConfigDTOList
+     */
+    void saveOrUpdateByPrimaryKey(List<AppConfigDTO> appConfigDTOList);
+
+    /**
+     * 查找
+     *
+     * @param id
+     * @return
+     */
+    AppConfigDTO findByPrimaryKey(Integer id);
+
+    /**
+     * 按组查找
+     *
+     * @param groupId
+     * @return
+     */
+    List<AppConfigDTO> findByGroupId(Integer groupId);
+
+    /**
+     * 按归属平台查找,结果进行分组
+     *
+     * @param platform
+     * @return
+     */
+    List<AppGroupDTO> findByScopePlatform(Platform platform);
+
+    /**
+     * 按公司关联规则查找,结果进行分组
+     *
+     * @param companyRelate
+     * @return
+     */
+    List<AppGroupDTO> findByCompanyRelate(CompanyRelate companyRelate);
+
+    /**
+     * 查找属于该公司的应用配置(包括私有配置 + 公有配置),结果进行分组
+     * <pre>
+     *     例如 uas系统里面获取全部配置,来进行启用、禁用、编辑等操作
+     * </pre>
+     *
+     * @param scopeCompanyId
+     * @return
+     */
+    List<CompanyAppGroupDTO> findByScopeCompanyId(Long scopeCompanyId);
+
+    /**
+     * 查找属于该公司的且已启用的应用配置(包括私有配置 + 公有配置),结果进行分组
+     *
+     * @param scopeCompanyId
+     * @return
+     */
+    List<AppGroupDTO> findEnabledByScopeCompanyId(Long scopeCompanyId);
+
+    /**
+     * 查找指定平台的属于该公司的且已启用的应用配置(包括私有配置 + 公有配置),结果进行分组
+     *
+     * @param platform
+     * @param scopeCompanyId
+     * @return
+     */
+    List<AppGroupDTO> findEnabledByScopePlatformAndCompanyId(Platform platform, Long scopeCompanyId);
+
+    /**
+     * 查找个人相关配置
+     * <pre>
+     *     即companyRelate != CompanyRelate.ONLY_COMPANY
+     *     例如 uu互联以个人身份登录后获取配置
+     * </pre>
+     *
+     * @return
+     */
+    List<AppGroupDTO> findPersonal();
+
+    /**
+     * 按归属平台查找个人相关配置
+     * <pre>
+     *     例如 以个人身份登录商城后获取配置
+     * </pre>
+     *
+     * @param platform
+     * @return
+     */
+    List<AppGroupDTO> findPersonalByScopePlatform(Platform platform);
+
+    /**
+     * 查找启用的配置
+     * <pre>
+     *     根据companyId是否为空来判断取个人相关还是企业相关配置
+     * </pre>
+     *
+     * @param companyId
+     * @return
+     */
+    default List<AppGroupDTO> findEnabled(Long companyId) {
+        if (null == companyId) {
+            return findPersonal();
+        } else {
+            return findEnabledByScopeCompanyId(companyId);
+        }
+    }
+
+    /**
+     * 按指定平台查找启用的配置
+     * <pre>
+     *     根据companyId是否为空来判断取个人相关还是企业相关配置
+     * </pre>
+     *
+     * @param platform
+     * @param companyId
+     * @return
+     */
+    default List<AppGroupDTO> findEnabledByScopePlatform(Platform platform, Long companyId) {
+        if (null == companyId) {
+            return findPersonalByScopePlatform(platform);
+        } else {
+            return findEnabledByScopePlatformAndCompanyId(platform, companyId);
+        }
+    }
+
+    /**
+     * 按组删除
+     *
+     * @param groupId
+     * @return
+     */
+    boolean removeByGroupId(Integer groupId);
+
+    /**
+     * 公司绑定应用
+     *
+     * @param appId
+     * @param companyId
+     * @return
+     */
+    boolean bindCompany(Integer appId, Long companyId);
+
+    /**
+     * 公司解除绑定应用
+     *
+     * @param appId
+     * @param companyId
+     * @return
+     */
+    boolean unbindCompany(Integer appId, Long companyId);
+}

+ 50 - 0
apis/app-api/src/main/java/com/usoftchina/uu/app/api/AppGroupApi.java

@@ -0,0 +1,50 @@
+package com.usoftchina.uu.app.api;
+
+import com.usoftchina.uu.app.dto.AppGroupDTO;
+
+import java.util.List;
+
+/**
+ * @author yingp
+ * @date 2019/4/18
+ */
+public interface AppGroupApi {
+    /**
+     * 保存
+     *
+     * @param appGroupDTO
+     * @return
+     */
+    boolean save(AppGroupDTO appGroupDTO);
+
+    /**
+     * 删除
+     *
+     * @param id
+     * @return
+     */
+    boolean removeByPrimaryKey(Integer id);
+
+    /**
+     * 更新
+     *
+     * @param appGroupDTO
+     * @return
+     */
+    boolean updateByPrimaryKey(AppGroupDTO appGroupDTO);
+
+    /**
+     * 查找
+     *
+     * @param id
+     * @return
+     */
+    AppGroupDTO findByPrimaryKey(Integer id);
+
+    /**
+     * 查找全部
+     *
+     * @return
+     */
+    List<AppGroupDTO> findAll();
+}

+ 146 - 0
apis/app-api/src/main/java/com/usoftchina/uu/app/dto/AppConfigDTO.java

@@ -0,0 +1,146 @@
+package com.usoftchina.uu.app.dto;
+
+import com.usoftchina.uu.base.CompanyRelate;
+import com.usoftchina.uu.base.ViewType;
+
+/**
+ * @author yingp
+ * @date 2019/4/18
+ */
+public class AppConfigDTO {
+    /**
+     * 组ID
+     */
+    protected Integer groupId;
+    protected Integer id;
+    protected String name;
+    /**
+     * 图标
+     */
+    protected String icon;
+    /**
+     * 视图类型 0 - widget, 1 - web
+     */
+    protected Integer viewType;
+    protected String androidWidget;
+    protected String iosWidget;
+    /**
+     * 网页
+     */
+    protected String webUrl;
+    /**
+     * 专属平台的应用
+     */
+    protected Integer scopePlatform;
+    /**
+     * 专属企业的应用
+     */
+    protected Long scopeCompanyId;
+    /**
+     * 与公司相关的类型,默认CompanyRelate.COMPANY_OR_PERSONAL
+     *
+     * @see com.usoftchina.uu.base.CompanyRelate
+     */
+    protected Integer companyRelate;
+
+    public Integer getGroupId() {
+        return groupId;
+    }
+
+    public void setGroupId(Integer groupId) {
+        this.groupId = groupId;
+    }
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getIcon() {
+        return icon;
+    }
+
+    public void setIcon(String icon) {
+        this.icon = icon;
+    }
+
+    public Integer getViewType() {
+        return viewType;
+    }
+
+    public void setViewType(Integer viewType) {
+        this.viewType = viewType;
+    }
+
+    public String getAndroidWidget() {
+        return androidWidget;
+    }
+
+    public void setAndroidWidget(String androidWidget) {
+        this.androidWidget = androidWidget;
+    }
+
+    public String getIosWidget() {
+        return iosWidget;
+    }
+
+    public void setIosWidget(String iosWidget) {
+        this.iosWidget = iosWidget;
+    }
+
+    public String getWebUrl() {
+        return webUrl;
+    }
+
+    public void setWebUrl(String webUrl) {
+        this.webUrl = webUrl;
+    }
+
+    public Integer getScopePlatform() {
+        return scopePlatform;
+    }
+
+    public void setScopePlatform(Integer scopePlatform) {
+        this.scopePlatform = scopePlatform;
+    }
+
+    public Long getScopeCompanyId() {
+        return scopeCompanyId;
+    }
+
+    public void setScopeCompanyId(Long scopeCompanyId) {
+        this.scopeCompanyId = scopeCompanyId;
+    }
+
+    @Override
+    public String toString() {
+        return "AppConfigDTO{" +
+                "id=" + id +
+                ", name='" + name + '\'' +
+                ", icon='" + icon + '\'' +
+                ", viewType=" + viewType +
+                ", androidWidget='" + androidWidget + '\'' +
+                ", iosWidget='" + iosWidget + '\'' +
+                ", webUrl='" + webUrl + '\'' +
+                '}';
+    }
+
+    public CompanyRelate companyRelate() {
+        return CompanyRelate.of(companyRelate);
+    }
+
+    public ViewType viewType() {
+        return ViewType.of(viewType);
+    }
+}

+ 56 - 0
apis/app-api/src/main/java/com/usoftchina/uu/app/dto/AppGroupDTO.java

@@ -0,0 +1,56 @@
+package com.usoftchina.uu.app.dto;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author yingp
+ * @date 2019/4/18
+ */
+public class AppGroupDTO {
+    private Integer id;
+    private String name;
+    private List<AppConfigDTO> appConfigList;
+
+    public AppGroupDTO() {
+    }
+
+    public AppGroupDTO(Integer id, String name) {
+        this.id = id;
+        this.name = name;
+        this.appConfigList = new ArrayList<>();
+    }
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public List<AppConfigDTO> getAppConfigList() {
+        return appConfigList;
+    }
+
+    public void setAppConfigList(List<AppConfigDTO> appConfigList) {
+        this.appConfigList = appConfigList;
+    }
+
+    @Override
+    public String toString() {
+        return "AppConfigDTO{" +
+                "id=" + id +
+                ", name='" + name + '\'' +
+                ", appConfigList=" + appConfigList +
+                '}';
+    }
+}

+ 38 - 0
apis/app-api/src/main/java/com/usoftchina/uu/app/dto/CompanyAppConfigDTO.java

@@ -0,0 +1,38 @@
+package com.usoftchina.uu.app.dto;
+
+/**
+ * @author yingp
+ * @date 2019/4/25
+ */
+public class CompanyAppConfigDTO extends AppConfigDTO{
+    /**
+     * 是否启用
+     */
+    private Boolean enable;
+
+    public Boolean getEnable() {
+        return enable;
+    }
+
+    public void setEnable(Boolean enable) {
+        this.enable = enable;
+    }
+
+    @Override
+    public String toString() {
+        return "CompanyAppConfigDTO{" +
+                "enable=" + enable +
+                ", groupId=" + groupId +
+                ", id=" + id +
+                ", name='" + name + '\'' +
+                ", icon='" + icon + '\'' +
+                ", viewType=" + viewType +
+                ", androidWidget='" + androidWidget + '\'' +
+                ", iosWidget='" + iosWidget + '\'' +
+                ", webUrl='" + webUrl + '\'' +
+                ", scopePlatform=" + scopePlatform +
+                ", scopeCompanyId=" + scopeCompanyId +
+                ", companyRelate=" + companyRelate +
+                '}';
+    }
+}

+ 54 - 0
apis/app-api/src/main/java/com/usoftchina/uu/app/dto/CompanyAppGroupDTO.java

@@ -0,0 +1,54 @@
+package com.usoftchina.uu.app.dto;
+
+import java.util.List;
+
+/**
+ * @author yingp
+ * @date 2019/4/25
+ */
+public class CompanyAppGroupDTO {
+    private Integer id;
+    private String name;
+    private List<CompanyAppConfigDTO> appConfigList;
+
+    public CompanyAppGroupDTO() {
+    }
+
+    public CompanyAppGroupDTO(Integer id, String name) {
+        this.id = id;
+        this.name = name;
+    }
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public List<CompanyAppConfigDTO> getAppConfigList() {
+        return appConfigList;
+    }
+
+    public void setAppConfigList(List<CompanyAppConfigDTO> appConfigList) {
+        this.appConfigList = appConfigList;
+    }
+
+    @Override
+    public String toString() {
+        return "CompanyAppGroupDTO{" +
+                "id=" + id +
+                ", name='" + name + '\'' +
+                ", appConfigList=" + appConfigList +
+                '}';
+    }
+}

+ 3 - 0
apis/home-api/build.gradle

@@ -0,0 +1,3 @@
+dependencies {
+    compile project(':shared:core')
+}

+ 193 - 0
apis/home-api/src/main/java/com/usoftchina/uu/home/api/HomeConfigApi.java

@@ -0,0 +1,193 @@
+package com.usoftchina.uu.home.api;
+
+import com.usoftchina.uu.base.CompanyRelate;
+import com.usoftchina.uu.base.Platform;
+import com.usoftchina.uu.home.dto.CompanyHomeConfigDTO;
+import com.usoftchina.uu.home.dto.HomeConfigDTO;
+
+import java.util.List;
+
+/**
+ * @author yingp
+ * @date 2019/4/25
+ */
+public interface HomeConfigApi {
+    /**
+     * 保存
+     *
+     * @param homeConfigDTO
+     * @return
+     */
+    boolean save(HomeConfigDTO homeConfigDTO);
+
+    /**
+     * 批量保存
+     *
+     * @param homeConfigDTOList
+     * @return
+     */
+    boolean save(List<HomeConfigDTO> homeConfigDTOList);
+
+    /**
+     * 批量保存或更新
+     *
+     * @param homeConfigDTOList
+     * @return
+     */
+    boolean saveOrUpdateByPrimaryKey(List<HomeConfigDTO> homeConfigDTOList);
+
+    /**
+     * 删除
+     *
+     * @param id
+     * @return
+     */
+    boolean removeByPrimaryKey(Integer id);
+
+    /**
+     * 更新
+     *
+     * @param homeConfigDTO
+     * @return
+     */
+    boolean updateByPrimaryKey(HomeConfigDTO homeConfigDTO);
+
+    /**
+     * 批量更新
+     *
+     * @param homeConfigDTOList
+     * @return
+     */
+    boolean updateByPrimaryKey(List<HomeConfigDTO> homeConfigDTOList);
+
+    /**
+     * 查找
+     *
+     * @param id
+     * @return
+     */
+    HomeConfigDTO findByPrimaryKey(Integer id);
+
+    /**
+     * 全部配置
+     *
+     * @return
+     */
+    List<HomeConfigDTO> findAll();
+
+    /**
+     * 按归属平台查找
+     *
+     * @param platform
+     * @return
+     */
+    List<HomeConfigDTO> findByScopePlatform(Platform platform);
+
+    /**
+     * 按公司关联规则查找
+     *
+     * @param companyRelate
+     * @return
+     */
+    List<HomeConfigDTO> findByCompanyRelate(CompanyRelate companyRelate);
+
+    /**
+     * 查找属于该公司的应用配置(包括私有配置 + 公有配置,包括是否启用状态)
+     *
+     * @param scopeCompanyId
+     * @return
+     */
+    List<CompanyHomeConfigDTO> findByScopeCompanyId(Long scopeCompanyId);
+
+    /**
+     * 查找属于该公司的且已启用的应用配置(包括私有配置 + 公有配置)
+     *
+     * @param scopeCompanyId
+     * @return
+     */
+    List<HomeConfigDTO> findEnabledByScopeCompanyId(Long scopeCompanyId);
+
+    /**
+     * 查找指定平台的属于该公司的且已启用的配置(包括私有配置 + 公有配置)
+     *
+     * @param platform
+     * @param scopeCompanyId
+     * @return
+     */
+    List<HomeConfigDTO> findEnabledByScopePlatformAndCompanyId(Platform platform, Long scopeCompanyId);
+
+    /**
+     * 查找个人相关配置
+     * <pre>
+     *     即companyRelate != CompanyRelate.ONLY_COMPANY
+     *     例如 uu互联以个人身份登录后获取配置
+     * </pre>
+     *
+     * @return
+     */
+    List<HomeConfigDTO> findPersonal();
+
+    /**
+     * 按归属平台查找个人相关配置
+     * <pre>
+     *     例如 以个人身份登录商城后获取配置
+     * </pre>
+     *
+     * @param platform
+     * @return
+     */
+    List<HomeConfigDTO> findPersonalByScopePlatform(Platform platform);
+
+    /**
+     * 查找启用的配置
+     * <pre>
+     *     根据companyId是否为空来判断取个人相关还是企业相关配置
+     * </pre>
+     *
+     * @param companyId
+     * @return
+     */
+    default List<HomeConfigDTO> findEnabled(Long companyId) {
+        if (null == companyId) {
+            return findPersonal();
+        } else {
+            return findEnabledByScopeCompanyId(companyId);
+        }
+    }
+
+    /**
+     * 按指定平台查找启用的配置
+     * <pre>
+     *     根据companyId是否为空来判断取个人相关还是企业相关配置
+     * </pre>
+     *
+     * @param platform
+     * @param companyId
+     * @return
+     */
+    default List<HomeConfigDTO> findEnabledByScopePlatform(Platform platform, Long companyId) {
+        if (null == companyId) {
+            return findPersonalByScopePlatform(platform);
+        } else {
+            return findEnabledByScopePlatformAndCompanyId(platform, companyId);
+        }
+    }
+
+    /**
+     * 公司绑定配置
+     *
+     * @param id
+     * @param companyId
+     * @return
+     */
+    boolean bindCompany(Integer id, Long companyId);
+
+    /**
+     * 公司解除绑定配置
+     *
+     * @param id
+     * @param companyId
+     * @return
+     */
+    boolean unbindCompany(Integer id, Long companyId);
+}

+ 20 - 0
apis/home-api/src/main/java/com/usoftchina/uu/home/dto/CompanyHomeConfigDTO.java

@@ -0,0 +1,20 @@
+package com.usoftchina.uu.home.dto;
+
+/**
+ * @author yingp
+ * @date 2019/4/25
+ */
+public class CompanyHomeConfigDTO extends HomeConfigDTO {
+    /**
+     * 公司是否启用该配置
+     */
+    private Boolean enable;
+
+    public Boolean getEnable() {
+        return enable;
+    }
+
+    public void setEnable(Boolean enable) {
+        this.enable = enable;
+    }
+}

+ 161 - 0
apis/home-api/src/main/java/com/usoftchina/uu/home/dto/HomeConfigDTO.java

@@ -0,0 +1,161 @@
+package com.usoftchina.uu.home.dto;
+
+import com.usoftchina.uu.base.CompanyRelate;
+import com.usoftchina.uu.base.ViewType;
+
+/**
+ * @author yingp
+ * @date 2019/4/25
+ */
+public class HomeConfigDTO {
+    protected Integer id;
+    /**
+     * 顺序
+     */
+    protected Integer orderNum;
+    /**
+     * 消息名,例如 "待办事项"
+     */
+    protected String name;
+    /**
+     * 图标
+     */
+    protected String icon;
+    /**
+     * 打开/展示视图类型 0 - widget, 1 - web
+     */
+    protected Integer viewType;
+    protected String androidWidget;
+    protected String iosWidget;
+    /**
+     * 网页
+     */
+    protected String webUrl;
+    /**
+     * 归属某个平台,默认是Platform.ALL
+     */
+    protected String scopePlatform;
+    /**
+     * 归属某个公司私有的配置
+     */
+    protected Long scopeCompanyId;
+    /**
+     * 与公司相关的类型,默认CompanyRelate.COMPANY_OR_PERSONAL
+     *
+     * @see com.usoftchina.uu.base.CompanyRelate
+     */
+    protected Integer companyRelate;
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public Integer getOrderNum() {
+        return orderNum;
+    }
+
+    public void setOrderNum(Integer orderNum) {
+        this.orderNum = orderNum;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getIcon() {
+        return icon;
+    }
+
+    public void setIcon(String icon) {
+        this.icon = icon;
+    }
+
+    public Integer getViewType() {
+        return viewType;
+    }
+
+    public void setViewType(Integer viewType) {
+        this.viewType = viewType;
+    }
+
+    public String getAndroidWidget() {
+        return androidWidget;
+    }
+
+    public void setAndroidWidget(String androidWidget) {
+        this.androidWidget = androidWidget;
+    }
+
+    public String getIosWidget() {
+        return iosWidget;
+    }
+
+    public void setIosWidget(String iosWidget) {
+        this.iosWidget = iosWidget;
+    }
+
+    public String getWebUrl() {
+        return webUrl;
+    }
+
+    public void setWebUrl(String webUrl) {
+        this.webUrl = webUrl;
+    }
+
+    public String getScopePlatform() {
+        return scopePlatform;
+    }
+
+    public void setScopePlatform(String scopePlatform) {
+        this.scopePlatform = scopePlatform;
+    }
+
+    public Long getScopeCompanyId() {
+        return scopeCompanyId;
+    }
+
+    public void setScopeCompanyId(Long scopeCompanyId) {
+        this.scopeCompanyId = scopeCompanyId;
+    }
+
+    public Integer getCompanyRelate() {
+        return companyRelate;
+    }
+
+    public void setCompanyRelate(Integer companyRelate) {
+        this.companyRelate = companyRelate;
+    }
+
+    public CompanyRelate companyRelate() {
+        return CompanyRelate.of(companyRelate);
+    }
+
+    public ViewType viewType() {
+        return ViewType.of(viewType);
+    }
+
+    @Override
+    public String toString() {
+        return "HomeConfigDTO{" +
+                "id=" + id +
+                ", orderNum=" + orderNum +
+                ", name='" + name + '\'' +
+                ", icon='" + icon + '\'' +
+                ", viewType=" + viewType +
+                ", androidWidget='" + androidWidget + '\'' +
+                ", iosWidget='" + iosWidget + '\'' +
+                ", webUrl='" + webUrl + '\'' +
+                ", scopePlatform='" + scopePlatform + '\'' +
+                ", scopeCompanyId=" + scopeCompanyId +
+                ", companyRelate=" + companyRelate +
+                '}';
+    }
+}

+ 4 - 0
apis/message-api/build.gradle

@@ -0,0 +1,4 @@
+dependencies {
+    compile project(':shared:core')
+    compile "$pageHelperSpringBoot"
+}

+ 84 - 0
apis/message-api/src/main/java/com/usoftchina/uu/message/api/MessageApi.java

@@ -0,0 +1,84 @@
+package com.usoftchina.uu.message.api;
+
+import com.github.pagehelper.PageInfo;
+import com.usoftchina.uu.base.Platform;
+import com.usoftchina.uu.message.dto.MessageDTO;
+import com.usoftchina.uu.message.dto.SendMessageDTO;
+import com.usoftchina.uu.message.dto.UnreadMessageCountDTO;
+import com.usoftchina.uu.page.PageRequest;
+
+import java.util.List;
+
+/**
+ * 消息接口
+ *
+ * @author yingp
+ * @date 2019/4/19
+ */
+public interface MessageApi {
+    /**
+     * 发送消息
+     *
+     * @param sendMessageDTO
+     * @return
+     */
+    boolean send(SendMessageDTO sendMessageDTO);
+
+    /**
+     * 获取未读消息数
+     *
+     * @param code
+     * @param accountId
+     * @param companyId
+     * @return
+     */
+    int getUnreadCount(String code, Long accountId, Long companyId);
+
+    /**
+     * 全部未读消息数
+     *
+     * @param accountId
+     * @param companyId
+     * @return
+     */
+    List<UnreadMessageCountDTO> getAllUnreadCount(Long accountId, Long companyId);
+
+    /**
+     * 按归属平台查找 全部未读消息数
+     *
+     * @param platform
+     * @param accountId
+     * @param companyId
+     * @return
+     */
+    List<UnreadMessageCountDTO> getAllUnreadCountByScopePlatform(Platform platform, Long accountId, Long companyId);
+
+    /**
+     * 设置消息已读
+     *
+     * @param messageId
+     * @param platform  操作的平台
+     * @return
+     */
+    boolean setRead(Long messageId, Platform platform);
+
+    /**
+     * 批量设置消息已读
+     *
+     * @param messageIds
+     * @param platform   操作的平台
+     * @return
+     */
+    boolean setRead(List<Long> messageIds, Platform platform);
+
+    /**
+     * 分页查找某个消息类的消息
+     *
+     * @param pageRequest
+     * @param code
+     * @param accountId
+     * @param companyId
+     * @return
+     */
+    PageInfo<MessageDTO> findByPageAndCode(PageRequest pageRequest, String code, Long accountId, Long companyId);
+}

+ 203 - 0
apis/message-api/src/main/java/com/usoftchina/uu/message/api/MessageConfigApi.java

@@ -0,0 +1,203 @@
+package com.usoftchina.uu.message.api;
+
+import com.usoftchina.uu.base.CompanyRelate;
+import com.usoftchina.uu.base.Platform;
+import com.usoftchina.uu.message.dto.CompanyMessageConfigDTO;
+import com.usoftchina.uu.message.dto.MessageConfigDTO;
+
+import java.util.List;
+
+/**
+ * 消息配置接口
+ *
+ * @author yingp
+ * @date 2019/4/19
+ */
+public interface MessageConfigApi {
+    /**
+     * 保存
+     *
+     * @param messageConfigDTO
+     * @return
+     */
+    boolean save(MessageConfigDTO messageConfigDTO);
+
+    /**
+     * 批量保存
+     *
+     * @param messageConfigDTOList
+     * @return
+     */
+    boolean save(List<MessageConfigDTO> messageConfigDTOList);
+
+    /**
+     * 批量保存或更新
+     *
+     * @param messageConfigDTOList
+     * @return
+     */
+    boolean saveOrUpdate(List<MessageConfigDTO> messageConfigDTOList);
+
+    /**
+     * 删除
+     *
+     * @param id
+     * @return
+     */
+    boolean removeByPrimaryKey(Integer id);
+
+    /**
+     * 更新
+     *
+     * @param messageConfigDTO
+     * @return
+     */
+    boolean updateByPrimaryKey(MessageConfigDTO messageConfigDTO);
+
+    /**
+     * 批量更新
+     *
+     * @param messageConfigDTOList
+     * @return
+     */
+    boolean updateByPrimaryKey(List<MessageConfigDTO> messageConfigDTOList);
+
+    /**
+     * 查找
+     *
+     * @param id
+     * @return
+     */
+    MessageConfigDTO findByPrimaryKey(Integer id);
+
+    /**
+     * 查找
+     *
+     * @param code
+     * @return
+     */
+    MessageConfigDTO findByCode(String code);
+
+    /**
+     * 全部配置
+     *
+     * @return
+     */
+    List<MessageConfigDTO> findAll();
+
+    /**
+     * 按归属平台查找
+     *
+     * @param platform
+     * @return
+     */
+    List<MessageConfigDTO> findByScopePlatform(Platform platform);
+
+    /**
+     * 按公司关联规则查找
+     *
+     * @param companyRelate
+     * @return
+     */
+    List<MessageConfigDTO> findByCompanyRelate(CompanyRelate companyRelate);
+
+    /**
+     * 查找属于该公司的应用配置(包括私有配置 + 公有配置,包括是否启用状态)
+     *
+     * @param scopeCompanyId
+     * @return
+     */
+    List<CompanyMessageConfigDTO> findByScopeCompanyId(Long scopeCompanyId);
+
+    /**
+     * 查找属于该公司的且已启用的应用配置(包括私有配置 + 公有配置)
+     *
+     * @param scopeCompanyId
+     * @return
+     */
+    List<MessageConfigDTO> findEnabledByScopeCompanyId(Long scopeCompanyId);
+
+    /**
+     * 查找指定平台的属于该公司的且已启用的应用配置(包括私有配置 + 公有配置)
+     *
+     * @param platform
+     * @param scopeCompanyId
+     * @return
+     */
+    List<MessageConfigDTO> findEnabledByScopePlatformAndCompanyId(Platform platform, Long scopeCompanyId);
+
+    /**
+     * 查找个人相关消息配置
+     * <pre>
+     *     即companyRelate != CompanyRelate.ONLY_COMPANY
+     *     例如 uu互联以个人身份登录后获取消息配置
+     * </pre>
+     *
+     * @return
+     */
+    List<MessageConfigDTO> findPersonal();
+
+    /**
+     * 按归属平台查找个人相关消息配置
+     * <pre>
+     *     例如 以个人身份登录商城后获取消息
+     * </pre>
+     *
+     * @param platform
+     * @return
+     */
+    List<MessageConfigDTO> findPersonalByScopePlatform(Platform platform);
+
+    /**
+     * 查找启用的配置
+     * <pre>
+     *     根据companyId是否为空来判断取个人相关还是企业相关配置
+     * </pre>
+     *
+     * @param companyId
+     * @return
+     */
+    default List<MessageConfigDTO> findEnabled(Long companyId) {
+        if (null == companyId) {
+            return findPersonal();
+        } else {
+            return findEnabledByScopeCompanyId(companyId);
+        }
+    }
+
+    /**
+     * 按指定平台查找启用的配置
+     * <pre>
+     *     根据companyId是否为空来判断取个人相关还是企业相关配置
+     * </pre>
+     *
+     * @param platform
+     * @param companyId
+     * @return
+     */
+    default List<MessageConfigDTO> findEnabledByScopePlatform(Platform platform, Long companyId) {
+        if (null == companyId) {
+            return findPersonalByScopePlatform(platform);
+        } else {
+            return findEnabledByScopePlatformAndCompanyId(platform, companyId);
+        }
+    }
+
+    /**
+     * 公司绑定消息类
+     *
+     * @param id
+     * @param companyId
+     * @return
+     */
+    boolean bindCompany(Integer id, Long companyId);
+
+    /**
+     * 公司解除绑定消息类
+     *
+     * @param id
+     * @param companyId
+     * @return
+     */
+    boolean unbindCompany(Integer id, Long companyId);
+}

+ 38 - 0
apis/message-api/src/main/java/com/usoftchina/uu/message/dto/CompanyMessageConfigDTO.java

@@ -0,0 +1,38 @@
+package com.usoftchina.uu.message.dto;
+
+/**
+ * @author yingp
+ * @date 2019/4/23
+ */
+public class CompanyMessageConfigDTO extends MessageConfigDTO {
+    /**
+     * 是否启用
+     */
+    private Boolean enable;
+
+    public Boolean getEnable() {
+        return enable;
+    }
+
+    public void setEnable(Boolean enable) {
+        this.enable = enable;
+    }
+
+    @Override
+    public String toString() {
+        return "CompanyMessageConfigDTO{" +
+                "enable=" + enable +
+                ", id=" + id +
+                ", code='" + code + '\'' +
+                ", orderNum=" + orderNum +
+                ", name='" + name + '\'' +
+                ", icon='" + icon + '\'' +
+                ", viewType=" + viewType +
+                ", androidWidget='" + androidWidget + '\'' +
+                ", iosWidget='" + iosWidget + '\'' +
+                ", webUrl='" + webUrl + '\'' +
+                ", scopePlatform='" + scopePlatform + '\'' +
+                ", scopeCompanyId=" + scopeCompanyId +
+                '}';
+    }
+}

+ 174 - 0
apis/message-api/src/main/java/com/usoftchina/uu/message/dto/MessageConfigDTO.java

@@ -0,0 +1,174 @@
+package com.usoftchina.uu.message.dto;
+
+import com.usoftchina.uu.base.CompanyRelate;
+import com.usoftchina.uu.base.ViewType;
+
+/**
+ * @author yingp
+ * @date 2019/4/19
+ */
+public class MessageConfigDTO {
+    protected Integer id;
+    /**
+     * 唯一编码,例如 "uas.todo"
+     */
+    protected String code;
+    /**
+     * 顺序
+     */
+    protected Integer orderNum;
+    /**
+     * 消息名,例如 "待办事项"
+     */
+    protected String name;
+    /**
+     * 图标
+     */
+    protected String icon;
+    /**
+     * 打开视图类型 0 - widget, 1 - web
+     */
+    protected Integer viewType;
+    protected String androidWidget;
+    protected String iosWidget;
+    /**
+     * 网页
+     */
+    protected String webUrl;
+    /**
+     * 归属某个平台,默认是Platform.ALL
+     */
+    protected String scopePlatform;
+    /**
+     * 归属某个公司私有的配置
+     */
+    protected Long scopeCompanyId;
+    /**
+     * 与公司相关的类型,默认CompanyRelate.COMPANY_OR_PERSONAL
+     *
+     * @see CompanyRelate
+     */
+    protected Integer companyRelate;
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public void setCode(String code) {
+        this.code = code;
+    }
+
+    public Integer getOrderNum() {
+        return orderNum;
+    }
+
+    public void setOrderNum(Integer orderNum) {
+        this.orderNum = orderNum;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getIcon() {
+        return icon;
+    }
+
+    public void setIcon(String icon) {
+        this.icon = icon;
+    }
+
+    public Integer getViewType() {
+        return viewType;
+    }
+
+    public void setViewType(Integer viewType) {
+        this.viewType = viewType;
+    }
+
+    public String getAndroidWidget() {
+        return androidWidget;
+    }
+
+    public void setAndroidWidget(String androidWidget) {
+        this.androidWidget = androidWidget;
+    }
+
+    public String getIosWidget() {
+        return iosWidget;
+    }
+
+    public void setIosWidget(String iosWidget) {
+        this.iosWidget = iosWidget;
+    }
+
+    public String getWebUrl() {
+        return webUrl;
+    }
+
+    public void setWebUrl(String webUrl) {
+        this.webUrl = webUrl;
+    }
+
+    public String getScopePlatform() {
+        return scopePlatform;
+    }
+
+    public void setScopePlatform(String scopePlatform) {
+        this.scopePlatform = scopePlatform;
+    }
+
+    public Long getScopeCompanyId() {
+        return scopeCompanyId;
+    }
+
+    public void setScopeCompanyId(Long scopeCompanyId) {
+        this.scopeCompanyId = scopeCompanyId;
+    }
+
+    public Integer getCompanyRelate() {
+        return companyRelate;
+    }
+
+    public void setCompanyRelate(Integer companyRelate) {
+        this.companyRelate = companyRelate;
+    }
+
+    public CompanyRelate companyRelate() {
+        return CompanyRelate.of(companyRelate);
+    }
+
+    @Override
+    public String toString() {
+        return "MessageConfigDTO{" +
+                "id=" + id +
+                ", code='" + code + '\'' +
+                ", orderNum=" + orderNum +
+                ", name='" + name + '\'' +
+                ", icon='" + icon + '\'' +
+                ", viewType=" + viewType +
+                ", androidWidget='" + androidWidget + '\'' +
+                ", iosWidget='" + iosWidget + '\'' +
+                ", webUrl='" + webUrl + '\'' +
+                ", scopePlatform='" + scopePlatform + '\'' +
+                ", scopeCompanyId=" + scopeCompanyId +
+                ", companyRelate=" + companyRelate +
+                '}';
+    }
+
+    public ViewType viewType() {
+        return ViewType.of(viewType);
+    }
+}

+ 76 - 0
apis/message-api/src/main/java/com/usoftchina/uu/message/dto/MessageDTO.java

@@ -0,0 +1,76 @@
+package com.usoftchina.uu.message.dto;
+
+/**
+ * @author yingp
+ * @date 2019/4/19
+ */
+public class MessageDTO {
+    protected Long id;
+    /**
+     * 消息类
+     */
+    protected String code;
+    /**
+     * 消息内容
+     */
+    protected String body;
+    /**
+     * 接收人
+     */
+    protected Long accountId;
+    /**
+     * 企业ID
+     */
+    protected Long companyId;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public void setCode(String code) {
+        this.code = code;
+    }
+
+    public String getBody() {
+        return body;
+    }
+
+    public void setBody(String body) {
+        this.body = body;
+    }
+
+    public Long getAccountId() {
+        return accountId;
+    }
+
+    public void setAccountId(Long accountId) {
+        this.accountId = accountId;
+    }
+
+    public Long getCompanyId() {
+        return companyId;
+    }
+
+    public void setCompanyId(Long companyId) {
+        this.companyId = companyId;
+    }
+
+    @Override
+    public String toString() {
+        return "MessageDTO{" +
+                "id=" + id +
+                ", code='" + code + '\'' +
+                ", body='" + body + '\'' +
+                ", accountId=" + accountId +
+                ", companyId=" + companyId +
+                '}';
+    }
+}

+ 68 - 0
apis/message-api/src/main/java/com/usoftchina/uu/message/dto/SendMessageDTO.java

@@ -0,0 +1,68 @@
+package com.usoftchina.uu.message.dto;
+
+import java.util.List;
+
+/**
+ * @author yingp
+ * @date 2019/4/19
+ */
+public class SendMessageDTO {
+    /**
+     * 消息类
+     */
+    private String code;
+    /**
+     * 消息内容
+     */
+    private String body;
+    /**
+     * 接收人
+     */
+    private List<Long> accountIds;
+    /**
+     * 企业ID
+     */
+    private Long companyId;
+
+    public String getCode() {
+        return code;
+    }
+
+    public void setCode(String code) {
+        this.code = code;
+    }
+
+    public String getBody() {
+        return body;
+    }
+
+    public void setBody(String body) {
+        this.body = body;
+    }
+
+    public List<Long> getAccountIds() {
+        return accountIds;
+    }
+
+    public void setAccountIds(List<Long> accountIds) {
+        this.accountIds = accountIds;
+    }
+
+    public Long getCompanyId() {
+        return companyId;
+    }
+
+    public void setCompanyId(Long companyId) {
+        this.companyId = companyId;
+    }
+
+    @Override
+    public String toString() {
+        return "SendMessageDTO{" +
+                "code='" + code + '\'' +
+                ", body='" + body + '\'' +
+                ", accountIds=" + accountIds +
+                ", companyId=" + companyId +
+                '}';
+    }
+}

+ 42 - 0
apis/message-api/src/main/java/com/usoftchina/uu/message/dto/UnreadMessageCountDTO.java

@@ -0,0 +1,42 @@
+package com.usoftchina.uu.message.dto;
+
+/**
+ * @author yingp
+ * @date 2019/4/19
+ */
+public class UnreadMessageCountDTO {
+    private String code;
+    private Integer count;
+
+    public UnreadMessageCountDTO() {
+    }
+
+    public UnreadMessageCountDTO(String code, Integer count) {
+        this.code = code;
+        this.count = count;
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public void setCode(String code) {
+        this.code = code;
+    }
+
+    public Integer getCount() {
+        return count;
+    }
+
+    public void setCount(Integer count) {
+        this.count = count;
+    }
+
+    @Override
+    public String toString() {
+        return "UnreadMessageCountDTO{" +
+                "code='" + code + '\'' +
+                ", count='" + count + '\'' +
+                '}';
+    }
+}

+ 21 - 0
apis/mobile-grpc-api/README.md

@@ -0,0 +1,21 @@
+### Android依赖
+
+```groovy
+repositories {
+    mavenLocal()
+    // usoftchina maven release
+    maven { url 'http://maven.ubtob.com/artifactory/libs-release' }
+    // usoftchina maven snapshot
+    maven { url 'http://maven.ubtob.com/artifactory/libs-snapshot' }
+    maven { url 'http://maven.aliyun.com/nexus/content/groups/public/' }
+
+}
+  
+dependencies {
+    compile 'com.usoftchina.uu:android-grpc-api:1.0.0-SNAPSHOT'
+}
+```
+
+### Android开发
+
+[文档](https://doc.ubtob.com/web/#/3?page_id=166)

+ 51 - 0
apis/mobile-grpc-api/build-android.gradle

@@ -0,0 +1,51 @@
+apply plugin: 'com.google.protobuf'
+
+sourceSets {
+    main {
+        proto {
+            srcDir 'src/main/proto'
+        }
+    }
+}
+
+archivesBaseName = 'android-grpc-api'
+
+dependencies {
+    compile "io.grpc:grpc-okhttp:$grpcVersion"
+    compile "io.grpc:grpc-protobuf-lite:$grpcVersion"
+    compile "io.grpc:grpc-stub:$grpcVersion"
+    testCompile 'junit:junit'
+}
+
+protobuf {
+    protoc {
+        artifact = "com.google.protobuf:protoc:$protocVersion"
+    }
+    plugins {
+        javalite {
+            artifact = 'com.google.protobuf:protoc-gen-javalite:3.0.0'
+        }
+        grpc {
+            artifact = "io.grpc:protoc-gen-grpc-java:$grpcVersion"
+        }
+//        objcgrpc {
+//            path = ""
+//        }
+    }
+    generatedFilesBaseDir = "$projectDir/build/lite-generated"
+    generateProtoTasks {
+        all().each { task ->
+            task.builtins {
+                remove java
+                // ios .h/.m
+                objc { }
+//                objcgrpc { }
+            }
+            task.plugins {
+                // android jar
+                javalite { }
+                grpc { option 'lite' }
+            }
+        }
+    }
+}

+ 32 - 0
apis/mobile-grpc-api/build-default.gradle

@@ -0,0 +1,32 @@
+apply plugin: 'com.google.protobuf'
+
+sourceSets {
+    main {
+        proto {
+            srcDir 'src/main/proto'
+        }
+    }
+}
+
+dependencies {
+    compile "io.grpc:grpc-netty-shaded:$grpcVersion"
+    compile "io.grpc:grpc-protobuf:$grpcVersion"
+    compile "io.grpc:grpc-stub:$grpcVersion"
+    testCompile 'junit:junit'
+}
+
+protobuf {
+    protoc {
+        artifact = "com.google.protobuf:protoc:$protocVersion"
+    }
+    plugins {
+        grpc {
+            artifact = "io.grpc:protoc-gen-grpc-java:$grpcVersion"
+        }
+    }
+    generateProtoTasks {
+        all()*.plugins {
+            grpc {}
+        }
+    }
+}

+ 4 - 0
apis/mobile-grpc-api/build.gradle

@@ -0,0 +1,4 @@
+// build-default.gradle的包提供给服务端
+// build-android.gradle的包提供给客户端
+def profile = System.getProperty("profile") ?: "default"
+apply from: "build-${profile}.gradle"

+ 193 - 0
apis/mobile-grpc-api/src/main/proto/account.proto

@@ -0,0 +1,193 @@
+syntax = "proto3";
+
+package uu.mobile;
+
+import "base.proto";
+
+option java_multiple_files = true;
+option java_package = "com.usoftchina.uu.mobile.grpc.api";
+
+// 账户服务
+service AccountService {
+    // 注册
+    rpc signup (AccountSignupRequest) returns (AccountSignupResponse) {};
+    // 登录
+    rpc signin (AccountSigninRequest) returns (AccountSigninResponse) {};
+    // 切换公司
+    rpc switchCompany (SwitchCompanyRequest) returns (SwitchCompanyResponse) {};
+    // 获取已登录账户信息
+    rpc getInfo (GetAccountInfoRequest) returns (GetAccountInfoResponse) {};
+    // 保存账户信息
+    rpc saveInfo (SaveAccountInfoRequest) returns (SaveAccountInfoResponse) {};
+    // 退出
+    rpc signout (AccountSignoutRequest) returns (AccountSignoutResponse) {};
+}
+
+// 身份令牌,超时需重新登录
+message AuthedToken {
+    // 令牌
+    string token = 1;
+    // 有效期/秒
+    int32 expire = 2;
+    // 产生时间
+    int64 timestamp = 3;
+}
+
+// 注册请求参数
+message AccountSignupRequest {
+    // 手机号
+    string mobile = 1;
+    // 密码
+    string password = 2;
+    // 真实姓名
+    string realname = 3;
+    // 邮箱
+    string email = 4;
+    // 性别
+    AccountInfo.Sex sex = 5;
+    // 头像
+    string avatarUrl = 6;
+}
+
+// 注册响应参数
+message AccountSignupResponse {
+    ResponseHeader responseHeader = 1;
+}
+
+// 登录请求参数
+message AccountSigninRequest {
+    // 手机号
+    string mobile = 1;
+    // 密码
+    string password = 2;
+    // 设备信息
+    DeviceInfo deviceInfo = 3;
+}
+
+// 登录响应参数
+message AccountSigninResponse {
+    ResponseHeader responseHeader = 1;
+    // 身份令牌
+    AuthedToken authedToken = 2;
+    // 账户信息
+    AccountInfo account = 3;
+    // 当前选择的公司(如果只有一个公司,会自动登录到该公司)
+    int64 activeCompanyId = 4;
+    // 账户已绑定公司
+    repeated Company company = 5;
+}
+
+// 切换公司请求参数
+message SwitchCompanyRequest {
+    // 公司ID
+    int64 companyId = 1;
+}
+
+// 切换公司响应参数
+message SwitchCompanyResponse {
+    ResponseHeader responseHeader = 1;
+    // 身份令牌
+    AuthedToken authedToken = 2;
+}
+
+// 获取账户信息请求参数
+message GetAccountInfoRequest {
+}
+
+// 获取账户信息响应参数
+message GetAccountInfoResponse {
+    ResponseHeader responseHeader = 1;
+    // 账户信息
+    AccountInfo account = 2;
+    // 当前选择的公司
+    int64 activeCompanyId = 3;
+    // 账户已绑定公司
+    repeated Company company = 4;
+}
+
+// 保存账户信息请求参数
+message SaveAccountInfoRequest {
+    // 真实姓名
+    string realname = 1;
+    // 头像
+    string avatarUrl = 2;
+    // 性别
+    AccountInfo.Sex sex = 3;
+}
+
+// 保存账户信息响应参数
+message SaveAccountInfoResponse {
+    ResponseHeader responseHeader = 1;
+}
+
+// 退出请求参数
+message AccountSignoutRequest {
+}
+
+// 退出响应参数
+message AccountSignoutResponse {
+    ResponseHeader responseHeader = 1;
+}
+
+// 密码找回相关
+service PasswordService {
+    // 手机验证码方式找回密码,发送手机验证码
+    rpc sendCheckCodeByMobile (SendCheckCodeByMobileRequest) returns (SendCheckCodeByMobileResponse) {};
+    // 手机验证码方式找回密码,校验验证码
+    rpc resetByCheckCode (ResetByCheckCodeRequest) returns (ResetByCheckCodeResponse) {};
+    // 邮箱链接方式找回密码,按手机号获取邮箱号
+    rpc getEmailByMobile (GetEmailByMobileRequest) returns (GetEmailByMobileResponse) {};
+    // 发送带验证链接的邮件
+    rpc sendCheckEmail (SendCheckEmailRequest) returns (SendCheckEmailResponse) {};
+}
+
+// 手机验证码方式找回密码,发送手机验证码请求参数
+message SendCheckCodeByMobileRequest {
+    string mobile = 1;
+}
+
+// 手机验证码方式找回密码,发送手机验证码响应参数
+message SendCheckCodeByMobileResponse {
+    ResponseHeader responseHeader = 1;
+    // 本次验证标志
+    string token = 2;
+}
+
+// 手机验证码方式找回密码,重置密码请求参数
+message ResetByCheckCodeRequest {
+    string mobile = 1;
+    // SendCheckCodeByMobileResponse返回的token标志
+    string token = 2;
+    // 验证码
+    string code = 3;
+    // 新的密码
+    string password = 4;
+}
+
+// 手机验证码方式找回密码,重置密码响应参数
+message ResetByCheckCodeResponse {
+    ResponseHeader responseHeader = 1;
+}
+
+// 邮箱链接方式找回密码,按手机号获取邮箱号请求参数
+message GetEmailByMobileRequest {
+    string mobile = 1;
+}
+
+// 邮箱链接方式找回密码,按手机号获取邮箱号响应参数
+message GetEmailByMobileResponse {
+    ResponseHeader responseHeader = 1;
+    // 本次验证标志
+    string token = 2;
+    string email = 3;
+}
+
+// 发送带验证链接的邮件请求参数
+message SendCheckEmailRequest {
+    string token = 1;
+}
+
+// 发送带验证链接的邮件响应参数
+message SendCheckEmailResponse {
+    ResponseHeader responseHeader = 1;
+}

+ 24 - 0
apis/mobile-grpc-api/src/main/proto/app.proto

@@ -0,0 +1,24 @@
+syntax = "proto3";
+
+package uu.mobile;
+
+import "base.proto";
+
+option java_multiple_files = true;
+option java_package = "com.usoftchina.uu.mobile.grpc.api";
+
+// 应用中心
+service AppService {
+    // 获取应用配置
+    rpc getConfig (GetAppConfigRequest) returns (GetAppConfigResponse) {};
+}
+
+// 获取应用配置请求参数
+message GetAppConfigRequest {
+}
+
+// 获取应用配置响应参数
+message GetAppConfigResponse {
+    ResponseHeader responseHeader = 1;
+    repeated AppGroupConfig config = 2;
+}

+ 170 - 0
apis/mobile-grpc-api/src/main/proto/base.proto

@@ -0,0 +1,170 @@
+syntax = "proto3";
+
+package uu.mobile;
+
+option java_multiple_files = true;
+option java_package = "com.usoftchina.uu.mobile.grpc.api";
+
+// 响应头
+message ResponseHeader {
+    // 是否成功
+    bool success = 1;
+    // 错误码
+    int32 code = 2;
+    // 错误信息
+    string message = 3;
+}
+
+// 分页信息
+message Paging {
+    // 总页数
+    int32 totalPage = 1;
+    // 总条数
+    int64 totalCount = 2;
+    // 每页条数
+    int32 pageSize = 3;
+    // 当前页
+    int32 pageNumber = 4;
+}
+
+// 账户
+message AccountInfo {
+    int64 id = 1;
+    // 真实姓名(考虑是企业应用,非社交类型,不需要昵称)
+    string realname = 2;
+    // 手机号
+    string mobile = 3;
+    // 邮箱
+    string email = 4;
+    // 头像
+    string avatarUrl = 5;
+    Sex sex = 6;
+    // 性别
+    enum Sex {
+        // 女
+        FEMALE = 0;
+        // 男
+        MALE = 1;
+    }
+}
+
+// 公司
+message Company {
+    int64 id = 1;
+    // 名称
+    string name = 2;
+}
+
+// 视图类型
+enum ViewType {
+    // 原生
+    WIDGET = 0;
+    // 网页
+    WEB = 1;
+}
+
+// 消息配置
+message MessageConfig {
+    // 唯一编码,例如 uas.todo
+    string code = 1;
+    // 消息名,例如 待办事项
+    string name = 2;
+    // 图标
+    string icon = 3;
+    // 打开视图类型
+    ViewType viewType = 4;
+    // Android
+    string androidWidget = 5;
+    // IOS
+    string iosWidget = 6;
+    // 网页
+    string webUrl = 7;
+}
+
+// 未读消息统计
+message UnreadMessageCount {
+    // 消息编码
+    string code = 1;
+    // 消息数
+    int32 count = 2;
+}
+
+// 消息
+message MessageInfo {
+    // ID
+    int64 id = 1;
+    // 消息内容
+    string body = 2;
+    // 状态
+    Status status = 3;
+    enum Status {
+        // 未读
+        UNREAD = 0;
+        // 已读
+        READ = 1;
+    }
+}
+
+// 应用组配置
+message AppGroupConfig {
+    string name = 1;
+    repeated AppConfig appConfig = 2;
+}
+
+// 应用配置
+message AppConfig {
+    int32 id = 1;
+    // 应用名
+    string name = 2;
+    // 图标
+    string icon = 3;
+    // 打开视图类型
+    ViewType viewType = 4;
+    // Android
+    string androidWidget = 5;
+    // IOS
+    string iosWidget = 6;
+    // 网页
+    string webUrl = 7;
+}
+
+// 我的主页配置
+message HomeConfig {
+    int32 id = 1;
+    // 显示名
+    string name = 2;
+    // 图标
+    string icon = 3;
+    // 显示/打开视图类型
+    ViewType viewType = 4;
+    // 显示/打开Android控件
+    string androidWidget = 5;
+    // 显示/打开IOS控件
+    string iosWidget = 6;
+    // 打开网页
+    string webUrl = 7;
+}
+
+// 设备信息
+message DeviceInfo {
+    // 客户端发行版本,例如1.0.0
+    string version = 1;
+    // 设备型号
+    string model = 2;
+    // 系统
+    OS os = 3;
+    enum OS {
+        ANDROID = 0;
+        IOS = 1;
+    }
+    // 系统版本,例如7.1
+    string osVersion = 4;
+    // 经度
+    double longitude = 5;
+    // 纬度
+    double latitude = 6;
+    // 位置
+    string location = 7;
+    // 语言
+    string lang = 8;
+}

+ 24 - 0
apis/mobile-grpc-api/src/main/proto/home.proto

@@ -0,0 +1,24 @@
+syntax = "proto3";
+
+package uu.mobile;
+
+import "base.proto";
+
+option java_multiple_files = true;
+option java_package = "com.usoftchina.uu.mobile.grpc.api";
+
+// 我的主页
+service HomeService {
+    // 获取我的主页配置
+    rpc getConfig (GetHomeConfigRequest) returns (GetHomeConfigResponse);
+}
+
+// 获取我的主页配置请求参数
+message GetHomeConfigRequest {
+}
+
+// 获取我的主页配置响应参数
+message GetHomeConfigResponse {
+    ResponseHeader responseHeader = 1;
+    repeated HomeConfig config = 2;
+}

+ 78 - 0
apis/mobile-grpc-api/src/main/proto/message.proto

@@ -0,0 +1,78 @@
+syntax = "proto3";
+
+package uu.mobile;
+
+import "base.proto";
+
+option java_multiple_files = true;
+option java_package = "com.usoftchina.uu.mobile.grpc.api";
+
+// 消息服务
+service MessageService {
+    // 获取消息配置
+    rpc getConfig (GetMessageConfigRequest) returns (GetMessageConfigResponse) {};
+    // 未读消息统计
+    rpc getUnreadCount (GetUnreadMessageCountRequest) returns (GetUnreadMessageCountResponse) {};
+    // 获取消息
+    rpc getMessages (GetMessagesRequest) returns (GetMessagesResponse) {};
+    // 设置为已读
+    rpc setRead (SetMessageReadRequest) returns (SetMessageReadResponse) {};
+}
+
+// 获取消息配置请求参数
+message GetMessageConfigRequest {
+}
+
+// 获取消息配置响应参数
+message GetMessageConfigResponse {
+    ResponseHeader responseHeader = 1;
+    repeated MessageConfig config = 2;
+}
+
+// 未读消息统计请求参数
+message GetUnreadMessageCountRequest {
+}
+
+// 未读消息统计响应参数
+message GetUnreadMessageCountResponse {
+    ResponseHeader responseHeader = 1;
+    repeated UnreadMessageCount unread = 2;
+}
+
+// 获取消息请求参数
+message GetMessagesRequest {
+    // 每页条数
+    int32 pageSize = 1;
+    // 当前页
+    int32 pageNumber = 2;
+    // 消息编码
+    string code = 3;
+    // 消息状态
+    Status status = 4;
+
+    enum Status {
+        // 未读
+        UNREAD = 0;
+        // 已读
+        READ = 1;
+        // 全部
+        ALL = 2;
+    }
+}
+
+// 获取消息响应参数
+message GetMessagesResponse {
+    ResponseHeader responseHeader = 1;
+    Paging paging = 2;
+    repeated MessageInfo message = 3;
+}
+
+// 设置消息已读请求参数
+message SetMessageReadRequest {
+    int64 messageId = 1;
+}
+
+// 设置消息已读响应参数
+message SetMessageReadResponse {
+    ResponseHeader responseHeader = 1;
+}

+ 31 - 0
apis/open-grpc-api/build.gradle

@@ -0,0 +1,31 @@
+apply plugin: 'com.google.protobuf'
+
+dependencies {
+    compile "io.grpc:grpc-netty-shaded:$grpcVersion"
+    compile "io.grpc:grpc-protobuf:$grpcVersion"
+    compile "io.grpc:grpc-stub:$grpcVersion"
+}
+
+sourceSets {
+    main {
+        proto {
+            srcDir 'src/main/proto'
+        }
+    }
+}
+
+protobuf {
+    protoc {
+        artifact = "com.google.protobuf:protoc:$protocVersion"
+    }
+    plugins {
+        grpc {
+            artifact = "io.grpc:protoc-gen-grpc-java:$grpcVersion"
+        }
+    }
+    generateProtoTasks {
+        all()*.plugins {
+            grpc {}
+        }
+    }
+}

+ 46 - 0
apis/open-grpc-api/src/main/proto/account.proto

@@ -0,0 +1,46 @@
+syntax = "proto3";
+
+package uu.open;
+
+import "base.proto";
+
+option java_multiple_files = true;
+option java_package = "com.usoftchina.uu.open.grpc.api";
+
+// 账户服务
+service AccountService {
+    // 按token获取账户信息,移动端访问第三方平台接口时带入用户token,第三方平台调用此接口获取用户信息
+    rpc getInfoByToken (GetAccountInfoByTokenRequest) returns (GetAccountInfoByTokenResponse) {};
+    // 保存账户信息
+    rpc saveInfo (SaveAccountInfoRequest) returns (SaveAccountInfoResponse) {};
+}
+
+// 按token获取账户信息请求参数
+message GetAccountInfoByTokenRequest {
+    string token = 1;
+}
+
+// 按token获取账户信息响应参数
+message GetAccountInfoByTokenResponse {
+    ResponseHeader responseHeader = 1;
+    // 账户信息
+    AccountInfo account = 2;
+    // 当前登录的公司
+    int64 activeCompanyId = 3;
+}
+
+// 保存账户信息请求参数,不允许修改手机号
+message SaveAccountInfoRequest {
+    int64 id = 1;
+    // 真实姓名(考虑是企业应用,非社交类型,不需要昵称)
+    string realname = 2;
+    // 头像
+    string avatarUrl = 3;
+    // 性别
+    AccountInfo.Sex sex = 4;
+}
+
+// 保存账户信息响应参数
+message SaveAccountInfoResponse {
+    ResponseHeader responseHeader = 1;
+}

+ 69 - 0
apis/open-grpc-api/src/main/proto/app.proto

@@ -0,0 +1,69 @@
+syntax = "proto3";
+
+package uu.open;
+
+import "base.proto";
+
+option java_multiple_files = true;
+option java_package = "com.usoftchina.uu.open.grpc.api";
+
+// 应用中心
+service AppService {
+    // 获取应用配置
+    rpc getConfig (GetAppConfigRequest) returns (GetAppConfigResponse) {};
+    // 启用/禁用 应用
+    rpc setEnable (SetEnableRequest) returns (SetEnableResponse) {};
+    // 保存应用配置
+    rpc saveConfig (SaveConfigRequest) returns (SaveConfigResponse) {};
+    // 删除应用配置
+    rpc deleteConfig (DeleteConfigRequest) returns (DeleteCOnfigResponse) {};
+}
+
+// 获取应用配置请求参数
+message GetAppConfigRequest {
+    Platform platform = 1;
+    enum Platform {
+        // uas、uas saas
+        UAS = 0;
+        // 简易版saas
+        SAAS = 1;
+        LUBAN = 2;
+    }
+}
+
+// 获取应用配置响应参数
+message GetAppConfigResponse {
+    ResponseHeader responseHeader = 1;
+    repeated AppGroupConfig config = 2;
+}
+
+// 启用/禁用 应用请求参数
+message SetEnableRequest {
+    int32 appId = 1;
+    bool enable = 2;
+}
+
+// 启用/禁用 应用响应参数
+message SetEnableResponse {
+    ResponseHeader responseHeader = 1;
+}
+
+// 保存应用配置请求参数
+message SaveConfigRequest {
+    AppConfig appConfig = 1;
+}
+
+// 保存应用配置响应参数
+message SaveConfigResponse {
+    ResponseHeader responseHeader = 1;
+}
+
+// 删除应用配置请求参数
+message DeleteConfigRequest {
+    int32 appId = 1;
+}
+
+// 删除应用配置响应参数
+message DeleteCOnfigResponse {
+    ResponseHeader responseHeader = 1;
+}

+ 116 - 0
apis/open-grpc-api/src/main/proto/base.proto

@@ -0,0 +1,116 @@
+syntax = "proto3";
+
+package uu.open;
+
+option java_multiple_files = true;
+option java_package = "com.usoftchina.uu.open.grpc.api";
+
+// 响应头
+message ResponseHeader {
+    // 是否成功
+    bool success = 1;
+    // 错误码
+    int32 code = 2;
+    // 错误信息
+    string message = 3;
+}
+
+// 分页信息
+message Paging {
+    // 总页数
+    int32 totalPage = 1;
+    // 总条数
+    int32 totalCount = 2;
+    // 每页条数
+    int32 pageSize = 3;
+    // 当前页
+    int32 pageNumber = 4;
+}
+
+// 视图类型
+enum ViewType {
+    // 原生
+    WIDGET = 0;
+    // 网页
+    WEB = 1;
+}
+
+// 应用组配置
+message AppGroupConfig {
+    int32 id = 1;
+    string name = 2;
+    repeated AppConfig appConfig = 3;
+}
+
+// 应用配置
+message AppConfig {
+    int32 id = 1;
+    // 应用名
+    string name = 2;
+    // 图标
+    string icon = 3;
+    // 打开视图类型
+    ViewType viewType = 4;
+    // Android
+    string androidWidget = 5;
+    // IOS
+    string iosWidget = 6;
+    // 网页
+    string webUrl = 7;
+    // 是否启用
+    bool enable = 8;
+    // 是否企业私有应用配置
+    bool private = 9;
+}
+
+// 未读消息统计
+message UnreadMessageCount {
+    // 消息编码
+    string code = 1;
+    // 消息数
+    int32 count = 2;
+}
+
+// 消息
+message MessageInfo {
+    // ID
+    int64 id = 1;
+    // 消息内容
+    string body = 2;
+    // 状态
+    Status status = 3;
+    enum Status {
+        // 未读
+        UNREAD = 0;
+        // 已读
+        READ = 1;
+    }
+}
+
+// 账户
+message AccountInfo {
+    int64 id = 1;
+    // 真实姓名(考虑是企业应用,非社交类型,不需要昵称)
+    string realname = 2;
+    // 手机号
+    string mobile = 3;
+    // 邮箱
+    string email = 4;
+    // 头像
+    string avatarUrl = 5;
+    Sex sex = 6;
+    // 性别
+    enum Sex {
+        // 女
+        FEMALE = 0;
+        // 男
+        MALE = 1;
+    }
+}
+
+// 公司
+message Company {
+    int64 id = 1;
+    // 名称
+    string name = 2;
+}

+ 79 - 0
apis/open-grpc-api/src/main/proto/message.proto

@@ -0,0 +1,79 @@
+syntax = "proto3";
+
+package uu.open;
+
+import "base.proto";
+
+option java_multiple_files = true;
+option java_package = "com.usoftchina.uu.open.grpc.api";
+
+// 消息服务
+service MessageService {
+    // 发送消息
+    rpc send (SendMessageRequest) returns (SendMessageResponse) {};
+    // 未读消息统计
+    rpc getUnreadCount (GetUnreadMessageCountRequest) returns (GetUnreadMessageCountResponse) {};
+    // 获取消息
+    rpc getMessages (GetMessagesRequest) returns (GetMessagesResponse) {};
+    // 设置为已读
+    rpc setRead (SetMessageReadRequest) returns (SetMessageReadResponse) {};
+}
+
+// 发送消息请求参数
+message SendMessageRequest {
+    // 消息配置编码
+    string code = 1;
+    // 消息内容
+    string message = 2;
+}
+
+// 发送消息响应参数
+message SendMessageResponse {
+    ResponseHeader responseHeader = 1;
+}
+
+// 未读消息统计请求参数
+message GetUnreadMessageCountRequest {
+}
+
+// 未读消息统计响应参数
+message GetUnreadMessageCountResponse {
+    ResponseHeader responseHeader = 1;
+    repeated UnreadMessageCount unread = 2;
+}
+
+// 获取消息请求参数
+message GetMessagesRequest {
+    // 每页条数
+    int32 pageSize = 1;
+    // 当前页
+    int32 pageNumber = 2;
+    // 消息状态
+    Status status = 3;
+
+    enum Status {
+        // 未读
+        UNREAD = 0;
+        // 已读
+        READ = 1;
+        // 全部
+        ALL = 2;
+    }
+}
+
+// 获取消息响应参数
+message GetMessagesResponse {
+    ResponseHeader responseHeader = 1;
+    Paging paging = 2;
+    repeated MessageInfo message = 3;
+}
+
+// 设置消息已读请求参数
+message SetMessageReadRequest {
+    int64 messageId = 1;
+}
+
+// 设置消息已读响应参数
+message SetMessageReadResponse {
+    ResponseHeader responseHeader = 1;
+}

+ 65 - 0
build.gradle

@@ -0,0 +1,65 @@
+plugins {
+    id "io.spring.dependency-management" version "1.0.7.RELEASE" apply false
+    id "org.springframework.boot" version "2.1.4.RELEASE" apply false
+    id "com.google.protobuf" version "0.8.8" apply false
+}
+
+allprojects {
+    group 'com.usoftchina.uu'
+    version '1.0.0-SNAPSHOT'
+}
+
+subprojects { Project subproject ->
+    if (subproject.name in ["apis", "services", "external", "shared", "runtime"]) {
+        return
+    }
+    apply plugin: 'java'
+    apply plugin: 'idea'
+    apply plugin: 'maven'
+    apply plugin: 'io.spring.dependency-management'
+
+    sourceCompatibility = 1.8
+    targetCompatibility = 1.8
+
+    [compileJava,compileTestJava,javadoc]*.options*.encoding = 'UTF-8'
+
+    ext {
+        springBootVersion = '2.1.4.RELEASE'
+        springCloudVersion = 'Greenwich.SR1'
+        grpcVersion = '1.20.0'
+        protocVersion = '3.7.1'
+        feignFormVersion = '3.8.0'
+        // dependencies
+        grpcSpringBoot = 'io.github.lognet:grpc-spring-boot-starter:3.2.2'
+        alibabaThreadLocal = 'com.alibaba:transmittable-thread-local:2.10.2'
+        mysqlConnector = 'mysql:mysql-connector-java:6.0.6'
+        mybatisSpringBoot = 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.0.1'
+        pageHelperSpringBoot = 'com.github.pagehelper:pagehelper-spring-boot-starter:1.2.7'
+        gson = 'com.google.code.gson:gson:2.8.5'
+    }
+
+    repositories {
+        mavenLocal()
+        mavenCentral()
+        maven { url "http://repo.spring.io/libs-milestone" }
+        maven { url "http://maven.aliyun.com/nexus/content/groups/public/" }
+        maven { url "https://oss.sonatype.org/content/repositories/snapshots"}
+    }
+
+    dependencyManagement {
+        imports {
+            mavenBom "org.springframework.boot:spring-boot-dependencies:${springBootVersion}"
+            mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
+        }
+    }
+
+    uploadArchives {
+        repositories {
+            mavenDeployer {
+                repository(url: "http://maven.ubtob.com/artifactory/libs-snapshot-local") {
+                    authentication(userName: "yingp", password: "111111")
+                }
+            }
+        }
+    }.dependsOn build
+}

+ 54 - 0
db/account-schema.sql

@@ -0,0 +1,54 @@
+create table if not exists `ac_account`
+(
+id bigint unsigned primary key not null,
+realname varchar(100) comment '姓名',
+mobile varchar(30) comment '手机号',
+email varchar(100) comment '邮箱',
+avatar_url varchar(300) comment '头像',
+sex int default 0 comment '性别'
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='个人账户';
+
+create table if not exists `ac_company`
+(
+id bigint unsigned primary key not null,
+name varchar(300) comment '名称',
+secret_key varchar(64) comment '私钥'
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='公司';
+
+create table if not exists `ac_account_company`
+(
+account_id bigint unsigned comment '账户ID',
+company_id bigint unsigned comment '公司ID'
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='公司账户绑定';
+
+create table if not exists `ac_device_info`
+(
+account_id bigint unsigned comment '账户ID',
+version varchar(20) comment '客户端发行版本,例如1.0.0',
+model varchar(30) comment '设备型号',
+os int comment '系统',
+os_version varchar(20) comment '系统版本,例如7.1',
+longitude double comment '经度',
+latitude double comment '纬度',
+location varchar(300) comment '位置',
+lang varchar(10) comment '语言',
+login_time datetime comment '登录时间',
+channel_id varchar(100) comment '消息通道ID'
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='设备信息';
+
+create table if not exists `ac_login_log`
+(
+id bigint unsigned primary key not null auto_increment,
+account_id bigint unsigned comment '账户ID',
+version varchar(20) comment '客户端发行版本,例如1.0.0',
+model varchar(30) comment '设备型号',
+os int comment '系统',
+os_version varchar(20) comment '系统版本,例如7.1',
+longitude double comment '经度',
+latitude double comment '纬度',
+location varchar(300) comment '位置',
+lang varchar(10) comment '语言',
+login_time datetime comment '登录时间',
+logon bool comment '登录是否成功',
+login_error varchar(1000) comment '登录失败错误信息'
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='设备信息';

+ 27 - 0
db/app-schema.sql

@@ -0,0 +1,27 @@
+create table if not exists `app_group`
+(
+id int unsigned primary key not null auto_increment,
+name varchar(100) comment '名称',
+order_num int comment '顺序'
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='应用组';
+
+create table if not exists `app_config`
+(
+id int unsigned primary key not null auto_increment,
+group_id int not null,
+name varchar(100) comment '名称',
+icon varchar(100) comment '图标',
+order_num int comment '顺序',
+view_type int default 0 comment '视图类型 0 - widget, 1 - web',
+android_widget varchar(100) comment 'android控件',
+ios_widget varchar(100) comment 'ios控件',
+web_url varchar(300) comment '网页',
+scope_platform int default 0 comment '专属平台的应用 0 -ALL',
+scope_company_id bigint comment '专属企业的应用'
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='应用组';
+
+create table if not exists `app_company`
+(
+app_id int not null comment 'app_config.id',
+company_id bigint not null comment 'ac_company.id'
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='企业应用绑定';

+ 20 - 0
db/home-schema.sql

@@ -0,0 +1,20 @@
+create table if not exists `home_config`
+(
+id int unsigned primary key not null auto_increment,
+order_num int comment '顺序',
+name varchar(100) comment '名称',
+icon varchar(100) comment '图标',
+view_type int default 0 comment '视图类型 0 - widget, 1 - web',
+android_widget varchar(100) comment 'android控件',
+ios_widget varchar(100) comment 'ios控件',
+web_url varchar(300) comment '网页',
+scope_platform int default 0 comment '专属平台的应用 0 - ALL',
+scope_company_id bigint comment '专属企业的应用',
+company_relate int comment '与公司相关的类型 0 - COMPANY_OR_PERSONAL'
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='个人主页配置';
+
+create table if not exists `home_company`
+(
+account_id bigint not null,
+company_id bigint not null
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='企业绑定个人主页配置';

+ 67 - 0
db/message-schema.sql

@@ -0,0 +1,67 @@
+create table if not exists `message_config`
+(
+id int unsigned primary key not null auto_increment,
+code varchar(30) comment '唯一编码',
+order_num int comment '顺序',
+name varchar(100) comment '消息名',
+icon varchar(100) comment '图标',
+view_type int default 0 comment '视图类型 0 - widget, 1 - web',
+android_widget varchar(100) comment 'android控件',
+ios_widget varchar(100) comment 'ios控件',
+web_url varchar(300) comment '网页',
+scope_platform int default 0 comment '专属平台的应用 0 - ALL',
+scope_company_id bigint comment '专属企业的应用',
+company_relate int comment '与公司相关的类型 0 - COMPANY_OR_PERSONAL'
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='消息配置';
+
+create table if not exists `message_company`
+(
+account_id bigint not null,
+company_id bigint not null
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='企业绑定消息配置';
+
+create table if not exists `message_unread`
+(
+id bigint unsigned primary key not null auto_increment,
+code varchar(30) not null comment 'message_config.code',
+body varchar(1000) comment '消息内容',
+account_id bigint unsigned not null comment 'ac_account.id',
+company_id bigint comment 'ac_company.id',
+create_time datetime comment '创建时间',
+push_time datetime comment '推送到客户端时间',
+push_error_code int comment '推送相关错误码',
+push_error_msg varchar(500) comment '推送相关错误信息'
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='未读消息';
+
+create table if not exists `message_history`
+(
+id bigint unsigned primary key not null,
+code varchar(30) not null comment 'message_config.code',
+body varchar(1000) comment '消息内容',
+account_id bigint unsigned not null comment 'ac_account.id',
+company_id bigint comment 'ac_company.id',
+create_time datetime comment '创建时间',
+push_time datetime comment '推送到客户端时间',
+push_error_code int comment '推送相关错误码',
+push_error_msg varchar(500) comment '推送相关错误信息',
+read_time datetime comment '阅读时间',
+read_platform int comment '在哪个平台/系统阅读的'
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='已读消息';
+
+drop procedure if exists `p_message_all_read`;
+DELIMITER ;;
+create procedure `p_message_all_read`
+(
+in i_account_id bigint,
+in i_platform int
+)
+begin
+  insert into message_history(id,code,body,account_id,company_id,create_time,push_time,push_error_code,
+  push_error_msg,read_time,read_platform)
+  select id,code,body,account_id,company_id,create_time,push_time,push_error_code,push_error_msg,sysdate(),
+  i_platform from message_unread where account_id=i_account_id;
+  delete from message_unread where account_id=i_account_id;
+  commit;
+end
+;;
+DELIMITER ;

+ 11 - 0
external/README.md

@@ -0,0 +1,11 @@
+## 第三方对接
+
+### 项目结构
+
+```
+├─external
+│  │
+│  ├─bdpush-feign-api-------------------------百度推送rest接口的feign封装  
+│  ├─sso-feign-api----------------------------sso.ubtob.com账户中心接口的feign封装
+│  │
+```

+ 4 - 0
external/baidu-push-feign-client/build.gradle

@@ -0,0 +1,4 @@
+dependencies {
+    compile project(':shared:feign-starter')
+    testCompile 'org.springframework.boot:spring-boot-starter-test'
+}

+ 86 - 0
external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/auth/feign/BaiduSignatureInterceptor.java

@@ -0,0 +1,86 @@
+package com.usoftchina.uu.baidu.auth.feign;
+
+import com.usoftchina.uu.baidu.config.BaiduPushProperties;
+import feign.RequestInterceptor;
+import feign.RequestTemplate;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.util.DigestUtils;
+
+import java.net.URLEncoder;
+import java.util.*;
+
+/**
+ * 百度接口添加签名信息
+ *
+ * @author yingp
+ * @date 2019/4/20
+ */
+public class BaiduSignatureInterceptor implements RequestInterceptor {
+    private final Logger logger = LoggerFactory.getLogger(BaiduSignatureInterceptor.class);
+
+    private final BaiduPushProperties baiduPushProperties;
+    private final String userAgent;
+
+    public BaiduSignatureInterceptor(BaiduPushProperties baiduPushProperties) {
+        this.baiduPushProperties = baiduPushProperties;
+        this.userAgent = String.format("BCCS_SDK/3.0 (%s; %s; %s) JAVA/%s (Baidu Push Server SDK V3.0.1)",
+                System.getProperty("os.name"),
+                System.getProperty("os.arch"),
+                System.getProperty("os.version"),
+                System.getProperty("java.version"));
+    }
+
+    @Override
+    public void apply(RequestTemplate template) {
+        template.header("User-Agent", userAgent);
+
+        long timestamp = System.currentTimeMillis()/ 1000;
+        template.query("apikey", baiduPushProperties.getAndroid().getApiKey())
+                .query("timestamp", String.valueOf(timestamp));
+
+        StringBuffer signText = new StringBuffer()
+                // method
+                .append(template.method())
+                // url base
+                .append(encodeUrl(baiduPushProperties.getBaseUrl()))
+                // url path
+                .append(encodeUrl(template.path()));
+
+        // params
+        getEncodedParams(template).stream().sorted().forEach(signText::append);
+        // secret key
+        signText.append(baiduPushProperties.getAndroid().getSecretKey());
+
+        // sign = MD5( urlencode( $http_method$url$k1=$v1$k2=$v2$k3=$v3$secret_key ));
+        String sign = DigestUtils.md5DigestAsHex(signText.toString().getBytes());
+        template.query("sign", sign);
+        logger.debug("Baidu Signature BaseStr {} \nSign {}", signText.toString(), sign);
+    }
+
+    private List<String> getEncodedParams(RequestTemplate template) {
+        List<String> params = new ArrayList<>();
+        // form params
+        if (template.requestBody().length() > 0) {
+            params.addAll(Arrays.asList(template.requestBody().asString().replace("=", "%3D").split("&")));
+        }
+        // query params
+        Map<String, Collection<String>> queries = template.queries();
+        queries.keySet().forEach(key -> {
+            Collection<String> values = queries.get(key);
+            values.forEach(value -> {
+                params.add(encodeUrl(key + "=" + value));
+            });
+        });
+        return params;
+    }
+
+    private String encodeUrl(String text) {
+        try {
+            return URLEncoder.encode(text, "UTF-8");
+        } catch (Exception e) {
+            e.printStackTrace();
+            return text;
+        }
+    }
+}

+ 58 - 0
external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/base/BaiduResult.java

@@ -0,0 +1,58 @@
+package com.usoftchina.uu.baidu.base;
+
+/**
+ * @author yingp
+ * @date 2019/4/19
+ */
+public class BaiduResult<T> {
+    private String request_id;
+    private T response_params;
+    private Integer error_code;
+    private String error_msg;
+
+    public String getRequest_id() {
+        return request_id;
+    }
+
+    public void setRequest_id(String request_id) {
+        this.request_id = request_id;
+    }
+
+    public T getResponse_params() {
+        return response_params;
+    }
+
+    public void setResponse_params(T response_params) {
+        this.response_params = response_params;
+    }
+
+    public Integer getError_code() {
+        return error_code;
+    }
+
+    public void setError_code(Integer error_code) {
+        this.error_code = error_code;
+    }
+
+    public String getError_msg() {
+        return error_msg;
+    }
+
+    public void setError_msg(String error_msg) {
+        this.error_msg = error_msg;
+    }
+
+    public boolean isSuccess() {
+        return null == error_code;
+    }
+
+    @Override
+    public String toString() {
+        return "BaiduResult{" +
+                "request_id='" + request_id + '\'' +
+                ", response_params=" + response_params +
+                ", error_code=" + error_code +
+                ", error_msg='" + error_msg + '\'' +
+                '}';
+    }
+}

+ 33 - 0
external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/config/BaiduFeignConfig.java

@@ -0,0 +1,33 @@
+package com.usoftchina.uu.baidu.config;
+
+import com.usoftchina.uu.baidu.auth.feign.BaiduSignatureInterceptor;
+import com.usoftchina.uu.baidu.exception.feign.BaiduFeignErrorDecoder;
+import com.usoftchina.uu.feign.config.BaseFeignConfig;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @author yingp
+ * @date 2019/4/17
+ */
+@Configuration
+@EnableConfigurationProperties(BaiduPushProperties.class)
+public class BaiduFeignConfig extends BaseFeignConfig {
+
+    @Autowired
+    private BaiduPushProperties baiduPushProperties;
+
+    @Bean
+    public BaiduSignatureInterceptor baiduSignatureInterceptor() {
+        return new BaiduSignatureInterceptor(baiduPushProperties);
+    }
+
+    @Bean
+    @ConditionalOnMissingBean
+    BaiduFeignErrorDecoder baiduFeignErrorDecoder() {
+        return new BaiduFeignErrorDecoder();
+    }
+}

+ 69 - 0
external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/config/BaiduPushProperties.java

@@ -0,0 +1,69 @@
+package com.usoftchina.uu.baidu.config;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+/**
+ * @author yingp
+ * @date 2019/4/19
+ */
+@ConfigurationProperties(BaiduPushProperties.PREFIX)
+public class BaiduPushProperties {
+    public static final String PREFIX = "baidu.push";
+
+    private String baseUrl;
+
+    private AndroidProperties android;
+
+    private IosProperties ios;
+
+    public String getBaseUrl() {
+        return baseUrl;
+    }
+
+    public void setBaseUrl(String baseUrl) {
+        this.baseUrl = baseUrl;
+    }
+
+    public AndroidProperties getAndroid() {
+        return android;
+    }
+
+    public void setAndroid(AndroidProperties android) {
+        this.android = android;
+    }
+
+    public IosProperties getIos() {
+        return ios;
+    }
+
+    public void setIos(IosProperties ios) {
+        this.ios = ios;
+    }
+
+    public static abstract class ApiProperties {
+        protected String apiKey;
+        protected String secretKey;
+
+        public String getApiKey() {
+            return apiKey;
+        }
+
+        public void setApiKey(String apiKey) {
+            this.apiKey = apiKey;
+        }
+
+        public String getSecretKey() {
+            return secretKey;
+        }
+
+        public void setSecretKey(String secretKey) {
+            this.secretKey = secretKey;
+        }
+    }
+
+    public static class AndroidProperties extends ApiProperties{
+    }
+
+    public static class IosProperties extends ApiProperties{
+    }
+}

+ 22 - 0
external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/exception/BaiduException.java

@@ -0,0 +1,22 @@
+package com.usoftchina.uu.baidu.exception;
+
+import com.usoftchina.uu.baidu.base.BaiduResult;
+import com.usoftchina.uu.exception.BaseCheckedException;
+
+/**
+ * @author yingp
+ * @date 2019/4/20
+ */
+public class BaiduException extends BaseCheckedException {
+    public BaiduException(int code, String message) {
+        super(code, message);
+    }
+
+    public BaiduException(int code, String message, Object... args) {
+        super(code, message, args);
+    }
+
+    public BaiduException(BaiduResult result) {
+        super(result.getError_code(), result.getError_msg());
+    }
+}

+ 42 - 0
external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/exception/BaiduExceptionCode.java

@@ -0,0 +1,42 @@
+package com.usoftchina.uu.baidu.exception;
+
+import com.usoftchina.uu.exception.BaseExceptionCode;
+
+/**
+ * @author yingp
+ * @date 2019/4/19
+ */
+public enum BaiduExceptionCode implements BaseExceptionCode {
+    Internal_Server_Error(30600, "服务内部错误"),
+    Method_Not_Allowed(30601, "请求方法不允许"),
+    Request_Params_Not_Valid(30602, "请求参数错误"),
+    Authentication_Failed(30603, "权限验证失败"),
+    Quota_Use_Up_Payment_Required(30604, "配额用尽需要续费"),
+    Data_Required_Not_Found(30605, "请求数据不存在"),
+    Request_Time_Expires_Timeout(30606, "请求时间戳验证超时"),
+    Channel_Token_Timeout(30607, "服务令牌有效期超时"),
+    Bind_Relation_Not_Found(30608, "绑定关系未找到或不存在"),
+    Bind_Number_Too_Many(30609, "绑定关系太多");
+
+    private int code;
+    private String message;
+
+    BaiduExceptionCode(int code, String message) {
+        this.code = code;
+        this.message = message;
+    }
+
+    @Override
+    public int getCode() {
+        return code;
+    }
+
+    @Override
+    public String getMessage() {
+        return message;
+    }
+
+    public BaiduException asException() {
+        return new BaiduException(code, message);
+    }
+}

+ 38 - 0
external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/exception/feign/BaiduFeignErrorDecoder.java

@@ -0,0 +1,38 @@
+package com.usoftchina.uu.baidu.exception.feign;
+
+import com.usoftchina.uu.baidu.base.BaiduResult;
+import com.usoftchina.uu.baidu.exception.BaiduException;
+import com.usoftchina.uu.baidu.exception.BaiduExceptionCode;
+import com.usoftchina.uu.util.GsonUtils;
+import feign.Response;
+import feign.codec.ErrorDecoder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.util.StreamUtils;
+
+import java.io.IOException;
+import java.nio.charset.Charset;
+
+/**
+ * @author yingp
+ * @date 2019/4/20
+ */
+public class BaiduFeignErrorDecoder implements ErrorDecoder {
+    private final static Logger logger = LoggerFactory.getLogger(BaiduFeignErrorDecoder.class);
+
+    @Override
+    public Exception decode(String methodKey, Response response) {
+        try {
+            String body = StreamUtils.copyToString(response.body().asInputStream(), Charset.defaultCharset());
+            if (null != body) {
+                BaiduResult result = GsonUtils.fromJson(body, BaiduResult.class);
+                logger.error("Baidu Request Error, Method: {}, Status: {}, Code: {}, Message: {}", methodKey, response.status(),
+                        result.getError_code(), result.getError_msg());
+                return new BaiduException(result);
+            }
+        } catch (IOException e) {
+        }
+        logger.error("Baidu Request Error, Method: {}, Status: {}, Reason: {}", methodKey, response.status(), response.reason());
+        return BaiduExceptionCode.Internal_Server_Error.asException();
+    }
+}

+ 109 - 0
external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/push/api/BaiduPushApi.java

@@ -0,0 +1,109 @@
+package com.usoftchina.uu.baidu.push.api;
+
+import com.usoftchina.uu.baidu.base.BaiduResult;
+import com.usoftchina.uu.baidu.config.BaiduFeignConfig;
+import com.usoftchina.uu.baidu.exception.BaiduException;
+import com.usoftchina.uu.baidu.push.dto.*;
+import feign.Headers;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+
+/**
+ * @author yingp
+ * @date 2019/4/19
+ */
+@FeignClient(url = "${baidu.push.base-url}", name = "baidu-push-server", configuration = BaiduFeignConfig.class)
+@RequestMapping("/rest/3.0")
+public interface BaiduPushApi {
+
+    /**
+     * 根据给定的channel_id推送消息给单个设备
+     *
+     * @param request
+     * @return
+     * @throws BaiduException
+     */
+    @PostMapping(value = "/push/single_device", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
+    BaiduResult<BaiduPushSingleResponse> pushSingleDevice(BaiduPushSingleRequest request) throws BaiduException;
+
+    /**
+     * 根据给定的channel_id推送消息给单个Android设备
+     *
+     * @param channelId
+     * @param notification
+     * @return
+     * @throws BaiduException
+     */
+    default BaiduPushSingleResponse pushSingleDevice(String channelId, Notification notification) throws BaiduException {
+        BaiduPushSingleRequest request = BaiduPushSingleRequest.newBuilder()
+                .setChannelId(channelId)
+                .setMsg(notification).build();
+        BaiduResult<BaiduPushSingleResponse> result = pushSingleDevice(request);
+        return result.getResponse_params();
+    }
+
+    /**
+     * 推送消息给批量设备(批量单播)
+     *
+     * @param request
+     * @return
+     * @throws BaiduException
+     */
+    @PostMapping(value = "/push/single_device", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
+    BaiduResult<BaiduBatchPushResponse> batchPushDevice(BaiduBatchPushRequest request) throws BaiduException;
+
+    /**
+     * 向当前app下所有设备推送一条消息
+     *
+     * @param request
+     * @return
+     * @throws BaiduException
+     */
+    @PostMapping(value = "/push/all", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
+    BaiduResult<BaiduPushAllResponse> pushAll(BaiduPushAllRequest request) throws BaiduException;
+
+    /**
+     * 推送消息或通知给指定的标签
+     *
+     * @param request
+     * @return
+     * @throws BaiduException
+     */
+    @PostMapping(value = "/push/tags", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
+    BaiduResult<BaiduPushTagResponse> pushByTag(BaiduPushTagRequest request) throws BaiduException;
+
+    /**
+     * 查询推送过程中使用过的分类主题列表
+     *
+     * @param request
+     * @return
+     * @throws BaiduException
+     */
+    @Headers("Content-Type: application/x-www-form-urlencoded")
+    @RequestMapping(value = "/topic/query_list", method = RequestMethod.GET)
+    BaiduResult<BaiduQueryTopicResponse> queryTopicList(BaiduQueryTopicRequest request) throws BaiduException;
+
+    /**
+     * 查看还未执行的定时任务,每个应用可设置的有效的定时任务有限制(目前为10个)
+     *
+     * @param request
+     * @return
+     * @throws BaiduException
+     */
+    @GetMapping(value = "/timer/query_list", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
+    BaiduResult<BaiduQueryTimerResponse> queryTimerList(BaiduQueryTimerRequest request) throws BaiduException;
+
+    /**
+     * 取消尚未执行的定时推送任务
+     *
+     * @param request
+     * @return
+     * @throws BaiduException
+     */
+    @PostMapping(value = "/timer/cancel", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
+    BaiduResult cancelTimer(BaiduCancelTimerRequest request) throws BaiduException;
+}

+ 185 - 0
external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/push/dto/AndroidNotification.java

@@ -0,0 +1,185 @@
+package com.usoftchina.uu.baidu.push.dto;
+
+/**
+ * Android通知格式
+ *
+ * @author yingp
+ * @date 2019/4/19
+ */
+public class AndroidNotification implements Notification{
+    /**
+     * 通知标题,可以为空;如果为空则设为appid对应的应用名。
+     */
+    private String title;
+    /**
+     * 通知文本内容,不能为空。
+     */
+    private String description;
+    /**
+     * android客户端自定义通知样式,如果没有设置默认为0。
+     */
+    private Integer notification_builder_id = 0;
+    /**
+     * 只有notification_builder_id为0时有效,可以设置通知的基本样式包括(响铃:0x04;振动:0x02;可清除:0x01;),
+     * 这是一个flag整形,每一位代表一种样式,如果想选择任意两种或三种通知样式,notification_basic_style的值即为
+     * 对应样式数值相加后的值。
+     */
+    private Integer notification_basic_style = 7;
+    /**
+     * 点击通知后的行为(1:打开Url; 2:自定义行为;)。 open_type =0,只回调onNotificationClicked方法,不做其他操作;
+     * open_type = 1,url != null:打开网页; open_type = 2,pkg_content = null:直接打开应用;
+     * open_type = 2,pkg_content != null:自定义动作打开应用。
+     */
+    private Integer open_type = 0;
+    /**
+     * 需要打开的Url地址,open_type为1时才有效。
+     */
+    private String url;
+    /**
+     * open_type为2时才有效,Android端SDK会把pkg_content字符串转换成Android Intent,通过该Intent打开对应app组件,
+     * 所以pkg_content字符串格式必须遵循Intent uri格式,最简单的方法可以通过Intent方法toURI()获取。
+     */
+    private String pkg_content;
+    /**
+     * 自定义内容,键值对,Json对象形式(可选);在android客户端,这些键值对将以Intent中的extra进行传递。
+     */
+    private String custom_content;
+
+    private AndroidNotification() {
+    }
+
+    private AndroidNotification(String title, String description, Integer notification_builder_id, Integer notification_basic_style, Integer open_type, String url, String pkg_content, String custom_content) {
+        this.title = title;
+        this.description = description;
+        this.notification_builder_id = notification_builder_id;
+        this.notification_basic_style = notification_basic_style;
+        this.open_type = open_type;
+        this.url = url;
+        this.pkg_content = pkg_content;
+        this.custom_content = custom_content;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public Integer getNotification_builder_id() {
+        return notification_builder_id;
+    }
+
+    public void setNotification_builder_id(Integer notification_builder_id) {
+        this.notification_builder_id = notification_builder_id;
+    }
+
+    public Integer getNotification_basic_style() {
+        return notification_basic_style;
+    }
+
+    public void setNotification_basic_style(Integer notification_basic_style) {
+        this.notification_basic_style = notification_basic_style;
+    }
+
+    public Integer getOpen_type() {
+        return open_type;
+    }
+
+    public void setOpen_type(Integer open_type) {
+        this.open_type = open_type;
+    }
+
+    public String getUrl() {
+        return url;
+    }
+
+    public void setUrl(String url) {
+        this.url = url;
+    }
+
+    public String getPkg_content() {
+        return pkg_content;
+    }
+
+    public void setPkg_content(String pkg_content) {
+        this.pkg_content = pkg_content;
+    }
+
+    public String getCustom_content() {
+        return custom_content;
+    }
+
+    public void setCustom_content(String custom_content) {
+        this.custom_content = custom_content;
+    }
+
+    public static Builder newBuilder() {
+        return new Builder();
+    }
+
+    public static class Builder {
+        private String title;
+        private String description;
+        private Integer notificationBuilderId = 0;
+        private Integer notificationBasicStyle = 7;
+        private Integer openType = 0;
+        private String url;
+        private String pkgContent;
+        private String customContent;
+
+        public Builder setTitle(String title) {
+            this.title = title;
+            return this;
+        }
+
+        public Builder setDescription(String description) {
+            this.description = description;
+            return this;
+        }
+
+        public Builder setNotificationBuilderId(Integer notificationBuilderId) {
+            this.notificationBuilderId = notificationBuilderId;
+            return this;
+        }
+
+        public Builder setNotificationBasicStyle(Integer notificationBasicStyle) {
+            this.notificationBasicStyle = notificationBasicStyle;
+            return this;
+        }
+
+        public Builder setOpenType(Integer openType) {
+            this.openType = openType;
+            return this;
+        }
+
+        public Builder setUrl(String url) {
+            this.url = url;
+            return this;
+        }
+
+        public Builder setPkgContent(String pkgContent) {
+            this.pkgContent = pkgContent;
+            return this;
+        }
+
+        public Builder setCustomContent(String customContent) {
+            this.customContent = customContent;
+            return this;
+        }
+
+        public AndroidNotification build() {
+            return new AndroidNotification(title, description, notificationBuilderId, notificationBasicStyle,
+                    openType, url, pkgContent, customContent);
+        }
+    }
+}

+ 83 - 0
external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/push/dto/BaiduBatchPushRequest.java

@@ -0,0 +1,83 @@
+package com.usoftchina.uu.baidu.push.dto;
+
+/**
+ * @author yingp
+ * @date 2019/4/19
+ */
+public class BaiduBatchPushRequest {
+    /**
+     * 对应一批设备
+     * <pre>
+     *     一组channel_id(最多为一万个)组成的json数组字符串
+     * </pre>
+     */
+    private String channel_ids;
+    /**
+     * 消息类型
+     * <pre>
+     *     取值如下:0:消息;1:通知。默认为0
+     * </pre>
+     */
+    private Integer msg_type;
+    /**
+     * 消息内容,json格式
+     *
+     * @see AndroidNotification
+     * @see IosNotification
+     */
+    private String msg;
+    /**
+     * 相对于当前时间的消息过期时间,单位为秒
+     * <pre>
+     *     0~604800(86400*7),默认为5小时(18000秒)
+     * </pre>
+     */
+    private Integer msg_expires;
+    /**
+     * 分类主题名称
+     * <pre>
+     *     字母、数字及下划线组成,长度限制为1~128
+     * </pre>
+     */
+    private String topic_id;
+
+    public String getChannel_ids() {
+        return channel_ids;
+    }
+
+    public void setChannel_ids(String channel_ids) {
+        this.channel_ids = channel_ids;
+    }
+
+    public Integer getMsg_type() {
+        return msg_type;
+    }
+
+    public void setMsg_type(Integer msg_type) {
+        this.msg_type = msg_type;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+
+    public void setMsg(String msg) {
+        this.msg = msg;
+    }
+
+    public Integer getMsg_expires() {
+        return msg_expires;
+    }
+
+    public void setMsg_expires(Integer msg_expires) {
+        this.msg_expires = msg_expires;
+    }
+
+    public String getTopic_id() {
+        return topic_id;
+    }
+
+    public void setTopic_id(String topic_id) {
+        this.topic_id = topic_id;
+    }
+}

+ 40 - 0
external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/push/dto/BaiduBatchPushResponse.java

@@ -0,0 +1,40 @@
+package com.usoftchina.uu.baidu.push.dto;
+
+/**
+ * @author yingp
+ * @date 2019/4/19
+ */
+public class BaiduBatchPushResponse {
+    /**
+     * 该条消息id
+     */
+    private String msg_id;
+    /**
+     * 消息的实际推送时间
+     */
+    private Long send_time;
+
+    public String getMsg_id() {
+        return msg_id;
+    }
+
+    public void setMsg_id(String msg_id) {
+        this.msg_id = msg_id;
+    }
+
+    public Long getSend_time() {
+        return send_time;
+    }
+
+    public void setSend_time(Long send_time) {
+        this.send_time = send_time;
+    }
+
+    @Override
+    public String toString() {
+        return "BaiduBatchPushResponse{" +
+                "msg_id='" + msg_id + '\'' +
+                ", send_time=" + send_time +
+                '}';
+    }
+}

+ 23 - 0
external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/push/dto/BaiduCancelTimerRequest.java

@@ -0,0 +1,23 @@
+package com.usoftchina.uu.baidu.push.dto;
+
+/**
+ * @author yingp
+ * @date 2019/4/19
+ */
+public class BaiduCancelTimerRequest {
+    /**
+     * 定时任务ID
+     * <pre>
+     *     只有未被执行并且距离实际执行时间一分钟以上的定时任务才能被取消
+     * </pre>
+     */
+    private String timer_id;
+
+    public String getTimer_id() {
+        return timer_id;
+    }
+
+    public void setTimer_id(String timer_id) {
+        this.timer_id = timer_id;
+    }
+}

+ 83 - 0
external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/push/dto/BaiduPushAllRequest.java

@@ -0,0 +1,83 @@
+package com.usoftchina.uu.baidu.push.dto;
+
+/**
+ * @author yingp
+ * @date 2019/4/19
+ */
+public class BaiduPushAllRequest {
+    /**
+     * 消息类型
+     * <pre>
+     *     取值如下:0:消息;1:通知。默认为0
+     * </pre>
+     */
+    private Integer msg_type;
+    /**
+     * 消息内容,json格式
+     *
+     * @see AndroidNotification
+     * @see IosNotification
+     */
+    private String msg;
+    /**
+     * 相对于当前时间的消息过期时间,单位为秒
+     * <pre>
+     *     0~604800(86400*7),默认为5小时(18000秒)
+     * </pre>
+     */
+    private Integer msg_expires;
+    /**
+     * 设置iOS应用的部署状态,仅iOS应用推送时使用
+     * <pre>
+     *     取值为:1:开发状态;2:生产状态; 若不指定,则默认设置为生产状态。
+     * </pre>
+     */
+    private Integer deploy_status;
+    /**
+     * 定时推送,用于指定的实际发送时间
+     * <pre>
+     *     指定的实际发送时间,必须在当前时间60s以外,1年以内
+     * </pre>
+     */
+    private Long send_time;
+
+    public Integer getMsg_type() {
+        return msg_type;
+    }
+
+    public void setMsg_type(Integer msg_type) {
+        this.msg_type = msg_type;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+
+    public void setMsg(String msg) {
+        this.msg = msg;
+    }
+
+    public Integer getMsg_expires() {
+        return msg_expires;
+    }
+
+    public void setMsg_expires(Integer msg_expires) {
+        this.msg_expires = msg_expires;
+    }
+
+    public Integer getDeploy_status() {
+        return deploy_status;
+    }
+
+    public void setDeploy_status(Integer deploy_status) {
+        this.deploy_status = deploy_status;
+    }
+
+    public Long getSend_time() {
+        return send_time;
+    }
+
+    public void setSend_time(Long send_time) {
+        this.send_time = send_time;
+    }
+}

+ 53 - 0
external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/push/dto/BaiduPushAllResponse.java

@@ -0,0 +1,53 @@
+package com.usoftchina.uu.baidu.push.dto;
+
+/**
+ * @author yingp
+ * @date 2019/4/19
+ */
+public class BaiduPushAllResponse {
+    /**
+     * 该条消息id
+     */
+    private String msg_id;
+    /**
+     * 定时任务ID
+     */
+    private String timer_id;
+    /**
+     * 消息的实际推送时间
+     */
+    private Long send_time;
+
+    public String getMsg_id() {
+        return msg_id;
+    }
+
+    public void setMsg_id(String msg_id) {
+        this.msg_id = msg_id;
+    }
+
+    public String getTimer_id() {
+        return timer_id;
+    }
+
+    public void setTimer_id(String timer_id) {
+        this.timer_id = timer_id;
+    }
+
+    public Long getSend_time() {
+        return send_time;
+    }
+
+    public void setSend_time(Long send_time) {
+        this.send_time = send_time;
+    }
+
+    @Override
+    public String toString() {
+        return "BaiduPushAllResponse{" +
+                "msg_id='" + msg_id + '\'' +
+                ", timer_id='" + timer_id + '\'' +
+                ", send_time=" + send_time +
+                '}';
+    }
+}

+ 137 - 0
external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/push/dto/BaiduPushSingleRequest.java

@@ -0,0 +1,137 @@
+package com.usoftchina.uu.baidu.push.dto;
+
+import com.usoftchina.uu.util.GsonUtils;
+
+/**
+ * @author yingp
+ * @date 2019/4/19
+ */
+public class BaiduPushSingleRequest {
+    /**
+     * 唯一对应一台设备
+     * <pre>
+     *     必须为端上初始化channel成功之后返回的channel_id
+     * </pre>
+     */
+    private String channel_id;
+    /**
+     * 消息类型
+     * <pre>
+     *     取值如下:0:消息;1:通知。默认为0
+     * </pre>
+     */
+    private Integer msg_type = 0;
+    /**
+     * 消息内容,json格式
+     *
+     * @see AndroidNotification
+     * @see IosNotification
+     */
+    private String msg;
+    /**
+     * 相对于当前时间的消息过期时间,单位为秒
+     * <pre>
+     *     0~604800(86400*7),默认为5小时(18000秒)
+     * </pre>
+     */
+    private Integer msg_expires = 18000;
+    /**
+     * 设置iOS应用的部署状态,仅iOS应用推送时使用
+     * <pre>
+     *     取值为:1:开发状态;2:生产状态; 若不指定,则默认设置为生产状态。
+     * </pre>
+     */
+    private Integer deploy_status = 2;
+
+    private BaiduPushSingleRequest(String channel_id, Integer msg_type, String msg, Integer msg_expires, Integer deploy_status) {
+        this.channel_id = channel_id;
+        this.msg_type = msg_type;
+        this.msg = msg;
+        this.msg_expires = msg_expires;
+        this.deploy_status = deploy_status;
+    }
+
+    public String getChannel_id() {
+        return channel_id;
+    }
+
+    public void setChannel_id(String channel_id) {
+        this.channel_id = channel_id;
+    }
+
+    public Integer getMsg_type() {
+        return msg_type;
+    }
+
+    public void setMsg_type(Integer msg_type) {
+        this.msg_type = msg_type;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+
+    public void setMsg(String msg) {
+        this.msg = msg;
+    }
+
+    public Integer getMsg_expires() {
+        return msg_expires;
+    }
+
+    public void setMsg_expires(Integer msg_expires) {
+        this.msg_expires = msg_expires;
+    }
+
+    public Integer getDeploy_status() {
+        return deploy_status;
+    }
+
+    public void setDeploy_status(Integer deploy_status) {
+        this.deploy_status = deploy_status;
+    }
+
+    public static Builder newBuilder() {
+        return new Builder();
+    }
+
+    public static class Builder {
+        private String channelId;
+        private Integer msgType = 0;
+        private String msg;
+        private Integer msgExpires = 18000;
+        private Integer deployStatus = 2;
+
+        public Builder() {
+        }
+
+        public Builder setChannelId(String channelId) {
+            this.channelId = channelId;
+            return this;
+        }
+
+        public Builder setMsgType(Integer msgType) {
+            this.msgType = msgType;
+            return this;
+        }
+
+        public Builder setMsg(Notification msg) {
+            this.msg = msg.serialize();
+            return this;
+        }
+
+        public Builder setMsgExpires(Integer msgExpires) {
+            this.msgExpires = msgExpires;
+            return this;
+        }
+
+        public Builder setDeployStatus(Integer deployStatus) {
+            this.deployStatus = deployStatus;
+            return this;
+        }
+
+        public BaiduPushSingleRequest build() {
+            return new BaiduPushSingleRequest(channelId, msgType, msg, msgExpires, deployStatus);
+        }
+    }
+}

+ 46 - 0
external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/push/dto/BaiduPushSingleResponse.java

@@ -0,0 +1,46 @@
+package com.usoftchina.uu.baidu.push.dto;
+
+import java.util.Date;
+
+/**
+ * @author yingp
+ * @date 2019/4/19
+ */
+public class BaiduPushSingleResponse {
+    /**
+     * 该条消息id
+     */
+    private String msg_id;
+    /**
+     * 消息的实际推送时间
+     */
+    private Long send_time;
+
+    public String getMsg_id() {
+        return msg_id;
+    }
+
+    public void setMsg_id(String msg_id) {
+        this.msg_id = msg_id;
+    }
+
+    public Long getSend_time() {
+        return send_time;
+    }
+
+    public void setSend_time(Long send_time) {
+        this.send_time = send_time;
+    }
+
+    public Date getSendTime() {
+        return new Date(send_time * 1000);
+    }
+
+    @Override
+    public String toString() {
+        return "BaiduPushSingleResponse{" +
+                "msg_id='" + msg_id + '\'' +
+                ", send_time=" + send_time +
+                '}';
+    }
+}

+ 107 - 0
external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/push/dto/BaiduPushTagRequest.java

@@ -0,0 +1,107 @@
+package com.usoftchina.uu.baidu.push.dto;
+
+/**
+ * @author yingp
+ * @date 2019/4/19
+ */
+public class BaiduPushTagRequest {
+    /**
+     * 推送的标签类型
+     */
+    private Integer type = 1;
+    /**
+     * 标签名
+     */
+    private String tag;
+    /**
+     * 消息类型
+     * <pre>
+     *     取值如下:0:消息;1:通知。默认为0
+     * </pre>
+     */
+    private Integer msg_type;
+    /**
+     * 消息内容,json格式
+     *
+     * @see AndroidNotification
+     * @see IosNotification
+     */
+    private String msg;
+    /**
+     * 相对于当前时间的消息过期时间,单位为秒
+     * <pre>
+     *     0~604800(86400*7),默认为5小时(18000秒)
+     * </pre>
+     */
+    private Integer msg_expires;
+    /**
+     * 设置iOS应用的部署状态,仅iOS应用推送时使用
+     * <pre>
+     *     取值为:1:开发状态;2:生产状态; 若不指定,则默认设置为生产状态。
+     * </pre>
+     */
+    private Integer deploy_status;
+    /**
+     * 定时推送,用于指定的实际发送时间
+     * <pre>
+     *     指定的实际发送时间,必须在当前时间60s以外,1年以内
+     * </pre>
+     */
+    private Long send_time;
+
+    public Integer getType() {
+        return type;
+    }
+
+    public void setType(Integer type) {
+        this.type = type;
+    }
+
+    public String getTag() {
+        return tag;
+    }
+
+    public void setTag(String tag) {
+        this.tag = tag;
+    }
+
+    public Integer getMsg_type() {
+        return msg_type;
+    }
+
+    public void setMsg_type(Integer msg_type) {
+        this.msg_type = msg_type;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+
+    public void setMsg(String msg) {
+        this.msg = msg;
+    }
+
+    public Integer getMsg_expires() {
+        return msg_expires;
+    }
+
+    public void setMsg_expires(Integer msg_expires) {
+        this.msg_expires = msg_expires;
+    }
+
+    public Integer getDeploy_status() {
+        return deploy_status;
+    }
+
+    public void setDeploy_status(Integer deploy_status) {
+        this.deploy_status = deploy_status;
+    }
+
+    public Long getSend_time() {
+        return send_time;
+    }
+
+    public void setSend_time(Long send_time) {
+        this.send_time = send_time;
+    }
+}

+ 53 - 0
external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/push/dto/BaiduPushTagResponse.java

@@ -0,0 +1,53 @@
+package com.usoftchina.uu.baidu.push.dto;
+
+/**
+ * @author yingp
+ * @date 2019/4/19
+ */
+public class BaiduPushTagResponse {
+    /**
+     * 该条消息id
+     */
+    private String msg_id;
+    /**
+     * 定时任务ID
+     */
+    private String timer_id;
+    /**
+     * 消息的实际推送时间
+     */
+    private Long send_time;
+
+    public String getMsg_id() {
+        return msg_id;
+    }
+
+    public void setMsg_id(String msg_id) {
+        this.msg_id = msg_id;
+    }
+
+    public String getTimer_id() {
+        return timer_id;
+    }
+
+    public void setTimer_id(String timer_id) {
+        this.timer_id = timer_id;
+    }
+
+    public Long getSend_time() {
+        return send_time;
+    }
+
+    public void setSend_time(Long send_time) {
+        this.send_time = send_time;
+    }
+
+    @Override
+    public String toString() {
+        return "BaiduPushTagResponse{" +
+                "msg_id='" + msg_id + '\'' +
+                ", timer_id='" + timer_id + '\'' +
+                ", send_time=" + send_time +
+                '}';
+    }
+}

+ 45 - 0
external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/push/dto/BaiduQueryTimerRequest.java

@@ -0,0 +1,45 @@
+package com.usoftchina.uu.baidu.push.dto;
+
+/**
+ * @author yingp
+ * @date 2019/4/19
+ */
+public class BaiduQueryTimerRequest {
+    /**
+     * 如果指定该参数,将仅返回该timer_id对应定时任务的相关信息
+     * <pre>
+     *     推送接口返回的timer_id唯一标识一个定时推送任务
+     * </pre>
+     */
+    private String timer_id;
+    /**
+     * 指定返回记录的起始索引位置
+     * <pre>
+     *     整数,默认为0
+     * </pre>
+     */
+    private Integer start = 0;
+    /**
+     * 返回的记录条数
+     * <pre>
+     *     整数:[1,20],默认10
+     * </pre>
+     */
+    private Integer limit = 10;
+
+    public Integer getStart() {
+        return start;
+    }
+
+    public void setStart(Integer start) {
+        this.start = start;
+    }
+
+    public Integer getLimit() {
+        return limit;
+    }
+
+    public void setLimit(Integer limit) {
+        this.limit = limit;
+    }
+}

+ 42 - 0
external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/push/dto/BaiduQueryTimerResponse.java

@@ -0,0 +1,42 @@
+package com.usoftchina.uu.baidu.push.dto;
+
+import java.util.List;
+
+/**
+ * @author yingp
+ * @date 2019/4/19
+ */
+public class BaiduQueryTimerResponse {
+    /**
+     * 所使用过的分类主题总数
+     */
+    private Integer total_num;
+    /**
+     * 定时任务的相关信息
+     */
+    private List<BaiduTimer> result;
+
+    public Integer getTotal_num() {
+        return total_num;
+    }
+
+    public void setTotal_num(Integer total_num) {
+        this.total_num = total_num;
+    }
+
+    public List<BaiduTimer> getResult() {
+        return result;
+    }
+
+    public void setResult(List<BaiduTimer> result) {
+        this.result = result;
+    }
+
+    @Override
+    public String toString() {
+        return "BaiduQueryTimerResponse{" +
+                "total_num=" + total_num +
+                ", result=" + result +
+                '}';
+    }
+}

+ 38 - 0
external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/push/dto/BaiduQueryTopicRequest.java

@@ -0,0 +1,38 @@
+package com.usoftchina.uu.baidu.push.dto;
+
+/**
+ * @author yingp
+ * @date 2019/4/19
+ */
+public class BaiduQueryTopicRequest {
+    /**
+     * 指定返回记录的起始索引位置
+     * <pre>
+     *     整数,默认为0
+     * </pre>
+     */
+    private Integer start = 0;
+    /**
+     * 返回的记录条数
+     * <pre>
+     *     整数:[1,20],默认20
+     * </pre>
+     */
+    private Integer limit = 20;
+
+    public Integer getStart() {
+        return start;
+    }
+
+    public void setStart(Integer start) {
+        this.start = start;
+    }
+
+    public Integer getLimit() {
+        return limit;
+    }
+
+    public void setLimit(Integer limit) {
+        this.limit = limit;
+    }
+}

+ 42 - 0
external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/push/dto/BaiduQueryTopicResponse.java

@@ -0,0 +1,42 @@
+package com.usoftchina.uu.baidu.push.dto;
+
+import java.util.List;
+
+/**
+ * @author yingp
+ * @date 2019/4/19
+ */
+public class BaiduQueryTopicResponse {
+    /**
+     * 所使用过的分类主题总数
+     */
+    private Integer total_num;
+    /**
+     * 分类主题的相关信息
+     */
+    private List<BaiduTopic> topics;
+
+    public Integer getTotal_num() {
+        return total_num;
+    }
+
+    public void setTotal_num(Integer total_num) {
+        this.total_num = total_num;
+    }
+
+    public List<BaiduTopic> getTopics() {
+        return topics;
+    }
+
+    public void setTopics(List<BaiduTopic> topics) {
+        this.topics = topics;
+    }
+
+    @Override
+    public String toString() {
+        return "BaiduQueryTopicResponse{" +
+                "total_num=" + total_num +
+                ", topics=" + topics +
+                '}';
+    }
+}

+ 79 - 0
external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/push/dto/BaiduTimer.java

@@ -0,0 +1,79 @@
+package com.usoftchina.uu.baidu.push.dto;
+
+/**
+ * @author yingp
+ * @date 2019/4/19
+ */
+public class BaiduTimer {
+    /**
+     * 发送定时消息时返回的timer_id
+     */
+    private String timer_id;
+    /**
+     * 发送消息的内容
+     */
+    private String msg;
+    /**
+     * 消息的实际推送时间
+     */
+    private Long send_time;
+    /**
+     * 消息类型:0:透传消息;1:通知;2:带格式的消息;3:富媒体消息;
+     */
+    private Integer msg_type;
+    /**
+     * 消息发送范围: 0:tag组播;1:广播;2:批量单播;3:标签组合;4:精准推送;5:LBS推送;6:系统保留;7:单播;
+     */
+    private Integer range_type;
+
+    public String getTimer_id() {
+        return timer_id;
+    }
+
+    public void setTimer_id(String timer_id) {
+        this.timer_id = timer_id;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+
+    public void setMsg(String msg) {
+        this.msg = msg;
+    }
+
+    public Long getSend_time() {
+        return send_time;
+    }
+
+    public void setSend_time(Long send_time) {
+        this.send_time = send_time;
+    }
+
+    public Integer getMsg_type() {
+        return msg_type;
+    }
+
+    public void setMsg_type(Integer msg_type) {
+        this.msg_type = msg_type;
+    }
+
+    public Integer getRange_type() {
+        return range_type;
+    }
+
+    public void setRange_type(Integer range_type) {
+        this.range_type = range_type;
+    }
+
+    @Override
+    public String toString() {
+        return "BaiduTimer{" +
+                "timer_id='" + timer_id + '\'' +
+                ", msg='" + msg + '\'' +
+                ", send_time=" + send_time +
+                ", msg_type=" + msg_type +
+                ", range_type=" + range_type +
+                '}';
+    }
+}

+ 79 - 0
external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/push/dto/BaiduTopic.java

@@ -0,0 +1,79 @@
+package com.usoftchina.uu.baidu.push.dto;
+
+/**
+ * @author yingp
+ * @date 2019/4/19
+ */
+public class BaiduTopic {
+    /**
+     * 总的到达数,-1代表数据未ready
+     */
+    private Long ack_cnt;
+    /**
+     * 第一次发送时间
+     */
+    private Long ctime;
+    /**
+     * 最后一次发送时间
+     */
+    private Long mtime;
+    /**
+     * 总的推送目标数
+     */
+    private Long push_cnt;
+    /**
+     * 分类主题名称
+     */
+    private String topic_id;
+
+    public Long getAck_cnt() {
+        return ack_cnt;
+    }
+
+    public void setAck_cnt(Long ack_cnt) {
+        this.ack_cnt = ack_cnt;
+    }
+
+    public Long getCtime() {
+        return ctime;
+    }
+
+    public void setCtime(Long ctime) {
+        this.ctime = ctime;
+    }
+
+    public Long getMtime() {
+        return mtime;
+    }
+
+    public void setMtime(Long mtime) {
+        this.mtime = mtime;
+    }
+
+    public Long getPush_cnt() {
+        return push_cnt;
+    }
+
+    public void setPush_cnt(Long push_cnt) {
+        this.push_cnt = push_cnt;
+    }
+
+    public String getTopic_id() {
+        return topic_id;
+    }
+
+    public void setTopic_id(String topic_id) {
+        this.topic_id = topic_id;
+    }
+
+    @Override
+    public String toString() {
+        return "BaiduTopic{" +
+                "ack_cnt=" + ack_cnt +
+                ", ctime=" + ctime +
+                ", mtime=" + mtime +
+                ", push_cnt=" + push_cnt +
+                ", topic_id='" + topic_id + '\'' +
+                '}';
+    }
+}

+ 117 - 0
external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/push/dto/IosNotification.java

@@ -0,0 +1,117 @@
+package com.usoftchina.uu.baidu.push.dto;
+
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * @author yingp
+ * @date 2019/4/19
+ */
+public class IosNotification extends LinkedHashMap<String, Object> implements Notification{
+
+    private Alert aps;
+
+    public Alert getAps() {
+        return aps;
+    }
+
+    public void setAps(Alert aps) {
+        this.aps = aps;
+    }
+
+    private IosNotification(Map<? extends String, ?> m, Alert aps) {
+        super(m);
+        this.aps = aps;
+    }
+
+    /**
+     * "key1" "value1" "key2" "value2": 用户自定义参数的字段的key值和对应的vlue值。
+     */
+
+    public static class Alert {
+        /**
+         * 其内容可以为字符串或者字典,如果是字符串,那么将会在通知中显示这条内容。
+         */
+        private String alert;
+        /**
+         * 指定通知展现时伴随的提醒音文件名。如果找不到指定的文件或者值为 default,那么默认的系统音将会被使用。
+         * 如果为空,那么将没有声音。
+         */
+        private String sound;
+        /**
+         * 其值为数字,表示当通知到达设备时,应用的角标变为多少。如果没有使用这个字段,那么应用的角标将不会改变。
+         * 设置为 0 时,会清除应用的角标。
+         */
+        private Integer badge = 0;
+
+        private Alert(String alert, String sound, Integer badge) {
+            this.alert = alert;
+            this.sound = sound;
+            this.badge = badge;
+        }
+
+        public String getAlert() {
+            return alert;
+        }
+
+        public void setAlert(String alert) {
+            this.alert = alert;
+        }
+
+        public String getSound() {
+            return sound;
+        }
+
+        public void setSound(String sound) {
+            this.sound = sound;
+        }
+
+        public Integer getBadge() {
+            return badge;
+        }
+
+        public void setBadge(Integer badge) {
+            this.badge = badge;
+        }
+    }
+
+    public static Builder newBuilder() {
+        return new Builder();
+    }
+
+    public static class Builder {
+        private String alert;
+        private String sound;
+        private Integer badge = 0;
+        private Map<String, Object> params;
+
+        private Builder() {
+            this.params = new HashMap<>();
+        }
+
+        public Builder setAlert(String alert) {
+            this.alert = alert;
+            return this;
+        }
+
+        public Builder setSound(String sound) {
+            this.sound = sound;
+            return this;
+        }
+
+        public Builder setBadge(Integer badge) {
+            this.badge = badge;
+            return this;
+        }
+
+        public Builder put(String key, String value) {
+            this.params.put(key, value);
+            return this;
+        }
+
+        public IosNotification build() {
+            return new IosNotification(params, new Alert(alert, sound, badge));
+        }
+    }
+}

+ 36 - 0
external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/push/dto/Notification.java

@@ -0,0 +1,36 @@
+package com.usoftchina.uu.baidu.push.dto;
+
+import com.usoftchina.uu.util.GsonUtils;
+
+/**
+ * @author yingp
+ * @date 2019/4/24
+ */
+public interface Notification {
+    /**
+     * 序列化
+     *
+     * @return
+     */
+    default String serialize() {
+        return GsonUtils.toJson(this);
+    }
+
+    /**
+     * android消息
+     *
+     * @return
+     */
+    static AndroidNotification.Builder android() {
+        return AndroidNotification.newBuilder();
+    }
+
+    /**
+     * ios消息
+     *
+     * @return
+     */
+    static IosNotification.Builder ios() {
+        return IosNotification.newBuilder();
+    }
+}

+ 68 - 0
external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/report/api/BaiduReportApi.java

@@ -0,0 +1,68 @@
+package com.usoftchina.uu.baidu.report.api;
+
+import com.usoftchina.uu.baidu.base.BaiduResult;
+import com.usoftchina.uu.baidu.config.BaiduFeignConfig;
+import com.usoftchina.uu.baidu.exception.BaiduException;
+import com.usoftchina.uu.baidu.report.dto.*;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+/**
+ * @author yingp
+ * @date 2019/4/19
+ */
+@FeignClient(url = "${baidu.push.base-url}", name = "baidu-report-server", configuration = BaiduFeignConfig.class)
+@RequestMapping("/rest/3.0/report")
+public interface BaiduReportApi {
+
+    /**
+     * 根据msg_id获取消息推送报告
+     *
+     * @param request
+     * @return
+     * @throws BaiduException
+     */
+    @GetMapping(value = "/query_msg_status", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
+    BaiduResult<BaiduMsgReportResponse> queryMsgStatus(BaiduMsgReportRequest request) throws BaiduException;
+
+    /**
+     * 根据timer_id获取定时消息推送记录
+     *
+     * @param request
+     * @return
+     * @throws BaiduException
+     */
+    @GetMapping(value = "/query_timer_records", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
+    BaiduResult<BaiduTimerMsgReportResponse> queryTimerRecords(BaiduTimerMsgReportRequest request) throws BaiduException;
+
+    /**
+     * 根据分类主题获取消息推送记录
+     *
+     * @param request
+     * @return
+     * @throws BaiduException
+     */
+    @GetMapping(value = "/query_topic_records", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
+    BaiduResult<BaiduTopicMsgReportResponse> queryTopicRecords(BaiduTopicMsgReportRequest request) throws BaiduException;
+
+    /**
+     * 统计APP 设备数
+     *
+     * @return
+     * @throws BaiduException
+     */
+    @GetMapping(value = "/statistic_device", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
+    BaiduStatisticDeviceResponse statisticDevice() throws BaiduException;
+
+    /**
+     * 统计当前应用下一个分类主题的消息数量
+     *
+     * @param request
+     * @return
+     * @throws BaiduException
+     */
+    @GetMapping(value = "/statistic_topic", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
+    BaiduStatisticTopicResponse statisticTopic(BaiduStatisticTopicRequest request) throws BaiduException;
+}

+ 20 - 0
external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/report/dto/BaiduMsgReportRequest.java

@@ -0,0 +1,20 @@
+package com.usoftchina.uu.baidu.report.dto;
+
+/**
+ * @author yingp
+ * @date 2019/4/19
+ */
+public class BaiduMsgReportRequest {
+    /**
+     * 推送接口返回的msg_id,支持一个由msg_id组成的json数组
+     */
+    private String msg_id;
+
+    public String getMsg_id() {
+        return msg_id;
+    }
+
+    public void setMsg_id(String msg_id) {
+        this.msg_id = msg_id;
+    }
+}

+ 41 - 0
external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/report/dto/BaiduMsgReportResponse.java

@@ -0,0 +1,41 @@
+package com.usoftchina.uu.baidu.report.dto;
+
+import java.util.List;
+
+/**
+ * 消息推送报告
+ *
+ * @author yingp
+ * @date 2019/4/19
+ */
+public class BaiduMsgReportResponse {
+    /**
+     * 结果数量
+     */
+    private Integer total_num;
+    private List<BaiduMsgStatus> result;
+
+    public Integer getTotal_num() {
+        return total_num;
+    }
+
+    public void setTotal_num(Integer total_num) {
+        this.total_num = total_num;
+    }
+
+    public List<BaiduMsgStatus> getResult() {
+        return result;
+    }
+
+    public void setResult(List<BaiduMsgStatus> result) {
+        this.result = result;
+    }
+
+    @Override
+    public String toString() {
+        return "BaiduMsgReportResponse{" +
+                "total_num=" + total_num +
+                ", result=" + result +
+                '}';
+    }
+}

+ 68 - 0
external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/report/dto/BaiduMsgStatus.java

@@ -0,0 +1,68 @@
+package com.usoftchina.uu.baidu.report.dto;
+
+/**
+ * 消息推送状态
+ *
+ * @author yingp
+ * @date 2019/4/19
+ */
+public class BaiduMsgStatus {
+    /**
+     * 该条消息ID
+     */
+    private String msg_id;
+    /**
+     * 取值如下:0:已发送;1:未发送;2:正在发送;3:失败;
+     */
+    private Integer status;
+    /**
+     * 成功到达数
+     */
+    private Integer success;
+    /**
+     * 消息的实际推送时间
+     */
+    private Long send_time;
+
+    public String getMsg_id() {
+        return msg_id;
+    }
+
+    public void setMsg_id(String msg_id) {
+        this.msg_id = msg_id;
+    }
+
+    public Integer getStatus() {
+        return status;
+    }
+
+    public void setStatus(Integer status) {
+        this.status = status;
+    }
+
+    public Integer getSuccess() {
+        return success;
+    }
+
+    public void setSuccess(Integer success) {
+        this.success = success;
+    }
+
+    public Long getSend_time() {
+        return send_time;
+    }
+
+    public void setSend_time(Long send_time) {
+        this.send_time = send_time;
+    }
+
+    @Override
+    public String toString() {
+        return "BaiduMsgStatus{" +
+                "msg_id='" + msg_id + '\'' +
+                ", status=" + status +
+                ", success=" + success +
+                ", send_time=" + send_time +
+                '}';
+    }
+}

+ 116 - 0
external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/report/dto/BaiduStatisticDeviceResponse.java

@@ -0,0 +1,116 @@
+package com.usoftchina.uu.baidu.report.dto;
+
+import java.util.Map;
+
+/**
+ * @author yingp
+ * @date 2019/4/19
+ */
+public class BaiduStatisticDeviceResponse {
+    /**
+     * 统计结果集的条数
+     */
+    private Integer total_num;
+    /**
+     * key为统计信息当天的0点0分的时间戳
+     */
+    private Map<String, Statistic> result;
+
+    public Integer getTotal_num() {
+        return total_num;
+    }
+
+    public void setTotal_num(Integer total_num) {
+        this.total_num = total_num;
+    }
+
+    public Map<String, Statistic> getResult() {
+        return result;
+    }
+
+    public void setResult(Map<String, Statistic> result) {
+        this.result = result;
+    }
+
+    @Override
+    public String toString() {
+        return "BaiduStatisticDeviceResponse{" +
+                "total_num=" + total_num +
+                ", result=" + result +
+                '}';
+    }
+
+    public class Statistic {
+        /**
+         * 当天新增用户数
+         */
+        private Integer new_term;
+        /**
+         * 当天解绑用户数
+         */
+        private Integer del_term;
+        /**
+         * 当天在线用户数
+         */
+        private Integer online_term;
+        /**
+         * 当天累计终端数
+         */
+        private Integer addup_term;
+        /**
+         * 有效channelId总数,等于addup_term - del_term
+         */
+        private Integer total_term;
+
+        public Integer getNew_term() {
+            return new_term;
+        }
+
+        public void setNew_term(Integer new_term) {
+            this.new_term = new_term;
+        }
+
+        public Integer getDel_term() {
+            return del_term;
+        }
+
+        public void setDel_term(Integer del_term) {
+            this.del_term = del_term;
+        }
+
+        public Integer getOnline_term() {
+            return online_term;
+        }
+
+        public void setOnline_term(Integer online_term) {
+            this.online_term = online_term;
+        }
+
+        public Integer getAddup_term() {
+            return addup_term;
+        }
+
+        public void setAddup_term(Integer addup_term) {
+            this.addup_term = addup_term;
+        }
+
+        public Integer getTotal_term() {
+            return total_term;
+        }
+
+        public void setTotal_term(Integer total_term) {
+            this.total_term = total_term;
+        }
+
+        @Override
+        public String toString() {
+            return "Statistic{" +
+                    "new_term=" + new_term +
+                    ", del_term=" + del_term +
+                    ", online_term=" + online_term +
+                    ", addup_term=" + addup_term +
+                    ", total_term=" + total_term +
+                    '}';
+        }
+    }
+}

+ 23 - 0
external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/report/dto/BaiduStatisticTopicRequest.java

@@ -0,0 +1,23 @@
+package com.usoftchina.uu.baidu.report.dto;
+
+/**
+ * @author yingp
+ * @date 2019/4/19
+ */
+public class BaiduStatisticTopicRequest {
+    /**
+     * 个已使用过的分类主题
+     * <pre>
+     *     字母、数字及下划线组成,长度限制为1~128
+     * </pre>
+     */
+    private String topic_id;
+
+    public String getTopic_id() {
+        return topic_id;
+    }
+
+    public void setTopic_id(String topic_id) {
+        this.topic_id = topic_id;
+    }
+}

+ 64 - 0
external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/report/dto/BaiduStatisticTopicResponse.java

@@ -0,0 +1,64 @@
+package com.usoftchina.uu.baidu.report.dto;
+
+import java.util.Map;
+
+/**
+ * @author yingp
+ * @date 2019/4/19
+ */
+public class BaiduStatisticTopicResponse {
+    /**
+     * 所发的分类主题总数
+     */
+    private Integer total_num;
+    /**
+     * key为统计信息当天的0点0分的时间戳
+     */
+    private Map<String, Statistic> result;
+
+    public Integer getTotal_num() {
+        return total_num;
+    }
+
+    public void setTotal_num(Integer total_num) {
+        this.total_num = total_num;
+    }
+
+    public Map<String, Statistic> getResult() {
+        return result;
+    }
+
+    public void setResult(Map<String, Statistic> result) {
+        this.result = result;
+    }
+
+    @Override
+    public String toString() {
+        return "BaiduStatisticTopicResponse{" +
+                "total_num=" + total_num +
+                ", result=" + result +
+                '}';
+    }
+
+    public class Statistic {
+        /**
+         * 当天消息到达数
+         */
+        private Integer ack;
+
+        public Integer getAck() {
+            return ack;
+        }
+
+        public void setAck(Integer ack) {
+            this.ack = ack;
+        }
+
+        @Override
+        public String toString() {
+            return "Statistic{" +
+                    "ack=" + ack +
+                    '}';
+        }
+    }
+}

+ 83 - 0
external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/report/dto/BaiduTimerMsgReportRequest.java

@@ -0,0 +1,83 @@
+package com.usoftchina.uu.baidu.report.dto;
+
+/**
+ * @author yingp
+ * @date 2019/4/19
+ */
+public class BaiduTimerMsgReportRequest {
+    /**
+     * 定时任务ID
+     * <pre>
+     *     推送接口返回的timer_id
+     * </pre>
+     */
+    private String timer_id;
+    /**
+     * 指定返回记录的起始索引位置
+     * <pre>
+     *     整数,默认为0
+     * </pre>
+     */
+    private Integer start = 0;
+    /**
+     * 返回的记录条数
+     * <pre>
+     *     整数:[1,100],默认100
+     * </pre>
+     */
+    private Integer limit = 100;
+    /**
+     * unix时间戳
+     * <pre>
+     *     指定查询起始时间范围,以服务端实际推送时间为准;默认为七天前的0点时间
+     * </pre>
+     */
+    private Integer range_start;
+    /**
+     * unix时间戳
+     * <pre>
+     *     指定查询截止时间范围,以服务端实际推送时间为准;默认时间为当前时间
+     * </pre>
+     */
+    private Integer range_end;
+
+    public String getTimer_id() {
+        return timer_id;
+    }
+
+    public void setTimer_id(String timer_id) {
+        this.timer_id = timer_id;
+    }
+
+    public Integer getStart() {
+        return start;
+    }
+
+    public void setStart(Integer start) {
+        this.start = start;
+    }
+
+    public Integer getLimit() {
+        return limit;
+    }
+
+    public void setLimit(Integer limit) {
+        this.limit = limit;
+    }
+
+    public Integer getRange_start() {
+        return range_start;
+    }
+
+    public void setRange_start(Integer range_start) {
+        this.range_start = range_start;
+    }
+
+    public Integer getRange_end() {
+        return range_end;
+    }
+
+    public void setRange_end(Integer range_end) {
+        this.range_end = range_end;
+    }
+}

+ 39 - 0
external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/report/dto/BaiduTimerMsgReportResponse.java

@@ -0,0 +1,39 @@
+package com.usoftchina.uu.baidu.report.dto;
+
+import java.util.List;
+
+/**
+ * @author yingp
+ * @date 2019/4/19
+ */
+public class BaiduTimerMsgReportResponse {
+    /**
+     * 定时任务ID
+     */
+    private String timer_id;
+    private List<BaiduTimerMsgStatus> result;
+
+    public String getTimer_id() {
+        return timer_id;
+    }
+
+    public void setTimer_id(String timer_id) {
+        this.timer_id = timer_id;
+    }
+
+    public List<BaiduTimerMsgStatus> getResult() {
+        return result;
+    }
+
+    public void setResult(List<BaiduTimerMsgStatus> result) {
+        this.result = result;
+    }
+
+    @Override
+    public String toString() {
+        return "BaiduTimerMsgReportResponse{" +
+                "timer_id='" + timer_id + '\'' +
+                ", result=" + result +
+                '}';
+    }
+}

+ 53 - 0
external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/report/dto/BaiduTimerMsgStatus.java

@@ -0,0 +1,53 @@
+package com.usoftchina.uu.baidu.report.dto;
+
+/**
+ * @author yingp
+ * @date 2019/4/19
+ */
+public class BaiduTimerMsgStatus {
+    /**
+     * 该条消息ID
+     */
+    private String msg_id;
+    /**
+     * 取值如下:0:已发送;1:未发送;2:正在发送;3:失败;
+     */
+    private Integer status;
+    /**
+     * 消息的实际推送时间
+     */
+    private Long send_time;
+
+    public String getMsg_id() {
+        return msg_id;
+    }
+
+    public void setMsg_id(String msg_id) {
+        this.msg_id = msg_id;
+    }
+
+    public Integer getStatus() {
+        return status;
+    }
+
+    public void setStatus(Integer status) {
+        this.status = status;
+    }
+
+    public Long getSend_time() {
+        return send_time;
+    }
+
+    public void setSend_time(Long send_time) {
+        this.send_time = send_time;
+    }
+
+    @Override
+    public String toString() {
+        return "BaiduTimerMsgStatus{" +
+                "msg_id='" + msg_id + '\'' +
+                ", status=" + status +
+                ", send_time=" + send_time +
+                '}';
+    }
+}

+ 83 - 0
external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/report/dto/BaiduTopicMsgReportRequest.java

@@ -0,0 +1,83 @@
+package com.usoftchina.uu.baidu.report.dto;
+
+/**
+ * @author yingp
+ * @date 2019/4/19
+ */
+public class BaiduTopicMsgReportRequest {
+    /**
+     * 分类主题名称
+     * <pre>
+     *     字母、数字及下划线组成,长度限制为1~128
+     * </pre>
+     */
+    private String topic_id;
+    /**
+     * 返回记录的索引位置
+     * <pre>
+     *     整数,默认为0
+     * </pre>
+     */
+    private Integer start = 0;
+    /**
+     * 返回的记录条数
+     * <pre>
+     *     整数:[1,100],默认100
+     * </pre>
+     */
+    private Integer limit = 100;
+    /**
+     * unix时间戳
+     * <pre>
+     *     指定查询起始时间范围,以服务端实际推送时间为准;默认为七天前的0点时间
+     * </pre>
+     */
+    private Integer range_start;
+    /**
+     * unix时间戳
+     * <pre>
+     *     指定查询截止时间范围,以服务端实际推送时间为准;默认时间为当前时间
+     * </pre>
+     */
+    private Integer range_end;
+
+    public String getTopic_id() {
+        return topic_id;
+    }
+
+    public void setTopic_id(String topic_id) {
+        this.topic_id = topic_id;
+    }
+
+    public Integer getStart() {
+        return start;
+    }
+
+    public void setStart(Integer start) {
+        this.start = start;
+    }
+
+    public Integer getLimit() {
+        return limit;
+    }
+
+    public void setLimit(Integer limit) {
+        this.limit = limit;
+    }
+
+    public Integer getRange_start() {
+        return range_start;
+    }
+
+    public void setRange_start(Integer range_start) {
+        this.range_start = range_start;
+    }
+
+    public Integer getRange_end() {
+        return range_end;
+    }
+
+    public void setRange_end(Integer range_end) {
+        this.range_end = range_end;
+    }
+}

+ 39 - 0
external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/report/dto/BaiduTopicMsgReportResponse.java

@@ -0,0 +1,39 @@
+package com.usoftchina.uu.baidu.report.dto;
+
+import java.util.List;
+
+/**
+ * @author yingp
+ * @date 2019/4/19
+ */
+public class BaiduTopicMsgReportResponse {
+    /**
+     * 消息发送时指定的分类主题
+     */
+    private String topic_id;
+    private List<BaiduTopicMsgStatus> result;
+
+    public String getTopic_id() {
+        return topic_id;
+    }
+
+    public void setTopic_id(String topic_id) {
+        this.topic_id = topic_id;
+    }
+
+    public List<BaiduTopicMsgStatus> getResult() {
+        return result;
+    }
+
+    public void setResult(List<BaiduTopicMsgStatus> result) {
+        this.result = result;
+    }
+
+    @Override
+    public String toString() {
+        return "BaiduTopicMsgReportResponse{" +
+                "topic_id='" + topic_id + '\'' +
+                ", result=" + result +
+                '}';
+    }
+}

+ 53 - 0
external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/report/dto/BaiduTopicMsgStatus.java

@@ -0,0 +1,53 @@
+package com.usoftchina.uu.baidu.report.dto;
+
+/**
+ * @author yingp
+ * @date 2019/4/19
+ */
+public class BaiduTopicMsgStatus {
+    /**
+     * 该条消息ID
+     */
+    private String msg_id;
+    /**
+     * 取值如下:0:已发送;1:未发送;2:正在发送;3:失败;
+     */
+    private Integer status;
+    /**
+     * 消息的实际推送时间
+     */
+    private Long send_time;
+
+    public String getMsg_id() {
+        return msg_id;
+    }
+
+    public void setMsg_id(String msg_id) {
+        this.msg_id = msg_id;
+    }
+
+    public Integer getStatus() {
+        return status;
+    }
+
+    public void setStatus(Integer status) {
+        this.status = status;
+    }
+
+    public Long getSend_time() {
+        return send_time;
+    }
+
+    public void setSend_time(Long send_time) {
+        this.send_time = send_time;
+    }
+
+    @Override
+    public String toString() {
+        return "BaiduTopicMsgStatus{" +
+                "msg_id='" + msg_id + '\'' +
+                ", status=" + status +
+                ", send_time=" + send_time +
+                '}';
+    }
+}

+ 79 - 0
external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/tag/api/BaiduTagApi.java

@@ -0,0 +1,79 @@
+package com.usoftchina.uu.baidu.tag.api;
+
+import com.usoftchina.uu.baidu.config.BaiduFeignConfig;
+import com.usoftchina.uu.baidu.exception.BaiduException;
+import com.usoftchina.uu.baidu.tag.dto.*;
+import com.usoftchina.uu.baidu.base.BaiduResult;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+/**
+ * @author yingp
+ * @date 2019/4/19
+ */
+@FeignClient(url = "${baidu.push.base-url}", name = "baidu-tag-server", configuration = BaiduFeignConfig.class)
+@RequestMapping("/rest/3.0")
+public interface BaiduTagApi {
+    /**
+     * 查询应用的tag
+     *
+     * @param request
+     * @return
+     * @throws BaiduException
+     */
+    @GetMapping(value = "/app/query_tags", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
+    BaiduResult<BaiduQueryTagsResponse> queryTags(BaiduQueryTagsRequest request) throws BaiduException;
+
+    /**
+     * 创建一个空的标签组
+     *
+     * @param request
+     * @return
+     * @throws BaiduException
+     */
+    @PostMapping(value = "/app/create_tag", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
+    BaiduResult<BaiduCreateTagResponse> createTag(BaiduCreateTagRequest request) throws BaiduException;
+
+    /**
+     * 删除一个已存在的tag
+     *
+     * @param request
+     * @return
+     * @throws BaiduException
+     */
+    @PostMapping(value = "/app/del_tag", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
+    BaiduResult<BaiduDelTagResponse> delTag(BaiduDelTagRequest request) throws BaiduException;
+
+    /**
+     * 向tag中批量添加设备
+     *
+     * @param request
+     * @return
+     * @throws BaiduException
+     */
+    @PostMapping(value = "/tag/add_devices", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
+    BaiduResult<BaiduAddDevicesToTagResponse> addDevicesToTag(BaiduAddDevicesToTagRequest request) throws BaiduException;
+
+    /**
+     * 从tag中批量解绑设备
+     *
+     * @param request
+     * @return
+     * @throws BaiduException
+     */
+    @PostMapping(value = "/tag/del_devices", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
+    BaiduResult<BaiduDelDevicesFromTagResponse> delDevicesFromTag(BaiduDelDevicesFromTagRequest request) throws BaiduException;
+
+    /**
+     * 查询某个tag关联的设备数量
+     *
+     * @param request
+     * @return
+     * @throws BaiduException
+     */
+    @GetMapping(value = "/tag/device_num", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
+    BaiduResult<BaiduGetDeviceNumResponse> getDeviceNumByTag(BaiduGetDeviceNumRequest request) throws BaiduException;
+}

+ 38 - 0
external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/tag/dto/BaiduAddDevicesToTagRequest.java

@@ -0,0 +1,38 @@
+package com.usoftchina.uu.baidu.tag.dto;
+
+/**
+ * @author yingp
+ * @date 2019/4/19
+ */
+public class BaiduAddDevicesToTagRequest {
+    /**
+     * 标签名称
+     * <pre>
+     *     1~128字节,但不能为‘default’
+     * </pre>
+     */
+    private String tag;
+    /**
+     * 对应一批设备
+     * <pre>
+     *     一组channel_id(最少1个,最多为10个)组成的json数组字符串
+     * </pre>
+     */
+    private String channel_ids;
+
+    public String getTag() {
+        return tag;
+    }
+
+    public void setTag(String tag) {
+        this.tag = tag;
+    }
+
+    public String getChannel_ids() {
+        return channel_ids;
+    }
+
+    public void setChannel_ids(String channel_ids) {
+        this.channel_ids = channel_ids;
+    }
+}

+ 65 - 0
external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/tag/dto/BaiduAddDevicesToTagResponse.java

@@ -0,0 +1,65 @@
+package com.usoftchina.uu.baidu.tag.dto;
+
+import java.util.List;
+
+/**
+ * @author yingp
+ * @date 2019/4/19
+ */
+public class BaiduAddDevicesToTagResponse {
+
+    /**
+     * 每个元素表示对应的一个channel_id是否添加成功
+     */
+    private List<AddDeviceResult> devices;
+
+    public List<AddDeviceResult> getDevices() {
+        return devices;
+    }
+
+    public void setDevices(List<AddDeviceResult> devices) {
+        this.devices = devices;
+    }
+
+    @Override
+    public String toString() {
+        return "BaiduAddDevicesToTagResponse{" +
+                "devices=" + devices +
+                '}';
+    }
+
+    public class AddDeviceResult {
+        /**
+         * 设备ID
+         */
+        private String channel_id;
+        /**
+         * 状态 0:添加成功; 1:添加失败
+         */
+        private Integer result;
+
+        public String getChannel_id() {
+            return channel_id;
+        }
+
+        public void setChannel_id(String channel_id) {
+            this.channel_id = channel_id;
+        }
+
+        public Integer getResult() {
+            return result;
+        }
+
+        public void setResult(Integer result) {
+            this.result = result;
+        }
+
+        @Override
+        public String toString() {
+            return "AddDeviceResult{" +
+                    "channel_id='" + channel_id + '\'' +
+                    ", result=" + result +
+                    '}';
+        }
+    }
+}

+ 23 - 0
external/baidu-push-feign-client/src/main/java/com/usoftchina/uu/baidu/tag/dto/BaiduCreateTagRequest.java

@@ -0,0 +1,23 @@
+package com.usoftchina.uu.baidu.tag.dto;
+
+/**
+ * @author yingp
+ * @date 2019/4/19
+ */
+public class BaiduCreateTagRequest {
+    /**
+     * 标签名称
+     * <pre>
+     *     1~128字节,但不能为‘default’
+     * </pre>
+     */
+    private String tag;
+
+    public String getTag() {
+        return tag;
+    }
+
+    public void setTag(String tag) {
+        this.tag = tag;
+    }
+}

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