Browse Source

帕科\格屋\丰凯利

pruple_boy 2 years ago
parent
commit
5fc63e5982
24 changed files with 669 additions and 91 deletions
  1. 46 1
      mjava-fengkaili/src/main/java/com/malk/fengkaili/controller/FKLController.java
  2. 5 17
      mjava-fengkaili/src/main/resources/application-dev.yml
  3. 7 19
      mjava-fengkaili/src/main/resources/application-prod.yml
  4. 5 17
      mjava-fengkaili/target/classes/application-dev.yml
  5. 7 19
      mjava-fengkaili/target/classes/application-prod.yml
  6. 28 0
      mjava-pake/pom.xml
  7. 32 0
      mjava-pake/src/main/java/com/malk/pake/Boot.java
  8. 80 0
      mjava-pake/src/main/java/com/malk/pake/controller/SFController.java
  9. 60 0
      mjava-pake/src/main/resources/application-dev.yml
  10. 33 0
      mjava-pake/src/main/resources/application-prod.yml
  11. 28 0
      mjava-shangfeng/pom.xml
  12. 32 0
      mjava-shangfeng/src/main/java/com/malk/shangfeng/Boot.java
  13. 80 0
      mjava-shangfeng/src/main/java/com/malk/shangfeng/controller/SFController.java
  14. 60 0
      mjava-shangfeng/src/main/resources/application-dev.yml
  15. 33 0
      mjava-shangfeng/src/main/resources/application-prod.yml
  16. 21 0
      mjava/src/main/java/com/malk/service/dingtalk/DDClient_Attendance.java
  17. 7 9
      mjava/src/main/java/com/malk/service/dingtalk/DDClient_Contacts.java
  18. 8 0
      mjava/src/main/java/com/malk/service/dingtalk/DDService.java
  19. 35 1
      mjava/src/main/java/com/malk/service/dingtalk/impl/DDImplClient_Attendance.java
  20. 10 7
      mjava/src/main/java/com/malk/service/dingtalk/impl/DDImplClient_Contacts.java
  21. 47 0
      mjava/src/main/java/com/malk/service/dingtalk/impl/DDImplService.java
  22. 1 1
      mjava/src/main/java/com/malk/utils/UtilMap.java
  23. 2 0
      mjava/src/main/java/com/malk/utils/UtilNumber.java
  24. 2 0
      pom.xml

+ 46 - 1
mjava-fengkaili/src/main/java/com/malk/fengkaili/controller/FKLController.java

@@ -5,19 +5,64 @@ package com.malk.fengkaili.controller;
  */
 
 import com.malk.server.common.McR;
+import com.malk.service.dingtalk.DDClient;
+import com.malk.service.dingtalk.DDClient_Attendance;
+import com.malk.service.dingtalk.DDClient_Contacts;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
 @Slf4j
 @RestController
 @RequestMapping
 public class FKLController {
 
+    @Autowired
+    private DDClient ddClient;
+
+    @Autowired
+    private DDClient_Attendance ddClient_attendance;
+
+    @Autowired
+    private DDClient_Contacts ddClient_contacts;
 
     @PostMapping("test")
     McR test() {
-        return McR.success();
+
+        List<String> columnNames = Arrays.asList("下班1打卡结果", "上班1打卡结果", "旷工天数", "出勤天数", "工作时长", "考勤结果", "出差时长", "迟到次数", "早退次数", "下班缺卡次数", "上班缺卡次数", "外出时长", "休息日加班", "工作日加班", "节假日加班", "严重迟到次数", "应出勤天数");
+        List<String> leaveNames = new ArrayList<>();
+        List<Map> columns = ddClient_attendance.getAttColumns(ddClient.getAccessToken());
+        List<String> columnIds = columns.stream().filter(column -> {
+
+                    if (column.get("alias").equals("leave_")) {
+                        leaveNames.add(String.valueOf(column.get("name")));
+                        return false;
+                    }
+                    return columnNames.contains(column.get("name"));
+                }
+
+        ).map(column -> String.valueOf(column.get("id"))).collect(Collectors.toList());
+
+//        ddClient_contacts.getDepartmentId_all(ddClient.getAccessToken(), true).forEach(deptId -> {
+//                
+//            
+//        });
+
+
+        ddClient_attendance.getAttColumnVal(ddClient.getAccessToken(), "01340563171287111,01386135062129166507", columnIds, "2023-07-01 00:00:00", "2023-07-22 23:59:59");
+        ddClient_attendance.getLeaveTimeByNames(ddClient.getAccessToken(), "01340563171287111", leaveNames, "2023-07-01 00:00:00", "2023-07-22 23:59:59");
+
+//        getLeaveTimeByNames
+//        ddClient_attendance.getAttColumns(ddClient.getAccessToken());
+//        getAttColumnVal
+        return McR.success(columns);
     }
 }

+ 5 - 17
mjava-fengkaili/src/main/resources/application-dev.yml

@@ -49,24 +49,12 @@ logging:
 
 # dingtalk
 dingtalk:
