Explorar o código

哈克\泰森\莱帝\快客利

pruple_boy %!s(int64=2) %!d(string=hai) anos
pai
achega
b7b2e8f7fb
Modificáronse 58 ficheiros con 1990 adicións e 119 borrados
  1. 9 0
      mjava-cloudpure/src/main/java/com/malk/cloudpure/controller/XBBController.java
  2. 37 0
      mjava-gewu/src/main/java/com/malk/gewu/controller/GWController.java
  3. 3 3
      mjava-guyuan/src/main/java/com/malk/guyuan/controller/IVController.java
  4. 4 2
      mjava-guyuan/src/main/java/com/malk/guyuan/service/tencent/impl/TXYImplInvoice.java
  5. 5 1
      mjava-guyuan/src/main/resources/static/mjs/mjs.js
  6. 1 1
      mjava-guyuan/src/main/resources/static/mjs/mjs.min.js
  7. 5 1
      mjava-guyuan/target/classes/static/mjs/mjs.js
  8. 1 1
      mjava-guyuan/target/classes/static/mjs/mjs.min.js
  9. 54 0
      mjava-hake/pom.xml
  10. 32 0
      mjava-hake/src/main/java/com/malk/hake/Boot.java
  11. 235 0
      mjava-hake/src/main/java/com/malk/hake/controller/HKController.java
  12. 51 0
      mjava-hake/src/main/resources/application-dev.yml
  13. 38 0
      mjava-hake/src/main/resources/application-prod.yml
  14. 272 0
      mjava-hake/src/main/resources/static/json/form.json
  15. 39 0
      mjava-hake/src/test/resource/server.sh
  16. 65 0
      mjava-kuaikeli/src/main/java/com/malk/kuaikeli/controller/KKLController.java
  17. 12 0
      mjava-kuaikeli/src/main/resources/application-dev.yml
  18. 2 2
      mjava-kuaikeli/src/main/resources/application-prod.yml
  19. 50 25
      mjava-laidi/src/main/java/com/malk/laidi/controller/LDController.java
  20. 17 5
      mjava-laidi/src/main/resources/application-dev.yml
  21. 1 1
      mjava-laidi/src/main/resources/application-prod.yml
  22. 87 0
      mjava-laidi/src/test/resources/sample/CP_Utils.cs
  23. 42 0
      mjava-laidi/src/test/resources/sample/附件同步钉盘.cs
  24. 50 0
      mjava-laidi/src/test/resources/sample/附件同步钉盘.js
  25. 21 0
      mjava-luyi/src/main/java/com/malk/luyi/controller/LYController.java
  26. 32 0
      mjava-mcli/src/main/java/com/malk/mcli/Boot.java
  27. 53 0
      mjava-mcli/src/main/java/com/malk/mcli/controller/TControl.java
  28. 8 8
      mjava-mcli/src/main/resources/application-dev.yml
  29. 8 8
      mjava-mcli/target/classes/application-dev.yml
  30. 54 0
      mjava-taisen/pom.xml
  31. 32 0
      mjava-taisen/src/main/java/com/malk/taisen/Boot.java
  32. 205 0
      mjava-taisen/src/main/java/com/malk/taisen/controller/TSController.java
  33. 69 0
      mjava-taisen/src/main/resources/application-dev.yml
  34. 38 0
      mjava-taisen/src/main/resources/application-prod.yml
  35. 15 1
      mjava-zhuogao/src/main/java/com/malk/zhuogao/controller/ZGController.java
  36. 18 0
      mjava-zhuogao/src/main/java/com/malk/zhuogao/repository/dao/TrustDeviceDao.java
  37. 25 0
      mjava-zhuogao/src/main/java/com/malk/zhuogao/repository/entity/TrustDevicePo.java
  38. 3 1
      mjava/src/main/java/com/malk/server/aliwork/YDConf.java
  39. 4 0
      mjava/src/main/java/com/malk/server/aliwork/YDParam.java
  40. 1 1
      mjava/src/main/java/com/malk/server/common/McREnum.java
  41. 2 0
      mjava/src/main/java/com/malk/server/dingtalk/DDConf.java
  42. 7 9
      mjava/src/main/java/com/malk/server/dingtalk/DDR_New.java
  43. 5 2
      mjava/src/main/java/com/malk/service/aliwork/impl/YDClientImpl.java
  44. 0 1
      mjava/src/main/java/com/malk/service/aliwork/impl/YDServiceImpl.java
  45. 0 11
      mjava/src/main/java/com/malk/service/dingtalk/DDClient_CRM.java
  46. 4 1
      mjava/src/main/java/com/malk/service/dingtalk/DDClient_Contacts.java
  47. 11 0
      mjava/src/main/java/com/malk/service/dingtalk/DDClient_Dedicated.java
  48. 19 1
      mjava/src/main/java/com/malk/service/dingtalk/DDClient_Storage.java
  49. 12 2
      mjava/src/main/java/com/malk/service/dingtalk/DDService.java
  50. 0 21
      mjava/src/main/java/com/malk/service/dingtalk/impl/DDImplClient_CRM.java
  51. 24 1
      mjava/src/main/java/com/malk/service/dingtalk/impl/DDImplClient_Dedicated.java
  52. 50 1
      mjava/src/main/java/com/malk/service/dingtalk/impl/DDImplClient_Storage.java
  53. 26 3
      mjava/src/main/java/com/malk/service/dingtalk/impl/DDImplService.java
  54. 7 4
      mjava/src/main/java/com/malk/utils/UtilHttp.java
  55. 1 1
      mjava/src/main/java/com/malk/utils/UtilMap.java
  56. 87 0
      mjava/src/test/resources/sample/CP_Utils.cs
  57. 35 0
      mjava/target/classes/META-INF/spring-configuration-metadata.json
  58. 2 0
      pom.xml

+ 9 - 0
mjava-cloudpure/src/main/java/com/malk/cloudpure/controller/XBBController.java

@@ -4,6 +4,8 @@ import com.alibaba.fastjson.JSON;
 import com.malk.server.common.McException;
 import com.malk.server.common.McR;
 import com.malk.server.xbongbong.XBBConf;
+import com.malk.service.dingtalk.DDClient;
+import com.malk.service.dingtalk.DDClient_Contacts;
 import com.malk.service.xbongbong.XBBClient;
 import com.malk.utils.UtilMap;
 import lombok.extern.slf4j.Slf4j;
@@ -115,9 +117,16 @@ public class XBBController {
     }
 
 
+    @Autowired
+    private DDClient ddClient;
+
+    @Autowired
+    private DDClient_Contacts ddClient_contacts;
+
     @PostMapping("test")
     McR test() {
 
+        ddClient_contacts.getUserInfoById(ddClient.getAccessToken(), "16608972969409067");
         return McR.success();
     }
 }

+ 37 - 0
mjava-gewu/src/main/java/com/malk/gewu/controller/GWController.java

@@ -4,15 +4,26 @@ package com.malk.gewu.controller;
  * 错误抛出与拦截详见 CatchException
  */
 
+import com.alibaba.fastjson.JSON;
 import com.malk.gewu.service.GWService;
+import com.malk.server.aliwork.YDConf;
+import com.malk.server.aliwork.YDParam;
 import com.malk.server.common.McR;
+import com.malk.service.aliwork.YDClient;
 import com.malk.utils.UtilFile;
+import com.malk.utils.UtilMap;
+import com.malk.utils.UtilServlet;
 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 javax.servlet.http.HttpServletRequest;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
 @Slf4j
 @RestController
 @RequestMapping
@@ -32,6 +43,32 @@ public class GWController {
         return McR.success();
     }
 
+    @Autowired
+    private YDClient ydClient;
+
+    /**
+     * 拆分培训记录表
+     */
+    @PostMapping("copy")
+    McR copyTrain(HttpServletRequest request) {
+
+        Map data = UtilServlet.getParamMap(request);
+        log.info("拆分培训记录表, {}", data);
+        Map formData = (Map) JSON.parse(String.valueOf(data.get("formData")));
+        List<String> userIds = (List<String>) JSON.parse(String.valueOf(formData.get("employeeField_limyct1y")));
+        for (String userId : userIds) {
+            Map form = UtilMap.putAll(UtilMap.empty(), formData);
+            form.put("employeeField_limyct1y", Arrays.asList(userId));
+            ydClient.operateData(YDParam.builder()
+                    .formUuid("FORM-AC666081OYZE6LMAELILADKXFZO8231E9GLNL5")
+                    .formDataJson(JSON.toJSONString(form))
+                    .build(), YDConf.FORM_OPERATION.create);
+        }
+
+        return McR.success();
+    }
+
+
     /**
      * test
      */

+ 3 - 3
mjava-guyuan/src/main/java/com/malk/guyuan/controller/IVController.java

