pruple_boy 1 year ago
parent
commit
428359e590
78 changed files with 1570 additions and 271 deletions
  1. 1 1
      mjava-cloudpure/src/main/java/com/malk/cloudpure/Boot.java
  2. 1 1
      mjava-cloudpure/src/main/java/com/malk/cloudpure/service/impl/CPImplClient.java
  3. 1 1
      mjava-cloudpure/src/main/resources/application-dev.yml
  4. 1 1
      mjava-cloudpure/src/main/resources/application-prod.yml
  5. 1 1
      mjava-cloudpure/target/classes/application-dev.yml
  6. 1 1
      mjava-cloudpure/target/classes/application-prod.yml
  7. 1 1
      mjava-fengkaili/src/main/java/com/malk/fengkaili/Boot.java
  8. 1 1
      mjava-fengkaili/src/main/java/com/malk/fengkaili/service/impl/FKLImplService.java
  9. 1 1
      mjava-gewu/src/main/java/com/malk/gewu/Boot.java
  10. 1 1
      mjava-guyuan/pom.xml
  11. 1 1
      mjava-guyuan/src/main/java/com/malk/guyuan/Boot.java
  12. 79 7
      mjava-guyuan/src/main/java/com/malk/guyuan/controller/IVController.java
  13. 26 2
      mjava-guyuan/src/main/java/com/malk/guyuan/server/model/McInvoiceDto.java
  14. 3 1
      mjava-guyuan/src/main/java/com/malk/guyuan/server/model/McInvoiceKind.java
  15. 2 0
      mjava-guyuan/src/main/java/com/malk/guyuan/server/tencent/TXYConf.java
  16. 4 2
      mjava-guyuan/src/main/java/com/malk/guyuan/service/tencent/TXYInvoice.java
  17. 2 3
      mjava-guyuan/src/main/java/com/malk/guyuan/service/tencent/impl/TXYImplInvoice.java
  18. 79 5
      mjava-guyuan/src/main/resources/static/mjs/mjs.js
  19. 1 1
      mjava-guyuan/src/main/resources/static/mjs/mjs.min.js
  20. 4 2
      mjava-guyuan/target/classes/META-INF/spring-configuration-metadata.json
  21. 79 5
      mjava-guyuan/target/classes/static/mjs/mjs.js
  22. 1 1
      mjava-guyuan/target/classes/static/mjs/mjs.min.js
  23. 1 1
      mjava-kuaikeli/src/main/java/com/malk/kuaikeli/Boot.java
  24. 1 1
      mjava-kuaikeli/src/main/java/com/malk/kuaikeli/controller/KKLController.java
  25. 2 2
      mjava-kuaikeli/src/main/resources/application-prod.yml
  26. 54 0
      mjava-laidi/pom.xml
  27. 32 0
      mjava-laidi/src/main/java/com/malk/laidi/Boot.java
  28. 157 0
      mjava-laidi/src/main/java/com/malk/laidi/controller/LDController.java
  29. 39 0
      mjava-laidi/src/main/resources/application-dev.yml
  30. 39 0
      mjava-laidi/src/main/resources/application-prod.yml
  31. 35 0
      mjava-laidi/src/test/resources/server.sh
  32. 54 0
      mjava-luyi/pom.xml
  33. 32 0
      mjava-luyi/src/main/java/com/malk/luyi/Boot.java
  34. 97 0
      mjava-luyi/src/main/java/com/malk/luyi/controller/LYController.java
  35. 65 0
      mjava-luyi/src/main/resources/application-dev.yml
  36. 39 0
      mjava-luyi/src/main/resources/application-prod.yml
  37. 35 0
      mjava-luyi/src/test/resources/server.sh
  38. 1 1
      mjava-mcli/src/test/java/com/malk/mcli/YSTest.java
  39. 1 1
      mjava-pake/src/main/java/com/malk/pake/Boot.java
  40. 2 1
      mjava-pake/src/main/java/com/malk/pake/controller/SFController.java
  41. 1 1
      mjava-shangfeng/src/main/java/com/malk/shangfeng/Boot.java
  42. 1 1
      mjava-suodisi/src/main/java/com/malk/suodisi/Boot.java
  43. 1 1
      mjava-suodisi/src/main/java/com/malk/suodisi/controller/SDSController.java
  44. 1 1
      mjava-yangu/pom.xml
  45. 1 1
      mjava-yangu/src/main/java/com/malk/yangu/Boot.java
  46. 1 1
      mjava-yangu/src/main/java/com/malk/yangu/server/tencent/TXYConf.java
  47. 2 6
      mjava-yangu/src/main/java/com/malk/yangu/tencent/impl/TXYImplInvoice.java
  48. 1 1
      mjava/src/main/java/com/malk/base/BaseDto.java
  49. 1 1
      mjava/src/main/java/com/malk/base/JpaMap.java
  50. 1 0
      mjava/src/main/java/com/malk/server/aliwork/YDConf.java
  51. 0 1
      mjava/src/main/java/com/malk/server/common/VenR.java
  52. 32 2
      mjava/src/main/java/com/malk/server/dingtalk/DDR_New.java
  53. 15 1
      mjava/src/main/java/com/malk/server/h3yun/CYConf.java
  54. 0 32
      mjava/src/main/java/com/malk/server/h3yun/CYR.java
  55. 36 2
      mjava/src/main/java/com/malk/service/aliwork/YDService.java
  56. 3 0
      mjava/src/main/java/com/malk/service/aliwork/impl/YDClientImpl.java
  57. 34 1
      mjava/src/main/java/com/malk/service/aliwork/impl/YDServiceImpl.java
  58. 11 0
      mjava/src/main/java/com/malk/service/dingtalk/DDClient_CRM.java
  59. 19 0
      mjava/src/main/java/com/malk/service/dingtalk/DDClient_Storage.java
  60. 21 0
      mjava/src/main/java/com/malk/service/dingtalk/impl/DDImplClient_CRM.java
  61. 40 0
      mjava/src/main/java/com/malk/service/dingtalk/impl/DDImplClient_Storage.java
  62. 1 1
      mjava/src/main/java/com/malk/service/dingtalk/impl/DDImplClient_Log.java
  63. 4 4
      mjava/src/main/java/com/malk/service/ekuaibao/EKBClient.java
  64. 51 0
      mjava/src/main/java/com/malk/service/h3yun/CYClient.java
  65. 59 3
      mjava/src/main/java/com/malk/service/h3yun/impl/CYImplClient.java
  66. 0 1
      mjava/src/main/java/com/malk/utils/UtilDateTime.java
  67. 1 1
      mjava/src/main/java/com/malk/utils/UtilHttp.java
  68. 61 5
      mjava/src/main/java/com/malk/utils/UtilMap.java
  69. 17 1
      mjava/src/main/java/com/malk/utils/UtilNumber.java
  70. 6 1
      mjava/src/main/java/com/malk/utils/UtilString.java
  71. 25 20
      mjava/src/main/resources/application-dev.yml
  72. 24 19
      mjava/src/main/resources/application-prod.yml
  73. 28 23
      mjava/src/main/resources/application-test.yml
  74. 15 30
      mjava/target/classes/META-INF/spring-configuration-metadata.json
  75. 25 20
      mjava/target/classes/application-dev.yml
  76. 24 19
      mjava/target/classes/application-prod.yml
  77. 28 23
      mjava/target/classes/application-test.yml
  78. 2 0
      pom.xml

+ 1 - 1
mjava-cloudpure/src/main/java/com/malk/cloudpure/Boot.java

@@ -12,7 +12,7 @@ import javax.persistence.EntityManager;
  * corp项目: 扫描公共模块
  * -
  * 若是无需数据库模块, 配置无效地址也可启动, 引入mjava不支持直接 @SpringBootApplication(exclude = DataSourceAutoConfiguration.class) 配置
- * 需要配置 jpa.hibernate.ddl-auto 为 none. 标识对表没有任何操作. 若不设置为 non, flyway.enabled 配置会无效, 在没有数库连接情况下程序无法启动
+ * 需要配置 jpa.hibernate.ddl-auto 为 none. 标识对表没有任何操作. 若不设置为 none, flyway.enabled 配置会无效, 在没有数库连接情况下程序无法启动
  */
 @EnableJpaAuditing
 @SpringBootApplication(scanBasePackages = {"com.malk"})

+ 1 - 1
mjava-cloudpure/src/main/java/com/malk/cloudpure/service/impl/CPImplClient.java