-  agentId: 1963716187
-  appKey: ding8qyulwwmad6j7k6c
-  appSecret: e_hRHuubw-Xi0OuPJOYdXSElVzOC0IPgMrHQTBuAM9BqW-DFnrcsSyBHi7Me3xSv
-  corpId: ding321c72787fffc78b35c2f4657eb6378f
+  agentId: 2664525556
+  appKey: dingmcbz0lceeusy2kk4
+  appSecret: nhNVAbjjtb1Y_Q3WM1SkV4Wk3qDxTjfKEVUZd2iMrF5DtlGVcVDi5aIK-8CundeZ
+  corpId: dingade22a8c4fd34b8535c2f4657eb6378f
   aesKey:
   token:
-  operator: "095358016629044412"   # 牧语[开头需要转一下字符串], OA管理员账号
-
-# aliwork
-aliwork:
-  appType: APP_YH7W0E5637YUBU5UJ837
-  systemToken: IC766WA11EW8BMOPBEZZMBA4MPUQ214JDL7FLC9
-
-# xbongbong
-xbongbong:
-  corpid: dingcc1b1ffad0d5ca1d
-  token: f760ea3d154e45c839b2169f09b76f23
-  userId: 102314374732747224 # 汐瑶
-  callbackToken:
+  operator: ""   # OA管理员账号 [0开头需要转一下字符串]
 
 

+ 7 - 19
mjava-fengkaili/src/main/resources/application-prod.yml

@@ -16,30 +16,18 @@ 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
 
 # dingtalk
 dingtalk:
-  agentId: 1963716187
-  appKey: ding8qyulwwmad6j7k6c
-  appSecret: e_hRHuubw-Xi0OuPJOYdXSElVzOC0IPgMrHQTBuAM9BqW-DFnrcsSyBHi7Me3xSv
-  corpId: ding321c72787fffc78b35c2f4657eb6378f
+  agentId: 2664525556
+  appKey: dingmcbz0lceeusy2kk4
+  appSecret: nhNVAbjjtb1Y_Q3WM1SkV4Wk3qDxTjfKEVUZd2iMrF5DtlGVcVDi5aIK-8CundeZ
+  corpId: dingade22a8c4fd34b8535c2f4657eb6378f
   aesKey:
   token:
-  operator: "095358016629044412"   # 牧语[开头需要转一下字符串], OA管理员账号
-
-# aliwork
-aliwork:
-  appType: APP_YH7W0E5637YUBU5UJ837
-  systemToken: IC766WA11EW8BMOPBEZZMBA4MPUQ214JDL7FLC9
-
-# xbongbong
-xbongbong:
-  corpid: dingcc1b1ffad0d5ca1d
-  token: f760ea3d154e45c839b2169f09b76f23
-  userId: 102314374732747224 # 汐瑶
-  callbackToken:
+  operator: ""   # OA管理员账号 [0开头需要转一下字符串]

+ 5 - 17
mjava-fengkaili/target/classes/application-dev.yml

@@ -49,24 +49,12 @@ logging:
 
 # dingtalk
 dingtalk:
-  agentId: 1963716187
-  appKey: ding8qyulwwmad6j7k6c
-  appSecret: e_hRHuubw-Xi0OuPJOYdXSElVzOC0IPgMrHQTBuAM9BqW-DFnrcsSyBHi7Me3xSv
-  corpId: ding321c72787fffc78b35c2f4657eb6378f
+  agentId: 2664525556
+  appKey: dingmcbz0lceeusy2kk4
+  appSecret: nhNVAbjjtb1Y_Q3WM1SkV4Wk3qDxTjfKEVUZd2iMrF5DtlGVcVDi5aIK-8CundeZ
+  corpId: dingade22a8c4fd34b8535c2f4657eb6378f
   aesKey:
   token:
-  operator: "095358016629044412"   # 牧语[开头需要转一下字符串], OA管理员账号
-
-# aliwork
-aliwork:
-  appType: APP_YH7W0E5637YUBU5UJ837
-  systemToken: IC766WA11EW8BMOPBEZZMBA4MPUQ214JDL7FLC9
-
-# xbongbong
-xbongbong:
-  corpid: dingcc1b1ffad0d5ca1d
-  token: f760ea3d154e45c839b2169f09b76f23
-  userId: 102314374732747224 # 汐瑶
-  callbackToken:
+  operator: ""   # OA管理员账号 [0开头需要转一下字符串]
 
 

+ 7 - 19
mjava-fengkaili/target/classes/application-prod.yml

@@ -16,30 +16,18 @@ 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
 
 # dingtalk
 dingtalk:
-  agentId: 1963716187
-  appKey: ding8qyulwwmad6j7k6c
-  appSecret: e_hRHuubw-Xi0OuPJOYdXSElVzOC0IPgMrHQTBuAM9BqW-DFnrcsSyBHi7Me3xSv
-  corpId: ding321c72787fffc78b35c2f4657eb6378f
+  agentId: 2664525556
+  appKey: dingmcbz0lceeusy2kk4
+  appSecret: nhNVAbjjtb1Y_Q3WM1SkV4Wk3qDxTjfKEVUZd2iMrF5DtlGVcVDi5aIK-8CundeZ
+  corpId: dingade22a8c4fd34b8535c2f4657eb6378f
   aesKey:
   token:
-  operator: "095358016629044412"   # 牧语[开头需要转一下字符串], OA管理员账号
-
-# aliwork
-aliwork:
-  appType: APP_YH7W0E5637YUBU5UJ837
-  systemToken: IC766WA11EW8BMOPBEZZMBA4MPUQ214JDL7FLC9
-
-# xbongbong
-xbongbong:
-  corpid: dingcc1b1ffad0d5ca1d
-  token: f760ea3d154e45c839b2169f09b76f23
-  userId: 102314374732747224 # 汐瑶
-  callbackToken:
+  operator: ""   # OA管理员账号 [0开头需要转一下字符串]