@@ -324,8 +324,8 @@ public class IVController {
             if (dto.getName().contains("普通发票")) {
                 String serialTips = serial + "有疑问";
                 try {
-                    // ppExt: 识别与验真后抬头对比
-                    Map rsp = txyInvoice.doVatInvoiceVerifyNew(dto.getName(), dto.getCode(), invoiceNo, dto.getDate(), String.valueOf(dto.getAmount()), dto.getCheckCode(), String.valueOf(dto.getExcludingTax()), serialTips);
+                    // ppExt: 识别与验真后抬头对比 [全电票, 新版本识别接口, 返回名称为: 电子发票(普通发票) 不包含全电标识, 发类型为: 全电发票. 注意取值]
+                    Map rsp = txyInvoice.doVatInvoiceVerifyNew(dto.getKindName(), dto.getCode(), invoiceNo, dto.getDate(), String.valueOf(dto.getAmount()), dto.getCheckCode(), String.valueOf(dto.getExcludingTax()), serialTips);
                     Map invoice = (Map) rsp.get("Invoice");
                     McException.assertAccessException(!dto.getBuyerName().equals(guyuanNameRepalce(invoice.get("BuyerName").toString())), serialTips + ", 购买方名称不匹配!");
                     McException.assertAccessException(!dto.getBuyerTaxId().equals(invoice.get("BuyerTaxCode")), serialTips + ", 购买方税号不匹配!");
@@ -335,7 +335,7 @@ public class IVController {
                     log.error(e.getMessage(), e);
                     // prd: 上传发票为假发票时,提示:该发票有疑问,请联系财务人员
                     String message = e.getMessage();
-                    // ppExt: 已经是新版本接口, 过滤提示
+                    // ppExt: 已经是新版本接口, 过滤提示 [官方答复: 提示不会检测您是否使用的是新版,所有的用户都会提示, 忽略即可]
                     if (message.contains("温馨提示")) {
                         message = message.split("温馨提示")[0];
                     }

+ 4 - 2
mjava-guyuan/src/main/java/com/malk/guyuan/service/tencent/impl/TXYImplInvoice.java

@@ -108,6 +108,7 @@ public class TXYImplInvoice implements TXYInvoice {
         req.setInvoiceDate(invoiceDate);
         req.setInvoiceCode(invoiceCode);
         req.setCheckCode(checkCode);
+        // ppExt: 全电票, 新版本识别接口, 返回名称为: 电子发票(普通发票) 不包含全电标识, 发类型为: 全电发票. 注意取值
         if (invoiceKind.contains("全电")) {
             // 全电票, 需要价税合计且无发票代码与校验码
             req.setCheckCode(null);
@@ -117,7 +118,7 @@ public class TXYImplInvoice implements TXYInvoice {
             req.setAmount(null);
             req.setAmount(excludingTax);
         }
-        log.info("发票验真, {}", JSON.toJSONString(req));
+        log.debug("发票验真, {}, {}", invoiceKind, JSON.toJSONString(req));
         VatInvoiceVerifyNewResponse resp = client.VatInvoiceVerifyNew(req);
         String result = VatInvoiceVerifyNewResponse.toJsonString(resp);
         Map rsp = (Map) JSON.parse(result);
@@ -129,7 +130,8 @@ public class TXYImplInvoice implements TXYInvoice {
         }
         log.debug("请求响应, {}", result);
         McException.assertAccessException(!UtilNumber.equalBigDecimal(UtilMap.getString(invoice, "AmountWithTax"), amount), tips + ", 价税合计金额不匹配!");
-        McException.assertAccessException(!UtilNumber.equalBigDecimal(UtilMap.getString(invoice, "AmountWithoutTax"), excludingTax), tips + ", 不含税金额不匹配!");
+        // ppExt: 增值税卷票: 票面无税率, 税额. 但接口验证返回或本质上发票是有税率, 税额. 因此取消后置判断
+        McException.assertAccessException(!invoiceKind.contains("卷票") && !UtilNumber.equalBigDecimal(UtilMap.getString(invoice, "AmountWithoutTax"), excludingTax), tips + ", 不含税金额不匹配!");
         return rsp;
     }
 

+ 5 - 1
mjava-guyuan/src/main/resources/static/mjs/mjs.js

@@ -9248,7 +9248,9 @@ var guyuan = {
       var details = mjs.$this.$('tableField_liv5f4d2').getValue();
       var param = details.map(function (item) {
         return {
-          name: item.textField_liwbaczr, // 发票类型全称
+          // ppExt: 全电票, 新版本识别接口, 返回名称为: 电子发票(普通发票) 不包含全电标识, 发类型为: 全电发票. 注意取值
+          name: item.textField_liwbaczr,
+          kindName: item.selectField_liihyrta,
           serial: item.textField_liihyrt8,
           code: item.textField_lil34mnc,
           date: item.textField_livimrja,
@@ -9286,7 +9288,9 @@ var guyuan = {
       }
       // 非作废校验
       var param = {
+        // ppExt: 全电票, 新版本识别接口, 返回名称为: 电子发票(普通发票) 不包含全电标识, 发类型为: 全电发票. 注意取值
         name: mjs.$this.$("textField_ljasce9j").getValue(),
+        kindName: mjs.$this.$("selectField_liihyrta").getValue(),
         serial: mjs.$this.$("textField_liihyrt8").getValue(),
         code: mjs.$this.$("textField_lil34mnc").getValue(),
         date: mjs.$this.$("textField_liwadykg").getValue(),

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 1 - 1
mjava-guyuan/src/main/resources/static/mjs/mjs.min.js


+ 5 - 1
mjava-guyuan/target/classes/static/mjs/mjs.js

@@ -9248,7 +9248,9 @@ var guyuan = {
       var details = mjs.$this.$('tableField_liv5f4d2').getValue();
       var param = details.map(function (item) {
         return {
-          name: item.textField_liwbaczr, // 发票类型全称
+          // ppExt: 全电票, 新版本识别接口, 返回名称为: 电子发票(普通发票) 不包含全电标识, 发类型为: 全电发票. 注意取值
+          name: item.textField_liwbaczr,
+          kindName: item.selectField_liihyrta,
           serial: item.textField_liihyrt8,
           code: item.textField_lil34mnc,
           date: item.textField_livimrja,
@@ -9286,7 +9288,9 @@ var guyuan = {
       }
       // 非作废校验
       var param = {
+        // ppExt: 全电票, 新版本识别接口, 返回名称为: 电子发票(普通发票) 不包含全电标识, 发类型为: 全电发票. 注意取值
         name: mjs.$this.$("textField_ljasce9j").getValue(),
+        kindName: mjs.$this.$("selectField_liihyrta").getValue(),
         serial: mjs.$this.$("textField_liihyrt8").getValue(),
         code: mjs.$this.$("textField_lil34mnc").getValue(),
         date: mjs.$this.$("textField_liwadykg").getValue(),

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 1 - 1
mjava-guyuan/target/classes/static/mjs/mjs.min.js


+ 54 - 0
mjava-hake/pom.xml

@@ -0,0 +1,54 @@
+<?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-hake</artifactId>
+    <description>宜搭对接monitor</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>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>2.1.1.RELEASE</version>
+                <configuration>
+                    <includeSystemScope>true</includeSystemScope>
+                    <!-- 如果没有该配置,devtools不会生效: 打包时关闭 -->
+                    <fork>false</fork>
+                    <!-- 避免中文乱码 -->
+                    <jvmArguments>-Dfile.encoding=UTF-8</jvmArguments>
+                </configuration>
+                <!-- 允许生成可运行jar -->
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+        <finalName>${project.artifactId}</finalName>
+    </build>
+</project>

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

@@ -0,0 +1,32 @@
+package com.malk.hake;
+
+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. 标识对表没有任何操作. 若不设置为 none, 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);
+    }
+}

+ 235 - 0
mjava-hake/src/main/java/com/malk/hake/controller/HKController.java

@@ -0,0 +1,235 @@
+package com.malk.hake.controller;
+
+/**
+ * 错误抛出与拦截详见 CatchException
+ */
+
+import com.alibaba.fastjson.JSON;
+import com.malk.server.aliwork.YDConf;
+import com.malk.server.aliwork.YDParam;
+import com.malk.server.common.McException;
+import com.malk.server.common.McR;
+import com.malk.server.common.McREnum;
+import com.malk.server.dingtalk.DDConf;
+import com.malk.service.aliwork.YDClient;
+import com.malk.service.dingtalk.DDClient;
+import com.malk.service.dingtalk.DDClient_Contacts;
+import com.malk.service.dingtalk.DDService;
+import com.malk.utils.*;
+import lombok.SneakyThrows;
+import lombok.Synchronized;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+import java.time.LocalDateTime;
+import java.util.*;
+
+@Slf4j
+@RestController
+@RequestMapping
+public class HKController {
+
+    @Autowired
+    private YDClient ydClient;
+
+    /**
+     * 通用流程发起
+     */
+    @SneakyThrows
+    @PostMapping("process/start")
+    McR startProcess(@RequestBody Map data, HttpServletRequest request, @RequestParam String code) {
+
+        log.info("流程发起, {}, {}", code, data);
+        Map header = UtilServlet.getHeaders(request);
+        McException.assertException(!"dinge61fe69900ea236b35c2f4657eb6378f".equals(header.get("authorization")), McREnum.NOT_AUTHORIZED);
+        Map meta = (Map) UtilFile.readJsonObjectFromResource("static/json/form.json"); // 本地匹配了宜搭组件ID
+        McException.assertAccessException(!meta.containsKey(code), "单据编码未匹配!");
+        // 组织单据数据
+        Map<String, ?> component = (Map) ((Map) meta.get(code)).get("compIds");
+        Map formData = UtilMap.empty();
+        for (String key : component.keySet()) {
+            if (key.startsWith("employeeField_")) {
+                formData.put(key, Arrays.asList(data.get(component.get(key))));
+            } else if (key.startsWith("tableField_")) {
+                List<Map> rows = (List<Map>) data.get("rows");
+                List<Map> details = new ArrayList<>();
+                Map<String, String> compIds = (Map) component.get(key);
+                for (Map row : rows) {
+                    Map detail = UtilMap.empty();
+                    for (String prop : compIds.keySet()) {
+                        detail.put(prop, row.get(compIds.get(prop)));
+                    }
+                    details.add(detail);
+                }
+                formData.put(key, details);
+            } else {
+                formData.put(key, data.get(component.get(key)));
+            }
+        }
+        // 发起人匹配规则
+        String userId = _getUserId(code, meta, data);
+        Object InstanceId = ydClient.operateData(YDParam.builder()
+                .formUuid(String.valueOf(((Map) meta.get(code)).get("formUuid")))
+                .processCode(String.valueOf(((Map) meta.get(code)).get("processCode")))
+                .userId(userId)
+                .formDataJson(JSON.toJSONString(formData))
+                .build(), YDConf.FORM_OPERATION.start);
+        // 回传钉钉单据号
+        Thread.sleep(800);
+        Map form = ydClient.queryData(YDParam.builder()
+                .formInstanceId(String.valueOf(InstanceId))
+                .build(), YDConf.FORM_QUERY.retrieve_id).getFormData();
+        return McR.success(UtilMap.map("ddProcessId, dtNumber", InstanceId, form.get(meta.get(code + "_RC"))));
+    }
+
+    /// 发起人处理
+    String _getUserId(String code, Map meta, Map data) {
+        String userId = String.valueOf(data.get(String.valueOf(((Map) meta.get(code)).get("creator"))));
+        // 报价单
+        if ("BJ".equals(code)) {
+            if (Arrays.asList("样品", "大货").contains(data.get("quoteType"))) {
+                userId = String.valueOf(data.get("dtOurReferencePersonId"));
+            } else {
+                userId = String.valueOf(data.get("dtSellerPersonId"));
+            }
+        }
+        if (UtilString.isBlankCompatNull(userId)) {
+            userId = YDConf.PUB_ACCOUNT;
+        }
+        return userId;
+    }
+
+    @Autowired
+    private DDClient ddClient;
+
+    @Autowired
+    private DDClient_Contacts ddClient_contacts;
+
+    @Autowired
+    private DDService ddService;
+
+    private static final String AUTH = "bbb76928-a9db-42fa-ac83-cc9a2ed75162";
+
+    /**
+     * 通用审批校验 [区分类型, 宜搭提示不同报错信息]
+     */
+    @PostMapping("process/validate")
+    McR validateProcess(HttpServletRequest request) {
+
+        Map data = UtilServlet.getParamMap(request);
+        log.info("审批校验, {}", JSON.toJSONString(data));
+        // 拒绝审批意见必填校验
+        McException.assertParamException_Null(data, "Remark");
+        return McR.success();
+    }
+
+    /**
+     * 通用审批回调 [区分类型, 宜搭提示不同报错信息]
+     */
+    @PostMapping("process/callback")
+    McR callbackProcess(HttpServletRequest request) {
+
+        Map data = UtilServlet.getParamMap(request);
+
+        // 拒绝审批意见必填校验
+        McException.assertParamException_Null(data, "Result");
+        if ("0".equals(data.get("Result"))) {
+            McException.assertParamException_Null(data, "Remark");
+        }
+        // 回调monitor审批信息
+        data.put("Url", "https://pxi03f.aliwork.com/APP_QWUVLI1R6XYUXWAOPF6O/processDetail?procInsId=" + data.get("DdProcessId"));
+        data.put("ApprovalDate", UtilDateTime.formatLocalDateTime(LocalDateTime.now()));
+        Map UserInfo = ddClient_contacts.getUserInfoById(ddClient.getAccessToken(), String.valueOf(data.get("Approver")));
+        data.put("Approver", String.valueOf(UserInfo.get("name")));
+        log.info("审批回调, {}", JSON.toJSONString(data));
+        // prd: 通过 http status 判定, 200 即为成功
+        String rsp = UtilHttp.doPost("http://116.228.113.106:10001/api/public/Approval", UtilMap.map("Authorization", AUTH), UtilMap.map("Code", data.get("Code")), data);
+        Map result = (Map) JSON.parse(rsp);
+        McException.assertException(result.containsKey("errorMsg"), String.valueOf(result.get("status")), String.valueOf(result.get("errorMsg")), "Monitor");
+        return McR.success();
+    }
+
+    /**
+     * 通讯录同步
+     */
+    @Synchronized
+    @PostMapping("contact/sync")
+    McR syncContact() {
+
+//        List<Long> deptList = Arrays.asList(475336040L);
+        // prd: 非全量同步: 总部\哈克\负责人
+        List<Long> deptList = UtilList.asList(DDConf.TOP_DEPARTMENT);
+        deptList.addAll(ddClient_contacts.getDepartmentId_all(ddClient.getAccessToken(), true, 129113277L)); // 总部
+        deptList.addAll(ddClient_contacts.getDepartmentId_all(ddClient.getAccessToken(), true, 128984162L)); // 哈克
+        for (long deptId : deptList) {
+            List<String> userIds = ddClient_contacts.listDepartmentUserId(ddClient.getAccessToken(), deptId);
+            if (userIds.size() == 0) {
+                continue;
+            }
+            // prd: 取第3层作为部门, 为空取值总经办
+            String dpetCascade = ddService.getUserDepartmentHierarchyJoin(ddClient.getAccessToken(), userIds.get(0), "-");
+            String deptName = "总经办";
+            String[] depts = dpetCascade.split("-");
+            if (depts.length >= 3) {
+                deptName = depts[2];
+            }
+            for (String userId : userIds) {
+                Map userInfo = ddClient_contacts.getUserInfoById(ddClient.getAccessToken(), userId);
+                Map data = UtilMap.map("employeeNumber, employeeName, dtPersonId, lastName", userInfo.get("job_number"), userInfo.get("name"), userInfo.get("userid"), userInfo.get("title"));
+                // prd: 手机号花名册未展示, 因此添加判空, 避免覆盖Monitor
+                if (StringUtils.isNotBlank(String.valueOf(userInfo.get("mobile")))) {
+                    data.put("mobilePhone", userInfo.get("mobile"));
+                }
+                if (userInfo.containsKey("org_email")) {
+                    data.put("email", userInfo.get("org_email"));
+                }
+                data.put("employeeDept", deptName);
+                data.put("dtDepts", dpetCascade);
+                data.put("dtPersonGroup", "");
+                log.info("同步人员, {}", JSON.toJSONString(UtilMap.map("employees", Arrays.asList(data))));
+                // prd: 通过 http status 判定, 200 即为成功
+                String rsp = UtilHttp.doPost("http://116.228.113.106:10001/api/public/EmployeeImport", UtilMap.map("Authorization", AUTH), null, UtilMap.map("employees", Arrays.asList(data)));
+                Map result = (Map) JSON.parse(rsp);
+                if (UtilList.isNotEmpty(UtilMap.getList(result, "fail"))) {
+                    result = (Map) UtilMap.getList(result, "fail").get(0); // 单条同步, 记录错误人员
+                }
+                if (result.containsKey("msg")) {
+                    ydClient.operateData(YDParam.builder()
+                            .formUuid("FORM-W2A66Z91912F39B2AHY0VD4CRK9F3C4JB74OLN")
+                            .formDataJson(JSON.toJSONString(UtilMap.map("dateField_lo47byyd, employeeField_lo47byyj, textareaField_lo47byyo, textareaField_lo47sanj", new Date().getTime(), userId, result, data)))
+                            .build(), YDConf.FORM_OPERATION.create);
+                }
+                //McException.assertException(result.containsKey("msg"), String.valueOf(result.get("status")), String.valueOf(result.get("msg")), "Monitor");
+            }
+        }
+        return McR.success();
+    }
+
+    @PostMapping("test11")
+    McR test11() {
+
+        ddClient_contacts.getUserInfoById(ddClient.getAccessToken(), "131022580326061279");
+        ddClient_contacts.getDepartmentDetail_all(ddClient.getAccessToken(), true);
+        return McR.success();
+    }
+
+    //////
+
+    // dslink或连接器内, 会转换json为map, 需要条件两层
+    @PostMapping("test")
+    Map test(@RequestBody Map data) {
+
+        log.info("xxx, {}", data);
+        return UtilMap.map("json", JSON.toJSONString(JSON.toJSONString(data)));
+    }
+
+    @PostMapping("test2")
+    Map test2(@RequestBody Map<String, ?> data) {
+
+        log.info("xxx, {}", data);
+        return UtilMap.map("data", JSON.parse(String.valueOf(data.get("json"))));
+    }
+}

+ 51 - 0
mjava-hake/src/main/resources/application-dev.yml

@@ -0,0 +1,51 @@
+# 环境配置
+server:
+  port: 9001
+  servlet:
+    context-path: /api/hake
+
+# 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
+  jpa:
+    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: 2757249888
+  appKey: ding3zk0vhfifznseopg
+  appSecret: Eso_p9HrVrJClEqcwbYuuOeDbS5Lb0e8Qq_HWtJm4_GYR38E-O5UEvakWpxXAvqq
+  corpId: dinge61fe69900ea236b35c2f4657eb6378f
+  aesKey:
+  token:
+  operator: ""   # OA管理员账号
+
+# aliwork
+aliwork:
+  appType: "APP_QWUVLI1R6XYUXWAOPF6O"
+  systemToken: "SE766NA1XW0F9PG19UX926VYF9RS31DVAYMNLJ27"
+

+ 38 - 0
mjava-hake/src/main/resources/application-prod.yml

@@ -0,0 +1,38 @@
+# 环境配置
+server:
+  port: 9019
+  servlet:
+    context-path: /api/hake
+
+# 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: 2757249888
+  appKey: ding3zk0vhfifznseopg
+  appSecret: Eso_p9HrVrJClEqcwbYuuOeDbS5Lb0e8Qq_HWtJm4_GYR38E-O5UEvakWpxXAvqq
+  corpId: dinge61fe69900ea236b35c2f4657eb6378f
+  aesKey:
+  token:
+  operator: ""   # OA管理员账号
+
+# aliwork
+aliwork:
+  appType: "APP_QWUVLI1R6XYUXWAOPF6O"
+  systemToken: "SE766NA1XW0F9PG19UX926VYF9RS31DVAYMNLJ27"

+ 272 - 0
mjava-hake/src/main/resources/static/json/form.json

@@ -0,0 +1,272 @@
+{
+  "BJ": {
+    "formUuid": "FORM-4IA66891ZYZEIU2K9N4HD60ZUL3F2QJGHYMNL7",
+    "processCode": "TPROC--4IA66891ZYZEIU2K9N4HD60ZUL3F2RJGHYMNL8",
+    "creator": "dtPersonId",
+    "compIds": {
+      "textField_lnmyiqad": "orderNumber",
+      "textField_lnmyiqae": "customerNumber",
+      "textField_lnmyiqaf": "customerStatus",
+      "textField_lnmyiqag": "customerName",
+      "textField_lnmyiqai": "deliveryAddress",
+      "textField_lnmyiqak": "dtPersonId",
+      "textField_lnmyiqan": "dtPersonGroup",
+      "textField_lnwqhgoy": "dtOurReferencePersonId",
+      "textField_lnwqhgoz": "dtSellerPersonId",
+      "textField_lnwqhgp2": "quoteType",
+      "employeeField_lnwqhgox": "dtPersonId",
+      "employeeField_lnwqhgp0": "dtOurReferencePersonId",
+      "employeeField_lnwqhgp1": "dtSellerPersonId",
+      "tableField_lnmyiqau": {
+        "textField_lnmyiqav": "partNumber",
+        "textField_lnmyiqaw": "partName",
+        "numberField_lnmyiqax": "quantity",
+        "textField_lnmyiqaz": "currency",
+        "numberField_lnmyiqb1": "exchangeRate",
+        "numberField_lnmyiqb2": "priceInCompanyCurrencyExTax",
+        "numberField_lnmyiqb3": "priceInTax",
+        "numberField_lnmyiqb4": "",
+        "numberField_lnmyiqb5": "",
+        "textField_lnmyiqb6": "deliveryDate"
+      }
+    }
+  },
+  "BJ_RC": "serialNumberField_lntocd8t",
+  "XSDD": {
+    "formUuid": "FORM-NO766591M91FUF566DE1X4733DB83URWQYMNL1",
+    "processCode": "TPROC--NO766591M91FUF566DE1X4733DB831TWQYMNL2",
+    "creator": "dtPersonId",
+    "compIds": {
+      "textField_lnmyiqad": "orderNumber",
+      "textField_lnmyiqae": "customerNumber",
+      "textField_lnmyiqag": "customerName",
+      "textField_lnmyiqai": "deliveryAddress",
+      "textField_lnmyiqaf": "seller",
+      "textField_lnmyiqak": "dtPersonId",
+      "textField_lnmyiqan": "dtPersonGroup",
+      "numberField_lnmyrzwx": "reason",
+      "tableField_lnmyiqau": {
+        "textField_lnmyiqav": "partNumber",
+        "textField_lnmyiqaw": "partName",
+        "numberField_lnmyiqax": "quantity",
+        "textField_lnmyiqaz": "unit",
+        "numberField_lnmyiqb2": "priceExTax",
+        "textField_lnmyrzx0": "deliveryDate",
+        "textField_lnmyrzwy": "currency",
+        "numberField_lnmyiqb1": "exchangeRate",
+        "numberField_lnmyrzwz": "priceInCompanyCurrencyExTax",
+        "textField_lnmyiqb6": "rowType"
+      }
+    }
+  },
+  "XSDD_RC": "serialNumberField_lntocd8t",
+  "GYSZQ": {
+    "formUuid": "FORM-JD8668C1FYZEYMQ6BY5HA43UFP9T2HUBYYMNL7",
+    "processCode": "TPROC--JD8668C1FYZEYMQ6BY5HA43UFP9T2JVBYYMNL8",
+    "creator": "dtPersonId",
+    "compIds": {
+      "textField_lnmyiqad": "supplierNumber",
+      "textField_lnmyiqae": "supplierName",
+      "textField_lnmyiqag": "term",
+      "textField_lnmyiqak": "dtPersonId",
+      "textField_lnmyiqan": "dtPersonGroup"
+    }
+  },
+  "GYSZQ_RC": "serialNumberField_lntocd8t",
+  "CGDD": {
+    "formUuid": "FORM-FDA66N81Q50FAELE9UEQDC4R2OR43ZDP1ZMNL9",
+    "processCode": "TPROC--FDA66N81Q50FAELE9UEQDC4R2OR435FP1ZMNLA",
+    "creator": "dtPersonId",
+    "compIds": {
+      "textField_lnmyiqad": "supplierNumber",
+      "textField_lnmyiqae": "supplierName",
+      "textField_lnmyiqag": "seller",
+      "textField_lnmyiqak": "dtPersonId",
+      "textField_lnmyiqan": "dtPersonGroup",
+      "tableField_lnmyiqau": {
+        "textField_lnmyiqaw": "partNumber",
+        "textField_lnmyiqav": "partName",
+        "textField_lnmyiqaz": "unit",
+        "numberField_lnmyiqax": "quantity",
+        "numberField_lnmyiqb2": "priceExTax",
+        "textField_lnmyrzx0": "deliveryDate",
+        "textField_lnmyrzwy": "currency",
+        "numberField_lnmyiqb1": "exchangeRate",
+        "numberField_lnmyrzwz": "priceInCompanyCurrencyExTax"
+      }
+    }
+  },
+  "CGDD_RC": "serialNumberField_lntocd8t",
+  "CGDDJQ": {
+    "formUuid": "FORM-0K666DC1000FWTLICOT0GAHRLA363XSU5ZMNL9",
+    "processCode": "TPROC--0K666DC1000FWTLICOT0GAHRLA363YTU5ZMNLA",
+    "creator": "dtPersonId",
+    "compIds": {
+      "textField_lnmyiqad": "supplierNumber",
+      "textField_lnmyiqae": "supplierName",
+      "textField_lnmyiqag": "seller",
+      "textField_lnmyiqak": "dtPersonId",
+      "textField_lnmyiqan": "dtPersonGroup",
+      "tableField_lnmyiqau": {
+        "textField_lnmyiqaw": "partNumber",
+        "textField_lnmyiqav": "partName",
+        "textField_lnmyiqaz": "unit",
+        "numberField_lnmyiqax": "quantity",
+        "numberField_lnmyiqb2": "priceExTax",
+        "textField_lnmyrzx0": "deliveryDate",
+        "textField_lnmyrzwy": "currency",
+        "numberField_lnmyiqb1": "exchangeRate",
+        "numberField_lnmyrzwz": "priceInCompanyCurrencyExTax"
+      }
+    }
+  },
+  "CGDDJQ_RC": "serialNumberField_lntocd8t",
+  "FKSQ": {
+    "formUuid": "FORM-DJC666A1JXZELRB4852YS9GU85MM2BYSAZMNLC",
+    "processCode": "TPROC--DJC666A1JXZELRB4852YS9GU85MM2KZSAZMNLD",
+    "creator": "",
+    "compIds": {
+      "textField_lnmyiqad": "supplierNumber",
+      "textField_lnmyiqae": "supplierName",
+      "textField_lnmyiqag": "paymentDate",
+      "textField_lnmyiqak": "paymentMethod",
+      "textField_lnmyiqan": "dueDate",
+      "textField_lnmzbyzu": "invoiceNumber",
+      "numberField_lnmzbyzz": "paymentAmount",
+      "numberField_lnmzbz00": "invoiceAmount",
+      "numberField_lnmzbz01": "restAmount"
+    }
+  },
+  "FKSQ_RC": "serialNumberField_lntocd8t",
+  "YFKSQ": {
+    "formUuid": "FORM-GI666T81Q50FXN4QD7AJW6J7U2M52U8TDZMNLG",
+    "processCode": "TPROC--GI666T81Q50FXN4QD7AJW6J7U2M52W9TDZMNLH",
+    "creator": "",
+    "compIds": {
+      "textField_lnmyiqad": "supplierNumber",
+      "textField_lnmyiqae": "supplierName",
+      "textField_lnmyiqag": "paymentDate",
+      "textField_lnmyiqak": "paymentMethod",
+      "textField_lnmyiqan": "orderNumber",
+      "numberField_lnmzbyzz": "orderAmount",
+      "numberField_lnmzbz00": "paymentAmount",
+      "tableField_lnmzeuoe": {
+        "textField_lnmzeuof": "position",
+        "numberField_lnmzeuoh": "rowAmount",
+        "numberField_lnmzeuoi": "rowPaymentAmount",
+        "textField_lnmzeuok": "partNumber",
+        "textField_lnmzeuom": "partName",
+        "numberField_lnmzeuon": "quantity",
+        "numberField_lnmzeuoo": "price",
+        "numberField_lnmzeuop": "vat",
+        "numberField_lnmzeuoq": "discount"
+      }
+    }
+  },
+  "YFKSQ_RC": "serialNumberField_lntocd8t",
+  "SJJY": {
+    "formUuid": "FORM-0X966971YVZEJ2FKE4JL29YKGQ3Q3I0OHZMNL8",
+    "processCode": "TPROC--0X966971YVZEJ2FKE4JL29YKGQ3Q3T1OHZMNL9",
+    "creator": "dtPersonId",
+    "compIds": {
+      "numberField_lnmzi8vv": "reportNumber",
+      "textField_lnmyiqae ": "orderNumber",
+      "numberField_lnmzi8vw": "reportQuantity",
+      "textField_lnmyiqak": "reporter",
+      "textField_lnmyiqan": "operationNumber",
+      "textField_lnmzi8vx": "operationName",
+      "textField_lnmzi8vy": "reportDate",
+      "textField_lnmzi8vz": "dtPersonId",
+      "textField_lnmzi8w0": "dtPersonGroup"
+    }
+  },
+  "SJJY_RC": "serialNumberField_lntocd8t",
+  "SCJS": {
+    "formUuid": "FORM-6L866J71Z00FM70UDURM67IU0YY92JRZ10NNLU",
+    "processCode": "TPROC--6L866J71Z00FM70UDURM67IU0YY92JSZ10NNLV",
+    "creator": "dtPersonId",
+    "compIds": {
+      "textField_lnn033p5": "finishedGoodsOpNo",
+      "textField_lnmyiqae ": "finishedInspectionOpNo",
+      "textField_lnn033p6": "orderNumber",
+      "textField_lnmyiqak": "partNumber",
+      "textField_lnmyiqan": "partName",
+      "numberField_lnn033pe": "reportQuantity",
+      "textField_lnn033p7": "reporter",
+      "textField_lnn033p9": "operationNumber",
+      "textField_lnn033pb": "operationName",
+      "textField_lnmzi8vy": "reportDate",
+      "textField_lnmzi8vz": "dtPersonId",
+      "textField_lnmzi8w0": "dtPersonGroup"
+    }
+  },
+  "SCJS_RC": "serialNumberField_lntocd8t",
+  "CGDH": {
+    "formUuid": "FORM-JD8668C1N00FS3ZB8FYUT8P7TPW23KY590NNL3",
+    "processCode": "TPROC--JD8668C1N00FS3ZB8FYUT8P7TPW23KZ590NNL4",
+    "creator": "dtPersonId",
+    "compIds": {
+      "textField_lnn033p5": "supplierNumber",
+      "textField_lnmyiqae ": "supplierName",
+      "textField_lnn033p6": "orderNumber",
+      "textField_lnmyiqak": "orderType",
+      "textField_lnmyiqan": "partNumber",
+      "textField_lnn07qeq": "partName",
+      "textField_lnn033p7": "unit",
+      "numberField_lnn0a6sw": "quantity",
+      "textField_lnn033pb": "deliveryDate",
+      "textField_lnmzi8vy": "dtPersonId"
+    }
+  },
+  "CGDH_RC": "serialNumberField_lntocd8t",
+  "XJSP": {
+    "formUuid": "FORM-K5766HA1XYZEAU3BA7C3V95ZODMT36T8E0NNLC",
+    "processCode": "TPROC--K5766HA1XYZEAU3BA7C3V95ZODMT3KU8E0NNLD",
+    "creator": "dtPersonId",
+    "compIds": {
+      "textField_lnmyiqad": "orderNumber",
+      "textField_lnmyiqae": "customerNumber",
+      "textField_lnmyiqaf": "customerStatus",
+      "textField_lnmyiqag": "customerName",
+      "textField_lnmyiqai": "deliveryAddress",
+      "textField_lnmyiqak": "dtPersonId",
+      "textField_lnmyiqan": "dtPersonGroup",
+      "tableField_lnmyiqau": {
+        "textField_lnmyiqav": "partNumber",
+        "textField_lnmyiqaw": "partName",
+        "numberField_lnmyiqax": "quantity",
+        "textField_lnmyiqaz": "currency",
+        "numberField_lnmyiqb1": "exchangeRate",
+        "numberField_lnmyiqb2": "priceInCompanyCurrencyExTax",
+        "numberField_lnmyiqb3": "priceInTax",
+        "textField_lnmyiqb6": "deliveryDate"
+      }
+    }
+  },
+  "XJSP_RC": "serialNumberField_lntocd8t",
+  "DJFP": {
+    "formUuid": "FORM-NO766591W11FGLKA7ZIGY5B9FEBB2CZAH0NNL8",
+    "processCode": "TPROC--NO766591W11FGLKA7ZIGY5B9FEBB2U0BH0NNL9",
+    "creator": "dtPersonId",
+    "compIds": {
+      "textField_lnmyiqad": "orderNumber",
+      "textField_lnmyiqae": "customerNumber",
+      "textField_lnmyiqaf": "customerName",
+      "textField_lnmyiqag": "seller",
+      "textField_lnmyiqai": "dtPersonId",
+      "textField_lnmyiqak": "dtPersonGroup",
+      "numberField_lnn0i86l": "reason",
+      "tableField_lnmyiqau": {
+        "textField_lnmyiqav": "partNumber",
+        "textField_lnmyiqaw": "partName",
+        "numberField_lnmyiqax": "quantity",
+        "textField_lnmyiqaz": "unit",
+        "numberField_lnmyiqb1": "priceExTax",
+        "textField_lnn0i86n": "currency",
+        "numberField_lnn0i86m": "exchangeRate",
+        "numberField_lnmyiqb2": "priceInCompanyCurrencyExTax"
+      }
+    }
+  },
+  "DJFP_RC": "serialNumberField_lntocd8t"
+}

+ 39 - 0
mjava-hake/src/test/resource/server.sh

@@ -0,0 +1,39 @@
+#!/bin/bash
+
+appname='mjava-hake'
+
+if [ "$1" == "dev" ]; then
+  java -Xms256m -Xmx256m -jar $appname.jar --spring.profiles.active=dev
+else
+  if [ "$1" == "start" ]; then
+    nohup java -Xms256m -Xmx256m -jar $appname.jar &
+    echo "server prod is starting"
+    tail -f log/info.log
+  else
+    if [ "$1" == "test" ]; then
+      nohup java -Xms256m -Xmx256m -jar $appname.jar --spring.profiles.active=test &
+      echo "server test is starting"
+      tail -f log/info.log
+    else
+      if [ "$1" == "stop" ]; then
+        PID=$(ps -ef | grep $appname.jar | grep -v grep | awk '{ print $2 }')
+        if [ -z "$PID" ]; then
+          echo "server is already stopped"
+        else
+          echo kill $PID
+          kill $PID
+        fi
+      else
+        if [ "$1" == "status" ]; then
+          PID=$(ps -ef | grep $appname.jar | grep -v grep | awk '{ print $2 }')
+          if [ -z "$PID" ]; then
+            echo "server is stopped"
+          else
+            echo "server is running"
+            echo $PID
+          fi
+        fi
+      fi
+    fi
+  fi
+fi

+ 65 - 0
mjava-kuaikeli/src/main/java/com/malk/kuaikeli/controller/KKLController.java

@@ -2,13 +2,17 @@ package com.malk.kuaikeli.controller;
 
 import com.alibaba.fastjson.JSON;
 import com.malk.server.aliwork.YDConf;
+import com.malk.server.aliwork.YDParam;
 import com.malk.server.common.McR;
+import com.malk.service.aliwork.YDClient;
 import com.malk.service.aliwork.YDService;
+import com.malk.utils.UtilMap;
 import com.malk.utils.UtilMc;
 import com.malk.utils.UtilServlet;
 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.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
@@ -28,6 +32,9 @@ public class KKLController {
     @Autowired
     private YDService ydService;
 
+    /**
+     * [动态] 发起单据, 分供应商进行流程推送
+     */
     @PostMapping("supplier")
     McR supplier(HttpServletRequest request) {
 
@@ -56,6 +63,64 @@ public class KKLController {
         return McR.success();
     }
 
+    @Autowired
+    private YDClient ydClient;
+
+    /**
+     * 菜单计划, 编辑校验
+     * -
+     * 前端提交动作: 校验是否审批通过, 是否当日之前计划, 是否当日且在16点及以后时间, 均不允许提交
+     * 后端校验返回、加任何产品都要走审批,减少20%以内直接过,每一个原材料
+     */
+    @PostMapping("validate")
+    McR validate(@RequestBody Map data) {
+
+        log.info("validate, {}", JSON.toJSONString(data));
+
+        boolean approve = false;
+        List<Map> dataList = UtilMap.getList(data, "list");
+        for (Map row : dataList) {
+
+            // 匹配切配工作单, 采购
+            List<Map> formList = (List<Map>) ydClient.queryData(YDParam.builder()
+                            .formUuid("FORM-RK966E71T0LDSTW39WFHE9OQ5GU23FKRRDNLL2")
+                            .searchFieldJson(JSON.toJSONString(UtilMap.map("textField_lmsuq8am, textField_lm8zta2z, textField_ln1ez5li", data.get("name"), data.get("area"), row.get("textField_ln1ez5li"))))
+                            .build(),
+                    YDConf.FORM_QUERY.retrieve_search_form).getData();
+
+            if (formList.size() == 0) {
+                approve = true;
+                break;
+            }
+            Map formData = (Map) formList.get(0).get("formData");
+            float cur = UtilMap.getFloat(row, "numberField_lmym5628");
+            float src = UtilMap.getFloat(formData, "numberField_lnrkgimz");
+            if (cur > src || (src - cur) / src > 0.2f) {
+                approve = true;
+                break;
+            }
+        }
+
+        if (approve) {
+            // 发起菜单审批
+            ydClient.operateData(YDParam.builder()
+                    .formUuid("FORM-UP96637100HD036TA1M05B74GHLV3DRS54NLLC")
+                    .processCode("TPROC--UP96637100HD036TA1M05B74GHLV3ERS54NLLD")
+                    .formDataJson(JSON.toJSONString(data.get("form"))) // 前端数据组装
+                    .userId(data.get("user").toString())
+                    .build(), YDConf.FORM_OPERATION.start);
+
+            // 更新计划状态
+            ydService.operateData(YDParam.builder()
+                    .formInstanceId(data.get("poid").toString())
+                    .updateFormDataJson(JSON.toJSONString(UtilMap.map("textField_lm8znr9n", "执行中")))
+                    .build(), YDConf.FORM_OPERATION.update);
+        }
+
+        return McR.success();
+    }
+
+
     @PostMapping("test")
     McR test(HttpServletRequest request) {
 

+ 12 - 0
mjava-kuaikeli/src/main/resources/application-dev.yml

@@ -22,6 +22,18 @@ spring:
     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: 2737389469

+ 2 - 2
mjava-kuaikeli/src/main/resources/application-prod.yml

@@ -1,8 +1,8 @@
 # 环境配置
 server:
-  port: 9017
+  port: 9016
   servlet:
-    context-path: /api/laidi
+    context-path: /api/kuaikeli
 
 # condition
 spel:

+ 50 - 25
mjava-laidi/src/main/java/com/malk/laidi/controller/LDController.java

@@ -3,20 +3,15 @@ package com.malk.laidi.controller;
 import com.alibaba.fastjson.JSON;
 import com.malk.server.common.McR;
 import com.malk.server.dingtalk.DDConf;
-import com.malk.service.dingtalk.DDClient;
-import com.malk.service.dingtalk.DDClient_Contacts;
-import com.malk.service.dingtalk.DDClient_Storage;
-import com.malk.service.dingtalk.DDClient_Workflow;
+import com.malk.service.dingtalk.*;
 import com.malk.service.h3yun.CYClient;
 import com.malk.utils.UtilMap;
-import com.malk.utils.UtilServlet;
+import com.malk.utils.UtilString;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.collections4.map.HashedMap;
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
 
 import javax.servlet.http.HttpServletRequest;
 import java.util.ArrayList;
@@ -123,35 +118,65 @@ public class LDController {
     @Autowired
     private DDClient_Contacts ddClient_contacts;
 
+    @Autowired
+    private DDService ddService;
+
     /**
      * 同步氚云附件到钉盘
      */
+    @PostMapping("h3yun-http")
+    McR http(@RequestBody Map<String, String> data, @RequestParam String code) {
+
+        log.info("氚云http请求, code = {}, body = {}", code, JSON.toJSONString(data));
+
+        if (UtilString.isNotBlankCompatNull(data.get("attachments")) && StringUtils.isNotBlank(data.get("projectName"))) {
+
+            String spaceId = "2034568562"; // 钉盘空间
+            String parentId = "120089274640"; // 项目管理文件夹
+            String proName = data.get("projectName");
+
+            // 获取用户unionId
+            String unionId = String.valueOf(ddClient_contacts.getUserInfoById(ddClient.getAccessToken(), ddConf.getOperator()).get("unionid"));
+            // 获取项目文件夹 [RETURN_DENTRY_IF_EXISTS: 文件夹名称冲突策略, 返回已存在文件夹, 避免查询文件夹列表]UtilMap.map("conflictStrategy", "RETURN_DENTRY_IF_EXISTS")
+            Map dentry = ddClient_storage.addFolders(ddClient.getAccessToken(), unionId, spaceId, parentId, proName, UtilMap.map("conflictStrategy", "RETURN_DENTRY_IF_EXISTS"));
+
+            // 获取氚云附件ID, 项目名称
+            List<Map> attachments = (List<Map>) JSON.parse(data.get("attachments"));
+            for (Map attachment : attachments) {
+                String urlFile = cyClient.getTemporaryUrls(ddClient.getAccessToken(), String.valueOf(attachment.get("ObjectId")));
+                // 上传文件
+                ddService.uploadFileFormUrlForDingDrive(ddClient.getAccessToken(), unionId, spaceId, String.valueOf(dentry.get("id")), urlFile, String.valueOf(attachment.get("FileName")));
+            }
+        }
+        return McR.success(UtilMap.map("status", "是"));
+    }
+
     @PostMapping("sync-dp")
     McR syncDP(@RequestBody Map data) {
 
-        Map userInfo = ddClient_contacts.getUserInfoById(ddClient.getAccessToken(), ddConf.getOperator());
-        List<Map> spaces = ddClient_storage.getSpaces(ddClient.getAccessToken(), String.valueOf(userInfo.get("unionid")));
 
+        // 获取氚云附件ID, 项目名称
+
+        String spaceId = "2034568562";
+        String proName = "项目AA-2";
+
+        // 获取用户unionId
+        String unionId = String.valueOf(ddClient_contacts.getUserInfoById(ddClient.getAccessToken(), ddConf.getOperator()).get("unionid"));
+        // 获取项目文件夹 [RETURN_DENTRY_IF_EXISTS: 文件夹名称冲突策略, 返回已存在文件夹, 避免查询文件夹列表]UtilMap.map("conflictStrategy", "RETURN_DENTRY_IF_EXISTS")
+        Map dentry = ddClient_storage.addFolders(ddClient.getAccessToken(), unionId, spaceId, "0", proName, UtilMap.map("conflictStrategy", "RETURN_DENTRY_IF_EXISTS"));
+        // 上传文件
+        ddService.uploadFileFormUrlForDingDrive(ddClient.getAccessToken(), ddConf.getOperator(), spaceId, String.valueOf(dentry.get("id")), "https://mc.cloudpure.cn/portal/cloudpure/尾巴.jpg", "尾巴");
         return McR.success();
     }
 
     @PostMapping("test")
     McR test(HttpServletRequest request) {
 
-        Map data = UtilServlet.getParamMap(request);
-        log.info("xxxx, {}", data);
+        // 手动创建钉盘文件夹后, 获取spaceId
+        String unionId = String.valueOf(ddClient_contacts.getUserInfoById(ddClient.getAccessToken(), ddConf.getOperator()).get("unionid"));
+        ddClient_storage.getDentries(ddClient.getAccessToken(), unionId, "2034568562", "0", UtilMap.map("conflictStrategy", "RETURN_DENTRY_IF_EXISTS"));
 
-        List<Map> userList = new ArrayList<>();
-//
-//        List<Map> deptList = cyClient.getDepartmentInfoList(ddClient.getAccessToken(), null);
-//        for (Map dept : deptList) {
-//            userList.addAll(cyClient.getUserInfoList(ddClient.getAccessToken(), String.valueOf(dept.getDefault("id")), true));
-//
-//        }
-//        log.info("xxxx, {}", userList.size());
-
-
-        return McR.success(userList);
+//        ddClient_storage.getSpaces(ddClient.getAccessToken(), unionId);
+        return McR.success();
     }
-
 }

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

@@ -22,16 +22,28 @@ spring:
     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: 2673435445
-  appKey: dingozv6fzkpqkiupd3d
-  appSecret: bO4AA6ujXj8xgLBJI5pR7ns0vRsHCn8Ng9fTf9WF95HTOlCW0oybYpHsuxXuBPiO
-  corpId: dingcc1b1ffad0d5ca1d
+  agentId: 2741708038
+  appKey: ding0zl1or1vcgtirtob
+  appSecret: p_oYq2uaI4SZ-AatzNIb5N0HgothHqQCyJjlqtoy3UdrRNYL8Dak07sRdSRK4I_W
+  corpId: ding9ecc537cefafaf1c35c2f4657eb6378f
   aesKey:
   token:
   robotCode:
-  operator: "16608972969409067"   # 孙中保 [开头0, 需要转一下字符串]
+  operator: "102938654423116841"   # 孙中保 [开头0, 需要转一下字符串]
 
 # h3yun
 h3yun:

+ 1 - 1
mjava-laidi/src/main/resources/application-prod.yml

@@ -1,6 +1,6 @@
 # 环境配置
 server:
-  port: 9016
+  port: 9018
   servlet:
     context-path: /api/kuaikeli
 

+ 87 - 0
mjava-laidi/src/test/resources/sample/CP_Utils.cs

@@ -0,0 +1,87 @@
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using H3;
+
+public class CP_Utils
+{
+
+    /********** 莱蒂 **********/
+
+    /// 附件同步到钉盘
+    public static string syncDingDriveForProject(H3.IEngine engine, string projectName, string attachments) {
+        Dictionary < string, object > bodys = new Dictionary<string, object>();
+        bodys.Add("projectName", projectName); // 项目名称
+        bodys.Add("attachments", attachments);  // 同步附件
+        List < H3.BizBus.ItemSchema > structures = new List<H3.BizBus.ItemSchema>(); // 响应类型
+        structures.Add(new H3.BizBus.ItemSchema("status", "同步状态", H3.Data.BizDataType.String, null));
+        H3.BizBus.BizStructure data = CP_Utils.invokeVendorService(engine, "sync", bodys, structures); // 请求处理
+        // 传递同步状态
+        return data["status"] + string.Empty;
+    }
+
+    /********** 工具 **********/
+
+    /**
+     * 氚云HTTP
+     * 1. code 公用请求,code区分业务逻辑
+     * 2. bodys 请求参数,默认POST,application/json
+     * 3. structures 返回数据格式定义, 统一使用对象响应
+     */
+    public static H3.BizBus.BizStructure invokeVendorService(H3.IEngine engine, string code, Dictionary < string, object > bodys, List < H3.BizBus.ItemSchema > structures) {
+
+        // 请求信息
+        Dictionary < string, string > headers = new Dictionary<string, string>();
+        Dictionary < string, string > querys = new Dictionary<string, string>();
+        querys.Add("code", code);
+
+        // 定义响应数据整体结构体
+        H3.BizBus.BizStructureSchema structureSchema = new H3.BizBus.BizStructureSchema();
+        structureSchema.Add(new H3.BizBus.ItemSchema("code", "结果状态码", H3.Data.BizDataType.Int, null));
+        structureSchema.Add(new H3.BizBus.ItemSchema("success", "请求状态位", H3.Data.BizDataType.Bool, null));
+        structureSchema.Add(new H3.BizBus.ItemSchema("message", "描述信息", H3.Data.BizDataType.String, null));
+        // 定义响应数据的 data 属性 的结构体
+        H3.BizBus.BizStructureSchema dataSchema = new H3.BizBus.BizStructureSchema();
+        foreach(H3.BizBus.ItemSchema itemSchame in structures)
+        {
+            dataSchema.Add(itemSchame);
+        }
+        //将 data 属性的结构体添加进整体的响应数据结构体 [H3.Data.BizDataType.BizStructureArray 集合,H3.Data.BizDataType.BizStructure 对象]
+        structureSchema.Add(new H3.BizBus.ItemSchema("data", "响应数据", H3.Data.BizDataType.BizStructure, dataSchema));
+
+        //调用Invoke接口,系统底层访问第三方接口的Invoke方法
+        H3.BizBus.InvokeResult response = engine.BizBus.InvokeApi(
+            H3.Organization.User.SystemUserId, //固定值,无需改变
+            H3.BizBus.AccessPointType.ThirdConnection, //固定值,无需改变
+            "h3yun-http", //连接编码,对应 插件中心 中配置的连接的编码
+            "POST", //请求方式,取值:GET / POST
+            "application/json", //请求数据类型: json - "application/json";xml - "text/html;charset=utf-8"
+            headers, querys, bodys, structureSchema);
+        if(response != null)
+        {
+            // 氚云调用是否成功
+            if(response.Code == 0)
+            {
+                // 获取返回数据,此实例对应完整的响应JSON
+                H3.BizBus.BizStructure rspData = response.Data;
+                if(((bool) rspData["success"]) == true)
+                {
+                    // 对象响应【氚云自定义字段,需要通过[]直接取值才有效,序列化后返回前端,仅会保留结构】
+                    // H3.BizBus.BizStructure[] datas = rspData["data"] as H3.BizBus.BizStructure[]; // 集合解析
+                    // H3.BizBus.BizStructure data = rspData["data"] as H3.BizBus.BizStructure; // 对象解析
+                    return rspData["data"] as H3.BizBus.BizStructure;
+                } else
+            {
+                throw new Exception("响应异常," + rspData["message"]);
+            }
+        } else
+        {
+            throw new Exception("氚云异常," + response.Message);
+        }
+    } else
+    {
+        throw new Exception("系统异常,接口无响应");
+    }
+}
+}

+ 42 - 0
mjava-laidi/src/test/resources/sample/附件同步钉盘.cs

@@ -0,0 +1,42 @@
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using H3;
+
+public class D00086761755ee1ac3a4f30ab5aea330c1c47ff: H3.SmartForm.SmartFormController
+{
+    public D00086761755ee1ac3a4f30ab5aea330c1c47ff(H3.SmartForm.SmartFormRequest request): base(request)
+    {
+    }
+
+    protected override void OnLoad(H3.SmartForm.LoadSmartFormResponse response)
+    {
+        base.OnLoad(response);
+    }
+
+    protected override void OnSubmit(string actionName, H3.SmartForm.SmartFormPostValue postValue, H3.SmartForm.SubmitSmartFormResponse response)
+    {
+        // 表单提交:由于附件控件新增的时候获取不了ID,因此通过前端传递传递。注意1:非Submit的情况下,不能通过 this.Request.BizObject["组件ID"] 取值。注意2:前端 AfterSubmit 提交后事件 调用服务不执行
+        if(actionName == "sync")
+        {
+            // 附件控件 [注意:前端直接获取的附件ID,无文件相关信息。若需要如文件名称,需要单独再查询SQL]
+            System.Data.DataTable attachments = this.Engine.Query.QueryTable(string.Format("select * from H_bizobjectfile where ObjectId in ({0})", this.Request["attachmentIds"]), null);
+            // 请求处理 [项目名称,附件]
+            string status = CP_Utils.syncDingDriveForProject(this.Engine, this.Request["projectName"] + string.Empty, this.Serialize(attachments));
+            // 更新同步状态
+            this.Engine.Query.QueryTable(string.Format("update i_D00086761755ee1ac3a4f30ab5aea330c1c47ff set F0000003 = '{0}' where ObjectId = '{1}'", status, this.Request.BizObjectId), null);
+        }
+        // 审批节点:后端通过获取即可得到附件对象,返回值与H_bizobjectfile 结构一致
+        if(actionName == "Submit" && this.Request.ActivityCode == "Activity3")
+        {
+            // 附件控件 [注意:新增的时候获取不了ID,包含发起审批节点]
+            H3.DataModel.BizObjectFileHeader[] files = (H3.DataModel.BizObjectFileHeader[]) this.Request.BizObject["F0000001"];
+            // 请求处理 [项目名称,附件]
+            string status = CP_Utils.syncDingDriveForProject(this.Engine, this.Request.BizObject["F0000002"] + string.Empty, this.Serialize(files));
+            // 更新同步状态
+            this.Engine.Query.QueryTable(string.Format("update i_D00086761755ee1ac3a4f30ab5aea330c1c47ff set F0000003 = '{0}' where ObjectId = '{1}'", status, this.Request.BizObjectId), null);
+        }
+        base.OnSubmit(actionName, postValue, response);
+    }
+}

+ 50 - 0
mjava-laidi/src/test/resources/sample/附件同步钉盘.js

@@ -0,0 +1,50 @@
+/* 控件接口说明:
+ * 1. 读取控件: this.***,*号输入控件编码;
+ * 2. 读取控件的值: this.***.GetValue();
+ * 3. 设置控件的值: this.***.SetValue(???);
+ * 4. 绑定控件值变化事件: this.***.BindChange(key,function(){}),key是定义唯一的方法名;
+ * 5. 解除控件值变化事件: this.***.UnbindChange(key);
+ * 6. CheckboxList、DropDownList、RadioButtonList: $.***.AddItem(value,text),$.***.ClearItems();
+ */
+/* 公共接口:
+ * 1. ajax:$.SmartForm.PostForm(actionName,data,callBack,errorBack,async),
+ *          actionName:提交的ActionName;data:提交后台的数据;callback:回调函数;errorBack:错误回调函数;async:是否异步;
+ * 2. 打开表单:$.IShowForm(schemaCode, objectId, checkIsChange),
+ *          schemaCode:表单编码;objectId;表单数据Id;checkIsChange:关闭时,是否感知变化;
+ * 3. 定位接口:$.ILocation();
+ */
+
+// 表单插件代码
+$.extend($.JForm, {
+    // 加载事件
+    OnLoad: function () {
+
+        this.F0000001.BindChange("F0000001", () => {
+            console.log(this.F0000001.GetValue())
+
+            // 表单提交:由于附件控件新增的时候获取不了ID,因此通过前端传递传递。注意1:非Submit的情况下,不能通过 this.Request.BizObject["组件ID"] 取值。注意2:前端 AfterSubmit 提交后事件 调用服务不执行
+            // const attachmentIds = this.F0000001.GetValue().AttachmentIds.split(";").map(item => `'${item}'`);
+            // $.SmartForm.PostForm("sync", { "attachmentIds": attachmentIds.join(","), "projectName": this.F0000002.GetValue() })
+        })
+    },
+
+    // 按钮事件
+    OnLoadActions: function (actions) {
+    },
+
+    // 提交校验
+    OnValidate: function (actionControl) {
+        return true;
+    },
+
+    // 提交前事件
+    BeforeSubmit: function (action, postValue) {
+        // 表单提交:由于附件控件新增的时候获取不了ID,因此通过前端传递传递。注意1:非Submit的情况下,不能通过 this.Request.BizObject["组件ID"] 取值。注意2:前端 AfterSubmit 提交后事件 调用服务不执行
+        // const attachmentIds = this.F0000001.GetValue().AttachmentIds.split(";").map(item => `'${item}'`);
+        // $.SmartForm.PostForm("sync", { "attachmentIds": attachmentIds.join(","), "projectName": this.F0000002.GetValue() })
+    },
+
+    // 提交后事件
+    AfterSubmit: function (action, responseValue) {
+    }
+});

+ 21 - 0
mjava-luyi/src/main/java/com/malk/luyi/controller/LYController.java

@@ -75,6 +75,27 @@ public class LYController {
         return McR.success(ddr_new2);
     }
 
+
+    /**
+     * 细胞查询
+     */
+    @PostMapping("cell/query")
+    McR cell(@RequestBody Map data) {
+
+        log.info("细胞查询, {}", data);
+        McException.assertParamException_Null(data, "cardNo, name, page, size");
+
+        // 查询细胞结果
+        DDR_New ddr_new2 = ydClient.queryData(YDParam.builder()
+                .formUuid("FORM-FDA66N818YLEFETQ694XF5GV8CN73D6NFMFNLE")
+                .searchFieldJson(JSON.toJSONString(UtilMap.map("textField_lnspbi7w, textField_lnfmfzth", data.get("cardNo"), data.get("name"))))
+                .pageNumber(UtilMap.getInt(data, "page"))
+                .pageSize(UtilMap.getInt(data, "size"))
+                .dynamicOrder(JSON.toJSONString(UtilMap.map("dateField_lnsva9el", "-")))
+                .build(), YDConf.FORM_QUERY.retrieve_search_form);
+        return McR.success(ddr_new2);
+    }
+
     /**
      * 免登地址
      */

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

@@ -0,0 +1,32 @@
+package com.malk.mcli;
+
+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. 标识对表没有任何操作. 若不设置为 none, 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);
+    }
+}

+ 53 - 0
mjava-mcli/src/main/java/com/malk/mcli/controller/TControl.java

@@ -0,0 +1,53 @@
+package com.malk.mcli.controller;
+
+import com.alibaba.fastjson.JSON;
+import com.malk.server.aliwork.YDConf;
+import com.malk.server.aliwork.YDParam;
+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.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;
+
+/**
+ * 错误抛出与拦截详见CatchException
+ */
+@Slf4j
+@RestController
+@RequestMapping("/t")
+public class TControl {
+
+    @Autowired
+    private YDClient ydClient;
+
+    @PostMapping("test")
+    McR test() {
+
+        ydClient.operateData(YDParam.builder()
+                .formUuid("FORM-33666CB1C60F2AYREV95GC73TI3R3U5TU1NNLD")
+                .formDataJson(JSON.toJSONString(UtilMap.map("employeeField_lnn1v0s6", Arrays.asList("681140625426103999"))))
+                .processCode("TPROC--33666CB1C60F2AYREV95GC73TI3R3V5TU1NNLE")
+                .build(), YDConf.FORM_OPERATION.start);
+        return McR.success();
+    }
+
+    @Autowired
+    private DDClient ddClient;
+
+    @Autowired
+    private DDClient_Contacts ddClient_contacts;
+
+    @PostMapping("test11")
+    McR test11() {
+
+        ddClient_contacts.getUserInfoById(ddClient.getAccessToken(), "095515432139833944");
+        return McR.success();
+    }
+}

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

@@ -43,15 +43,15 @@ logging:
 
 # dingtalk
 dingtalk:
-  agentId: 2533464721
-  appKey: dingromjxexd1esgvwwg
-  appSecret: AcStrL5bdw69gqeUfTQiFoBsgqisL2g-egzaKyID9Q7d85f_z9EkuTSS9Vse6zDb
-  corpId: ding5e83ad92d917b47535c2f4657eb6378f
-  aesKey: NgBOhTTp38RmPYs3gz7xBRHGNhwLHAv3tZntZ6He54F
-  token: yLQuiiYIBvrzN3tmOduDn
+  agentId: 2704247534
+  appKey: dingqmijjypfepl0tsuq
+  appSecret: dixOqjK4Zw8PajvrtY1mbKxs4DIJJJmq6WvqdSDTCStBWAPyTeobgQFxZ1VhH-Z3
+  corpId: ding321c72787fffc78b35c2f4657eb6378f
+  aesKey:
+  token:
 
 # aliwork
 aliwork:
-  appType: APP_IW1FN8PPGGYQBWVMXS69
-  systemToken: UT866MB1WGX8VU029U93IA9DIKEG2GE9UU7FLI5
+  appType: APP_WBJG1I16K1N2L1FFQ3BX
+  systemToken: KBB665A1ABB3A25Q9U2346GV9VMT3TLW1F77L76
 

+ 8 - 8
mjava-mcli/target/classes/application-dev.yml

@@ -43,15 +43,15 @@ logging:
 
 # dingtalk
 dingtalk:
-  agentId: 2533464721
-  appKey: dingromjxexd1esgvwwg
-  appSecret: AcStrL5bdw69gqeUfTQiFoBsgqisL2g-egzaKyID9Q7d85f_z9EkuTSS9Vse6zDb
-  corpId: ding5e83ad92d917b47535c2f4657eb6378f
-  aesKey: NgBOhTTp38RmPYs3gz7xBRHGNhwLHAv3tZntZ6He54F
-  token: yLQuiiYIBvrzN3tmOduDn
+  agentId: 2704247534
+  appKey: dingqmijjypfepl0tsuq
+  appSecret: dixOqjK4Zw8PajvrtY1mbKxs4DIJJJmq6WvqdSDTCStBWAPyTeobgQFxZ1VhH-Z3
+  corpId: ding321c72787fffc78b35c2f4657eb6378f
+  aesKey:
+  token:
 
 # aliwork
 aliwork:
-  appType: APP_IW1FN8PPGGYQBWVMXS69
-  systemToken: UT866MB1WGX8VU029U93IA9DIKEG2GE9UU7FLI5
+  appType: APP_WBJG1I16K1N2L1FFQ3BX
+  systemToken: KBB665A1ABB3A25Q9U2346GV9VMT3TLW1F77L76
 

+ 54 - 0
mjava-taisen/pom.xml

@@ -0,0 +1,54 @@
+<?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-taisen</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>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>2.1.1.RELEASE</version>
+                <configuration>
+                    <includeSystemScope>true</includeSystemScope>
+                    <!-- 如果没有该配置,devtools不会生效: 打包时关闭 -->
+                    <fork>false</fork>
+                    <!-- 避免中文乱码 -->
+                    <jvmArguments>-Dfile.encoding=UTF-8</jvmArguments>
+                </configuration>
+                <!-- 允许生成可运行jar -->
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+        <finalName>${project.artifactId}</finalName>
+    </build>
+</project>

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

@@ -0,0 +1,32 @@
+package com.malk.taisen;
+
+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. 标识对表没有任何操作. 若不设置为 none, 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);
+    }
+}

+ 205 - 0
mjava-taisen/src/main/java/com/malk/taisen/controller/TSController.java

@@ -0,0 +1,205 @@
+package com.malk.taisen.controller;
+
+/**
+ * 错误抛出与拦截详见 CatchException
+ */
+
+import com.alibaba.fastjson.JSON;
+import com.malk.server.aliwork.YDConf;
+import com.malk.server.aliwork.YDParam;
+import com.malk.server.common.McR;
+import com.malk.service.aliwork.YDClient;
+import com.malk.service.aliwork.YDService;
+import com.malk.utils.UtilDateTime;
+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.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@Slf4j
+@RestController
+@RequestMapping
+public class TSController {
+
+    @Autowired
+    private YDClient ydClient;
+
+    @Autowired
+    private YDConf ydConf;
+
+    @PostMapping("test11")
+    McR test11() {
+
+
+        // 丢行处理
+
+        // 孙静
+//        String tId = "f54bb1ab-e989-4b61-ad9b-7cd9e2dab69b";
+//        String sId = "62f796fd-b35d-4db8-85ad-c14dbc2050ad";
+
+        // 陈黛珠
+//        String tId = "96af9edc-83cb-4027-9687-8ec0e1cbd4eb";
+//        String sId = "5005d16d-a392-43a6-bdcb-c1ae93d30deb";
+
+        // 陈豹
+        String tId = "640cff6e-89fb-4d50-9c45-aa2fcf8b06d5";
+        String sId = "13dfaba7-7f27-4f51-bcb6-5c8d71b758c1";
+
+        Map formData = ydClient.queryData(YDParam.builder()
+                        .formInstanceId(tId)
+                        .build(),
+                YDConf.FORM_QUERY.retrieve_id).getFormData();
+        List<Map> details = ((List<Map>) formData.get("tableField_l6lmxo5r")).stream().map(item -> {
+            item.put("associationFormField_l6vk2yxg", JSON.parse(item.get("associationFormField_l6vk2yxg_id").toString()));
+            // 关联申请
+//            List<Map> dataList = (List<Map>) ydClient.queryData(YDParam.builder()
+//                            .formUuid("FORM-78766VC1KTX2HZQ6E6IR3CYXWUFU3RO8RGN6L6")
+//                            .searchFieldJson(JSON.toJSONString(UtilMap.map("employeeField_l82gi80j, numberField_l6ngrh2h", formData.get("employeeField_l843wfsm_id"), Arrays.asList(item.get("numberField_l6lmxo60"), item.get("numberField_l6lmxo60")))))
+//                            .build(),
+//                    YDConf.FORM_QUERY.retrieve_search_form).getData();
+//            item.put("associationFormField_l6napwww", ydConf.associationForm("FORM-78766VC1KTX2HZQ6E6IR3CYXWUFU3RO8RGN6L6", dataList.get(0).get("formInstanceId").toString(), "深圳", null, false));
+            return item;
+        }).collect(Collectors.toList());
+
+        Map updateForm = UtilMap.map("tableField_l6lmxo5r", details);
+        ydClient.operateData(YDParam.builder()
+                .formInstanceId(sId)
+                .updateFormDataJson(JSON.toJSONString(updateForm)).build(), YDConf.FORM_OPERATION.update);
+
+        return McR.success(formData);
+    }
+
+    // 当前表税率为0处理
+    @PostMapping("test13")
+    McR test13() {
+
+        String fid = "0fa54443-8253-4f70-b1b7-18850e20a683";
+
+        Map formData = ydClient.queryData(YDParam.builder()
+                .formInstanceId(fid)
+                .build(), YDConf.FORM_QUERY.retrieve_id).getFormData();
+        List<Map> details = (List<Map>) formData.get("tableField_l6lmxo5r");
+
+        details.forEach(item -> {
+
+//            if (UtilString.isBlankCompatNull(String.valueOf(item.get("numberField_l6lmxo61")))) {
+//                item.put("numberField_l6lmxo61", 0);
+//            }
+//            item.put("associationFormField_l6vk2yxg", JSON.parse(String.valueOf(item.get("associationFormField_l6vk2yxg_id"))));
+//            item.put("associationFormField_l6napwww", JSON.parse(String.valueOf(item.get("associationFormField_l6napwww_id"))));
+
+            log.info("xxxx, {}", item.get("numberField_l6lmxo61"));
+        });
+
+        Map updateForm = UtilMap.map("tableField_l6lmxo5r", details);
+
+//        ydClient.operateData(YDParam.builder()
+//                .formInstanceId(fid)
+//                .updateFormDataJson(JSON.toJSONString(updateForm)).build(), YDConf.FORM_OPERATION.update);
+
+        return McR.success(updateForm);
+    }
+
+    @Autowired
+    private YDService ydService;
+
+    // 变更记录
+    @PostMapping("changed")
+    McR changed() {
+
+        for (int i = 1; i <= 40; i++) {
+
+            List<Map> dataList = (List<Map>) ydClient.queryData(YDParam.builder()
+                    .formUuid("FORM-UX866Q61LRK2LACIB8A6M6T1ZOLM2VY5NYB6LZ")
+                    .pageNumber(i)
+                    .currentPage(i)
+                    .build(), YDConf.FORM_QUERY.retrieve_search_form).getData();
+
+            Map<String, List<Map>> record = ydClient.queryData(YDParam.builder()
+                    .formUuid("FROM-UX866Q61LRK2LACIB8A6M6T1ZOLM2VY5NYB6LZ")
+                    .formInstanceIdList(dataList.stream().map(item -> String.valueOf(item.get("formInstanceId"))).collect(Collectors.toList()))
+                    .build(), YDConf.FORM_QUERY.retrieve_changed).getOperationLogMap();
+            for (String id : record.keySet()) {
+
+                Map form = dataList.stream().filter(item -> item.get("formInstanceId").equals(id)).findAny().get();
+                Map data = (Map) form.get("formData");
+                Map formData = UtilMap.map("associationFormField_lnukdrl8", ydConf.associationForm("FORM-UX866Q61LRK2LACIB8A6M6T1ZOLM2VY5NYB6LZ", id, String.valueOf(form.get("title")), null, true));
+                formData.put("textField_lnulmox7", data.get("textField_l7a7bf8d"));
+                formData.put("employeeField_lnulmox8", data.get("employeeField_l843wfsm_id"));
+
+                List<Map> details = record.get(id).stream().map(item -> UtilMap.map("textField_lnukfzeh, textField_lnukfzei, textField_lnukfzej, textField_lnukfzel, textField_lnukfzek, textField_lnukfzem",
+                        item.get("currentText"), item.get("preText"), item.get("gmtModified"), item.get("componentName"), item.get("operationType"), UtilMap.getMap(item, "operator").get("displayName")))
+                        .collect(Collectors.toList());
+                formData.put("tableField_lnukfzeg", details);
+                ydClient.operateData(YDParam.builder()
+                        .formUuid("FORM-4W8667D1440FEE4PFEX586YVOCEN3EXFDKUNLB1")
+                        .formDataJson(JSON.toJSONString(formData))
+                        .build(), YDConf.FORM_OPERATION.create);
+            }
+
+        }
+
+        return McR.success();
+    }
+
+
+    /// 广舜临时修改
+    @PostMapping("gc")
+    McR gc() {
+
+
+//        ydClient.operateData(YDParam.builder()
+//                .formInstanceId("39e50d18-fcd4-4b19-b825-23d421a255ff")
+//                .updateFormDataJson(JSON.toJSONString(UtilMap.map("textField_llalwnd7", "HA0051C")))
+//                .build(), YDConf.FORM_OPERATION.update);
+
+        List<Map> dataList = (List<Map>) ydClient.queryData(YDParam.builder()
+                .formUuid("FORM-08866RA1SPVC8CISDK79NBIXH4ZT3CBF61MKL0")
+                .dynamicOrder(JSON.toJSONString(UtilMap.map("gmt_create", "+")))
+                .build(), YDConf.FORM_QUERY.retrieve_search_process).getData();
+
+        Collections.reverse(dataList);
+
+        int i = 1;
+        for (Map formData : dataList) {
+
+            String newS = String.valueOf(UtilMap.getMap(formData, "data").get("textField_llalwnd7"));
+            if (UtilMap.getMap(formData, "data").containsKey("textField_lmu9nuzp")) {
+                newS += "-" + String.valueOf(UtilMap.getMap(formData, "data").get("textField_lmu9nuzp"));
+            } else {
+                newS += "-" + "M";
+            }
+            if (i > 9) {
+                newS += "00" + i;
+            } else {
+                newS += "000" + i;
+            }
+            newS += UtilDateTime.format(new Date(Long.valueOf(String.valueOf(UtilMap.getMap(formData, "data").get("dateField_llabt1ft")))), "yyMMdd");
+
+            log.info("xxxx, {}, ", newS);
+            ydClient.operateData(YDParam.builder()
+                    .formInstanceId(String.valueOf(formData.get("processInstanceId")))
+                    .updateFormDataJson(JSON.toJSONString(UtilMap.map("textField_lkkmaxdw, serialNumberField_lnlu5r43", newS, newS)))
+                    .build(), YDConf.FORM_OPERATION.update);
+            i++;
+//
+        }
+        return McR.success();
+    }
+
+
+    @PostMapping("test")
+    McR test() {
+
+        log.info("xxxx, {}");
+        return McR.success();
+    }
+}

+ 69 - 0
mjava-taisen/src/main/resources/application-dev.yml

@@ -0,0 +1,69 @@
+# 环境配置
+server:
+  port: 9001
+  servlet:
+    context-path: /api/taisen
+
+# 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
+  jpa:
+    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: 1782962089
+  appKey: dingfnrpklgoaoynrbsw
+  appSecret: 6FxZudtXjdYeHNQN7-Os_A-zXGF7slS7UX9d3alu9uIsK56w4gXiZN0yXPp67FDh
+  corpId: dinge61fe69900ea236b35c2f4657eb6378f
+  aesKey:
+  token:
+  operator: "01021447385039757257"   # OA管理员账号
+
+# aliwork
+aliwork:
+  appType: "APP_N9NPHVTQLPBPO8MR6WFG"
+  systemToken: "UM6660D1PGF2O34KAVVKG8XZ756E3O06MZX5LW"
+
+
+
+# 广舜临时修改
+# dingtalk
+#dingtalk:
+#  agentId: 2765522257
+#  appKey: ding9jyvueuuisilts3k
+#  appSecret: BmMpcEZqh7zqh-J5k0bw6ZZnz9-h0CwMufb9Vig1LMjqL4LRiWnuh1kV9BjvJLz4
+#  corpId: ding118abe041e66b68535c2f4657eb6378f
+#  aesKey:
+#  token:
+#  operator: ""   # OA管理员账号
+#
+## aliwork
+#aliwork:
+#  appType: "APP_DKH67ZJCOYTS28FQKR2P"
+#  systemToken: "UIA663C1XGSCK4YCF7HBSDK01NMJ3THCHOHKL7O2"
+

+ 38 - 0
mjava-taisen/src/main/resources/application-prod.yml

@@ -0,0 +1,38 @@
+# 环境配置
+server:
+  port: 9018
+  servlet:
+    context-path: /api/taisen
+
+# 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: 2660236361
+  appKey: dinguuieqv4lkvp3vkaf
+  appSecret: N5JjPU9RDk77pTze5vRWmiWLDjPKeYJV3sQrmYgN_SC57nOALmj570rVB0SGGcQQ
+  corpId: dingec9ee223c2b3a671
+  aesKey:
+  token:
+  operator: ""   # OA管理员账号
+
+# aliwork
+aliwork:
+  appType: APP_FX4PR3OWW4WCFOHI2ZSR
+  systemToken: 2G766HA1RDHC1C2CCRY62544NL8L21T5786KL27

+ 15 - 1
mjava-zhuogao/src/main/java/com/malk/zhuogao/controller/ZGController.java

@@ -9,6 +9,8 @@ import com.malk.utils.UtilDateTime;
 import com.malk.utils.UtilExcel;
 import com.malk.utils.UtilMap;
 import com.malk.utils.UtilString;
+import com.malk.zhuogao.repository.dao.TrustDeviceDao;
+import com.malk.zhuogao.repository.entity.TrustDevicePo;
 import com.malk.zhuogao.repository.entity.ZSDFileRecordPo;
 import com.malk.zhuogao.service.ZSDClient_File;
 import lombok.SneakyThrows;
@@ -130,7 +132,19 @@ public class ZGController {
         return McR.success(records);
     }
 
+    @Autowired
+    private TrustDeviceDao trustDeviceDao;
 
-}
+    /// 可信设备, 需要启停账号, 重新登录才会生效, 客户需要立即生效因此通过接口操作
+    @PostMapping("device")
+    McR device() {
 
+        List<TrustDevicePo> dataList = trustDeviceDao.findAll();
+        for (TrustDevicePo po : dataList) {
+//            ddClient_orgapp.orgAccountsDisable(ddClient.getAccessToken(), po.getUserId());
+            ddClient_orgapp.orgAccountsEnable(ddClient.getAccessToken(), po.getUserId());
+        }
+        return McR.success(dataList);
 
+    }
+}

+ 18 - 0
mjava-zhuogao/src/main/java/com/malk/zhuogao/repository/dao/TrustDeviceDao.java

@@ -0,0 +1,18 @@
+package com.malk.zhuogao.repository.dao;
+
+import com.malk.zhuogao.repository.entity.TrustDevicePo;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+
+import javax.transaction.Transactional;
+
+/**
+ * 接口多继承
+ * -
+ * - JpaRepository 中有常用的 CRUD 、分页、排序等方法
+ * - JpaSpecificationExecutor 可以实现任意的复杂查询
+ */
+@Transactional
+public interface TrustDeviceDao extends JpaRepository<TrustDevicePo, Long>, JpaSpecificationExecutor<TrustDevicePo> {
+
+}

+ 25 - 0
mjava-zhuogao/src/main/java/com/malk/zhuogao/repository/entity/TrustDevicePo.java

@@ -0,0 +1,25 @@
+package com.malk.zhuogao.repository.entity;
+
+import com.malk.base.BasePo;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.persistence.Entity;
+import javax.persistence.Table;
+
+@Entity
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+@Table(name = "trust_device")
+@Slf4j
+public class TrustDevicePo extends BasePo {
+
+    private String name;
+
+    private String userId;
+}

+ 3 - 1
mjava/src/main/java/com/malk/server/aliwork/YDConf.java

@@ -58,7 +58,8 @@ public class YDConf {
         retrieve_search_process_id,         // 流程列表
         retrieve_search_form_id,             // 表单列表
 
-        retrieve_details             // 子表数据[表单]
+        retrieve_details,             // 子表数据[表单]
+        retrieve_changed    // 变更记录
 
     }
 
@@ -80,6 +81,7 @@ public class YDConf {
      * 关联表单处理
      *
      * @param formType: "receipt" 跳转为表单【若是流程,则权限体系会失效,但也会显示审批节点】; formType: "process" 为流程
+     * @apiNote ppExt 接口更新, 传入jsonString或List都可以. 返回数据都是两层json解析, 组件 + _id格式
      */
     public List<Map> associationForm(String formUuid, String formInstanceId, String title, String subTitle, boolean isProcess) {
         String formType = isProcess ? "process" : "receipt";

+ 4 - 0
mjava/src/main/java/com/malk/server/aliwork/YDParam.java

@@ -159,6 +159,10 @@ public class YDParam extends BaseDto {
     @Builder.Default
     boolean useLatestFormSchemaVersion = true;
 
+    // 使用最新的表单版本进行更新。
+    @Builder.Default
+    boolean useLatestVersion = false;
+
     /**
      * 分组校验
      *

+ 1 - 1
mjava/src/main/java/com/malk/server/common/McREnum.java

@@ -11,7 +11,7 @@ public enum McREnum {
     IGNORE_EXECUTE(true, "200", "IGNORE THE CURRENT EXECUTE RESULT"),
     VALIDATED_PARAM(false, "4001", "PARAMETER VERIFICATION FAILS"),
     TOKEN_INVALID(false, "4002", "TOKEN INVALID"),
-    NOT_AUTHORIZED(false, "4003", "NOT AUTHORIZED"),
+    NOT_AUTHORIZED(false, "4003", "ERROR INVALID AUTH STATE"),
     VALIDATED_ACCESS(false, "4004", "VALIDATE IS DISSATISFY THE CONDITION"),
     METHOD_EXECUTE(false, "5001", "ENCOUNTER AN ERROR WHEN EXECUTE METHOD"),
     NULL_POINTER(false, "5002", "ENCOUNTER AN ERROR NULL POINTER EXCEPTION"),

+ 2 - 0
mjava/src/main/java/com/malk/server/dingtalk/DDConf.java

@@ -23,6 +23,8 @@ public class DDConf {
 
     private String corpId;
 
+    private String corpToken;
+
     private String aesKey;
 
     private String token;

+ 7 - 9
mjava/src/main/java/com/malk/server/dingtalk/DDR_New.java

@@ -62,18 +62,11 @@ public class DDR_New<T> extends VenR {
 
     private Map formData;
 
-    //// CRM ////
-
     /**
-     * 客户元数据
+     * 变更记录
      */
-    private String name;
-
-    private boolean customized;
-
-    private List<Map> fields;
+    private Map operationLogMap;
 
-    private boolean status;
 
     ////  储存空间  ////
 
@@ -107,8 +100,13 @@ public class DDR_New<T> extends VenR {
      */
     private String nextToken;
 
+    /// 空间列表
     private List<Map> spaces;
 
+    /// 文件或文件夹列表
+    private List<Map> dentries;
+
+
     ////  专属钉  ////
 
     // 避免无数据返回空

+ 5 - 2
mjava/src/main/java/com/malk/service/aliwork/impl/YDClientImpl.java

@@ -73,14 +73,14 @@ public class YDClientImpl implements YDClient {
                 break;
             case multi_update:
                 ddr_new = (DDR_New) UtilHttp.doPut(getRequestUrl("/forms/instances/components"), ddClient.initTokenHeader(), bodys, DDR_New.class);
-                return ddr_new.getResult(); // 表单实例Id
+                break;
             case batchSave:
                 ddr_new = (DDR_New) UtilHttp.doPost(getRequestUrl("/forms/instances/batchSave"), ddClient.initTokenHeader(), null, _initBodyParam(ydParam), DDR_New.class);
                 break;
             default:
                 break;
         }
-        return ddr_new.getData();
+        return ddr_new.getResult();
     }
 
     /**
@@ -121,6 +121,9 @@ public class YDClientImpl implements YDClient {
             case retrieve_details:
                 ddr_new = DDR_New.doGet(getRequestUrl("/forms/innerTables", ydParam.getFormInstanceId()), ddClient.initTokenHeader(), param);
                 break;
+            case retrieve_changed:
+                ddr_new = DDR_New.doPost(getRequestUrl("/forms/operationsLogs/query"), ddClient.initTokenHeader(), null, param);
+                break;
         }
         return ddr_new;
     }

+ 0 - 1
mjava/src/main/java/com/malk/service/aliwork/impl/YDServiceImpl.java

@@ -40,7 +40,6 @@ public class YDServiceImpl implements YDService {
         return ydClient.operateData(ydParam, type);
     }
 
-
     @Async
     @SneakyThrows
     @Override

+ 0 - 11
mjava/src/main/java/com/malk/service/dingtalk/DDClient_CRM.java

@@ -1,11 +0,0 @@
-package com.malk.service.dingtalk;
-
-import com.malk.server.dingtalk.DDR_New;
-
-public interface DDClient_CRM {
-
-    /**
-     * 获取个人或企业客户的元数据
-     */
-    DDR_New getObjectMetaFromPersonalCustomers(String accessToken, String relationType);
-}

+ 4 - 1
mjava/src/main/java/com/malk/service/dingtalk/DDClient_Contacts.java

@@ -39,7 +39,10 @@ public interface DDClient_Contacts {
     List<String> listDepartmentUserId(String access_token, long dept_id);
 
     /**
-     * 查询用户详情 [如入职时间 手机号等, 需要再=在花名册添加员工可见, 接口才会返回]
+     * 查询用户详情
+     * -
+     * [如入职时间 手机号等, 需要再在花名册添加员工可见, 接口才会返回]
+     * ppExt: 企业邮箱org_email, 若无则字段不返回; 手机号telephone无值, 但mobile会返回
      */
     Map getUserInfoById(String access_token, String userId);
 

+ 11 - 0
mjava/src/main/java/com/malk/service/dingtalk/DDClient_Dedicated.java

@@ -15,4 +15,15 @@ public interface DDClient_Dedicated {
      * @param preLastRecord nextGmtCreate/nextBizId,作为分页偏移量。[如果是非首次调用,该参数传上次调用时返回的最后一条记录的值。]
      */
     List<Map> obtainFileOperationRecords(String accessToken, @NotNull long startDate, @NotNull long endDate, @NotNull int pageSize, Map preLastRecord);
+
+    /**
+     * 启用企业帐号
+     **/
+
+    boolean orgAccountsEnable(String accessToken, String userId);
+
+    /**
+     * 停用企业帐号
+     */
+    boolean orgAccountsDisable(String accessToken, String userId);
 }

+ 19 - 1
mjava/src/main/java/com/malk/service/dingtalk/DDClient_Storage.java

@@ -18,12 +18,28 @@ public interface DDClient_Storage {
     DDR_New createSpaces(String accessToken, String name, String unionId);
 
     /**
-     * 获取空间列表
+     * 获取空间列表 [钉盘-团队文件-第一层目录列表]
      *
      * @implSpec 忽略分页, 一次性全量查询
      */
     List<Map> getSpaces(String accessToken, String unionId);
 
+    /**
+     * 获取文件或文件夹列表
+     *
+     * @param parentId 父目录Id。根目录时,该参数是0
+     * @implSpec 忽略分页, 一次性全量查询; extInfo 非必填参数
+     */
+    List<Map> getDentries(String accessToken, String unionId, String spaceId, String parentId, Map extInfo);
+
+    /**
+     * 添加文件夹
+     *
+     * @param name   文件夹的名称,命名有以下要求:头尾不能包含空格,否则会自动去除; 不能包含特殊字符,包括:制表符、*、"、<、>、|; 不能以"."结尾
+     * @param option ppExt: 文件夹名称冲突策略, 返回已存在文件夹, 避免查询文件夹列表  UtilMap.map("conflictStrategy", "RETURN_DENTRY_IF_EXISTS")
+     */
+    Map addFolders(String accessToken, String unionId, String spaceId, String parentId, String name, Map option);
+
     ///////////////////////// OA审批附件 /////////////////////////
 
     /**
@@ -45,6 +61,8 @@ public interface DDClient_Storage {
      */
     boolean addSpacePermissions(String access_token, String spaceId, String dentryId, String unionId, String roleId, List<Map> members, Map option);
 
+    ///////////////////////// 通用上传逻辑 /////////////////////////
+
     /**
      * 获取文件上传信息
      *

+ 12 - 2
mjava/src/main/java/com/malk/service/dingtalk/DDService.java

@@ -21,14 +21,24 @@ public interface DDService {
      * @param urlFile      远程文件地址
      * @param fileNamePure 文件名称[后缀自动通过地址获取]
      */
-    Map uploadFileFormUrl(String accessToken, String userId, String urlFile, String fileNamePure);
+    Map uploadFileFormUrlForOverflow(String accessToken, String userId, String urlFile, String fileNamePure);
 
     /**
      * 上传审批附件
      *
      * @param filePath 已存在文件, 本地file绝对路径
      */
-    Map uploadFileFormUrl(String accessToken, String userId, String filePath);
+    Map uploadFileFormUrlForOverflow(String accessToken, String userId, String filePath);
+
+
+    /**
+     * 上传钉盘文件
+     *
+     * @param urlFile      远程文件地址
+     * @param fileNamePure 氚云前端直接获取的附件ID,且免登后也无文件相关信息。若需要如文件名称,需要单独再查询SQL. 因此不能通过url截取文件名称
+     * @param unionId      String.valueOf(ddClient_contacts.getUserInfoById(ddClient.getAccessToken(), ddConf.getOperator()).get("unionid"));
+     */
+    Map uploadFileFormUrlForDingDrive(String accessToken, String unionId, String spaceId, String parentId, String urlFile, String fileNamePure);
 
     // todo 通讯录部门结构返回; 通讯录全量数据同步; 限流控制
 

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

@@ -1,21 +0,0 @@
-package com.malk.service.dingtalk.impl;
-
-import com.malk.server.dingtalk.DDConf;
-import com.malk.server.dingtalk.DDR_New;
-import com.malk.service.dingtalk.DDClient_CRM;
-import com.malk.utils.UtilMap;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Service;
-
-import java.util.Map;
-
-@Slf4j
-@Service
-public class DDImplClient_CRM implements DDClient_CRM {
-
-    @Override
-    public DDR_New getObjectMetaFromPersonalCustomers(String accessToken, String relationType) {
-        Map param = UtilMap.putNotEmpty(UtilMap.empty(), "relationType", relationType);
-        return DDR_New.doGet("https://api.dingtalk.com/v1.0/crm/personalCustomers/objectMeta", DDConf.initTokenHeader(accessToken), param);
-    }
-}

+ 24 - 1
mjava/src/main/java/com/malk/service/dingtalk/impl/DDImplClient_Dedicated.java

@@ -15,7 +15,7 @@ import java.util.Map;
 @Service
 @Slf4j
 public class DDImplClient_Dedicated implements DDClient_Dedicated {
-    
+
     /**
      * 获取文件操作记录
      *
@@ -32,4 +32,27 @@ public class DDImplClient_Dedicated implements DDClient_Dedicated {
         DDR_New ddr_new = DDR_New.doGet("https://api.dingtalk.com/v1.0/exclusive/fileAuditLogs", DDConf.initTokenHeader(accessToken), params);
         return ddr_new.getList();
     }
+
+    /**
+     * 启用企业帐号
+     *
+     * @apiNote https://open.dingtalk.com/document/orgapp/enable-a-dedicated-account
+     */
+    @Override
+    public boolean orgAccountsEnable(String accessToken, String userId) {
+        DDR_New ddr_new = DDR_New.doPost("https://api.dingtalk.com/v1.0/contact/orgAccounts/enable", DDConf.initTokenHeader(accessToken), null, UtilMap.map("userId", userId));
+        return (Boolean) ddr_new.getResult();
+    }
+
+    /**
+     * 停用企业帐号
+     *
+     * @apiNote https://open.dingtalk.com/document/orgapp/disable-an-exclusive-account
+     */
+    @Override
+    public boolean orgAccountsDisable(String accessToken, String userId) {
+        DDR_New ddr_new = DDR_New.doPost("https://api.dingtalk.com/v1.0/contact/orgAccounts/disable", DDConf.initTokenHeader(accessToken), null, UtilMap.map("userId", userId));
+        return (Boolean) ddr_new.getResult();
+    }
+
 }

+ 50 - 1
mjava/src/main/java/com/malk/service/dingtalk/impl/DDImplClient_Storage.java

@@ -30,6 +30,9 @@ public class DDImplClient_Storage implements DDClient_Storage {
 
     ///////////////////////// 钉盘附件 /////////////////////////
 
+    // ppExt 最大50. 参数不能为1, nextToken 传递后第二次调用就返回为空
+    private static final int maxResults = 50;
+
     /**
      * 新建空间
      *
@@ -48,9 +51,10 @@ public class DDImplClient_Storage implements DDClient_Storage {
     @Override
     public List<Map> getSpaces(String accessToken, String unionId) {
 
-        return _getSpaces(accessToken, unionId, 50, null, new ArrayList<>());
+        return _getSpaces(accessToken, unionId, maxResults, null, new ArrayList<>());
     }
 
+    /// 递归空间列表
     private List<Map> _getSpaces(String accessToken, String unionId, int maxResults, String nextToken, List<Map> dataList) {
 
         // spaceType: 空间类型。org:企业空间
@@ -64,6 +68,49 @@ public class DDImplClient_Storage implements DDClient_Storage {
         return dataList;
     }
 
+    /**
+     * 获取文件或文件夹列表
+     *
+     * @apiNote https://open.dingtalk.com/document/orgapp/obtain-the-file-list-storage
+     */
+
+    @Override
+    public List<Map> getDentries(String accessToken, String unionId, String spaceId, String parentId, Map extInfo) {
+
+        return _getDentries(accessToken, unionId, spaceId, parentId, maxResults, null, extInfo, new ArrayList<>());
+    }
+
+    /// 递归文件/文件夹列表
+    private List<Map> _getDentries(String accessToken, String unionId, String spaceId, String parentId, int maxResults, String nextToken, Map extInfo, List<Map> dataList) {
+
+        Map param = UtilMap.map("unionId, parentId, maxResults, nextToken", unionId, parentId, maxResults, nextToken);
+        UtilMap.putAll(param, extInfo);
+        DDR_New ddr_new = DDR_New.doGet("https://api.dingtalk.com//v1.0/storage/spaces/" + spaceId + "/dentries", DDConf.initTokenHeader(accessToken), param);
+        dataList.addAll(ddr_new.getDentries());
+        // 返回空字符串, 过滤
+        if (StringUtils.isNotBlank(ddr_new.getNextToken())) {
+            _getDentries(accessToken, unionId, spaceId, parentId, maxResults, ddr_new.getNextToken(), extInfo, dataList);
+        }
+        return dataList;
+    }
+
+    /**
+     * 添加文件夹
+     *
+     * @apiNote https://open.dingtalk.com/document/orgapp/add-folder
+     */
+    @Override
+    public Map addFolders(String accessToken, String unionId, String spaceId, String parentId, String name, Map option) {
+
+        Map param = UtilMap.map("unionId", unionId);
+        Map body = UtilMap.map("name", name);
+        if (ObjectUtil.isNotNull(option)) {
+            body.put("option", option);
+        }
+        DDR_New ddr_new = DDR_New.doPost("https://api.dingtalk.com//v1.0/storage/spaces/" + spaceId + "/dentries/" + parentId + "/folders", DDConf.initTokenHeader(accessToken), param, body);
+        return ddr_new.getDentry();
+    }
+
     ///////////////////////// OA审批附件 /////////////////////////
 
     /**
@@ -96,6 +143,8 @@ public class DDImplClient_Storage implements DDClient_Storage {
         return DDR_New.doPost(url, header, param, body).isSuccess();
     }
 
+    ///////////////////////// 通用上传逻辑 /////////////////////////
+
     /**
      * 获取文件上传信息
      *

+ 26 - 3
mjava/src/main/java/com/malk/service/dingtalk/impl/DDImplService.java

@@ -92,12 +92,12 @@ public class DDImplService implements DDService {
      * @param fileNamePure 文件名称[后缀自动通过地址获取]
      */
     @Override
-    public Map uploadFileFormUrl(String accessToken, String userId, String urlFile, String fileNamePure) {
+    public Map uploadFileFormUrlForOverflow(String accessToken, String userId, String urlFile, String fileNamePure) {
         // 下载到本地
         String fileName = fileNamePure + urlFile.substring(urlFile.lastIndexOf(".")).toLowerCase();
         File file = UtilFile.mkdirIfNot(fileName, filePath.getPath().getFile());
         UtilHttp.doDownload(urlFile, file);
-        return uploadFileFormUrl(accessToken, userId, file.getAbsolutePath());
+        return uploadFileFormUrlForOverflow(accessToken, userId, file.getAbsolutePath());
     }
 
     /**
@@ -106,7 +106,7 @@ public class DDImplService implements DDService {
      * @param filePath 已存在文件, 本地file绝对路径
      */
     @Override
-    public Map uploadFileFormUrl(String accessToken, String userId, String filePath) {
+    public Map uploadFileFormUrlForOverflow(String accessToken, String userId, String filePath) {
         // 获取用户unionId
         String unionId = String.valueOf(ddClient_contacts.getUserInfoById(accessToken, userId).get("unionid"));
         // 获取储存空间
@@ -123,6 +123,29 @@ public class DDImplService implements DDService {
         return ddClient_storage.commitFiles(accessToken, spaceId, unionId, ddr_new.getUploadKey(), String.valueOf(UtilList.getLast(filePath.split("/"))), "0", null);
     }
 
+    /**
+     * 上传钉盘文件
+     *
+     * @param urlFile 远程文件地址
+     */
+    @Override
+    public Map uploadFileFormUrlForDingDrive(String accessToken, String unionId, String spaceId, String parentId, String urlFile, String fileNamePure) {
+        // 下载到本地 [兼容中文]
+        // String fileName = URLDecoder.decode(String.valueOf(UtilList.getLast(urlFile.split("/"))));
+        File file = UtilFile.mkdirIfNot(fileNamePure, filePath.getPath().getFile());
+        UtilHttp.doDownload(urlFile, file);
+        // 获取空间上传信息
+        DDR_New ddr_new = ddClient_storage.getUploadInfos(accessToken, spaceId, unionId, null);
+        // 执行文件上传
+        String resourceUrl = ((List<String>) ddr_new.getHeaderSignatureInfo().get("resourceUrls")).get(0);
+        ddClient_storage.uploadFiles(resourceUrl, (Map<String, String>) ddr_new.getHeaderSignatureInfo().get("headers"), file.getAbsolutePath());
+        // 提交文件
+        Map dentry = ddClient_storage.commitFiles(accessToken, spaceId, unionId, ddr_new.getUploadKey(), fileNamePure, parentId, null);
+        // 删除本地临时文件
+        UtilFile.deleteFile(file.getAbsolutePath());
+        return dentry;
+    }
+
     /**
      * 判断员工是否在指定部门
      */

+ 7 - 4
mjava/src/main/java/com/malk/utils/UtilHttp.java

@@ -4,6 +4,7 @@ import cn.hutool.core.util.CharsetUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.XmlUtil;
 import cn.hutool.http.HttpRequest;
+import cn.hutool.http.HttpResponse;
 import cn.hutool.http.HttpUtil;
 import cn.hutool.http.webservice.SoapClient;
 import com.alibaba.fastjson.JSON;
@@ -74,9 +75,11 @@ public abstract class UtilHttp {
         if (StringUtils.isNotBlank(usr) && StringUtils.isNotBlank(pwd)) {
             request.basicAuth(usr, pwd);
         }
-        String rsp = request.execute().body();
-        log.debug("请求响应, {}", rsp);
-        return rsp;
+        HttpResponse out = request.execute();
+        log.debug("请求响应, {}", out.body()); // http 状态判定
+        // ppExt: 外部接口http状态异常, 不直接阻断, 通过 r.assertSuccess(); 校验
+        //McException.assertException(out.getStatus() != 200, String.valueOf(out.getStatus()), "ERROR HTTP STATUS EXCEPTION");
+        return out.body();
     }
 
     public static String doRequest(METHOD method, String url, Map header, Map<String, Object> param, Map body, Map form) {
@@ -87,8 +90,8 @@ public abstract class UtilHttp {
         return doRequest(method, url, header, param, body, null);
     }
 
-
     /*** ------------ 创建POST请求 ------------ ***/
+
     public static String doPost(String url, Map header, Map<String, Object> param, Map body, Map form) {
         return doRequest(METHOD.POST, url, header, param, body, form);
     }

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

@@ -45,7 +45,7 @@ public abstract class UtilMap {
     }
 
     /**
-     * 快速创建map [保留skeys, 取值ckeys]
+     * 快速创建map [保留skeys, 取值ckeys] todo: 新版本更新
      */
     public static Map<String, Object> map(String skeys, String ckeys, Map map) {
         String[] sprops = skeys.split(", ");

+ 87 - 0
mjava/src/test/resources/sample/CP_Utils.cs

@@ -0,0 +1,87 @@
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using H3;
+
+public class CP_Utils
+{
+
+    /********** 莱蒂 **********/
+
+    /// 附件同步到钉盘
+    public static string syncDingDriveForProject(H3.IEngine engine, string projectName, string attachments) {
+        Dictionary < string, object > bodys = new Dictionary<string, object>();
+        bodys.Add("projectName", projectName); // 项目名称
+        bodys.Add("attachments", attachments);  // 同步附件
+        List < H3.BizBus.ItemSchema > structures = new List<H3.BizBus.ItemSchema>(); // 响应类型
+        structures.Add(new H3.BizBus.ItemSchema("status", "同步状态", H3.Data.BizDataType.String, null));
+        H3.BizBus.BizStructure data = CP_Utils.invokeVendorService(engine, "sync", bodys, structures); // 请求处理
+        // 传递同步状态
+        return data["status"] + string.Empty;
+    }
+
+    /********** 工具 **********/
+
+    /**
+     * 氚云HTTP
+     * 1. code 公用请求,code区分业务逻辑
+     * 2. bodys 请求参数,默认POST,application/json
+     * 3. structures 返回数据格式定义, 统一使用对象响应
+     */
+    public static H3.BizBus.BizStructure invokeVendorService(H3.IEngine engine, string code, Dictionary < string, object > bodys, List < H3.BizBus.ItemSchema > structures) {
+
+        // 请求信息
+        Dictionary < string, string > headers = new Dictionary<string, string>();
+        Dictionary < string, string > querys = new Dictionary<string, string>();
+        querys.Add("code", code);
+
+        // 定义响应数据整体结构体
+        H3.BizBus.BizStructureSchema structureSchema = new H3.BizBus.BizStructureSchema();
+        structureSchema.Add(new H3.BizBus.ItemSchema("code", "结果状态码", H3.Data.BizDataType.Int, null));
+        structureSchema.Add(new H3.BizBus.ItemSchema("success", "请求状态位", H3.Data.BizDataType.Bool, null));
+        structureSchema.Add(new H3.BizBus.ItemSchema("message", "描述信息", H3.Data.BizDataType.String, null));
+        // 定义响应数据的 data 属性 的结构体
+        H3.BizBus.BizStructureSchema dataSchema = new H3.BizBus.BizStructureSchema();
+        foreach(H3.BizBus.ItemSchema itemSchame in structures)
+        {
+            dataSchema.Add(itemSchame);
+        }
+        //将 data 属性的结构体添加进整体的响应数据结构体 [H3.Data.BizDataType.BizStructureArray 集合,H3.Data.BizDataType.BizStructure 对象]
+        structureSchema.Add(new H3.BizBus.ItemSchema("data", "响应数据", H3.Data.BizDataType.BizStructure, dataSchema));
+
+        //调用Invoke接口,系统底层访问第三方接口的Invoke方法
+        H3.BizBus.InvokeResult response = engine.BizBus.InvokeApi(
+            H3.Organization.User.SystemUserId, //固定值,无需改变
+            H3.BizBus.AccessPointType.ThirdConnection, //固定值,无需改变
+            "h3yun-http", //连接编码,对应 插件中心 中配置的连接的编码
+            "POST", //请求方式,取值:GET / POST
+            "application/json", //请求数据类型: json - "application/json";xml - "text/html;charset=utf-8"
+            headers, querys, bodys, structureSchema);
+        if(response != null)
+        {
+            // 氚云调用是否成功
+            if(response.Code == 0)
+            {
+                // 获取返回数据,此实例对应完整的响应JSON
+                H3.BizBus.BizStructure rspData = response.Data;
+                if(((bool) rspData["success"]) == true)
+                {
+                    // 对象响应【氚云自定义字段,需要通过[]直接取值才有效,序列化后返回前端,仅会保留结构】
+                    // H3.BizBus.BizStructure[] datas = rspData["data"] as H3.BizBus.BizStructure[]; // 集合解析
+                    // H3.BizBus.BizStructure data = rspData["data"] as H3.BizBus.BizStructure; // 对象解析
+                    return rspData["data"] as H3.BizBus.BizStructure;
+                } else
+            {
+                throw new Exception("响应异常," + rspData["message"]);
+            }
+        } else
+        {
+            throw new Exception("氚云异常," + response.Message);
+        }
+    } else
+    {
+        throw new Exception("系统异常,接口无响应");
+    }
+}
+}

+ 35 - 0
mjava/target/classes/META-INF/spring-configuration-metadata.json

@@ -35,6 +35,11 @@
       "type": "com.malk.server.common.FilePath$Path",
       "sourceType": "com.malk.server.common.FilePath$Path"
     },
+    {
+      "name": "file.path",
+      "type": "com.malk.server.common.FilePath$Path",
+      "sourceType": "com.malk.server.common.FilePath$Path"
+    },
     {
       "name": "file.source",
       "type": "com.malk.server.common.FilePath$Source",
@@ -45,6 +50,11 @@
       "type": "com.malk.server.common.FilePath$Source",
       "sourceType": "com.malk.server.common.FilePath$Source"
     },
+    {
+      "name": "file.source",
+      "type": "com.malk.server.common.FilePath$Source",
+      "sourceType": "com.malk.server.common.FilePath$Source"
+    },
     {
       "name": "fxiaoke",
       "type": "com.malk.server.fxiaoke.FXKConf",
@@ -138,6 +148,11 @@
       "type": "java.lang.String",
       "sourceType": "com.malk.server.dingtalk.DDConf"
     },
+    {
+      "name": "dingtalk.corp-token",
+      "type": "java.lang.String",
+      "sourceType": "com.malk.server.dingtalk.DDConf"
+    },
     {
       "name": "dingtalk.operator",
       "type": "java.lang.String",
@@ -184,6 +199,16 @@
       "type": "java.lang.String",
       "sourceType": "com.malk.server.common.FilePath$Path"
     },
+    {
+      "name": "file.path.file",
+      "type": "java.lang.String",
+      "sourceType": "com.malk.server.common.FilePath$Path"
+    },
+    {
+      "name": "file.path.image",
+      "type": "java.lang.String",
+      "sourceType": "com.malk.server.common.FilePath$Path"
+    },
     {
       "name": "file.path.image",
       "type": "java.lang.String",
@@ -194,6 +219,16 @@
       "type": "java.lang.String",
       "sourceType": "com.malk.server.common.FilePath$Path"
     },
+    {
+      "name": "file.path.tmp",
+      "type": "java.lang.String",
+      "sourceType": "com.malk.server.common.FilePath$Path"
+    },
+    {
+      "name": "file.source.fonts",
+      "type": "java.lang.String",
+      "sourceType": "com.malk.server.common.FilePath$Source"
+    },
     {
       "name": "file.source.fonts",
       "type": "java.lang.String",

+ 2 - 0
pom.xml

@@ -24,6 +24,8 @@
         <module>mjava-kuaikeli</module>
         <module>mjava-laidi</module>
         <module>mjava-luyi</module>
+        <module>mjava-taisen</module>
+        <module>mjava-hake</module>
     </modules>
     <packaging>pom</packaging>