Ver código fonte

艾为版本

pruple_boy 3 meses atrás
pai
commit
a667d28cdb

BIN
mjava-fengkaili/src/main/resources/templates/Template_month.xlsx


+ 1 - 1
mjava-gewu/src/main/java/com/malk/gewu/service/impl/GWImplService.java

@@ -39,7 +39,7 @@ public class GWImplService implements GWService {
     private YDClient ydClient;
 
     /**
-     * 同步花名册信息
+     * 同步花名册信息 ppExt:: 格屋临时添加, 后续上线限流重试功能
      */
     @Override
     public void syncRoster() {

+ 22 - 0
mjava-mcli/src/main/java/com/malk/mcli/controller/DDController.java

@@ -0,0 +1,22 @@
+package com.malk.mcli.controller;
+
+import com.malk.controller.DDCallbackController;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 钉钉事件回调 3_1
+ * -
+ * [子项目直接继承即可有调用, 无需实现]
+ * -
+ * 注解 @RequestMapping 路径不能重复 [主子项目属同一个项目];
+ * 获取项目回调请求地址, https://mc.cloudpure.cn/frp/xxx/dd/callback [调试代理: frp + nginx]
+ */
+@Slf4j
+@RestController
+@RequestMapping("/dd")
+public class DDController extends DDCallbackController {
+
+
+}

+ 72 - 0
mjava-mcli/src/main/java/com/malk/mcli/controller/LYControl.java

@@ -0,0 +1,72 @@
+package com.malk.mcli.controller;
+
+import com.malk.server.common.McR;
+import com.malk.service.aliwork.YDClient;
+import com.malk.service.dingtalk.DDClient;
+import com.malk.service.dingtalk.DDClient_Contacts;
+import com.malk.service.dingtalk.DDClient_Workflow;
+import com.malk.utils.UtilDateTime;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Arrays;
+import java.util.Date;
+
+/**
+ * 错误抛出与拦截详见CatchException
+ */
+@Slf4j
+@RestController
+@RequestMapping("/ly")
+public class LYControl {
+
+    @Autowired
+    private YDClient ydClient;
+
+    @Autowired
+    private DDClient ddClient;
+
+    @Autowired
+    private DDClient_Contacts ddClient_contacts;
+
+    @Autowired
+    private DDClient_Workflow ddClient_workflow;
+
+
+    /**
+     * 0723
+     * 后端授权登录:
+     * 1 获取授权authCode,非jsapi授权码,不适用:
+     * api:https://open.dingtalk.com/document/orgapp/obtain-identity-credentials
+     * 2.通过回调到url下是授权码,获取用户token
+     * api:https://open.dingtalk.com/document/orgapp/obtain-user-token
+     * 3.基于用户token,调用钉钉新版本个人待办,支持任务完成,接口会返回taskId
+     * api:https://open.dingtalk.com/document/isvapp/api-createpersonaltodotask
+     * 
效果:脱离钉钉容器,实现用户信息获取进行单点登录;jsapi未容器内用户无感知授权
+     * 问题:查询不到创建的个人待办的进展
+     * <p>
+     * 3个待办
+     * - 旧版本,不支持完成任务
+     * - 新版本,支持完成任务,但查询不到进展
+     * - TB自由任务,创建后需要预期才会到待办里面显示
+     */
+    @GetMapping("todo")
+    McR todo(@RequestParam String code) {
+
+        // code: https://login.dingtalk.com/oauth2/auth?redirect_uri=https%3A%2F%2Fmc.cloudpure.cn%2F&response_type=code&client_id=dinghbynhnd2dbgypmsa&scope=095358016629044412 ding321c72787fffc78b35c2f4657eb6378f&prompt=consent
+        String userToken = ddClient.getUserAccessToken(false, code);
+        ddClient_workflow.createPersonalTodo(ddClient.getAccessToken(), userToken, UtilDateTime.formatDateTime(new Date()), Arrays.asList("095358016629044412"), null);
+
+        return McR.success();
+    }
+
+    @GetMapping("test")
+    McR test() {
+
+        return McR.success();
+    }
+}

+ 12 - 14
mjava-mcli/src/main/resources/application-dev.yml

@@ -2,7 +2,7 @@
 server:
   port: 9001
   servlet:
-    context-path: /api/mcli
+    context-path: /api/m
 
 # condition
 spel:
@@ -16,18 +16,15 @@ spring:
       connection-init-sql: SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci           # SqlServer, Oracle 无需设置类型
     driver-class-name: com.mysql.cj.jdbc.Driver
     username: root
-    password: cp-root@2022++
-    url: jdbc:mysql://47.97.181.40:3306/mjava?serverTimezone=Asia/Shanghai&useUnicode=yes&characterEncoding=UTF-8&useSSL=true
+    password: mu123
+    url: jdbc:mysql://127.0.0.1:3306/mjava?serverTimezone=Asia/Shanghai&useUnicode=yes&characterEncoding=UTF-8&useSSL=true
+  jpa:
+    database: MYSQL
+    database-platform: org.hibernate.dialect.MySQL57Dialect
   # MongoDB配置
   data:
     mongodb:
       uri: mongodb://tbread:Teambition999@192.168.31.201:27017/teambition   # 固定格式 [连接成功后, 需要为 teambition 库添加 admin 权限才可查询]
-  jpa:
-    hibernate:
-      ddl-auto: none      # JPA对表没有任何操作
-    show-sql: true
-    database: MYSQL
-    database-platform: org.hibernate.dialect.MySQLDialect
 
 # filepath
 file:
@@ -43,12 +40,13 @@ logging:
 
 # dingtalk
 dingtalk:
-  agentId: 2704247534
-  appKey: dingqmijjypfepl0tsuq
-  appSecret: dixOqjK4Zw8PajvrtY1mbKxs4DIJJJmq6WvqdSDTCStBWAPyTeobgQFxZ1VhH-Z3
+  agentId: 2691784047
+  appKey: dinghbynhnd2dbgypmsa
+  appSecret: Kl5Xw8x0TlEIlvcJuUkYZD18UTTShJmfdKrAIpY8oX-Q_tazyUKA28nQh7dG5-mq
   corpId: ding321c72787fffc78b35c2f4657eb6378f
-  aesKey:
-  token:
+  aesKey: hUKD4QaLkGTvh86GyOHCmWZ4I1YvAlaUvKkGufXFdaD
+  token: TE0bPgJ1v9Fc3Svu8cfMKcoBd6q5TkljPHg
+  operator: "095358016629044412"   # OA管理员账号
 
 # aliwork
 aliwork:

+ 5 - 9
mjava-mcli/src/main/resources/application-prod.yml

@@ -28,14 +28,10 @@ spring:
 
 # dingtalk
 dingtalk:
-  agentId: 2533464721
-  appKey: dingromjxexd1esgvwwg
-  appSecret: AcStrL5bdw69gqeUfTQiFoBsgqisL2g-egzaKyID9Q7d85f_z9EkuTSS9Vse6zDb
-  corpId: ding5e83ad92d917b47535c2f4657eb6378f
+  agentId: 2691784047
+  appKey: dinghbynhnd2dbgypmsa
+  appSecret: Kl5Xw8x0TlEIlvcJuUkYZD18UTTShJmfdKrAIpY8oX-Q_tazyUKA28nQh7dG5-mq
+  corpId: ding321c72787fffc78b35c2f4657eb6378f
   aesKey: NgBOhTTp38RmPYs3gz7xBRHGNhwLHAv3tZntZ6He54F
   token: yLQuiiYIBvrzN3tmOduDn
-
-# aliwork
-aliwork:
-  appType: APP_IW1FN8PPGGYQBWVMXS69
-  systemToken: UT866MB1WGX8VU029U93IA9DIKEG2GE9UU7FLI5
+  operator: "095358016629044412"   # OA管理员账号

+ 8 - 0
mjava/src/main/java/com/malk/server/dingtalk/DDR_New.java

@@ -27,6 +27,14 @@ public class DDR_New<T> extends VenR {
 
     private T result;
 
+    /**
+     * 用户 token 授权
+     */
+    private String accessToken;
+    private String refreshToken; // 生成的refresh_token。可以使用此刷新token,定期的获取用户的accessToken: 过期时间 30 天
+    private long expiresIn;
+    private String corpId;
+
     /**
      * 无权限对应CODE
      */

+ 2 - 0
mjava/src/main/java/com/malk/service/dingtalk/DDClient.java

@@ -11,6 +11,8 @@ public interface DDClient {
 
     String getAccessToken(String appKey, String appSecret);
 
+    String getUserAccessToken(boolean isRefresh, String code_refreshToken);
+    
     /**
      * token授权参数: 旧版本
      */

+ 9 - 1
mjava/src/main/java/com/malk/service/dingtalk/DDClient_Workflow.java

@@ -73,7 +73,7 @@ public interface DDClient_Workflow {
     List<String> getInstanceIds_all(String access_token, String processCode, long startTime, long endTime, Map extInfo);
 
     /**
-     * 创建钉钉待办任务新版SDK
+     * 创建钉钉待办任务
      *
      * @param createUserId       包含 unionId 与 operatorId 参数, 通过 userId 换取对应的 unionId 值
      * @param subject            待办标题,最大长度1024
@@ -86,5 +86,13 @@ public interface DDClient_Workflow {
      * @param priority           优先级,取值:10:较低, 20:普通, 30:紧急,40:非常紧急
      * @param notifyConfigs      待办通知配置: dingNotify DING通知配置,目前仅支持取值为1,表示应用内DING
      */
+    @Deprecated
     DDR_New createTBTask(String access_token, String createUserId, String subject, String description, long dueTime, List<String> executorIds, List<String> participantIds, Map detailUrl, boolean isOnlyShowExecutor, int priority, Map notifyConfigs);
+
+    /**
+     * 创建钉钉个人待办任务
+     *
+     * @apiNote https://open.dingtalk.com/document/isvapp/api-createpersonaltodotask
+     */
+    DDR_New createPersonalTodo(String access_token, String user_token, String subject, List<String> executorIds, Map extInfo);
 }

+ 28 - 0
mjava/src/main/java/com/malk/service/dingtalk/impl/DDImplClient.java

@@ -2,6 +2,7 @@ package com.malk.service.dingtalk.impl;
 
 import com.malk.server.dingtalk.DDConf;
 import com.malk.server.dingtalk.DDR;
+import com.malk.server.dingtalk.DDR_New;
 import com.malk.service.dingtalk.DDClient;
 import com.malk.utils.UtilHttp;
 import com.malk.utils.UtilMap;
@@ -43,6 +44,7 @@ public class DDImplClient implements DDClient {
         return accessToken;
     }
 
+
     @Override
     public String getAccessToken(String appKey, String appSecret) {
         Map param = UtilMap.map("appkey, appsecret", appKey, appSecret);
@@ -51,6 +53,32 @@ public class DDImplClient implements DDClient {
         return r.getAccessToken();
     }
 
+    /**
+     * 获取用户访问授权, ppExt: 生成的refresh_token。可以使用此刷新token,定期的获取用户的accessToken: 过期时间 30 天
+     *
+     * @apiNote https://open.dingtalk.com/document/orgapp/obtain-user-token
+     */
+    @Synchronized
+    @Override
+    public String getUserAccessToken(boolean isRefresh, String code_refreshToken) {
+        String accessToken = UtilToken.get("invalid-user-token-dingtalk");
+        if (StringUtils.isNotBlank(accessToken)) return accessToken;
+        Map boyd = UtilMap.map("clientId, clientSecret", ddConf.getAppKey(), ddConf.getAppSecret());
+        if (isRefresh) {
+            boyd.put("grantType", "refresh_token");
+            boyd.put("refreshToken", code_refreshToken);
+        } else {
+            boyd.put("grantType", "authorization_code");
+            boyd.put("code", code_refreshToken);
+        }
+        DDR_New r = (DDR_New) UtilHttp.doPost("https://api.dingtalk.com/v1.0/oauth2/userAccessToken", null, boyd, DDR_New.class);
+        log.info("用户token, {}", r.getAccessToken());
+        accessToken = r.getAccessToken();
+        // token失效自动重置: DD重新调用会重置过期时间
+        UtilToken.put("invalid-user-token-dingtalk", accessToken, r.getExpiresIn() * 1000L);
+        return accessToken;
+    }
+
     /**
      * token授权参数: 旧版本
      */

+ 4 - 0
mjava/src/main/java/com/malk/service/dingtalk/impl/DDImplClient_Contacts.java

@@ -8,6 +8,7 @@ import com.malk.service.dingtalk.DDClient_Contacts;
 import com.malk.utils.UtilDateTime;
 import com.malk.utils.UtilList;
 import com.malk.utils.UtilMap;
+import lombok.SneakyThrows;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.stereotype.Service;
@@ -27,10 +28,13 @@ public class DDImplClient_Contacts implements DDClient_Contacts {
      *
      * @apiNote https://open.dingtalk.com/document/orgapp/obtain-a-sub-department-id-list-v2
      */
+    @SneakyThrows
     @Override
     public List<Long> listSubDepartmentId(String access_token, long dept_id) {
         Map param = UtilMap.map("access_token", access_token);
         Map body = UtilMap.map("dept_id", dept_id);
+        // ppExt:: 格屋临时添加, 后续上线限流重试功能
+//        Thread.sleep(50);
         Map rsp = (Map) DDR.doPost("https://oapi.dingtalk.com/topapi/v2/department/listsubid", null, param, body).getResult();
         List<Number> list = (List<Number>) rsp.get("dept_id_list");
         // ppExt: 不要直接使用 Number 作为类型, 不同基本类型比较值时会有偏差 [可以作为父类接受数据, 避免直接强制类型转换错误, 再进行基本类型处理]

+ 25 - 1
mjava/src/main/java/com/malk/service/dingtalk/impl/DDImplClient_Workflow.java

@@ -18,6 +18,7 @@ import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.stream.Collectors;
 
 /**
  * OA审批
@@ -160,7 +161,7 @@ public class DDImplClient_Workflow implements DDClient_Workflow {
     private DDClient_Contacts ddClient_contacts;
 
     /**
-     * 创建钉钉待办任务新版SDK
+     * 创建钉钉待办任务
      *
      * @apiNote https://open.dingtalk.com/document/isvapp/add-dingtalk-to-do-task
      */
@@ -195,4 +196,27 @@ public class DDImplClient_Workflow implements DDClient_Workflow {
         if (ObjectUtil.isNotNull(detailUrl)) body.put("notifyConfigs", notifyConfigs);
         return DDR_New.doPost("https://api.dingtalk.com/v1.0/todo/users/" + unionId + "/tasks", DDConf.initTokenHeader(access_token), param, body);
     }
+
+    /**
+     * 创建钉钉个人待办任务
+     **/
+    @Override
+    public DDR_New createPersonalTodo(String access_token, String user_token, String subject, List<String> executorIds, Map extInfo) {
+
+        // 转换 unionid
+        executorIds = executorIds.stream()
+                .map(userId -> UtilMap.getString(ddClient_contacts.getUserInfoById(access_token, userId), "unionid"))
+                .collect(Collectors.toList());
+        if (ObjectUtil.isNotNull(extInfo) && extInfo.containsKey("participantIds")) {
+            List<String> participantIds = (List<String>) extInfo.get("participantIds");
+            participantIds = participantIds.stream()
+                    .map(userId -> UtilMap.getString(ddClient_contacts.getUserInfoById(access_token, userId), "unionid"))
+                    .collect(Collectors.toList());
+            extInfo.put("participantIds", participantIds);
+        }
+        // 创建钉钉待办, 不带 detailurl 地址
+        Map body = UtilMap.map("subject, executorIds", subject, executorIds);
+        UtilMap.putAll(body, extInfo);
+        return DDR_New.doPost("https://api.dingtalk.com/v1.0/todo/users/me/personalTasks", DDConf.initTokenHeader(user_token), null, body);
+    }
 }