+ 28 - 0
mjava-pake/pom.xml

@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>java-mcli</artifactId>
+        <groupId>com.malk</groupId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>mjava-pake</artifactId>
+    <description>帕科宜搭项目</description>
+
+    <properties>
+        <maven.compiler.source>8</maven.compiler.source>
+        <maven.compiler.target>8</maven.compiler.target>
+    </properties>
+
+    <dependencies>
+        <!-- 核心模块-->
+        <dependency>
+            <groupId>com.malk</groupId>
+            <artifactId>mjava</artifactId>
+            <version>${mjava.version}</version>
+        </dependency>
+    </dependencies>
+</project>

+ 32 - 0
mjava-pake/src/main/java/com/malk/pake/Boot.java

@@ -0,0 +1,32 @@
+package com.malk.pake;
+
+import com.querydsl.jpa.impl.JPAQueryFactory;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
+import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
+
+import javax.persistence.EntityManager;
+
+/**
+ * corp项目: 扫描公共模块
+ * -
+ * 若是无需数据库模块, 配置无效地址也可启动, 引入mjava不支持直接 @SpringBootApplication(exclude = DataSourceAutoConfiguration.class) 配置
+ * 需要配置 jpa.hibernate.ddl-auto 为 none. 标识对表没有任何操作. 若不设置为 non, flyway.enabled 配置会无效, 在没有数库连接情况下程序无法启动
+ */
+@EnableJpaAuditing
+@SpringBootApplication(scanBasePackages = {"com.malk"})
+public class Boot {
+
+    public static void main(String... args) {
+        SpringApplication.run(Boot.class, args);
+    }
+
+    /**
+     * 让Spring管理JPAQueryFactory [不使用Qualifier详见mjava-Boot]
+     */
+    @Bean
+    public JPAQueryFactory jpaQueryFactory(EntityManager entityManager) {
+        return new JPAQueryFactory(entityManager);
+    }
+}

+ 80 - 0
mjava-pake/src/main/java/com/malk/pake/controller/SFController.java

@@ -0,0 +1,80 @@
+package com.malk.pake.controller;
+
+/**
+ * 错误抛出与拦截详见 CatchException
+ */
+
+import com.malk.server.common.McR;
+import com.malk.service.dingtalk.DDClient;
+import com.malk.service.dingtalk.DDClient_Attendance;
+import com.malk.service.dingtalk.DDClient_Contacts;
+import com.malk.utils.UtilMap;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@Slf4j
+@RestController
+@RequestMapping
+public class SFController {
+
+    @Autowired
+    private DDClient ddClient;
+
+    @Autowired
+    private DDClient_Attendance ddClient_attendance;
+
+    @Autowired
+    private DDClient_Contacts ddClient_contacts;
+
+    @PostMapping("test")
+    McR test() {
+
+        List<String> columnNames = Arrays.asList("考勤结果", "下班1打卡结果", "下班1打卡时间", "旷工天数", "出勤天数", "休息天数", "工作时长", "考勤结果", "出差时长", "迟到次数", "早退次数", "下班缺卡次数", "上班缺卡次数", "外出时长", "休息日加班", "工作日加班", "节假日加班", "严重迟到次数", "应出勤天数");
+        List<Map> columns = ddClient_attendance.getAttColumns(ddClient.getAccessToken());
+        Map columnIds = new HashMap(); // 列id通过map提取, 月度汇总接口仅返回id, 存储映射关系
+        List<String> leaveNames = columns.stream().filter(column -> {
+                    if (columnNames.contains(column.get("name"))) {
+                        columnIds.put(column.get("id"), column.get("name"));
+                    }
+                    return column.get("alias").equals("leave_");
+                }
+        ).map(column -> String.valueOf(column.get("name"))).collect(Collectors.toList());
+
+//        ddClient_contacts.getDepartmentId_all(ddClient.getAccessToken(), true).forEach(deptId -> {
+//
+//            
+//        });
+
+
+        String start = "2023-07-01 00:00:00";
+        String end = "2023-07-22 23:59:59";
+        String userId = "196230404821883307";
+
+        Map userInfo = UtilMap.map("userId, userName", "196230404821883307", "吴迎梅");
+        ddClient_attendance.getAttColumnVal(ddClient.getAccessToken(), userId, (List<String>) columnIds.keySet(), start, end).forEach(attendance -> {
+
+            String columnId = ((Map) attendance.get("column_vo")).get("id").toString();
+            userInfo.put(columnIds.get(columnId), "");
+
+
+        });
+
+
+        List<Map> leaveList = ddClient_attendance.getLeaveTimeByNames(ddClient.getAccessToken(), userId, leaveNames, start, end);
+
+
+//        getLeaveTimeByNames
+//        ddClient_attendance.getAttColumns(ddClient.getAccessToken());
+//        getAttColumnVal
+        return McR.success(columns);
+    }
+}

+ 60 - 0
mjava-pake/src/main/resources/application-dev.yml