@@ -324,7 +324,7 @@ public class CPImplClient implements CPClient {
      */
     @Override
     public void sendCardMessage(String tDate, String... chatNames) {
-        
+
         // 推送群配置表
         List<Map> chatIdList = ydService.queryDataList_FormData("FORM-WV866IC1ZMDEQAWTAXYSFBJL2XMM2QY4WRPML0", null);
         // 全量查询, 分团队推送

+ 1 - 1
mjava-cloudpure/src/main/resources/application-dev.yml

@@ -56,7 +56,7 @@ dingtalk:
   aesKey: 6kaXxySzRcBlu8nvEJji7bg73rSX5F9ieXdVunqWvXc
   token: Mv4daF2LqpmoIOe5XMeipdl0YT
   robotCode: dingozv6fzkpqkiupd3d
-  operator: "16608972969409067"   # 牧语[开头0, 需要转一下字符串]
+  operator: "16608972969409067"   # 牧语 [开头0, 需要转一下字符串]
 
 # aliwork
 aliwork:

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

@@ -31,7 +31,7 @@ dingtalk:
   aesKey: 6kaXxySzRcBlu8nvEJji7bg73rSX5F9ieXdVunqWvXc
   token: Mv4daF2LqpmoIOe5XMeipdl0YT
   robotCode: dingozv6fzkpqkiupd3d
-  operator: "16608972969409067"   # 牧语[开头0, 需要转一下字符串]
+  operator: "16608972969409067"   # 牧语 [开头0, 需要转一下字符串]
 
 # aliwork
 aliwork:

+ 1 - 1
mjava-cloudpure/target/classes/application-dev.yml

@@ -56,7 +56,7 @@ dingtalk:
   aesKey: 6kaXxySzRcBlu8nvEJji7bg73rSX5F9ieXdVunqWvXc
   token: Mv4daF2LqpmoIOe5XMeipdl0YT
   robotCode: dingozv6fzkpqkiupd3d
-  operator: "16608972969409067"   # 牧语[开头0, 需要转一下字符串]
+  operator: "16608972969409067"   # 牧语 [开头0, 需要转一下字符串]
 
 # aliwork
 aliwork:

+ 1 - 1
mjava-cloudpure/target/classes/application-prod.yml

@@ -31,7 +31,7 @@ dingtalk:
   aesKey: 6kaXxySzRcBlu8nvEJji7bg73rSX5F9ieXdVunqWvXc
   token: Mv4daF2LqpmoIOe5XMeipdl0YT
   robotCode: dingozv6fzkpqkiupd3d
-  operator: "16608972969409067"   # 牧语[开头0, 需要转一下字符串]
+  operator: "16608972969409067"   # 牧语 [开头0, 需要转一下字符串]
 
 # aliwork
 aliwork:

+ 1 - 1
mjava-fengkaili/src/main/java/com/malk/fengkaili/Boot.java

@@ -12,7 +12,7 @@ import javax.persistence.EntityManager;
  * corp项目: 扫描公共模块
  * -
  * 若是无需数据库模块, 配置无效地址也可启动, 引入mjava不支持直接 @SpringBootApplication(exclude = DataSourceAutoConfiguration.class) 配置
- * 需要配置 jpa.hibernate.ddl-auto 为 none. 标识对表没有任何操作. 若不设置为 non, flyway.enabled 配置会无效, 在没有数库连接情况下程序无法启动
+ * 需要配置 jpa.hibernate.ddl-auto 为 none. 标识对表没有任何操作. 若不设置为 none, flyway.enabled 配置会无效, 在没有数库连接情况下程序无法启动
  */
 @EnableJpaAuditing
 @SpringBootApplication(scanBasePackages = {"com.malk"})

+ 1 - 1
mjava-fengkaili/src/main/java/com/malk/fengkaili/service/impl/FKLImplService.java

@@ -57,7 +57,7 @@ public class FKLImplService implements FKLService {
     public void syncUserInfo() {
         // 匹配部门信息, 全量
         ddClient_contacts.getDepartmentId_all(ddClient.getAccessToken(), true).forEach(deptId -> {
-            // String deptName = ddClient_contacts.getDepartmentInfo(ddClient.getAccessToken(), deptId).get("name").toString();
+            // String deptName = ddClient_contacts.getDepartmentInfo(ddClient.getAccessToken(), deptId).getDefault("name").toString();
             List<String> userIds = ddClient_contacts.listDepartmentUserId(ddClient.getAccessToken(), deptId);
             if (userIds.size() > 0) {
                 // 获取部门层级拼接

+ 1 - 1
mjava-gewu/src/main/java/com/malk/gewu/Boot.java

@@ -12,7 +12,7 @@ import javax.persistence.EntityManager;
  * corp项目: 扫描公共模块
  * -
  * 若是无需数据库模块, 配置无效地址也可启动, 引入mjava不支持直接 @SpringBootApplication(exclude = DataSourceAutoConfiguration.class) 配置
- * 需要配置 jpa.hibernate.ddl-auto 为 none. 标识对表没有任何操作. 若不设置为 non, flyway.enabled 配置会无效, 在没有数库连接情况下程序无法启动
+ * 需要配置 jpa.hibernate.ddl-auto 为 none. 标识对表没有任何操作. 若不设置为 none, flyway.enabled 配置会无效, 在没有数库连接情况下程序无法启动
  */
 @EnableJpaAuditing
 @SpringBootApplication(scanBasePackages = {"com.malk"})

+ 1 - 1
mjava-guyuan/pom.xml

@@ -31,7 +31,7 @@
             <artifactId>mjava</artifactId>
             <version>${mjava.version}</version>
         </dependency>
-        <!-- 腾讯云 [go to https://search.maven.org/search?q=tencentcloud-sdk-java and get the latest version.] -->
+        <!-- 腾讯云 [go to https://search.maven.org/search?q=tencentcloud-sdk-java and getDefault the latest version.] -->
         <dependency>
             <groupId>com.tencentcloudapi</groupId>
             <artifactId>tencentcloud-sdk-java</artifactId>

+ 1 - 1
mjava-guyuan/src/main/java/com/malk/guyuan/Boot.java

@@ -12,7 +12,7 @@ import javax.persistence.EntityManager;
  * corp项目: 扫描公共模块
  * -
  * 若是无需数据库模块, 配置无效地址也可启动, 引入mjava不支持直接 @SpringBootApplication(exclude = DataSourceAutoConfiguration.class) 配置
- * 需要配置 jpa.hibernate.ddl-auto 为 none. 标识对表没有任何操作. 若不设置为 non, flyway.enabled 配置会无效, 在没有数库连接情况下程序无法启动
+ * 需要配置 jpa.hibernate.ddl-auto 为 none. 标识对表没有任何操作. 若不设置为 none, flyway.enabled 配置会无效, 在没有数库连接情况下程序无法启动
  */
 @EnableJpaAuditing
 @SpringBootApplication(scanBasePackages = {"com.malk"})

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

@@ -150,7 +150,72 @@ public class IVController {
     }
 
     /**
-     * 混票识别 [旧版]
+     * 混票识别 [新版本]
+     */
+    @PostMapping("invoice-iv2")
+    McR invoice_iv2(@RequestBody Map<String, String> data) throws TencentCloudSDKException {
+
+        McException.assertParamException_Null(data, "url");
+        String image = ydClient.convertTemporaryUrl(data.get("url"));
+        log.info("混票识别, 免登地址, {}", image);
+        // 非PDF, 且内存大于3M, 压缩后上传
+        if (UtilMap.getFloat(data, "size") > 3.0f && !UtilMap.getBoolean(data, "isPdf")) {
+            image = imageUrlConvertBase64(image);
+        }
+        if (UtilMap.getFloat(data, "size") > 6.0f && UtilMap.getBoolean(data, "isPdf")) {
+            image = pdfUrlConvertBase64(image);
+        }
+        List<Map> invoices = (List<Map>) txyInvoice.doRecognizeGeneralInvoice(image).get("MixedInvoiceItems");
+        List<McInvoiceDto> result = invoices.stream().map(item -> {
+            Map prop = UtilMap.getMap(UtilMap.getMap(item, "SingleInvoiceInfos"), UtilMap.getString(item, "SubType"));
+            // ppExt: 通用字段定义
+            McInvoiceDto invoiceDto = McInvoiceDto.builder()
+                    .name(UtilMap.getString(item, "SubTypeDescription"))
+                    .kindName(UtilMap.getString(item, "TypeDescription"))
+                    .kind(UtilMap.getInt(item, "Type"))
+                    .code(UtilMap.getString(prop, "Code"))
+                    .serial(UtilMap.getString(prop, "Number"))
+                    .date(UtilString.replaceDateZH_cn(UtilMap.getString(prop, "Date")))
+                    .checkCode(UtilMap.getString(prop, "CheckCode"))
+                    // ppExt: 多明细行时, 优先取值合计 [全电票返回了subTotal字段, 但值为空]
+                    .amount(UtilNumber.setBigDecimal(UtilMap.getString_first(prop, "SubTotal", "Total")))
+                    .tax(UtilNumber.setBigDecimal(UtilMap.getString_first(prop, "SubTax", "Tax")))
+                    .excludingTax(UtilNumber.setBigDecimal(UtilMap.getString(prop, "PretaxAmount")))
+                    .buyerName(guyuanNameRepalce(UtilMap.getString(prop, "Buyer")))
+                    // ppExt: 中央非税未返回税号官方说明: 非税发票理论是没有税号的,图片中属于信用代码
+                    .buyerTaxId(UtilMap.getString(prop, "BuyerTaxID"))
+                    .sellerName(guyuanNameRepalce(UtilMap.getString_first(prop, "Seller", "Issuer")))                            // 行程单: 填开单位
+                    .sellerTaxId(UtilMap.getString_first(prop, "SellerTaxID", "AgentCode"))                       // 行程单: 销售单位代号
+                    .passengerName(UtilMap.getString_first(prop, "Name", "UserName"))                             // 火车票, 行程单
+                    // 交通出行
+                    .seatType(UtilMap.getString(prop, "Seat"))
+                    .departureTime(UtilString.replaceDateZH_cn(UtilMap.getString(prop, "DateGetOn")) + " " + UtilMap.getString(prop, "TimeGetOn"))
+                    .departurePort(UtilMap.getString_first(prop, "StationGetOn", "Entrance", "Place"))            // 火车票: 出发车站, 过路过桥费: 入口, 出租车: 发票所在地
+                    .arrivePort(UtilMap.getString_first(prop, "StationGetOff", "Exit"))                           // 行程单, 火车票: 到达车站, 过路过桥费: 出口
+                    .trainNo(UtilMap.getString_first(prop, "TrainNumber", "LicensePlate"))                        // 火车票: 车次, 出租车: 车牌号
+                    .insuranceCosts(UtilNumber.setBigDecimal((UtilMap.getString(prop, "Insurance"))))               // 行程单: 保险费
+                    .fuelCosts(UtilNumber.setBigDecimal((UtilMap.getString(prop, "FuelSurcharge"))))                // 行程单: 燃油附加费
+                    .constructionCosts(UtilNumber.setBigDecimal((UtilMap.getString(prop, "AirDevelopmentFund"))))   // 行程单: 民航发展基金
+                    .build();
+            // ppExt: 机票行程单, 行程与座位信息在明细内
+            if ("机票行程单".equals(item.get("TypeDescription"))) {
+                Map flight = (Map) UtilMap.getList(prop, "FlightItems").get(0);
+                invoiceDto.setDepartureTime(UtilString.replaceDateZH_cn(UtilMap.getString(item, "DateGetOn")) + " " + UtilMap.getString(prop, "TimeGetOn"));
+                invoiceDto.setDeparturePort(UtilMap.getString(flight, "StationGetOn"));
+                invoiceDto.setArrivePort(UtilMap.getString(flight, "StationGetOff"));
+                invoiceDto.setSeatType(UtilMap.getString(flight, "Seat"));
+            }
+            if ("出租车发票".equals(item.get("TypeDescription"))) {
+                // 上下车时间
+                invoiceDto.setDepartureTime(UtilMap.getString(prop, "TimeGetOn") + " ~ " + UtilMap.getString(prop, "TimeGetOff"));
+            }
+            return invoiceDto;
+        }).collect(Collectors.toList());
+        return McR.success(McInvoiceDto.formatResponse(result));
+    }
+
+    /**
+     * 混票识别 [旧版本, 已废弃]
      */
     @PostMapping("invoice-iv")
     McR invoice_iv(@RequestBody Map<String, String> data) throws TencentCloudSDKException {
@@ -207,6 +272,10 @@ public class IVController {
                     .fuelCosts(UtilNumber.setBigDecimal((findValue(infos, "燃油附加费")))) // 行程单
                     .constructionCosts(UtilNumber.setBigDecimal((findValue(infos, "民航发展基金")))) // 行程单
                     .build();
+            // 价格不一致情况下, 通过合计返回
+            if (!UtilNumber.equalBigDecimal(invoiceDto.getAmount(), invoiceDto.getExcludingTax().add(invoiceDto.getTax()))) {
+                invoiceDto.setAmount(invoiceDto.getExcludingTax().add(invoiceDto.getTax()));
+            }
             // 机票行程单
             if (kind.equals(McInvoiceKind.JP.getDesc())) {
                 String date = findValue(infos, "日期").replace("年", "-").replace("月", "-").replace("日", " ");
@@ -252,11 +321,11 @@ public class IVController {
                 McException.exceptionAccess(serial + "已存在, 请勿重复提交!");
             }
             // prd 仅仅识别增值税普通发票
-            if (dto.getKindName().contains("普通发票")) {
+            if (dto.getName().contains("普通发票")) {
                 String serialTips = serial + "有疑问";
                 try {
                     // ppExt: 识别与验真后抬头对比
-                    Map rsp = txyInvoice.doVatInvoiceVerifyNew(dto.getKindName(), dto.getCode(), invoiceNo, dto.getDate(), String.valueOf(dto.getAmount()), dto.getCheckCode(), String.valueOf(dto.getExcludingTax()), serialTips);
+                    Map rsp = txyInvoice.doVatInvoiceVerifyNew(dto.getName(), 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 + ", 购买方税号不匹配!");
@@ -266,6 +335,10 @@ public class IVController {
                     log.error(e.getMessage(), e);
                     // prd: 上传发票为假发票时,提示:该发票有疑问,请联系财务人员
                     String message = e.getMessage();
+                    // ppExt: 已经是新版本接口, 过滤提示
+                    if (message.contains("温馨提示")) {
+                        message = message.split("温馨提示")[0];
+                    }
                     if (message.contains("发票不存在")) {
                         message = "有疑问,请联系财务人员";
                     }
@@ -273,8 +346,7 @@ public class IVController {
                 }
             }
         }));
-
-        return McR.success("发票查重, 验真响应");
+        return McR.success();
     }
 
 
@@ -282,7 +354,7 @@ public class IVController {
     private YDService ydService;
 
     /**
-     * 发票状态更新: 服务注册 // todo 通用服务, { 组件Id: 值, 组件id: 值 }
+     * 发票状态更新: 服务注册
      */
     @PostMapping("invoice-up")
     McR invoice_va(HttpServletRequest request) {
@@ -306,7 +378,7 @@ public class IVController {
             update.put("radioField_liw7rb2q", "否"); // 提交后, 更新是否退回标识为否
         }
 
-        // prd 9.10 更新报销单, 关联到发票:: todo 宜搭服务注册拿不到系统默认字段, 先查询解决:::: 可能是提交校验的原因
+        // prd 9.10 更新报销单, 关联到发票:: ppExt 宜搭服务注册, 提交规则系统默认字段 [详见 YDService]
         ydService.operateData2(data, update, YDParam.builder()
                 .formUuid("FORM-W2A66Z910O9B3LP9C6IYUDPRVWY62DO0YHIILY")
                 .formInstanceIdList(formInstanceIds)

+ 26 - 2
mjava-guyuan/src/main/java/com/malk/guyuan/server/model/McInvoiceDto.java

@@ -1,5 +1,6 @@
 package com.malk.guyuan.server.model;
 
+import cn.hutool.core.util.ObjectUtil;
 import com.malk.base.BaseDto;
 import com.malk.server.common.McException;
 import com.malk.server.common.McREnum;
@@ -13,6 +14,11 @@ import org.apache.commons.lang3.StringUtils;
 import java.math.BigDecimal;
 import java.util.Map;
 
+/**
+ * ppExt: 新版本官方返回数据已结构化, 以官方为准
+ *
+ * @apiNote https://cloud.tencent.com/document/api/866/33527#AirTransport 数据结构
+ */
 @Data
 @Builder
 @AllArgsConstructor
@@ -23,7 +29,7 @@ public class McInvoiceDto extends BaseDto {
     /**************** 发票 ****************/
 
     /**
-     * 发票名称
+     * 发票名称 [类型全称]
      */
     private String name;
 
@@ -36,7 +42,9 @@ public class McInvoiceDto extends BaseDto {
     }
 
     /**
-     * 发票类型
+     * 发票类型 [类型简称]
+     * -
+     * ppExt: 全电票, 新版本识别接口, 返回名称为: 电子发票(普通发票) 不包含全电标识, 发类型为: 全电发票. 注意取值
      */
     private String kindName;
 
@@ -75,11 +83,27 @@ public class McInvoiceDto extends BaseDto {
      */
     private BigDecimal excludingTax;
 
+    /// 没有税额时, 税额可能没传递 [因此前提是不含税为空],不含税金额等于价税合计
+    public BigDecimal getExcludingTax() {
+        if (ObjectUtil.isNull((excludingTax)) && (ObjectUtil.isNull(tax) || BigDecimal.ZERO.compareTo(tax) == 0)) {
+            return amount;
+        }
+        return excludingTax;
+    }
+
     /**
      * 不含税金额
      */
     private BigDecimal tax;
 
+    /// 取值为null, 合计会异常
+    public BigDecimal getTax() {
+        if (ObjectUtil.isNull(tax)) {
+            return BigDecimal.ZERO;
+        }
+        return tax;
+    }
+
     /**
      * 购买方名称
      */

+ 3 - 1
mjava-guyuan/src/main/java/com/malk/guyuan/server/model/McInvoiceKind.java

@@ -7,8 +7,10 @@ import java.util.Arrays;
 import java.util.Optional;
 
 /**
- * 定义返回值和对应状态的信息
+ * 定义返回值和对应状态的信息 [旧版本]
+ * ppExt: 新版本官方返回数据已结构化, 以官方为准
  */
+@Deprecated
 @Slf4j
 public enum McInvoiceKind {
 

+ 2 - 0
mjava-guyuan/src/main/java/com/malk/guyuan/server/tencent/TXYConf.java

@@ -27,7 +27,9 @@ public class TXYConf {
      * 票据类型
      * -
      * 中央非税未返回税号官方说明: 非税发票理论是没有税号的,图片中那个属于信用代码 [两个版本接口均为返回]
+     * ppExt: 新版本官方返回数据已结构化, 以官方为准
      */
+    @Deprecated
     public static final Map<String, String> TYPE_INVOICE = UtilMap.map("-1, 0, 1, 2, 3, 5, 8, 9, 10, 11, 12, 13, 15, 16",
             "未知类型, 出租车发票, 定额发票, 火车票, 增值税发票, 机票行程单, 通用机打发票, 汽车票, 轮船票, 增值税发票(卷票) , 购车发票, 过路过桥费发票, 非税发票, 全电发票");
 

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

@@ -7,14 +7,15 @@ import java.util.Map;
 public interface TXYInvoice {
 
     /**
-     * 混贴票据识别 [将弃用, 直接返回识别数据, 官方停止更新]
+     * 混贴票据识别 [将弃用, 直接返回识别数据, ppExt: 官方停止更新, PDF多张异常]
      *
      * @param image 下载图片经Base64编码后不超过 7M。图片下载时间不超过 3 秒
      */
+    @Deprecated
     Map doMixedInvoiceOCR(String image) throws TencentCloudSDKException;
 
     /**
-     * 通用票据识别(高级版)[返回结构化数据]
+     * 通用票据识别(高级版)[返回结构化数据] ppExt: 新版本官方返回数据已结构化, 以官方为准
      *
      * @param image 下载图片经Base64编码后不超过 8M。图片下载时间不超过 3 秒
      */
@@ -23,6 +24,7 @@ public interface TXYInvoice {
     /**
      * 发票验真[新版]
      *
+     * @param invoiceKind         ppExt: 全电票, 新版本识别接口, 返回名称为: 电子发票(普通发票) 不包含全电标识, 发类型为: 全电发票. 注意取值
      * @param invoiceCode         票代码(10或12 位),全电发票为空
      * @param checkCode           校验码后 6 位,增值税普通发票、增值税电子普通发票、增值税普通发票(卷式)、增值税电子普通发票(通行费)时必填;
      * @param excludingTax/amount 不含税金额,增值税专用发票、增值税电子专用发票、机动车销售统一发票、二手车销售统一发票、区块链发票时必填; 全电发票为价税合计(含税金额)

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

@@ -80,7 +80,7 @@ public class TXYImplInvoice implements TXYInvoice {
             req.setImageBase64(image);
         }
         req.setEnableMultiplePage(true); // PDF多页识别, 仅支持返回文件前30页
-        req.setEnableCutImage(true); // 返回切割图片base64
+        req.setEnableCutImage(false); // 返回切割图片base64
         RecognizeGeneralInvoiceResponse resp = client.RecognizeGeneralInvoice(req);
         String result = MixedInvoiceOCRResponse.toJsonString(resp);
         log.debug("请求响应, {}", result);
@@ -127,10 +127,9 @@ public class TXYImplInvoice implements TXYInvoice {
         if (StringUtils.isBlank(tips)) {
             tips = "发票有疑问";
         }
+        log.debug("请求响应, {}", result);
         McException.assertAccessException(!UtilNumber.equalBigDecimal(UtilMap.getString(invoice, "AmountWithTax"), amount), tips + ", 价税合计金额不匹配!");
         McException.assertAccessException(!UtilNumber.equalBigDecimal(UtilMap.getString(invoice, "AmountWithoutTax"), excludingTax), tips + ", 不含税金额不匹配!");
-
-        log.debug("请求响应, {}", result);
         return rsp;
     }
 

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

@@ -8000,7 +8000,7 @@ request.doForm = function (url, param) {
 
   // 变更请求头类型, 传递form
   conf[KEY_M_CONTENT_TYPE] = true;
-  return this.doPost(url, param, data, conf);
+  return this.doPost(url, param, lib.stringify(data), conf);
 };
 
 /** 4.upload: body-formData, 一般用于文件上传, 追加数据流 */
@@ -9098,13 +9098,13 @@ var guyuan = {
   // 修改公共配置
   init: function init() {
     {
-      mjs.conf.api = "https://mc.cloudpure.cn/api/guyuan/";
+      mjs.conf.api = "https://mc.cloudpure.cn/api/guyuan";
     }
     return this; // this 指向当前项目本身
   },
 
 
-  // 发票识别, 混票
+  // 发票识别, 混票  ppExt: 官方已停止更新, PDF多张异常
   mixedInvoice: function mixedInvoice(file) {
     var _this = this;
 
@@ -9168,13 +9168,87 @@ var guyuan = {
   },
 
 
+  // 发票识别, 混票 ppExt: 新版本官方返回数据已结构化, 以官方为准
+  mixedInvoice2: function mixedInvoice2(file) {
+    var _this2 = this;
+
+    return _asyncToGenerator( /*#__PURE__*/regenerator.mark(function _callee2() {
+      var rsp, headers, prop, amount, tax, exTax, invoices;
+      return regenerator.wrap(function _callee2$(_context2) {
+        while (1) {
+          switch (_context2.prev = _context2.next) {
+            case 0:
+              _context2.next = 2;
+              return mjs.request.xhr.doPost(mjs.conf.api + "/invoice-iv2", {}, {
+                url: file.url,
+                isPdf: file.type.includes("pdf"),
+                size: file.size / 1024 / 1024
+              });
+
+            case 2:
+              rsp = _context2.sent;
+
+              // 明细数据匹配表头
+              headers = mjs.$this.$("tableField_liv5f4d2").props.children.props.children.map(function (_ref2) {
+                var _ref2$props = _ref2.props,
+                    label = _ref2$props.label,
+                    fieldId = _ref2$props.fieldId;
+                return { label: label, compId: fieldId };
+              });
+              prop = rsp.data.dto; // 通用字段定义
+              //合计数据
+
+              amount = 0, tax = 0, exTax = 0;
+              invoices = rsp.data.result.map(function (item) {
+                var rowData = _Object$keys(prop).reduce(function (acc, cur) {
+                  var comp = headers.find(function (c) {
+                    return c.label == cur;
+                  });
+                  if (comp) {
+                    acc[comp.compId] = item[prop[cur]];
+                  }
+                  // 非标准表头,格式化
+                  if (cur == "价税合计") {
+                    acc.numberField_liihyrt7 = item.amount;
+                  }
+                  if (cur == "开票日期") {
+                    acc.textField_livimrja = item[prop[cur]];
+                    acc.dateField_liihyrt9 = new Date(acc.textField_livimrja).getTime();
+                  }
+                  return acc;
+                }, {});
+                // 合计数据
+                amount += item.amount;
+                tax += item.tax;
+                exTax += item.excludingTax;
+                // 发票数据标题: 销售方 + 发票类型 + 价税合计
+                rowData.textField_ljmgqvbz = item.sellerName + "-" + item.kindName + "-" + item.amount;
+                return rowData;
+              });
+
+              mjs.$this.$('numberField_ln05ra1i').setValue(amount);
+              mjs.$this.$('numberField_ln05ra1n').setValue(exTax);
+              mjs.$this.$('numberField_ln05ra1o').setValue(tax);
+              mjs.$this.$('tableField_liv5f4d2').setValue(invoices);
+              return _context2.abrupt("return", invoices);
+
+            case 12:
+            case "end":
+              return _context2.stop();
+          }
+        }
+      }, _callee2, _this2);
+    }))();
+  },
+
+
   // 批量验证
   batchCheck: function batchCheck() {
     return new _Promise(function (resolve, reject) {
       var details = mjs.$this.$('tableField_liv5f4d2').getValue();
       var param = details.map(function (item) {
         return {
-          kindName: item.selectField_liihyrta,
+          name: item.textField_liwbaczr, // 发票类型全称
           serial: item.textField_liihyrt8,
           code: item.textField_lil34mnc,
           date: item.textField_livimrja,
@@ -9212,7 +9286,7 @@ var guyuan = {
       }
       // 非作废校验
       var param = {
-        kindName: mjs.$this.$("selectField_liihyrta").getValue(),
+        name: mjs.$this.$("textField_ljasce9j").getValue(),
         serial: mjs.$this.$("textField_liihyrt8").getValue(),
         code: mjs.$this.$("textField_lil34mnc").getValue(),
         date: mjs.$this.$("textField_liwadykg").getValue(),

File diff suppressed because it is too large
+ 1 - 1
mjava-guyuan/src/main/resources/static/mjs/mjs.min.js


+ 4 - 2
mjava-guyuan/target/classes/META-INF/spring-configuration-metadata.json

@@ -30,8 +30,10 @@
     {
       "name": "tencent.t-y-p-e-i-n-v-o-i-c-e",
       "type": "java.util.Map<java.lang.String,java.lang.String>",
-      "description": "票据类型 - 中央非税未返回税号官方说明: 非税发票理论是没有税号的,图片中那个属于信用代码 [两个版本接口均为返回]",
-      "sourceType": "com.malk.guyuan.server.tencent.TXYConf"
+      "description": "票据类型 - 中央非税未返回税号官方说明: 非税发票理论是没有税号的,图片中那个属于信用代码 [两个版本接口均为返回] ppExt: 新版本官方返回数据已结构化, 以官方为准",
+      "sourceType": "com.malk.guyuan.server.tencent.TXYConf",
+      "deprecated": true,
+      "deprecation": {}
     }
   ],
   "hints": []

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

@@ -8000,7 +8000,7 @@ request.doForm = function (url, param) {
 
   // 变更请求头类型, 传递form
   conf[KEY_M_CONTENT_TYPE] = true;
-  return this.doPost(url, param, data, conf);
+  return this.doPost(url, param, lib.stringify(data), conf);
 };
 
 /** 4.upload: body-formData, 一般用于文件上传, 追加数据流 */
@@ -9098,13 +9098,13 @@ var guyuan = {
   // 修改公共配置
   init: function init() {
     {
-      mjs.conf.api = "https://mc.cloudpure.cn/api/guyuan/";
+      mjs.conf.api = "https://mc.cloudpure.cn/api/guyuan";
     }
     return this; // this 指向当前项目本身
   },
 
 
-  // 发票识别, 混票
+  // 发票识别, 混票  ppExt: 官方已停止更新, PDF多张异常
   mixedInvoice: function mixedInvoice(file) {
     var _this = this;
 
@@ -9168,13 +9168,87 @@ var guyuan = {
   },
 
 
+  // 发票识别, 混票 ppExt: 新版本官方返回数据已结构化, 以官方为准
+  mixedInvoice2: function mixedInvoice2(file) {
+    var _this2 = this;
+
+    return _asyncToGenerator( /*#__PURE__*/regenerator.mark(function _callee2() {
+      var rsp, headers, prop, amount, tax, exTax, invoices;
+      return regenerator.wrap(function _callee2$(_context2) {
+        while (1) {
+          switch (_context2.prev = _context2.next) {
+            case 0:
+              _context2.next = 2;
+              return mjs.request.xhr.doPost(mjs.conf.api + "/invoice-iv2", {}, {
+                url: file.url,
+                isPdf: file.type.includes("pdf"),
+                size: file.size / 1024 / 1024
+              });
+
+            case 2:
+              rsp = _context2.sent;
+
+              // 明细数据匹配表头
+              headers = mjs.$this.$("tableField_liv5f4d2").props.children.props.children.map(function (_ref2) {
+                var _ref2$props = _ref2.props,
+                    label = _ref2$props.label,
+                    fieldId = _ref2$props.fieldId;
+                return { label: label, compId: fieldId };
+              });
+              prop = rsp.data.dto; // 通用字段定义
+              //合计数据
+
+              amount = 0, tax = 0, exTax = 0;
+              invoices = rsp.data.result.map(function (item) {
+                var rowData = _Object$keys(prop).reduce(function (acc, cur) {
+                  var comp = headers.find(function (c) {
+                    return c.label == cur;
+                  });
+                  if (comp) {
+                    acc[comp.compId] = item[prop[cur]];
+                  }
+                  // 非标准表头,格式化
+                  if (cur == "价税合计") {
+                    acc.numberField_liihyrt7 = item.amount;
+                  }
+                  if (cur == "开票日期") {
+                    acc.textField_livimrja = item[prop[cur]];
+                    acc.dateField_liihyrt9 = new Date(acc.textField_livimrja).getTime();
+                  }
+                  return acc;
+                }, {});
+                // 合计数据
+                amount += item.amount;
+                tax += item.tax;
+                exTax += item.excludingTax;
+                // 发票数据标题: 销售方 + 发票类型 + 价税合计
+                rowData.textField_ljmgqvbz = item.sellerName + "-" + item.kindName + "-" + item.amount;
+                return rowData;
+              });
+
+              mjs.$this.$('numberField_ln05ra1i').setValue(amount);
+              mjs.$this.$('numberField_ln05ra1n').setValue(exTax);
+              mjs.$this.$('numberField_ln05ra1o').setValue(tax);
+              mjs.$this.$('tableField_liv5f4d2').setValue(invoices);
+              return _context2.abrupt("return", invoices);
+
+            case 12:
+            case "end":
+              return _context2.stop();
+          }
+        }
+      }, _callee2, _this2);
+    }))();
+  },
+
+
   // 批量验证
   batchCheck: function batchCheck() {
     return new _Promise(function (resolve, reject) {
       var details = mjs.$this.$('tableField_liv5f4d2').getValue();
       var param = details.map(function (item) {
         return {
-          kindName: item.selectField_liihyrta,
+          name: item.textField_liwbaczr, // 发票类型全称
           serial: item.textField_liihyrt8,
           code: item.textField_lil34mnc,
           date: item.textField_livimrja,
@@ -9212,7 +9286,7 @@ var guyuan = {
       }
       // 非作废校验
       var param = {
-        kindName: mjs.$this.$("selectField_liihyrta").getValue(),
+        name: mjs.$this.$("textField_ljasce9j").getValue(),
         serial: mjs.$this.$("textField_liihyrt8").getValue(),
         code: mjs.$this.$("textField_lil34mnc").getValue(),
         date: mjs.$this.$("textField_liwadykg").getValue(),

File diff suppressed because it is too large
+ 1 - 1
mjava-guyuan/target/classes/static/mjs/mjs.min.js


+ 1 - 1
mjava-kuaikeli/src/main/java/com/malk/kuaikeli/Boot.java

@@ -12,7 +12,7 @@ import javax.persistence.EntityManager;
  * corp项目: 扫描公共模块
  * -
  * 若是无需数据库模块, 配置无效地址也可启动, 引入mjava不支持直接 @SpringBootApplication(exclude = DataSourceAutoConfiguration.class) 配置
- * 需要配置 jpa.hibernate.ddl-auto 为 none. 标识对表没有任何操作. 若不设置为 non, flyway.enabled 配置会无效, 在没有数库连接情况下程序无法启动
+ * 需要配置 jpa.hibernate.ddl-auto 为 none. 标识对表没有任何操作. 若不设置为 none, flyway.enabled 配置会无效, 在没有数库连接情况下程序无法启动
  */
 @EnableJpaAuditing
 @SpringBootApplication(scanBasePackages = {"com.malk"})

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

@@ -53,7 +53,7 @@ public class KKLController {
             data.put("formData", JSON.toJSONString(formData));
             ydService.copyFormData(data); // 发起流程
         }
-        return McR.errorToken();
+        return McR.success();
     }
 
     @PostMapping("test")

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

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

+ 54 - 0
mjava-laidi/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-laidi</artifactId>
+    <description>莱帝OA与氚云出差单同步, 附件同步至钉盘</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-laidi/src/main/java/com/malk/laidi/Boot.java

@@ -0,0 +1,32 @@
+package com.malk.laidi;
+
+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);
+    }
+}

+ 157 - 0
mjava-laidi/src/main/java/com/malk/laidi/controller/LDController.java

@@ -0,0 +1,157 @@
+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.h3yun.CYClient;
+import com.malk.utils.UtilMap;
+import com.malk.utils.UtilServlet;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.map.HashedMap;
+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 javax.servlet.http.HttpServletRequest;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 错误抛出与拦截详见 CatchException
+ */
+@Slf4j
+@RestController
+@RequestMapping()
+public class LDController {
+
+    @Autowired
+    private DDClient ddClient;
+
+    @Autowired
+    private DDClient_Workflow ddClient_workflow;
+
+    @Autowired
+    private CYClient cyClient;
+
+    /// 匹配氚云用户ID [ ppExt 临时方案为, H_User系统表, 字段DingTalkAccount「返回格式为 userId.corpId」, 通过氚云定时任务储存与钉钉对照关系 ]
+    String _getCYUserIdByDingTalkUserId(String dUserId) {
+        Map extInfo = UtilMap.map("matcherJson", JSON.toJSONString(UtilMap.map("Type, Name, Operator, Value", "Item", "F0000003", 2, dUserId)));
+        List<Map> userList = cyClient.queryData(ddClient.getAccessToken(), "D1489118960387db0274aa18b9168cde213c3d3", extInfo);
+        return String.valueOf(userList.get(0).get("F0000002"));
+    }
+
+    /**
+     * 同步OA出差单到氚云
+     */
+    @PostMapping("sync-cc")
+    McR syncCC(@RequestBody Map data) {
+
+        String processInstanceId = UtilMap.getString(data, "processInstanceId");
+//        String processInstanceId = "KGkpcf8qRUe26Y4Vh7ICxQ08031691566909"; //
+//        String processInstanceId = "ckDghK5NSHuLYBVammK4Cg08031694687962";
+
+        Map processData = ddClient_workflow.getProcessInstanceId(ddClient.getAccessToken(), processInstanceId);
+        List<Map> formComponentValues = (List<Map>) processData.get("formComponentValues");
+
+        // OA组件name, 匹配氚云组件ID
+        String schemaCode = "D148911abbb84666b4b481783235d0fcfc39d8d";
+        Map<String, String> compsId_main = UtilMap.map("出差事由, 出差天数, 出差备注, 同行人", "F0000002, F0000010, F0000011, F0000015");
+        Map<String, String> compsId_itinerary = UtilMap.map("交通工具, 单程往返, 出发城市, 目的城市, 开始时间, 结束时间, 时长", "F0000003, F0000004, F0000005, F0000006, F0000007, F0000008, F0000009");
+        compsId_main.put("行程明细", "D148911F875802263af84ddaa01b9e6bd679eb74"); // 子表组件
+
+        String dUserId = String.valueOf(processData.get("originatorUserId"));
+        String cUserId = _getCYUserIdByDingTalkUserId(dUserId);
+//        String cUserId = "fe68dfe1-27f7-4533-8a55-081590e4462a"; // 吴作江
+        Map formData = UtilMap.map("F0000013", cUserId);
+
+        for (String name : compsId_main.keySet()) {
+            String compId = compsId_main.get(name);
+            // 判定是否子表 [氚云]
+            if (compId.startsWith("D")) {
+                List<Map> details = new ArrayList<>();
+                // ppExt: 出差申请单为明细组件, 存在多条情况
+                String schedule = (String) formComponentValues.stream().filter(item -> "itinerary".equals(item.get("bizAlias"))).findAny().get().get("value");
+                List<Map> itineraryList = ((List<Map>) JSON.parse(schedule));
+                // 循环明细数据
+                for (Map itinerary : itineraryList) {
+                    List<Map> rowValue = (List<Map>) itinerary.get("rowValue");
+                    Map rowData = new HashedMap();
+                    // 循环子表组件
+                    for (String subName : compsId_itinerary.keySet()) {
+                        rowData.put(compsId_itinerary.get(subName), rowValue.stream().filter(item -> subName.equals(item.get("label"))).findAny().get().get("value"));
+                    }
+                    details.add(rowData);
+                }
+                formData.put(compId, details);
+                continue;
+            }
+            Map formComp = formComponentValues.stream().filter(item -> name.equals(item.get("name"))).findAny().get();
+            Object value = formComp.get("value");
+            // 同行人, 数据处理
+            if ("InnerContactField".equals(formComp.get("componentType")) && formComp.containsKey("value")) {
+                List<Map> empInfos = (List<Map>) JSON.parse(String.valueOf(formComp.get("extValue")));
+                List<String> emplsId = new ArrayList<>();
+                for (Map empInfo : empInfos) {
+                    emplsId.add(_getCYUserIdByDingTalkUserId(String.valueOf(empInfo.get("emplId"))));
+                }
+                value = emplsId; // 成员多选
+            }
+            formData.put(compId, value);
+        }
+
+        Map extInfo = UtilMap.map("opUserId, bizObjectJson, isDraft", cUserId, JSON.toJSONString(formData), true);
+        Map rsp = cyClient.operateData(ddClient.getAccessToken(), schemaCode, extInfo);
+        cyClient.operateData(ddClient.getAccessToken(), schemaCode, UtilMap.map("bizObjectId, opUserId", rsp.get("bizObjectId"), cUserId));
+
+        return McR.success();
+    }
+
+
+    @Autowired
+    private DDClient_Storage ddClient_storage;
+
+    @Autowired
+    private DDConf ddConf;
+
+    @Autowired
+    private DDClient_Contacts ddClient_contacts;
+
+    /**
+     * 同步氚云附件到钉盘
+     */
+    @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")));
+
+        return McR.success();
+    }
+
+    @PostMapping("test")
+    McR test(HttpServletRequest request) {
+
+        Map data = UtilServlet.getParamMap(request);
+        log.info("xxxx, {}", data);
+
+        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);
+    }
+
+}

+ 39 - 0
mjava-laidi/src/main/resources/application-dev.yml

@@ -0,0 +1,39 @@
+# 环境配置
+server:
+  port: 9001
+  servlet:
+    context-path: /api/laidi
+
+# 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
+
+# dingtalk
+dingtalk:
+  agentId: 2673435445
+  appKey: dingozv6fzkpqkiupd3d
+  appSecret: bO4AA6ujXj8xgLBJI5pR7ns0vRsHCn8Ng9fTf9WF95HTOlCW0oybYpHsuxXuBPiO
+  corpId: dingcc1b1ffad0d5ca1d
+  aesKey:
+  token:
+  robotCode:
+  operator: "16608972969409067"   # 孙中保 [开头0, 需要转一下字符串]
+
+# h3yun
+h3yun:
+  engineCode: vqvl30y6teuqgfydfolo4gqo2
+  secret: mV17Rp3hqzwiSX9woQBqQyFLJVKuUSDaJclzr7VTlBJbhLZ1XUxTgA==

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

@@ -0,0 +1,39 @@
+# 环境配置
+server:
+  port: 9016
+  servlet:
+    context-path: /api/kuaikeli
+
+# 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
+
+# dingtalk
+dingtalk:
+  agentId: 2737389469
+  appKey: dingbdo9neuaibv5yjzb
+  appSecret: Gqy7vUkifTDQMCy5kQH8NaNVu1JepPr0Ci66XX5PiNts_mo6kNJEzYPumf3WcnmF
+  corpId: ding7071108579851504f5bf40eda33b7ba0
+  aesKey:
+  token:
+  robotCode:
+  operator: "8c69e45f31f3102938654423116841"   # 孙中保 [开头0, 需要转一下字符串]
+
+# h3yun
+h3yun:
+  engineCode: vqvl30y6teuqgfydfolo4gqo2
+  secret: mV17Rp3hqzwiSX9woQBqQyFLJVKuUSDaJclzr7VTlBJbhLZ1XUxTgA==

+ 35 - 0
mjava-laidi/src/test/resources/server.sh

@@ -0,0 +1,35 @@
+#!/bin/bash
+appname='mjava-laidi'
+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"
+  else
+    if [ "$1" == "test" ]; then
+      nohup java -Xms256m -Xmx256m -jar $appname.jar --spring.profiles.active=test &
+      echo "server test is starting"
+    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

+ 54 - 0
mjava-luyi/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-luyi</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-luyi/src/main/java/com/malk/luyi/Boot.java

@@ -0,0 +1,32 @@
+package com.malk.luyi;
+
+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);
+    }
+}

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

@@ -0,0 +1,97 @@
+package com.malk.luyi.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.dingtalk.DDR_New;
+import com.malk.service.aliwork.YDClient;
+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.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+@Slf4j
+@RestController
+@RequestMapping()
+public class LYController {
+
+    @Autowired
+    private YDClient ydClient;
+
+    /**
+     * 报告查询
+     */
+    @PostMapping("report/query")
+    McR query(@RequestBody Map data) {
+
+        log.info("报告查询, {}", data);
+        McException.assertParamException_Null(data, "cardNo, phoneNo, page, size");
+
+        // 更新客户档案
+        DDR_New ddr_new = ydClient.queryData(YDParam.builder()
+                .formUuid("FORM-MFA66S91KKJDA2708OHTW6RBOJRK3SVWO7KLL1")
+                .searchFieldJson(JSON.toJSONString(UtilMap.map("textField_llvq2dqf", data.get("cardNo"))))
+                .build(), YDConf.FORM_QUERY.retrieve_search_form);
+        McException.assertAccessException(ddr_new.getTotalCount() == 0, "信息未登记! ");
+        Map formData = (Map) ((List<Map>) ddr_new.getData()).get(0).get("formData");
+        List<Map> details = (List<Map>) formData.get("tableField_llk8hw38");
+        Optional optional = details.stream().filter(item -> data.get("phoneNo").equals(item.get("textField_llvq2dqr"))).findAny();
+        if (!optional.isPresent()) {
+            details.add(UtilMap.map("textField_llvq2dqr, textField_llk8hw39, radioField_lndtpa2c", data.get("phoneNo"), "报告回写", "报告回写"));
+            formData.put("tableField_llk8hw38", details);
+            ydClient.operateData(YDParam.builder()
+                    .formInstId(String.valueOf(((List<Map>) ddr_new.getData()).get(0).get("formInstanceId")))
+                    .updateFormDataJson(JSON.toJSONString(formData))
+                    .build(), YDConf.FORM_OPERATION.update);
+            // 写入联系人记录表
+            ydClient.operateData(YDParam.builder()
+                    .formUuid("FORM-XHA6688148UDAB8RCH4TO7T0CBGF3NWHGI4ML8")
+                    .formDataJson(JSON.toJSONString(UtilMap.map("selectField_lm4kbce2, textField_lm4igzq0, textField_lm4igzq2, textField_lm4igzq4, radioField_lndtpa2c",
+                            formData.get("textField_llk8hw32"), formData.get("serialNumberField_llkb8w7t"), "报告回写", data.get("phoneNo"), "报告回写")))
+                    .build(), YDConf.FORM_OPERATION.create);
+        }
+        // 查询报告结果
+        DDR_New ddr_new2 = ydClient.queryData(YDParam.builder()
+                .formUuid("FORM-JK866XA1L4NDBEHOC479CB21O0JI2N3NA6WLLC")
+                .searchFieldJson(JSON.toJSONString(UtilMap.map("textField_ln1df1f3", data.get("cardNo"))))
+                .pageNumber(UtilMap.getInt(data, "page"))
+                .pageSize(UtilMap.getInt(data, "size"))
+                .dynamicOrder(JSON.toJSONString(UtilMap.map("dateField_lndqxkvh", "-")))
+                .build(), YDConf.FORM_QUERY.retrieve_search_form);
+        return McR.success(ddr_new2);
+    }
+
+    /**
+     * 免登地址
+     */
+    @PostMapping("report/temporary")
+    McR temporary(@RequestBody Map data) {
+        McException.assertParamException_Null(data, "urls");
+        List<String> images = new ArrayList<>();
+        for (String url : (List<String>) UtilMap.getList(data, "urls")) {
+            images.add(ydClient.convertTemporaryUrl(url));
+        }
+        log.info("免登地址, {}", images);
+        return McR.success(images);
+    }
+
+    @PostMapping("test")
+    McR test() {
+
+        return McR.success();
+    }
+}

+ 65 - 0
mjava-luyi/src/main/resources/application-dev.yml

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

+ 39 - 0
mjava-luyi/src/main/resources/application-prod.yml

@@ -0,0 +1,39 @@
+# 环境配置
+server:
+  port: 9017
+  servlet:
+    context-path: /api/luyi
+
+# 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: 2753454778
+  appKey: dingenx3hbv3cyniukvm
+  appSecret: OhFtEw-Uys4K1uAW9oAVRULPl91rNZgjqG2nXzhfcRdvVA4_AK9aDBMqzDcMW1-i
+  corpId: dingc6aaf57b32e5f80cffe93478753d9884
+  aesKey:
+  token:
+  robotCode:
+  operator: "0953580166-1416321485"   # 杨辉 [开头0, 需要转一下字符串]
+
+# aliwork
+aliwork:
+  appType: APP_I45JU7MQMRRVZ472GS1U
+  systemToken: TG766XB110HDPKPV6HMGMC2IGEOM2STS67KLLS8

+ 35 - 0
mjava-luyi/src/test/resources/server.sh

@@ -0,0 +1,35 @@
+#!/bin/bash
+appname='mjava-luyi'
+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"
+  else
+    if [ "$1" == "test" ]; then
+      nohup java -Xms256m -Xmx256m -jar $appname.jar --spring.profiles.active=test &
+      echo "server test is starting"
+    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

+ 1 - 1
mjava-mcli/src/test/java/com/malk/mcli/YSTest.java

@@ -45,7 +45,7 @@
 //        ysClient.queryStoreArchives(ysClient.getAccessToken(), (list, total) -> {
 //            for (Map map : list) {
 //                float coefficient = 1.0f;
-//                String shopCode = String.valueOf(map.get("shopCode"));
+//                String shopCode = String.valueOf(map.getDefault("shopCode"));
 //                if (shopCode.contains("-")) {
 //                    String[] arrStr = shopCode.split("-");
 //                    coefficient = Float.valueOf(arrStr[arrStr.length - 1]);

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

@@ -12,7 +12,7 @@ import javax.persistence.EntityManager;
  * corp项目: 扫描公共模块
  * -
  * 若是无需数据库模块, 配置无效地址也可启动, 引入mjava不支持直接 @SpringBootApplication(exclude = DataSourceAutoConfiguration.class) 配置
- * 需要配置 jpa.hibernate.ddl-auto 为 none. 标识对表没有任何操作. 若不设置为 non, flyway.enabled 配置会无效, 在没有数库连接情况下程序无法启动
+ * 需要配置 jpa.hibernate.ddl-auto 为 none. 标识对表没有任何操作. 若不设置为 none, flyway.enabled 配置会无效, 在没有数库连接情况下程序无法启动
  */
 @EnableJpaAuditing
 @SpringBootApplication(scanBasePackages = {"com.malk"})

+ 2 - 1
mjava-pake/src/main/java/com/malk/pake/controller/SFController.java

@@ -24,7 +24,7 @@ import java.util.Map;
 @Slf4j
 @RestController
 @RequestMapping
-public class SFController {
+public class PKController {
 
     @Autowired
     private YDService ydService;
@@ -41,6 +41,7 @@ public class SFController {
         Map data = UtilServlet.getParamMap(request);
         log.info("关联表单自关联, 业务自动化下传, {}", data);
         List<Map> association = ydConf.associationForm(data.get("formUuid").toString(), data.get("formInstId").toString(), data.get("title").toString(), UtilMap.getString(data, "subTitle"), true);
+
         ydService.operateData(YDParam.builder()
                 .formInstId(String.valueOf(data.get("formInstId")))
                 .updateFormDataJson(JSON.toJSONString(UtilMap.map(data.get("compId").toString(), association)))

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

@@ -12,7 +12,7 @@ import javax.persistence.EntityManager;
  * corp项目: 扫描公共模块
  * -
  * 若是无需数据库模块, 配置无效地址也可启动, 引入mjava不支持直接 @SpringBootApplication(exclude = DataSourceAutoConfiguration.class) 配置
- * 需要配置 jpa.hibernate.ddl-auto 为 none. 标识对表没有任何操作. 若不设置为 non, flyway.enabled 配置会无效, 在没有数库连接情况下程序无法启动
+ * 需要配置 jpa.hibernate.ddl-auto 为 none. 标识对表没有任何操作. 若不设置为 none, flyway.enabled 配置会无效, 在没有数库连接情况下程序无法启动
  */
 @EnableJpaAuditing
 @SpringBootApplication(scanBasePackages = {"com.malk"})

+ 1 - 1
mjava-suodisi/src/main/java/com/malk/suodisi/Boot.java

@@ -12,7 +12,7 @@ import javax.persistence.EntityManager;
  * corp项目: 扫描公共模块
  * -
  * 若是无需数据库模块, 配置无效地址也可启动, 引入mjava不支持直接 @SpringBootApplication(exclude = DataSourceAutoConfiguration.class) 配置
- * 需要配置 jpa.hibernate.ddl-auto 为 none. 标识对表没有任何操作. 若不设置为 non, flyway.enabled 配置会无效, 在没有数库连接情况下程序无法启动
+ * 需要配置 jpa.hibernate.ddl-auto 为 none. 标识对表没有任何操作. 若不设置为 none, flyway.enabled 配置会无效, 在没有数库连接情况下程序无法启动
  */
 @EnableJpaAuditing
 @SpringBootApplication(scanBasePackages = {"com.malk"})

+ 1 - 1
mjava-suodisi/src/main/java/com/malk/suodisi/controller/SDSController.java

@@ -66,7 +66,7 @@ public class SDSController {
         for (Map row : list) {
             Map mailCondition = new HashMap();
             Map formData = (Map) row.get("formData");
-            //String mail1 = String.valueOf(formData.get("textField_lisbeacp"));
+            //String mail1 = String.valueOf(formData.getDefault("textField_lisbeacp"));
             String mail1 = String.valueOf(formData.get(ProcessCoding));
             for (String mail : mail1.split(";#")) {
                 if (mail.contains("@")) {

+ 1 - 1
mjava-yangu/pom.xml

@@ -24,7 +24,7 @@
             <artifactId>mjava</artifactId>
             <version>${mjava.version}</version>
         </dependency>
-        <!-- 腾讯云 [go to https://search.maven.org/search?q=tencentcloud-sdk-java and get the latest version.] -->
+        <!-- 腾讯云 [go to https://search.maven.org/search?q=tencentcloud-sdk-java and getDefault the latest version.] -->
         <dependency>
             <groupId>com.tencentcloudapi</groupId>
             <artifactId>tencentcloud-sdk-java</artifactId>

+ 1 - 1
mjava-yangu/src/main/java/com/malk/yangu/Boot.java

@@ -12,7 +12,7 @@ import javax.persistence.EntityManager;
  * corp项目: 扫描公共模块
  * -
  * 若是无需数据库模块, 配置无效地址也可启动, 引入mjava不支持直接 @SpringBootApplication(exclude = DataSourceAutoConfiguration.class) 配置
- * 需要配置 jpa.hibernate.ddl-auto 为 none. 标识对表没有任何操作. 若不设置为 non, flyway.enabled 配置会无效, 在没有数库连接情况下程序无法启动
+ * 需要配置 jpa.hibernate.ddl-auto 为 none. 标识对表没有任何操作. 若不设置为 none, flyway.enabled 配置会无效, 在没有数库连接情况下程序无法启动
  */
 @EnableJpaAuditing
 @SpringBootApplication(scanBasePackages = {"com.malk"})

+ 1 - 1
mjava-yangu/src/main/java/com/malk/yangu/server/tencent/TXYConf.java

@@ -26,7 +26,7 @@ public class TXYConf {
     /**
      * 票据类型
      * -
-     * 中央非税未返回税号官方说明: 非税发票理论是没有税号的,图片中那个属于信用代码 [两个版本接口均返回]
+     * 中央非税未返回税号官方说明: 非税发票理论是没有税号的,图片中那个属于信用代码 [两个版本接口均返回]
      */
     public static final Map<String, String> TYPE_INVOICE = UtilMap.map("-1, 0, 1, 2, 3, 5, 8, 9, 10, 11, 12, 13, 15, 16",
             "未知类型, 出租车发票, 定额发票, 火车票, 增值税发票, 机票行程单, 通用机打发票, 汽车票, 轮船票, 增值税发票(卷票) , 购车发票, 过路过桥费发票, 非税发票, 全电发票");

+ 2 - 6
mjava-yangu/src/main/java/com/malk/yangu/tencent/impl/TXYImplInvoice.java

@@ -1,9 +1,6 @@
 package com.malk.yangu.tencent.impl;
 
 import com.alibaba.fastjson.JSON;
-import com.malk.server.common.McException;
-import com.malk.utils.UtilMap;
-import com.malk.utils.UtilNumber;
 import com.malk.yangu.server.tencent.TXYConf;
 import com.malk.yangu.tencent.TXYInvoice;
 import com.tencentcloudapi.common.Credential;
@@ -122,10 +119,9 @@ public class TXYImplInvoice implements TXYInvoice {
         if (StringUtils.isBlank(tips)) {
             tips = "发票有疑问";
         }
-        McException.assertAccessException(!UtilNumber.equalBigDecimal(UtilMap.getString(invoice, "AmountWithTax"), amount), tips + ", 价税合计金额不匹配!");
-        McException.assertAccessException(!UtilNumber.equalBigDecimal(UtilMap.getString(invoice, "AmountWithoutTax"), excludingTax), tips + ", 不含税金额不匹配!");
-
         log.debug("请求响应, {}", result);
+//     McException.assertAccessException(!UtilNumber.equalBigDecimal(UtilMap.getString(invoice, "AmountWithTax"), amount), tips + ", 价税合计金额不匹配!");
+//        McException.assertAccessException(!UtilNumber.equalBigDecimal(UtilMap.getString(invoice, "AmountWithoutTax"), excludingTax), tips + ", 不含税金额不匹配!");
         return rsp;
     }
 

+ 1 - 1
mjava/src/main/java/com/malk/base/BaseDto.java

@@ -28,7 +28,7 @@ import java.util.Set;
  * @AllArgsConstructor : 注在类上,提供类的全参构造
  * @NoArgsConstructor : 注在类上,提供类的无参构造
  * @Setter : 注在属性上,提供 set 方法
- * @Getter : 注在属性上,提供 get 方法
+ * @Getter : 注在属性上,提供 getDefault 方法
  * @EqualsAndHashCode : 注在类上,提供对应的 equals 和 hashCode 方法
  * @Log4j/@Slf4j : 注在类上,提供对应的 Logger 对象,变量名为 log
  * @Builder:为类生成相对略微复杂的构建器API。来初始化实例对象::类名.属性(值).属性(值).build()

+ 1 - 1
mjava/src/main/java/com/malk/base/JpaMap.java

@@ -61,7 +61,7 @@ public class JpaMap {
             }
 
             if (ObjectUtil.isNotNull(sTime)) {
-//            javax.persistence.criteria.Predicate predicate = criteriaBuilder.greaterThanOrEqualTo(root.get("dPlanDate").as(String.class), "2023-06-03 00:00:00");
+//            javax.persistence.criteria.Predicate predicate = criteriaBuilder.greaterThanOrEqualTo(root.getDefault("dPlanDate").as(String.class), "2023-06-03 00:00:00");
                 javax.persistence.criteria.Predicate predicate = criteriaBuilder.greaterThanOrEqualTo(root.get("dPlanDate"), sTime);
                 predicates.add(predicate);
             }

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

@@ -73,6 +73,7 @@ public class YDConf {
         delete_batch,               // 批量删除
         multi_update,               // 批量更新
         start,                      // 发起流程
+        batchSave,                  // 批量创建
     }
 
     /**

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

@@ -29,7 +29,6 @@ public class VenR extends BaseDto {
     public static final String RC_DD_New = "com.malk.server.dingtalk.DDR_New";
     public static final String RC_EKB = "com.malk.server.ekuaibao.EKBRR";
     public static final String RC_FXK = "com.malk.server.fxiaoke.FXKR ";
-    public static final String RC_CY = "com.malk.server.h3yun.CYR";
     public static final String RC_XBB = "com.malk.server.xbongbong.XBBR";
     public static final String RC_VK = "com.malk.server.vika.VKR";
 

+ 32 - 2
mjava/src/main/java/com/malk/server/dingtalk/DDR_New.java

@@ -27,6 +27,11 @@ public class DDR_New<T> extends VenR {
 
     private T result;
 
+    /**
+     * 无权限对应CODE
+     */
+    private Map accessdenieddetail;
+
     /**
      * 离职记录列表
      */
@@ -57,6 +62,19 @@ public class DDR_New<T> extends VenR {
 
     private Map formData;
 
+    //// CRM ////
+
+    /**
+     * 客户元数据
+     */
+    private String name;
+
+    private boolean customized;
+
+    private List<Map> fields;
+
+    private boolean status;
+
     ////  储存空间  ////
 
     /**
@@ -84,11 +102,20 @@ public class DDR_New<T> extends VenR {
      */
     private Map dentry;
 
+    /**
+     * 钉盘: 下一页的游标,为空字符串则表示分页结束
+     */
+    private String nextToken;
+
+    private List<Map> spaces;
+
     ////  专属钉  ////
 
-    // 无数据返回空 {}
+    // 避免无数据返回空
     private List<Map> list = new ArrayList<>();
 
+    // 成功状态标记 [氚云]
+    private final static String SUC_CODE = "success";
 
     /**
      * 断言错误信息
@@ -97,7 +124,10 @@ public class DDR_New<T> extends VenR {
      */
     @Override
     public void assertSuccess() {
-        McException.assertException(ObjectUtil.isNotNull(code), code, message, "dingtalk_new");
+        if (ObjectUtil.isNotNull(accessdenieddetail)) {
+            message = "没有调用该接口的权限: " + accessdenieddetail;
+        }
+        McException.assertException(ObjectUtil.isNotNull(code) && !SUC_CODE.equals(code), code, message, "dingtalk_new");
     }
 
     /**

+ 15 - 1
mjava/src/main/java/com/malk/server/h3yun/CYConf.java

@@ -1,9 +1,23 @@
 package com.malk.server.h3yun;
 
+import lombok.Data;
 import lombok.Getter;
-
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+@Data
+@Component
+@ConfigurationProperties(prefix = "h3yun")
+@Slf4j
 public class CYConf {
 
+    private String engineCode;
+
+    private String secret;
+    
+    /////////////////////////////// 静态方法 ///////////////////////////////
+
     // 按钮动作
     public enum ACTION_NAME {
 

+ 0 - 32
mjava/src/main/java/com/malk/server/h3yun/CYR.java

@@ -1,32 +0,0 @@
-package com.malk.server.h3yun;
-
-import com.malk.server.common.McException;
-import com.malk.server.common.VenR;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-
-/**
- * 返回值配置参考McR
- */
-@Data
-@NoArgsConstructor
-public class CYR<T> extends VenR {
-
-
-    private String code;
-
-    private String message;
-
-    private T data;
-
-    // 成功状态标记
-    private final static String SUC_CODE = "success";
-
-    /**
-     * 断言错误信息
-     */
-    @Override
-    public void assertSuccess() {
-        McException.assertException(!code.equals(SUC_CODE), code, message, "h3yun");
-    }
-}

+ 36 - 2
mjava/src/main/java/com/malk/service/aliwork/YDService.java

@@ -9,6 +9,9 @@ import java.util.Map;
 
 public interface YDService {
 
+    // todo: 批量创建接口异常; 查询子表超过50自动查询全量; 查询表单全部数据, 避免第一次重复查询优化, 添加直接返回formData, 兼容formInstId;  upsert方法
+
+
     /**
      * 操作数据 [异步]
      */
@@ -20,12 +23,21 @@ public interface YDService {
     Object operateData2(Map data, Map update, YDParam param, YDConf.FORM_OPERATION type);
 
     /**
-     * 查询数据 [子表]
+     * 查询数据 [子表] todo 参数控制
+     * <p>
+     * .formUuid("FORM-TD966Z81I9ODTCY66GH345S03VW03JJF6EQLL5")
+     * .formInstanceId(data.get("formInstanceId").toString())
+     * .tableFieldId("tableField_llqe7fgb")
      */
     List<Map> queryDetails(YDParam ydParam);
 
     /**
-     * 查询全部 [主表]
+     * 查询全部 [主表] todo 合并formData, 或data, putAll
+     * <p>
+     * .stream().map(item -> {
+     * item.putAll( (Map) item.get("formData"));
+     * return item;
+     * }).collect(Collectors.toList());
      */
     List<Map> queryAllFormData(YDParam YDParam);
 
@@ -46,4 +58,26 @@ public interface YDService {
      * 2. 所有组件通过英文逗号 + 空格区分, 子表组件为避免组件id相同但子表内组件不一致的情况, 在单独子表组件ID后添加 src/cur 区分来源
      */
     Object copyFormData(Map data);
+
+    /**
+     * upsert方法 [todo: 优化 批量的数据兼容]
+     *
+     * @param lambda 查询数据回调, 传递查询结果list, 接收回调返回map传递钉到formData内, 若返回为空则不支持Upsert
+     */
+    Object upsertFormData(String formUuid, Map condition, Map formData, UpsertLambda lambda);
+
+    /**
+     * ppExt 函数式编程:Stream类、Lambda表达式和函数接口(Functional Inteface)
+     * -
+     * 自定义Lambda是为了更好的代码提示和数据类型定义: @FunctionalInterface,该接口为函数接口,一个函数接口只能存在一个方法
+     * 特别注意,非异步情况下,和网络请求一致,回调默认同步等待【回调方式可自定义:如兼容并发可有,同步单次回调、同步累积回调、并发异步执行、并发累积回调】
+     * 函数编程的最大好处,是可传入执行逻辑,而无需等待全部数据结果,尤其并发和异步情况下【异步效果优于Future】
+     * -
+     * 结合异步与并发, @Async说明和配置详见core/AsyncConfig
+     */
+    @FunctionalInterface
+    interface UpsertLambda {
+        Map dataList(List<Map> list);
+    }
+
 }

+ 3 - 0
mjava/src/main/java/com/malk/service/aliwork/impl/YDClientImpl.java

@@ -74,6 +74,9 @@ public class YDClientImpl implements YDClient {
             case multi_update:
                 ddr_new = (DDR_New) UtilHttp.doPut(getRequestUrl("/forms/instances/components"), ddClient.initTokenHeader(), bodys, DDR_New.class);
                 return ddr_new.getResult(); // 表单实例Id
+            case batchSave:
+                ddr_new = (DDR_New) UtilHttp.doPost(getRequestUrl("/forms/instances/batchSave"), ddClient.initTokenHeader(), null, _initBodyParam(ydParam), DDR_New.class);
+                break;
             default:
                 break;
         }

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

@@ -1,5 +1,6 @@
 package com.malk.service.aliwork.impl;
 
+import cn.hutool.core.util.ObjectUtil;
 import com.alibaba.fastjson.JSON;
 import com.malk.server.aliwork.YDConf;
 import com.malk.server.aliwork.YDParam;
@@ -88,7 +89,7 @@ public class YDServiceImpl implements YDService {
     @Override
     public List<Map> queryAllFormData(YDParam ydParam) {
         float pageSize = YDConf.PAGE_SIZE_LIMIT;
-        // 查询数据量
+        // 查询数据量 [todo 先查询100, 再进行分页, 避免无效查询多一次]; 2. 直接返回formData, 兼容实例ID
         ydParam.setPageSize(1);
         long totalCount = ydClient.queryData(ydParam, YDConf.FORM_QUERY.retrieve_search_form).getTotalCount();
         // 轮询累计数据
@@ -168,4 +169,36 @@ public class YDServiceImpl implements YDService {
                 .formDataJson(JSON.toJSONString(dataForm))
                 .build(), type);
     }
+
+    /**
+     * upsert方法
+     */
+    @Override
+    public Object upsertFormData(String formUuid, Map condition, Map formData, UpsertLambda lambda) {
+        YDParam ydParam = YDParam.builder()
+                .formUuid(formUuid)
+                .searchFieldJson(JSON.toJSONString(condition))
+                .build();
+        // 查询数据, 是否存在
+        List<Map> dataList = (List<Map>) ydClient.queryData(ydParam, YDConf.FORM_QUERY.retrieve_search_form).getData();
+        McException.assertAccessException(dataList.size() > 1, "upsert方法, 查询条件返回数据不唯一");
+        // 异步回调, 查询结果
+        if (ObjectUtil.isNotNull(lambda)) {
+            Map form = lambda.dataList(dataList);
+            // 若返回为空, 不执行
+            if (ObjectUtil.isNull(form)) {
+                return null;
+            }
+            // 回调数据, 写入表单
+            formData.putAll(form);
+        }
+        if (dataList.size() > 0) {
+            ydParam.setUpdateFormDataJson(JSON.toJSONString(formData));
+            ydParam.setFormInstanceId(dataList.get(0).get("formInstanceId").toString());
+            return ydClient.operateData(ydParam, YDConf.FORM_OPERATION.update);
+        }
+        formData.putAll(condition); // 新增写入查询条件数据
+        ydParam.setFormDataJson(JSON.toJSONString(formData));
+        return ydClient.operateData(ydParam, YDConf.FORM_OPERATION.create);
+    }
 }

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

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

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

@@ -7,6 +7,25 @@ import java.util.Map;
 
 public interface DDClient_Storage {
 
+
+    ///////////////////////// 钉盘附件 /////////////////////////
+
+    /**
+     * 新建空间
+     *
+     * @implSpec 客户端云盘内是不可见: 1. 官方OA审批 - 审批钉盘空间&附件 - 获取审批钉盘空间信息; 2. 文档/文件 - 存储管理 - 空间管理 - 添加空间
+     */
+    DDR_New createSpaces(String accessToken, String name, String unionId);
+
+    /**
+     * 获取空间列表
+     *
+     * @implSpec 忽略分页, 一次性全量查询
+     */
+    List<Map> getSpaces(String accessToken, String unionId);
+
+    ///////////////////////// OA审批附件 /////////////////////////
+
     /**
      * 获取审批钉盘空间信息
      *

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

@@ -0,0 +1,21 @@
+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);
+    }
+}

+ 40 - 0
mjava/src/main/java/com/malk/service/dingtalk/impl/DDImplClient_Storage.java

@@ -7,6 +7,7 @@ import com.malk.service.dingtalk.DDClient_Storage;
 import com.malk.utils.UtilMap;
 import lombok.SneakyThrows;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.stereotype.Service;
 
 import java.io.FileInputStream;
@@ -14,6 +15,7 @@ import java.io.InputStream;
 import java.io.OutputStream;
 import java.net.HttpURLConnection;
 import java.net.URL;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 
@@ -26,6 +28,44 @@ import java.util.Map;
 @Slf4j
 public class DDImplClient_Storage implements DDClient_Storage {
 
+    ///////////////////////// 钉盘附件 /////////////////////////
+
+    /**
+     * 新建空间
+     *
+     * @apiNote https://open.dingtalk.com/document/orgapp/new-space
+     */
+    @Override
+    public DDR_New createSpaces(String accessToken, String name, String unionId) {
+        return null;
+    }
+
+    /**
+     * 获取空间列表
+     *
+     * @apiNote https://open.dingtalk.com/document/orgapp/queries-a-space-list
+     */
+    @Override
+    public List<Map> getSpaces(String accessToken, String unionId) {
+
+        return _getSpaces(accessToken, unionId, 50, null, new ArrayList<>());
+    }
+
+    private List<Map> _getSpaces(String accessToken, String unionId, int maxResults, String nextToken, List<Map> dataList) {
+
+        // spaceType: 空间类型。org:企业空间
+        Map param = UtilMap.map("unionId, spaceType, maxResults, nextToken", unionId, "org", maxResults, nextToken);
+        DDR_New ddr_new = DDR_New.doGet("https://api.dingtalk.com/v1.0/drive/spaces", DDConf.initTokenHeader(accessToken), param);
+        dataList.addAll(ddr_new.getSpaces());
+        // 返回空字符串, 过滤
+        if (StringUtils.isNotBlank(ddr_new.getNextToken())) {
+            _getSpaces(accessToken, unionId, maxResults, ddr_new.getNextToken(), dataList);
+        }
+        return dataList;
+    }
+
+    ///////////////////////// OA审批附件 /////////////////////////
+
     /**
      * 获取审批钉盘空间信息
      *

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

@@ -13,7 +13,7 @@ import java.util.Map;
 
 @Service
 @Slf4j
-public class DDImplClient_Log implements DDClient_Log {
+public class DDImplClient_WorkDaily implements DDClient_Log {
 
     /**
      * 获取用户发出的日志列表

+ 4 - 4
mjava/src/main/java/com/malk/service/ekuaibao/EKBClient.java

@@ -9,7 +9,7 @@ public interface EKBClient {
     /**
      * 根据单据编号获取单据详情
      *
-     * @apiNote https://docs.ekuaibao.com/docs/next/open-api/flows/get-forms-details-byCode?_highlight=%E5%8D%95%E6%8D%AE&_highlight=%E8%AF%A6%E6%83%85
+     * @apiNote https://docs.ekuaibao.com/docs/next/open-api/flows/getDefault-forms-details-byCode?_highlight=%E5%8D%95%E6%8D%AE&_highlight=%E8%AF%A6%E6%83%85
      */
     Map getFlowDetailsByCode(String accessToken, String code);
 
@@ -29,7 +29,7 @@ public interface EKBClient {
      *
      * @param type         STAFFID : 员工ID, CODE : 工号, CELLPHONE : 手机号, MAIL : 邮箱, USERID : 第三方ID
      * @param conditionIds 要查询条件值, 支持多个
-     * @apiNote https://docs.ekuaibao.com/docs/open-api/corporation/get-staff-ids
+     * @apiNote https://docs.ekuaibao.com/docs/open-api/corporation/getDefault-staff-ids
      */
     List<Map> getStaffInfo(String accessToken, String type, List conditionIds);
 
@@ -42,14 +42,14 @@ public interface EKBClient {
      * 根据模板ID获取模板信息
      *
      * @param ids 先通过api获取单据模板列表
-     * @apiNote https://docs.ekuaibao.com/docs/open-api/forms/get-template-byId
+     * @apiNote https://docs.ekuaibao.com/docs/open-api/forms/getDefault-template-byId
      */
     List<Map> getTemplateIdById(String accessToken, List<String> ids);
 
     /**
      * 获取自定义档案项(不带可见范围)
      *
-     * @apiNote https://docs.ekuaibao.com/docs/next/open-api/dimensions/get-dimension-items
+     * @apiNote https://docs.ekuaibao.com/docs/next/open-api/dimensions/getDefault-dimension-items
      */
     EKBR getDimensionsList(String accessToken, int start, int count, Map body_ext);
 }

+ 51 - 0
mjava/src/main/java/com/malk/service/h3yun/CYClient.java

@@ -1,10 +1,38 @@
 package com.malk.service.h3yun;
 
 import java.io.File;
+import java.util.List;
 import java.util.Map;
 
 public interface CYClient {
 
+    //////////////////////////// 单据流程 ////////////////////////////
+
+    // todo: 统一规划宜搭和氚云格式
+
+    /**
+     * 查询表单数据
+     *
+     * @param schemaCode 表单编码
+     * @param extInfo    扩展信息
+     *                   - pageNumber 分页页码; pageSize 分页页大小,最大值500
+     *                   - returnFields 需要返回的字段名,仅支持传入主表的字段
+     *                   - matcherJson json格式的动态条件过滤器
+     *                   - sortByFields: { fieldName: "排序字段名", direction: "Ascending:升序 / Descending:降序" } 排序字段结构列表
+     */
+    List<Map> queryData(String accessToken, String schemaCode, Map extInfo);
+
+    /**
+     * 创建流程数据 [todo: 接口代合并, 流程的逻辑为先创建表单数据为Draft, 再进行流程提交]
+     *
+     * @param extInfo 扩展信息, opUserId 操作用户ID
+     *                - 流程发起, 需要传递创建Draft数据ID;
+     *                - 创建表单数据 bizObjectJson ; isDraft 是否是草稿
+     */
+    Map operateData(String accessToken, String schemaCode, Map extInfo);
+
+    //////////////////////////// 附件处理 ////////////////////////////
+
     /**
      * 获取附件临时免登地址 [此返回地址有效期为三十分钟]
      *
@@ -17,4 +45,27 @@ public interface CYClient {
      * 储存氚云附件到本地, 保留文件名称与格式
      */
     File saveFromTemporaryUrl(String accessToken, Map attachmentId);
+
+
+    //////////////////////////// 组织架构 ////////////////////////////
+
+    /**
+     * 获取用户数据
+     * -
+     * ppExt 氚云组织架构只有全量查询接口, 且部门和用户ID, 有单独ID. 更甚接口未返回钉钉userId与手机号登信息
+     * 1. todo: 后续考虑新建氚云webservice进行写入
+     * 2. 临时方案为, H_User系统表, 字段DingTalkAccount「返回格式为 userId.corpId」, 通过氚云定时任务储存与钉钉对照关系
+     *
+     * @param isRecursive 是否递归获取子级部门下的用户。默认值为false
+     */
+    @Deprecated
+    List<Map> getUserInfoList(String accessToken, String departmentId, boolean isRecursive);
+
+    /**
+     * 获取组织数据 [ppExt: 氚云接口返回组织架构为平铺列表, 若需要可通过 parentId 构建]
+     *
+     * @param departmentId 为空返回同步部门
+     */
+    @Deprecated
+    List<Map> getDepartmentInfoList(String accessToken, String departmentId);
 }

+ 59 - 3
mjava/src/main/java/com/malk/service/h3yun/impl/CYImplClient.java

@@ -1,9 +1,8 @@
 package com.malk.service.h3yun.impl;
 
 import com.malk.server.common.FilePath;
-import com.malk.server.common.VenR;
 import com.malk.server.dingtalk.DDConf;
-import com.malk.server.h3yun.CYR;
+import com.malk.server.dingtalk.DDR_New;
 import com.malk.service.h3yun.CYClient;
 import com.malk.utils.UtilFile;
 import com.malk.utils.UtilHttp;
@@ -13,6 +12,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
 import java.io.File;
+import java.util.List;
 import java.util.Map;
 
 @Slf4j
@@ -32,13 +32,16 @@ public class CYImplClient implements CYClient {
     @Override
     public String getTemporaryUrls(String accessToken, String attachmentId) {
         Map param = UtilMap.map("attachmentId", attachmentId);
-        CYR cyr = (CYR) CYR.doGet(getRequestUrl("/attachments/temporaryUrls"), DDConf.initTokenHeader(accessToken), param, VenR.RC_CY);
+        DDR_New cyr = DDR_New.doGet(getRequestUrl("/attachments/temporaryUrls"), DDConf.initTokenHeader(accessToken), param);
         return UtilMap.getString(((Map) cyr.getData()), "attachmentUrl");
     }
 
     @Autowired
     private FilePath filePath;
 
+    /**
+     * 储存氚云附件到本地, 保留文件名称与格式
+     */
     @Override
     public File saveFromTemporaryUrl(String accessToken, Map attachment) {
         String fileUrl = getTemporaryUrls(accessToken, UtilMap.getString(attachment, "FileId"));
@@ -47,4 +50,57 @@ public class CYImplClient implements CYClient {
         UtilHttp.doDownload(fileUrl, file);
         return file;
     }
+
+    /**
+     * 查询表单数据
+     */
+    @Override
+    public List<Map> queryData(String accessToken, String schemaCode, Map extInfo) {
+
+        extInfo = UtilMap.empty(extInfo);
+        UtilMap.put(extInfo, "pageSize", 500);
+        UtilMap.put(extInfo, "pageNumber", 1);
+        extInfo.put("schemaCode", schemaCode);
+        DDR_New cyr = DDR_New.doPost(getRequestUrl("/forms/instances/search"), DDConf.initTokenHeader(accessToken), null, extInfo);
+        return (List<Map>) ((Map) cyr.getData()).get("bizObjects");
+    }
+
+    /**
+     * 创建流程数据
+     */
+    @Override
+    public Map operateData(String accessToken, String schemaCode, Map extInfo) {
+
+        Map body = UtilMap.map("schemaCode", schemaCode);
+
+        String path = "/forms/instances";
+        if (extInfo.containsKey("bizObjectId")) {
+            path = "/processes/instances";
+        }
+        UtilMap.putAll(body, extInfo);
+        DDR_New cyr = DDR_New.doPost(getRequestUrl(path), DDConf.initTokenHeader(accessToken), null, body);
+        return (Map) cyr.getData();
+    }
+
+    /**
+     * 获取用户数据
+     *
+     * @apiNote https://open.dingtalk.com/document/orgapp/obtain-user-data
+     */
+    @Override
+    public List<Map> getUserInfoList(String accessToken, String departmentId, boolean isRecursive) {
+        Map param = UtilMap.map("departmentId, isRecursive", departmentId, isRecursive);
+        DDR_New cyr = DDR_New.doGet(getRequestUrl("/users"), DDConf.initTokenHeader(accessToken), param);
+        return (List<Map>) cyr.getData();
+    }
+
+    /**
+     * 获取组织数据
+     */
+    @Override
+    public List<Map> getDepartmentInfoList(String accessToken, String departmentId) {
+        Map param = UtilMap.putNotEmpty(UtilMap.empty(), "departmentId", departmentId);
+        DDR_New cyr = DDR_New.doGet(getRequestUrl("/departments"), DDConf.initTokenHeader(accessToken), param);
+        return (List<Map>) cyr.getData();
+    }
 }

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

@@ -186,7 +186,6 @@ public abstract class UtilDateTime {
         return LocalTime.parse(dateStr, DateTimeFormatter.ofPattern(pattern));
     }
 
-
     //// Calendar ////
 
     // 获取上月最后一天

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

@@ -26,7 +26,7 @@ import java.util.Map;
  * 4. response 请求后若需要转为数据类型, 读取请求结果body为JSONString. 若直接获取格式字符串, 不能再转为对象或Map
  * -
  * -  前端请求格式
- * 1. get: url上param, 后端取值@requestParam,也可用request.getParameterMap().get(“key”), 参数会被放入一个集合
+ * 1. getDefault: url上param, 后端取值@requestParam,也可用request.getParameterMap().getDefault(“key”), 参数会被放入一个集合
  * 2. post: body内json, 后端取值@requestBody, Map 或转为实体
  * 3. form: body内格式为form, 和content-type有关系, 需要为form格式后端才能读取: 不能使用@RequestBody,参数会自动解析到实体; 若不是实体通过方法转Map
  * 4. upload: body-formData, 一般用于文件上传, 追加数据流

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

@@ -83,7 +83,7 @@ public abstract class UtilMap {
     /************* 赋值 ************/
 
     /**
-     * 赋值 [为空对象, 字符串空null, 忽略]
+     * 赋值 [为空对象null, 忽略]
      */
     public static Map putNotNull(Map data, String key, Object value) {
         if (ObjectUtil.isNull(data)) {
@@ -95,11 +95,27 @@ public abstract class UtilMap {
         return data;
     }
 
+    /**
+     * 赋值 [为空字符串, 忽略]
+     */
+    public static Map putNotEmpty(Map data, String key, String value) {
+        if (ObjectUtil.isNull(data)) {
+            data = new HashMap();
+        }
+        if (StringUtils.isNotBlank(value)) {
+            data.put(key, value);
+        }
+        return data;
+    }
+
     /**
      * 非空对象全量合并
      */
     public static Map putAll(Map data, Map value) {
         if (ObjectUtil.isNull(data)) {
+            if (ObjectUtil.isNull(value)) {
+                return empty();
+            }
             return value;
         }
         if (ObjectUtil.isNotNull(value)) {
@@ -108,7 +124,6 @@ public abstract class UtilMap {
         return data;
     }
 
-
     /**
      * 赋值 [值为0, 忽略]
      */
@@ -125,6 +140,18 @@ public abstract class UtilMap {
         return data;
     }
 
+    /**
+     * 赋值 [为空赋值默认值]
+     */
+    public static Map put(Map data, String key, Object defaultValue) {
+        Object value = data.get(key);
+        if (ObjectUtil.isNull(value)) {
+            value = defaultValue;
+        }
+        data.put(key, value);
+        return data;
+    }
+
     /************* 取值 ************/
 
     /**
@@ -180,7 +207,7 @@ public abstract class UtilMap {
     /**
      * 取值 [为空返回默认值]
      */
-    public static Object get(Map data, String key, Object defaultValue) {
+    public static Object get_default(Map data, String key, Object defaultValue) {
         Object value = data.get(key);
         if (ObjectUtil.isNull(value)) {
             return defaultValue;
@@ -191,7 +218,7 @@ public abstract class UtilMap {
     /**
      * 取值 [为空返回默认字符串]
      */
-    public static String getString(Map data, String key, String defaultValue) {
+    public static String getString_default(Map data, String key, String defaultValue) {
         String value = getString(data, key);
         if (StringUtils.isBlank(value)) {
             return defaultValue;
@@ -199,6 +226,35 @@ public abstract class UtilMap {
         return value;
     }
 
+    /**
+     * 取值 [未定key, 取第一个命中]
+     */
+    public static Object get_first(Map data, String... keys) {
+        Object value = null;
+        for (String key : keys) {
+            if (data.containsKey(key)) {
+                value = data.get(key);
+                break;
+            }
+        }
+        return value;
+    }
+
+    /**
+     * 取值 String [未定key, 取第一个命中]
+     */
+    public static String getString_first(Map data, String... keys) {
+        String value = "";
+        for (String key : keys) {
+            // 字段 + 值判定
+            if (data.containsKey(key) && StringUtils.isNotBlank(getString(data, key))) {
+                value = UtilString.stringFormatNull(data, key);
+                break;
+            }
+        }
+        return value;
+    }
+
     /**
      * 取值 List
      */
@@ -210,7 +266,7 @@ public abstract class UtilMap {
     }
 
     /**
-     * 取值 List
+     * 取值 Map
      */
     public static Map getMap(Map data, String key) {
         if (data.containsKey(key)) {

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

@@ -1,5 +1,6 @@
 package com.malk.utils;
 
+import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
 
 import java.math.BigDecimal;
@@ -13,6 +14,7 @@ import java.util.regex.Pattern;
  * -
  * ppExt: 不要直接使用 Number 作为类型, 不同基本类型比较值时会有偏差 [可以作为父类接受数据, 避免直接强制类型转换错误, 再进行基本类型处理]
  */
+@Slf4j
 public class UtilNumber {
 
     /**
@@ -98,7 +100,7 @@ public class UtilNumber {
      * 非数值型字符串, 空字符串兼容
      */
     public static final BigDecimal setBigDecimal(String strNum) {
-        BigDecimal decimal = null;
+        BigDecimal decimal = null; // 空
         if (StringUtils.isNotBlank(strNum)) {
             try {
                 decimal = new BigDecimal(strNum);
@@ -123,6 +125,20 @@ public class UtilNumber {
         return compareBigDecimal(n1, n2) == 0;
     }
 
+    /**
+     * 判断两个BigDecimal, 转数值后是否相等
+     */
+    public static final int compareBigDecimal(BigDecimal n1, BigDecimal n2) {
+        return n1.compareTo(n2);
+    }
+
+    /**
+     * 判断两个BigDecimal, 转数值后是否相等
+     */
+    public static final boolean equalBigDecimal(BigDecimal n1, BigDecimal n2) {
+        return compareBigDecimal(n1, n2) == 0;
+    }
+
     /**
      * 尾数: 0.5取整逻辑, 小于0.5为0.5, 大于0.5为1
      */

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

@@ -44,8 +44,13 @@ public abstract class UtilString {
         return value.replaceAll("\\u0028", "(").replaceAll("\\u0029", ")");
     }
 
-    // 中文圆括号转为英文圆括号 [参考: 常用Unicode字符对照表]
+    // 英文圆括号转为中文圆括号 [参考: 常用Unicode字符对照表]
     public static String replaceBracketIsWhole(String value) {
         return value.replaceAll("(", "(").replaceAll(")", ")");
     }
+
+    // 格式刷日期, 去除年月日
+    public static String replaceDateZH_cn(String date) {
+        return date.replace("年", "-").replace("月", "-").replace("日", "");
+    }
 }

+ 25 - 20
mjava/src/main/resources/application-dev.yml

@@ -52,25 +52,6 @@ logging:
   file:
     path: /Users/malk/server/_Tool/var/mjava/log
 
-# diwork
-diwork:
-  appKey: 09242de7dc2c44c0b2dbca1b389aa566
-  appSecret: cf2b924ccb2b47f39bc9841a39ef4784
-
-# u8open
-u8open:
-  appKey: opa75c6cbdd6375068f
-  appSecret: f2e79a74aa284b5e83be6f1cac84e4b6
-  toAccount: sangnuo8
-  fromAccount: zhixian666
-
-# feishu
-feishu:
-  appKey: cli_a2b72fadcafe100e
-  appSecret: SUy4raAtpO3dgOasOfO43GU6YfaMnQ3Q
-  encryptKey: DVeCYMQgcg5T8BpKnOIUkdsU8Rex1Ndx
-  verToken: agS2kgO39Y59JSQUduNOahd64woiKvxf
-
 # dingtalk
 dingtalk:
   agentId: 1963716187
@@ -93,6 +74,11 @@ aliwork:
   appType: APP_GTK6SIE4MNVEEVPJLM7Z
   systemToken: IA766O61FNR42YWEEEKTB5QAEEP827UYE3M9LK11
 
+# h3yun
+h3yun:
+  engineCode: vqvl30y6teuqgfydfolo4gqo2
+  secret: mV17Rp3hqzwiSX9woQBqQyFLJVKuUSDaJclzr7VTlBJbhLZ1XUxTgA==
+
 # ekuaibao
 ekuaibao:
   corpId: -yQbjbywbc640011                # 易快报 corpId
@@ -112,4 +98,23 @@ tencent:
   APPID: 1309939821
   SecretId: AKID2uqoryukbO2XuBThuxzdEpnmnmoocuCH
   SecretKey: wnmgYHo8wrmjlldKoHnIkDZlqvrVDpOz
-  Region: ap-shanghai
+  Region: ap-shanghai
+
+# diwork
+diwork:
+  appKey: 09242de7dc2c44c0b2dbca1b389aa566
+  appSecret: cf2b924ccb2b47f39bc9841a39ef4784
+
+# u8open
+u8open:
+  appKey: opa75c6cbdd6375068f
+  appSecret: f2e79a74aa284b5e83be6f1cac84e4b6
+  toAccount: sangnuo8
+  fromAccount: zhixian666
+
+# feishu
+feishu:
+  appKey: cli_a2b72fadcafe100e
+  appSecret: SUy4raAtpO3dgOasOfO43GU6YfaMnQ3Q
+  encryptKey: DVeCYMQgcg5T8BpKnOIUkdsU8Rex1Ndx
+  verToken: agS2kgO39Y59JSQUduNOahd64woiKvxf

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

@@ -22,25 +22,6 @@ spring:
     database: MYSQL
     database-platform: org.hibernate.dialect.MySQL57Dialect
 
-# diwork
-diwork:
-  appKey: 09242de7dc2c44c0b2dbca1b389aa566
-  appSecret: cf2b924ccb2b47f39bc9841a39ef4784
-
-# u8open
-u8open:
-  appKey: opa75c6cbdd6375068f
-  appSecret: f2e79a74aa284b5e83be6f1cac84e4b6
-  toAccount: sangnuo8
-  fromAccount: zhixian666
-
-# feishu
-feishu:
-  appKey: cli_a2b72fadcafe100e
-  appSecret: SUy4raAtpO3dgOasOfO43GU6YfaMnQ3Q
-  encryptKey: DVeCYMQgcg5T8BpKnOIUkdsU8Rex1Ndx
-  verToken: agS2kgO39Y59JSQUduNOahd64woiKvxf
-
 # dingtalk
 dingtalk:
   agentId: 1999093926
@@ -62,6 +43,11 @@ aliwork:
   appType: APP_GTK6SIE4MNVEEVPJLM7Z
   systemToken: IA766O61FNR42YWEEEKTB5QAEEP827UYE3M9LK11
 
+# h3yun
+h3yun:
+  engineCode: vqvl30y6teuqgfydfolo4gqo2
+  secret: mV17Rp3hqzwiSX9woQBqQyFLJVKuUSDaJclzr7VTlBJbhLZ1XUxTgA==
+
 # ekuaibao
 ekuaibao:
   corpId: -yQbjbywbc640011                # 易快报的 corpId
@@ -74,6 +60,25 @@ fxiaoke:
   permanentCode: 317DA531616A1569F906D1F9A1C74D15
   corpId: FSCID_2DA12EC0A1DC7EF6FD68E5AA33F25D8A  # 纷享销客 corpId
 
+# diwork
+diwork:
+  appKey: 09242de7dc2c44c0b2dbca1b389aa566
+  appSecret: cf2b924ccb2b47f39bc9841a39ef4784
+
+# u8open
+u8open:
+  appKey: opa75c6cbdd6375068f
+  appSecret: f2e79a74aa284b5e83be6f1cac84e4b6
+  toAccount: sangnuo8
+  fromAccount: zhixian666
+
+# feishu
+feishu:
+  appKey: cli_a2b72fadcafe100e
+  appSecret: SUy4raAtpO3dgOasOfO43GU6YfaMnQ3Q
+  encryptKey: DVeCYMQgcg5T8BpKnOIUkdsU8Rex1Ndx
+  verToken: agS2kgO39Y59JSQUduNOahd64woiKvxf
+
 # 企业配置
 corp:
   # 异常通知 list: [1, 2, 3] or - 1, - 2, - 3

+ 28 - 23
mjava/src/main/resources/application-test.yml

@@ -36,6 +36,34 @@ spring:
     database: MYSQL
     database-platform: org.hibernate.dialect.MySQL57Dialect
 
+# teambition
+teambition:
+  AppID: 63589b8bb6803e162f9a57d8
+  AppSecret: 5mB3b73OFhSwo38xEVqahCLwQVhG1MW3
+  TenantId: 5ca44db8ca4fd40001b10559
+
+# aliwork
+aliwork:
+  appType: APP_GTK6SIE4MNVEEVPJLM7Z
+  systemToken: IA766O61FNR42YWEEEKTB5QAEEP827UYE3M9LK11
+
+# h3yun
+h3yun:
+  engineCode: vqvl30y6teuqgfydfolo4gqo2
+  secret: mV17Rp3hqzwiSX9woQBqQyFLJVKuUSDaJclzr7VTlBJbhLZ1XUxTgA==
+
+# ekuaibao
+ekuaibao:
+  corpId: -yQbjbywbc640011                # 易快报的 corpId
+  platformApi: https://app.ekuaibao.com   # 易快报不同平台获取前缀的方式不同
+
+# fxiaoke
+fxiaoke:
+  appId: FSAID_131becb
+  appSecret: 1f516179d4e84ecba24752b0c4af5d02
+  permanentCode: 317DA531616A1569F906D1F9A1C74D15
+  corpId: FSCID_2DA12EC0A1DC7EF6FD68E5AA33F25D8A  # 纷享销客 corpId
+
 # diwork
 diwork:
   appKey: 09242de7dc2c44c0b2dbca1b389aa566
@@ -63,26 +91,3 @@ feishu:
   appSecret: SUy4raAtpO3dgOasOfO43GU6YfaMnQ3Q
   encryptKey: DVeCYMQgcg5T8BpKnOIUkdsU8Rex1Ndx
   verToken: agS2kgO39Y59JSQUduNOahd64woiKvxf
-
-# teambition
-teambition:
-  AppID: 63589b8bb6803e162f9a57d8
-  AppSecret: 5mB3b73OFhSwo38xEVqahCLwQVhG1MW3
-  TenantId: 5ca44db8ca4fd40001b10559
-
-# aliwork
-aliwork:
-  appType: APP_GTK6SIE4MNVEEVPJLM7Z
-  systemToken: IA766O61FNR42YWEEEKTB5QAEEP827UYE3M9LK11
-
-# ekuaibao
-ekuaibao:
-  corpId: -yQbjbywbc640011                # 易快报的 corpId
-  platformApi: https://app.ekuaibao.com   # 易快报不同平台获取前缀的方式不同
-
-# fxiaoke
-fxiaoke:
-  appId: FSAID_131becb
-  appSecret: 1f516179d4e84ecba24752b0c4af5d02
-  permanentCode: 317DA531616A1569F906D1F9A1C74D15
-  corpId: FSCID_2DA12EC0A1DC7EF6FD68E5AA33F25D8A  # 纷享销客 corpId

+ 15 - 30
mjava/target/classes/META-INF/spring-configuration-metadata.json

@@ -35,11 +35,6 @@
       "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",
@@ -50,16 +45,16 @@
       "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",
       "sourceType": "com.malk.server.fxiaoke.FXKConf"
     },
+    {
+      "name": "h3yun",
+      "type": "com.malk.server.h3yun.CYConf",
+      "sourceType": "com.malk.server.h3yun.CYConf"
+    },
     {
       "name": "spring.datasource.primary",
       "type": "javax.sql.DataSource",
@@ -189,16 +184,6 @@
       "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",
@@ -209,16 +194,6 @@
       "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",
@@ -244,6 +219,16 @@
       "type": "java.lang.String",
       "sourceType": "com.malk.server.fxiaoke.FXKConf"
     },
+    {
+      "name": "h3yun.engine-code",
+      "type": "java.lang.String",
+      "sourceType": "com.malk.server.h3yun.CYConf"
+    },
+    {
+      "name": "h3yun.secret",
+      "type": "java.lang.String",
+      "sourceType": "com.malk.server.h3yun.CYConf"
+    },
     {
       "name": "vika.api-token",
       "type": "java.lang.String",

+ 25 - 20
mjava/target/classes/application-dev.yml

@@ -52,25 +52,6 @@ logging:
   file:
     path: /Users/malk/server/_Tool/var/mjava/log
 
-# diwork
-diwork:
-  appKey: 09242de7dc2c44c0b2dbca1b389aa566
-  appSecret: cf2b924ccb2b47f39bc9841a39ef4784
-
-# u8open
-u8open:
-  appKey: opa75c6cbdd6375068f
-  appSecret: f2e79a74aa284b5e83be6f1cac84e4b6
-  toAccount: sangnuo8
-  fromAccount: zhixian666
-
-# feishu
-feishu:
-  appKey: cli_a2b72fadcafe100e
-  appSecret: SUy4raAtpO3dgOasOfO43GU6YfaMnQ3Q
-  encryptKey: DVeCYMQgcg5T8BpKnOIUkdsU8Rex1Ndx
-  verToken: agS2kgO39Y59JSQUduNOahd64woiKvxf
-
 # dingtalk
 dingtalk:
   agentId: 1963716187
@@ -93,6 +74,11 @@ aliwork:
   appType: APP_GTK6SIE4MNVEEVPJLM7Z
   systemToken: IA766O61FNR42YWEEEKTB5QAEEP827UYE3M9LK11
 
+# h3yun
+h3yun:
+  engineCode: vqvl30y6teuqgfydfolo4gqo2
+  secret: mV17Rp3hqzwiSX9woQBqQyFLJVKuUSDaJclzr7VTlBJbhLZ1XUxTgA==
+
 # ekuaibao
 ekuaibao:
   corpId: -yQbjbywbc640011                # 易快报 corpId
@@ -112,4 +98,23 @@ tencent:
   APPID: 1309939821
   SecretId: AKID2uqoryukbO2XuBThuxzdEpnmnmoocuCH
   SecretKey: wnmgYHo8wrmjlldKoHnIkDZlqvrVDpOz
-  Region: ap-shanghai
+  Region: ap-shanghai
+
+# diwork
+diwork:
+  appKey: 09242de7dc2c44c0b2dbca1b389aa566
+  appSecret: cf2b924ccb2b47f39bc9841a39ef4784
+
+# u8open
+u8open:
+  appKey: opa75c6cbdd6375068f
+  appSecret: f2e79a74aa284b5e83be6f1cac84e4b6
+  toAccount: sangnuo8
+  fromAccount: zhixian666
+
+# feishu
+feishu:
+  appKey: cli_a2b72fadcafe100e
+  appSecret: SUy4raAtpO3dgOasOfO43GU6YfaMnQ3Q
+  encryptKey: DVeCYMQgcg5T8BpKnOIUkdsU8Rex1Ndx
+  verToken: agS2kgO39Y59JSQUduNOahd64woiKvxf

+ 24 - 19
mjava/target/classes/application-prod.yml

@@ -22,25 +22,6 @@ spring:
     database: MYSQL
     database-platform: org.hibernate.dialect.MySQL57Dialect
 
-# diwork
-diwork:
-  appKey: 09242de7dc2c44c0b2dbca1b389aa566
-  appSecret: cf2b924ccb2b47f39bc9841a39ef4784
-
-# u8open
-u8open:
-  appKey: opa75c6cbdd6375068f
-  appSecret: f2e79a74aa284b5e83be6f1cac84e4b6
-  toAccount: sangnuo8
-  fromAccount: zhixian666
-
-# feishu
-feishu:
-  appKey: cli_a2b72fadcafe100e
-  appSecret: SUy4raAtpO3dgOasOfO43GU6YfaMnQ3Q
-  encryptKey: DVeCYMQgcg5T8BpKnOIUkdsU8Rex1Ndx
-  verToken: agS2kgO39Y59JSQUduNOahd64woiKvxf
-
 # dingtalk
 dingtalk:
   agentId: 1999093926
@@ -62,6 +43,11 @@ aliwork:
   appType: APP_GTK6SIE4MNVEEVPJLM7Z
   systemToken: IA766O61FNR42YWEEEKTB5QAEEP827UYE3M9LK11
 
+# h3yun
+h3yun:
+  engineCode: vqvl30y6teuqgfydfolo4gqo2
+  secret: mV17Rp3hqzwiSX9woQBqQyFLJVKuUSDaJclzr7VTlBJbhLZ1XUxTgA==
+
 # ekuaibao
 ekuaibao:
   corpId: -yQbjbywbc640011                # 易快报的 corpId
@@ -74,6 +60,25 @@ fxiaoke:
   permanentCode: 317DA531616A1569F906D1F9A1C74D15
   corpId: FSCID_2DA12EC0A1DC7EF6FD68E5AA33F25D8A  # 纷享销客 corpId
 
+# diwork
+diwork:
+  appKey: 09242de7dc2c44c0b2dbca1b389aa566
+  appSecret: cf2b924ccb2b47f39bc9841a39ef4784
+
+# u8open
+u8open:
+  appKey: opa75c6cbdd6375068f
+  appSecret: f2e79a74aa284b5e83be6f1cac84e4b6
+  toAccount: sangnuo8
+  fromAccount: zhixian666
+
+# feishu
+feishu:
+  appKey: cli_a2b72fadcafe100e
+  appSecret: SUy4raAtpO3dgOasOfO43GU6YfaMnQ3Q
+  encryptKey: DVeCYMQgcg5T8BpKnOIUkdsU8Rex1Ndx
+  verToken: agS2kgO39Y59JSQUduNOahd64woiKvxf
+
 # 企业配置
 corp:
   # 异常通知 list: [1, 2, 3] or - 1, - 2, - 3

+ 28 - 23
mjava/target/classes/application-test.yml

@@ -36,6 +36,34 @@ spring:
     database: MYSQL
     database-platform: org.hibernate.dialect.MySQL57Dialect
 
+# teambition
+teambition:
+  AppID: 63589b8bb6803e162f9a57d8
+  AppSecret: 5mB3b73OFhSwo38xEVqahCLwQVhG1MW3
+  TenantId: 5ca44db8ca4fd40001b10559
+
+# aliwork
+aliwork:
+  appType: APP_GTK6SIE4MNVEEVPJLM7Z
+  systemToken: IA766O61FNR42YWEEEKTB5QAEEP827UYE3M9LK11
+
+# h3yun
+h3yun:
+  engineCode: vqvl30y6teuqgfydfolo4gqo2
+  secret: mV17Rp3hqzwiSX9woQBqQyFLJVKuUSDaJclzr7VTlBJbhLZ1XUxTgA==
+
+# ekuaibao
+ekuaibao:
+  corpId: -yQbjbywbc640011                # 易快报的 corpId
+  platformApi: https://app.ekuaibao.com   # 易快报不同平台获取前缀的方式不同
+
+# fxiaoke
+fxiaoke:
+  appId: FSAID_131becb
+  appSecret: 1f516179d4e84ecba24752b0c4af5d02
+  permanentCode: 317DA531616A1569F906D1F9A1C74D15
+  corpId: FSCID_2DA12EC0A1DC7EF6FD68E5AA33F25D8A  # 纷享销客 corpId
+
 # diwork
 diwork:
   appKey: 09242de7dc2c44c0b2dbca1b389aa566
@@ -63,26 +91,3 @@ feishu:
   appSecret: SUy4raAtpO3dgOasOfO43GU6YfaMnQ3Q
   encryptKey: DVeCYMQgcg5T8BpKnOIUkdsU8Rex1Ndx
   verToken: agS2kgO39Y59JSQUduNOahd64woiKvxf
-
-# teambition
-teambition:
-  AppID: 63589b8bb6803e162f9a57d8
-  AppSecret: 5mB3b73OFhSwo38xEVqahCLwQVhG1MW3
-  TenantId: 5ca44db8ca4fd40001b10559
-
-# aliwork
-aliwork:
-  appType: APP_GTK6SIE4MNVEEVPJLM7Z
-  systemToken: IA766O61FNR42YWEEEKTB5QAEEP827UYE3M9LK11
-
-# ekuaibao
-ekuaibao:
-  corpId: -yQbjbywbc640011                # 易快报的 corpId
-  platformApi: https://app.ekuaibao.com   # 易快报不同平台获取前缀的方式不同
-
-# fxiaoke
-fxiaoke:
-  appId: FSAID_131becb
-  appSecret: 1f516179d4e84ecba24752b0c4af5d02
-  permanentCode: 317DA531616A1569F906D1F9A1C74D15
-  corpId: FSCID_2DA12EC0A1DC7EF6FD68E5AA33F25D8A  # 纷享销客 corpId

+ 2 - 0
pom.xml

@@ -22,6 +22,8 @@
         <module>mjava-pake</module>
         <module>mjava-yangu</module>
         <module>mjava-kuaikeli</module>
+        <module>mjava-laidi</module>
+        <module>mjava-luyi</module>
     </modules>
     <packaging>pom</packaging>