@@ -0,0 +1,60 @@
+# 环境配置
+server:
+  port: 9001
+  servlet:
+    context-path: /api/pake
+
+# condition
+spel:
+  scheduling: false        # 定时任务是否执行
+  multiSource: false       # 是否多数据源配置
+
+spring:
+  # database
+  datasource:
+    hikari:
+      connection-init-sql: SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci           # SqlServer, Oracle 无需设置类型
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    username: root
+    password: mu123
+    url: jdbc:mysql://127.0.0.1:3306/mjava?serverTimezone=Asia/Shanghai&useUnicode=yes&characterEncoding=UTF-8&useSSL=true
+    # 主库
+    primary:
+      username: root
+      password: mu123
+      jdbc-url: jdbc:mysql://127.0.0.1:3306/mjava?serverTimezone=Asia/Shanghai&useUnicode=yes&characterEncoding=UTF-8&useSSL=true
+    # 从库
+    slave:
+      username: root
+      password: mu123
+      jdbc-url: jdbc:mysql://127.0.0.1:3306/mjava_slave?serverTimezone=Asia/Shanghai&useUnicode=yes&characterEncoding=UTF-8&useSSL=true
+  jpa:
+    hibernate:
+      ddl-auto: none      # JPA对表没有任何操作
+    show-sql: true
+    database: MYSQL
+    database-platform: org.hibernate.dialect.MySQL57Dialect
+
+# filepath
+file:
+  path:
+    file: /Users/malk/server/_Tool/var/mjava/tmp/file/
+    image: /Users/malk/server/_Tool/var/mjava/tmp/image/
+    tmp: /Users/malk/server/_Tool/var/mjava/tmp/
+  source:
+    fonts: /Users/malk/server/_Tool/fonts/simsun.ttc
+logging:
+  file:
+    path: /Users/malk/server/_Tool/var/mjava/log
+
+# dingtalk
+dingtalk:
+  agentId: 2664525556
+  appKey: dingmcbz0lceeusy2kk4
+  appSecret: nhNVAbjjtb1Y_Q3WM1SkV4Wk3qDxTjfKEVUZd2iMrF5DtlGVcVDi5aIK-8CundeZ
+  corpId: dingade22a8c4fd34b8535c2f4657eb6378f
+  aesKey:
+  token:
+  operator: ""   # OA管理员账号 [0开头需要转一下字符串]
+
+

+ 33 - 0
mjava-pake/src/main/resources/application-prod.yml

@@ -0,0 +1,33 @@
+# 环境配置
+server:
+  port: 9012
+  servlet:
+    context-path: /api/pake
+
+# condition
+spel:
+  scheduling: true        # 定时任务是否执行
+  multiSource: false      # 是否多数据源配置
+
+spring:
+  # database
+  datasource:
+    hikari:
+      connection-init-sql: SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci           # SqlServer, Oracle 无需设置类型
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    username: root
+    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
+
+# dingtalk
+dingtalk:
+  agentId: 2664525556
+  appKey: dingmcbz0lceeusy2kk4
+  appSecret: nhNVAbjjtb1Y_Q3WM1SkV4Wk3qDxTjfKEVUZd2iMrF5DtlGVcVDi5aIK-8CundeZ
+  corpId: dingade22a8c4fd34b8535c2f4657eb6378f
+  aesKey:
+  token:
+  operator: ""   # OA管理员账号 [0开头需要转一下字符串]

+ 28 - 0
mjava-shangfeng/pom.xml

@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>java-mcli</artifactId>
+        <groupId>com.malk</groupId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>mjava-shangfeng</artifactId>
+    <description>上风同步U8项目档案至钉钉</description>
+
+    <properties>
+        <maven.compiler.source>8</maven.compiler.source>
+        <maven.compiler.target>8</maven.compiler.target>
+    </properties>
+
+    <dependencies>
+        <!-- 核心模块-->
+        <dependency>
+            <groupId>com.malk</groupId>
+            <artifactId>mjava</artifactId>
+            <version>${mjava.version}</version>
+        </dependency>
+    </dependencies>
+</project>

+ 32 - 0
mjava-shangfeng/src/main/java/com/malk/shangfeng/Boot.java

@@ -0,0 +1,32 @@
+package com.malk.shangfeng;
+
+import com.querydsl.jpa.impl.JPAQueryFactory;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
+import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
+
+import javax.persistence.EntityManager;
+
+/**
+ * corp项目: 扫描公共模块
+ * -
+ * 若是无需数据库模块, 配置无效地址也可启动, 引入mjava不支持直接 @SpringBootApplication(exclude = DataSourceAutoConfiguration.class) 配置
+ * 需要配置 jpa.hibernate.ddl-auto 为 none. 标识对表没有任何操作. 若不设置为 non, flyway.enabled 配置会无效, 在没有数库连接情况下程序无法启动
+ */
+@EnableJpaAuditing
+@SpringBootApplication(scanBasePackages = {"com.malk"})
+public class Boot {
+
+    public static void main(String... args) {
+        SpringApplication.run(Boot.class, args);
+    }
+
+    /**
+     * 让Spring管理JPAQueryFactory [不使用Qualifier详见mjava-Boot]
+     */
+    @Bean
+    public JPAQueryFactory jpaQueryFactory(EntityManager entityManager) {
+        return new JPAQueryFactory(entityManager);
+    }
+}

+ 80 - 0
mjava-shangfeng/src/main/java/com/malk/shangfeng/controller/SFController.java

@@ -0,0 +1,80 @@
+package com.malk.shangfeng.controller;
+
+/**
+ * 错误抛出与拦截详见 CatchException
+ */
+
+import com.malk.server.common.McR;
+import com.malk.service.dingtalk.DDClient;
+import com.malk.service.dingtalk.DDClient_Attendance;
+import com.malk.service.dingtalk.DDClient_Contacts;
+import com.malk.utils.UtilMap;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@Slf4j
+@RestController
+@RequestMapping
+public class SFController {
+
+    @Autowired
+    private DDClient ddClient;
+
+    @Autowired
+    private DDClient_Attendance ddClient_attendance;
+
+    @Autowired
+    private DDClient_Contacts ddClient_contacts;
+
+    @PostMapping("test")
+    McR test() {
+
+        List<String> columnNames = Arrays.asList("考勤结果", "下班1打卡结果", "下班1打卡时间", "旷工天数", "出勤天数", "休息天数", "工作时长", "考勤结果", "出差时长", "迟到次数", "早退次数", "下班缺卡次数", "上班缺卡次数", "外出时长", "休息日加班", "工作日加班", "节假日加班", "严重迟到次数", "应出勤天数");
+        List<Map> columns = ddClient_attendance.getAttColumns(ddClient.getAccessToken());
+        Map columnIds = new HashMap(); // 列id通过map提取, 月度汇总接口仅返回id, 存储映射关系
+        List<String> leaveNames = columns.stream().filter(column -> {
+                    if (columnNames.contains(column.get("name"))) {
+                        columnIds.put(column.get("id"), column.get("name"));
+                    }
+                    return column.get("alias").equals("leave_");
+                }
+        ).map(column -> String.valueOf(column.get("name"))).collect(Collectors.toList());
+
+//        ddClient_contacts.getDepartmentId_all(ddClient.getAccessToken(), true).forEach(deptId -> {
+//
+//            
+//        });
+
+
+        String start = "2023-07-01 00:00:00";
+        String end = "2023-07-22 23:59:59";
+        String userId = "196230404821883307";
+
+        Map userInfo = UtilMap.map("userId, userName", "196230404821883307", "吴迎梅");
+        ddClient_attendance.getAttColumnVal(ddClient.getAccessToken(), userId, (List<String>) columnIds.keySet(), start, end).forEach(attendance -> {
+
+            String columnId = ((Map) attendance.get("column_vo")).get("id").toString();
+            userInfo.put(columnIds.get(columnId), "");
+
+
+        });
+
+
+        List<Map> leaveList = ddClient_attendance.getLeaveTimeByNames(ddClient.getAccessToken(), userId, leaveNames, start, end);
+
+
+//        getLeaveTimeByNames
+//        ddClient_attendance.getAttColumns(ddClient.getAccessToken());
+//        getAttColumnVal
+        return McR.success(columns);
+    }
+}

+ 60 - 0
mjava-shangfeng/src/main/resources/application-dev.yml

@@ -0,0 +1,60 @@
+# 环境配置
+server:
+  port: 9001
+  servlet:
+    context-path: /api/shangfeng
+
+# condition
+spel:
+  scheduling: false        # 定时任务是否执行
+  multiSource: false       # 是否多数据源配置
+
+spring:
+  # database
+  datasource:
+    hikari:
+      connection-init-sql: SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci           # SqlServer, Oracle 无需设置类型
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    username: root
+    password: mu123
+    url: jdbc:mysql://127.0.0.1:3306/mjava?serverTimezone=Asia/Shanghai&useUnicode=yes&characterEncoding=UTF-8&useSSL=true
+    # 主库
+    primary:
+      username: root
+      password: mu123
+      jdbc-url: jdbc:mysql://127.0.0.1:3306/mjava?serverTimezone=Asia/Shanghai&useUnicode=yes&characterEncoding=UTF-8&useSSL=true
+    # 从库
+    slave:
+      username: root
+      password: mu123
+      jdbc-url: jdbc:mysql://127.0.0.1:3306/mjava_slave?serverTimezone=Asia/Shanghai&useUnicode=yes&characterEncoding=UTF-8&useSSL=true
+  jpa:
+    hibernate:
+      ddl-auto: none      # JPA对表没有任何操作
+    show-sql: true
+    database: MYSQL
+    database-platform: org.hibernate.dialect.MySQL57Dialect
+
+# filepath
+file:
+  path:
+    file: /Users/malk/server/_Tool/var/mjava/tmp/file/
+    image: /Users/malk/server/_Tool/var/mjava/tmp/image/
+    tmp: /Users/malk/server/_Tool/var/mjava/tmp/
+  source:
+    fonts: /Users/malk/server/_Tool/fonts/simsun.ttc
+logging:
+  file:
+    path: /Users/malk/server/_Tool/var/mjava/log
+
+# dingtalk
+dingtalk:
+  agentId: 2664525556
+  appKey: dingmcbz0lceeusy2kk4
+  appSecret: nhNVAbjjtb1Y_Q3WM1SkV4Wk3qDxTjfKEVUZd2iMrF5DtlGVcVDi5aIK-8CundeZ
+  corpId: dingade22a8c4fd34b8535c2f4657eb6378f
+  aesKey:
+  token:
+  operator: ""   # OA管理员账号 [0开头需要转一下字符串]
+
+

+ 33 - 0
mjava-shangfeng/src/main/resources/application-prod.yml

@@ -0,0 +1,33 @@
+# 环境配置
+server:
+  port: 9001
+  servlet:
+    context-path: /api/shangfeng
+
+# condition
+spel:
+  scheduling: true        # 定时任务是否执行
+  multiSource: false      # 是否多数据源配置
+
+spring:
+  # database
+  datasource:
+    hikari:
+      connection-init-sql: SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci           # SqlServer, Oracle 无需设置类型
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    username: root
+    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
+
+# dingtalk
+dingtalk:
+  agentId: 2664525556
+  appKey: dingmcbz0lceeusy2kk4
+  appSecret: nhNVAbjjtb1Y_Q3WM1SkV4Wk3qDxTjfKEVUZd2iMrF5DtlGVcVDi5aIK-8CundeZ
+  corpId: dingade22a8c4fd34b8535c2f4657eb6378f
+  aesKey:
+  token:
+  operator: ""   # OA管理员账号 [0开头需要转一下字符串]

+ 21 - 0
mjava/src/main/java/com/malk/service/dingtalk/DDClient_Attendance.java

@@ -54,4 +54,25 @@ public interface DDClient_Attendance {
      * @param userids      查询的人员userId列表,一次最多可传50个
      */
     List<Map> listScheduleUsers(String access_token, String op_user_id, List<String> userids, long from_date_time, long to_date_time);
+
+    /**
+     * 获取考勤报表列定义 [获取假期相关字段信息,不返回ID。如果希望获取假期相关信息,请调用获取报表假期数据接口]
+     */
+    List<Map> getAttColumns(String access_token);
+
+    /**
+     * 获取考勤报表列值
+     *
+     * @param column_id_list 报表列ID,多值用英文逗号分隔,最大长度20 [获取考勤报表列定义接口]
+     * @param to_date        结束时间,结束时间减去开始时间必须在31天以内 [格式为 yyyy-MM-dd HH:mm:ss]
+     */
+    List<Map> getAttColumnVal(String access_token, String userid, List<String> column_id_list, String from_date, String to_date);
+
+    /**
+     * 获取考勤报表列值
+     *
+     * @param leave_names 报表列ID,假期名称,多个用英文逗号分隔,最大长度20 [获取考勤报表列定义接口, 无Id列]
+     * @param to_date     结束时间,结束时间减去开始时间必须在31天以内 [格式为 yyyy-MM-dd HH:mm:ss]
+     */
+    List<Map> getLeaveTimeByNames(String access_token, String userid, List<String> leave_names, String from_date, String to_date);
 }

+ 7 - 9
mjava/src/main/java/com/malk/service/dingtalk/DDClient_Contacts.java

@@ -13,28 +13,27 @@ public interface DDClient_Contacts {
     /**
      * 获取子部门ID列表 [获取企业部门下的所有直属子部门列表]
      */
-    List<Number> listSubDepartmentId(String access_token, Number dept_id);
+    List<Long> listSubDepartmentId(String access_token, long dept_id);
 
     /**
      * 获取部门列表
      */
-    List<Map> listSubDepartmentDetail(String access_token, Number dept_id);
-
+    List<Map> listSubDepartmentDetail(String access_token, long dept_id);
 
     /**
-     * 获取全部架构内部门_全部 ID [包含一级部门]
+     * 获取全部架构内部门_全部 ID [是否包含一级部门]
      */
-    List<Number> getDepartmentId_all(String access_token, boolean containsTop);
+    List<Long> getDepartmentId_all(String access_token, boolean containsTop);
 
     /**
-     * 获取全部架构内部门_全部 detail [包含一级部门]
+     * 获取全部架构内部门_全部 detail [是否包含一级部门]
      */
     List<Map> getDepartmentDetail_all(String access_token, boolean containsTop);
 
     /**
      * 获取部门用户userid列表 [无需分页]
      */
-    List<String> listDepartmentUserId(String access_token, Number dept_id);
+    List<String> listDepartmentUserId(String access_token, long dept_id);
 
     /**
      * 查询用户详情
@@ -42,7 +41,7 @@ public interface DDClient_Contacts {
     Map getUserInfoById(String access_token, String userId);
 
     /**
-     * 根据手机号查询用户
+     * 根据手机号查询用户 [手机号查询仅返回userid, 查询详情后返回]
      */
     Map getUserInfoByMobile(String access_token, String mobile);
 
@@ -72,5 +71,4 @@ public interface DDClient_Contacts {
      * @param only_active 是否包含未激活钉钉人数
      */
     int getUserCount(String access_token, boolean only_active);
-
 }

+ 8 - 0
mjava/src/main/java/com/malk/service/dingtalk/DDService.java

@@ -1,5 +1,6 @@
 package com.malk.service.dingtalk;
 
+import java.util.List;
 import java.util.Map;
 
 public interface DDService {
@@ -13,4 +14,11 @@ public interface DDService {
      * 钉钉查询假期余额返回是记录, 按照消失/天单位计算该假期类型下的余额
      */
     Map queryVacationQuota_balance(String access_token, String op_userid, String leave_code, String userids, int offset, int size);
+
+    // todo 通讯录部门结构返回; 通讯录全量数据同步
+
+    /**
+     * 判断员工是否在指定部门
+     */
+    boolean matchDepartment(String access_token, String userId, List<Long> deptIds);
 }

+ 35 - 1
mjava/src/main/java/com/malk/service/dingtalk/impl/DDImplClient_Attendance.java

@@ -105,7 +105,6 @@ public class DDImplClient_Attendance implements DDClient_Attendance {
      */
     @Override
     public List<Map> listScheduleUsers(String access_token, String op_user_id, List<String> userids, long from_date_time, long to_date_time) {
-
         Map params = UtilMap.map("op_user_id, userids, from_date_time, to_date_time", op_user_id, String.join(",", userids), from_date_time, to_date_time);
         DDR ddr = DDR.doPost("https://oapi.dingtalk.com/topapi/attendance/schedule/listbyusers", null, DDConf.initTokenParams(access_token), params);
         if (ObjectUtil.isNull(ddr.getResult())) {
@@ -113,4 +112,39 @@ public class DDImplClient_Attendance implements DDClient_Attendance {
         }
         return (List<Map>) ddr.getResult();
     }
+
+    /**
+     * 获取考勤报表列定义
+     *
+     * @apiNote https://open.dingtalk.com/document/orgapp/queries-the-enterprise-attendance-report-column
+     */
+    @Override
+    public List<Map> getAttColumns(String access_token) {
+        DDR ddr = DDR.doPost("https://oapi.dingtalk.com/topapi/attendance/getattcolumns", null, DDConf.initTokenParams(access_token), null);
+        return (List<Map>) ((Map) (ddr.getResult())).get("columns");
+    }
+
+    /**
+     * 获取考勤报表列值
+     *
+     * @apiNote https://open.dingtalk.com/document/orgapp/queries-the-column-value-of-the-attendance-report
+     */
+    @Override
+    public List<Map> getAttColumnVal(String access_token, String userid, List<String> column_id_list, String from_date, String to_date) {
+        Map boyds = UtilMap.map("userid, column_id_list, from_date, to_date", userid, String.join(",", column_id_list), from_date, to_date);
+        DDR ddr = DDR.doPost("https://oapi.dingtalk.com/topapi/attendance/getcolumnval", null, DDConf.initTokenParams(access_token), boyds);
+        return (List<Map>) ((Map) (ddr.getResult())).get("column_vals");
+    }
+
+    /**
+     * 获取用户考勤数据
+     *
+     * @apiNote https://open.dingtalk.com/document/orgapp/obtains-the-holiday-data-from-the-smart-attendance-report
+     */
+    @Override
+    public List<Map> getLeaveTimeByNames(String access_token, String userid, List<String> leave_names, String from_date, String to_date) {
+        Map boyds = UtilMap.map("userid, leave_names, from_date, to_date", userid, String.join(",", leave_names), from_date, to_date);
+        DDR ddr = DDR.doPost("https://oapi.dingtalk.com/topapi/attendance/getleavetimebynames", null, DDConf.initTokenParams(access_token), boyds);
+        return (List<Map>) ((Map) (ddr.getResult())).get("columns");
+    }
 }

+ 10 - 7
mjava/src/main/java/com/malk/service/dingtalk/impl/DDImplClient_Contacts.java

@@ -24,11 +24,13 @@ public class DDImplClient_Contacts implements DDClient_Contacts {
      * @apiNote https://open.dingtalk.com/document/orgapp/obtain-a-sub-department-id-list-v2
      */
     @Override
-    public List<Number> listSubDepartmentId(String access_token, Number dept_id) {
+    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);
         Map rsp = (Map) DDR.doPost("https://oapi.dingtalk.com/topapi/v2/department/listsubid", null, param, body).getResult();
-        return (List<Number>) rsp.get("dept_id_list");
+        List<Number> list = (List<Number>) rsp.get("dept_id_list");
+        // ppExt: 不要直接使用 Number 作为类型, 不同基本类型比较值时会有偏差 [可以作为父类接受数据, 避免直接强制类型转换错误, 再进行基本类型处理]
+        return list.stream().map(item -> item.longValue()).collect(Collectors.toList());
     }
 
     /**
@@ -37,7 +39,7 @@ public class DDImplClient_Contacts implements DDClient_Contacts {
      * @apiNote https://open.dingtalk.com/document/orgapp/obtain-the-department-list-v2
      */
     @Override
-    public List<Map> listSubDepartmentDetail(String access_token, Number dept_id) {
+    public List<Map> listSubDepartmentDetail(String access_token, long dept_id) {
         Map param = UtilMap.map("access_token", access_token);
         Map body = UtilMap.map("dept_id", dept_id);
         return (List<Map>) DDR.doPost("https://oapi.dingtalk.com/topapi/v2/department/listsub", null, param, body).getResult();
@@ -56,9 +58,9 @@ public class DDImplClient_Contacts implements DDClient_Contacts {
      * 获取全部架构内部门_全部 id [包含一级部门]
      */
     @Override
-    public List<Number> getDepartmentId_all(String access_token, boolean containsTop) {
+    public List<Long> getDepartmentId_all(String access_token, boolean containsTop) {
         List<Long> deptList = containsTop ? UtilList.asList(DDConf.TOP_DEPARTMENT) : new ArrayList<>();
-        return (List<Number>) _getDepartment_all(access_token, DDConf.TOP_DEPARTMENT, deptList, true)
+        return (List<Long>) _getDepartment_all(access_token, DDConf.TOP_DEPARTMENT, deptList, true)
                 .stream().map(detpId -> Long.valueOf(String.valueOf(detpId))).collect(Collectors.toList());
     }
 
@@ -81,7 +83,7 @@ public class DDImplClient_Contacts implements DDClient_Contacts {
      * @apiNote https://open.dingtalk.com/document/orgapp/query-the-list-of-department-userids
      */
     @Override
-    public List<String> listDepartmentUserId(String access_token, Number dept_id) {
+    public List<String> listDepartmentUserId(String access_token, long dept_id) {
         Map param = UtilMap.map("access_token", access_token);
         Map body = UtilMap.map("dept_id", dept_id);
         Map rsp = (Map) DDR.doPost("https://oapi.dingtalk.com/topapi/user/listid", null, param, body).getResult();
@@ -105,7 +107,8 @@ public class DDImplClient_Contacts implements DDClient_Contacts {
     public Map getUserInfoByMobile(String access_token, String mobile) {
         Map param = UtilMap.map("access_token", access_token);
         Map body = UtilMap.map("mobile", mobile);
-        return (Map) DDR.doPost("https://oapi.dingtalk.com/topapi/v2/user/getbymobile", null, param, body).getResult();
+        Map result = (Map) DDR.doPost("https://oapi.dingtalk.com/topapi/v2/user/getbymobile", null, param, body).getResult();
+        return getUserInfoById(access_token, String.valueOf(result.get("userid")));
     }
 
     /**

+ 47 - 0
mjava/src/main/java/com/malk/service/dingtalk/impl/DDImplService.java

@@ -1,9 +1,12 @@
 package com.malk.service.dingtalk.impl;
 
 import cn.hutool.core.util.ObjectUtil;
+import com.malk.server.dingtalk.DDConf;
 import com.malk.service.dingtalk.DDClient_Attendance;
+import com.malk.service.dingtalk.DDClient_Contacts;
 import com.malk.service.dingtalk.DDClient_Workflow;
 import com.malk.service.dingtalk.DDService;
+import com.malk.utils.UtilMap;
 import lombok.SneakyThrows;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -24,6 +27,9 @@ public class DDImplService implements DDService {
     @Autowired
     private DDClient_Attendance ddClient_attendance;
 
+    @Autowired
+    private DDClient_Contacts ddClient_contacts;
+
     /**
      * 新发起审批15s内不允许撤销, 异步执行 [审批同意/拒绝只能通过节点操作, 系统无法直接介入]   -- 异步需要中转一层进行触发, client为原子接口
      */
@@ -61,4 +67,45 @@ public class DDImplService implements DDService {
         result.put("unit", unit);
         return result;
     }
+
+    /**
+     * 判断员工是否在指定部门
+     */
+    @Override
+    public boolean matchDepartment(String access_token, String userId, List<Long> deptIds) {
+        List<Number> deptIdList = (List<Number>) ddClient_contacts.getUserInfoById(access_token, userId).get("dept_id_list");
+        boolean isMatch = false;
+        // 兼容多部门场景
+        for (Number deptId : deptIdList) {
+            // ppExt: 不要直接使用 Number 作为类型, 不同基本类型比较值时会有偏差 [可以作为父类接受数据, 避免直接强制类型转换错误, 再进行基本类型处理]
+            isMatch = _matchDepartment(access_token, deptId.longValue(), deptIds);
+            if (isMatch) {
+                break;
+            }
+        }
+        return isMatch;
+    }
+
+    /// 递归: 判断员工是否在指定部门
+    boolean _matchDepartment(String access_token, long dept_id, List<Long> deptIds) {
+        // 判断入参
+        if (dept_id == DDConf.TOP_DEPARTMENT) {
+            return false;
+        }
+        if (deptIds.contains(dept_id)) {
+            return true;
+        }
+        Map deptInfo = ddClient_contacts.getDepartmentInfo(access_token, dept_id);
+        long parentId = UtilMap.getLong(deptInfo, "parent_id");
+        long deptId = UtilMap.getLong(deptInfo, "dept_id");
+        _matchDepartment(access_token, parentId, deptIds);
+        // 判断递归
+        if (deptId == DDConf.TOP_DEPARTMENT) {
+            return false;
+        }
+        if (deptIds.contains(parentId)) {
+            return true;
+        }
+        return false;
+    }
 }

+ 1 - 1
mjava/src/main/java/com/malk/utils/UtilMap.java

@@ -81,7 +81,7 @@ public abstract class UtilMap {
         return data;
     }
 
-    /************* 值 ************/
+    /************* 值 ************/
 
     /**
      * 取值 [String.valueOf 避免空指针]

+ 2 - 0
mjava/src/main/java/com/malk/utils/UtilNumber.java

@@ -9,6 +9,8 @@ import java.util.Locale;
 
 /**
  * 数字格式化
+ * -
+ * ppExt: 不要直接使用 Number 作为类型, 不同基本类型比较值时会有偏差 [可以作为父类接受数据, 避免直接强制类型转换错误, 再进行基本类型处理]
  */
 public class UtilNumber {
 

+ 2 - 0
pom.xml

@@ -18,6 +18,8 @@
         <module>mjava-zhuogao</module>
         <module>mjava-fengkaili</module>
         <module>mjava-gewu</module>
+        <module>mjava-shangfeng</module>
+        <module>mjava-pake</module>
     </modules>
     <packaging>pom</packaging>