Переглянути джерело

Merge remote-tracking branch 'origin/master'

floe 10 місяців тому
батько
коміт
918f9562d2
36 змінених файлів з 1131 додано та 171 видалено
  1. 10 2
      mjava-aipocloud/src/main/java/com/malk/aipocloud/controller/ABController.java
  2. 68 30
      mjava-aiwei/src/main/java/com/malk/aiwei/controller/TBxYDController.java
  3. 17 7
      mjava-aiwei/src/main/java/com/malk/aiwei/service/AWClint.java
  4. 16 0
      mjava-aiwei/src/main/java/com/malk/aiwei/service/AWYDClient.java
  5. 209 99
      mjava-aiwei/src/main/java/com/malk/aiwei/service/impl/AWImplClient.java
  6. 277 0
      mjava-aiwei/src/main/java/com/malk/aiwei/service/impl/AWYDImplClient.java
  7. 8 8
      mjava-aiwei/src/main/resources/application-dev.yml
  8. 1 0
      mjava-aiwei/src/main/resources/application-test.yml
  9. BIN
      mjava-aiwei/src/main/resources/templates/templates_xqrk.xlsx
  10. BIN
      mjava-aiwei/src/main/resources/templates/templates_xqwh.xlsx
  11. BIN
      mjava-aiwei/src/main/resources/templates/templates_xqwh_result.xlsx
  12. 14 18
      mjava-aiwei/src/test/java/com/malk/aiwei/AwTbTest.java
  13. 2 0
      mjava-cloudpure/src/main/java/com/malk/cloudpure/controller/TSController.java
  14. 3 1
      mjava-hake/src/main/java/com/malk/hake/controller/HKController.java
  15. 54 0
      mjava-ruisi/pom.xml
  16. 32 0
      mjava-ruisi/src/main/java/com/malk/ruisi/Boot.java
  17. 58 0
      mjava-ruisi/src/main/java/com/malk/ruisi/controller/CosController.java
  18. 35 0
      mjava-ruisi/src/main/java/com/malk/ruisi/schedule/RSScheduleTask.java
  19. 16 0
      mjava-ruisi/src/main/java/com/malk/ruisi/service/RSService.java
  20. 85 0
      mjava-ruisi/src/main/java/com/malk/ruisi/service/impl/RSImplService.java
  21. 64 0
      mjava-ruisi/src/main/resources/application-dev.yml
  22. 38 0
      mjava-ruisi/src/main/resources/application-prod.yml
  23. 39 0
      mjava-ruisi/src/test/resource/server.sh
  24. 0 1
      mjava/src/main/java/com/malk/base/BaseDto.java
  25. 3 0
      mjava/src/main/java/com/malk/schedule/McScheduleTask.java
  26. 10 1
      mjava/src/main/java/com/malk/server/aliwork/YDConf.java
  27. 1 0
      mjava/src/main/java/com/malk/server/common/VenR.java
  28. 6 0
      mjava/src/main/java/com/malk/service/aliwork/impl/YDClientImpl.java
  29. 1 1
      mjava/src/main/java/com/malk/service/aliwork/impl/YDServiceImpl.java
  30. 5 0
      mjava/src/main/java/com/malk/service/dingtalk/impl/DDImplClient_Contacts.java
  31. 11 2
      mjava/src/main/java/com/malk/service/teambition/TBClient.java
  32. 7 1
      mjava/src/main/java/com/malk/service/teambition/impl/TBClientImpl.java
  33. 15 0
      mjava/src/main/java/com/malk/test/TmpController.java
  34. 14 0
      mjava/src/main/java/com/malk/utils/UtilExcel.java
  35. 11 0
      mjava/src/main/java/com/malk/utils/UtilList.java
  36. 1 0
      pom.xml

+ 10 - 2
mjava-aipocloud/src/main/java/com/malk/aipocloud/controller/ABController.java

@@ -12,6 +12,8 @@ import com.malk.utils.UtilDateTime;
 import lombok.Synchronized;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
@@ -55,10 +57,16 @@ public class ABController {
     @Autowired
     private McDelegate mcDelegate;
 
-    @PostMapping("test")
+    @Value("${server.ssl.key-store}")
+    private String keyStore;
+
+    @Value("${server.ssl.key-store-password}")
+    private String keyStorePassword;
+
+    @GetMapping("test")
     McR test() {
 
-        log.info("11111");
+        log.info("11111, {}, {}", keyStore, keyStorePassword);
 
         mcDelegate.setTimeout(() -> {
 

+ 68 - 30
mjava-aiwei/src/main/java/com/malk/aiwei/controller/TBxYDController.java

@@ -5,9 +5,8 @@ package com.malk.aiwei.controller;
  */
 
 import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONObject;
-import com.malk.aiwei.server.YDSearch;
 import com.malk.aiwei.service.AWClint;
+import com.malk.aiwei.service.AWYDClient;
 import com.malk.delegate.McDelegate;
 import com.malk.server.aliwork.YDConf;
 import com.malk.server.aliwork.YDParam;
@@ -18,6 +17,7 @@ import com.malk.server.teambition.TBConf;
 import com.malk.service.aliwork.YDClient;
 import com.malk.service.aliwork.YDService;
 import com.malk.service.teambition.TBClient;
+import com.malk.utils.UtilExcel;
 import com.malk.utils.UtilMap;
 import com.malk.utils.UtilServlet;
 import lombok.extern.slf4j.Slf4j;
@@ -25,7 +25,11 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 
 import javax.servlet.http.HttpServletRequest;
-import java.util.*;
+import javax.servlet.http.HttpServletResponse;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
 
 @Slf4j
 @RestController
@@ -259,17 +263,6 @@ public class TBxYDController {
 
     /// todo workspace/sync //手动触发, 知识库权限矩阵同步
 
-    /**
-     * 提供verifier数据读取服务
-     */
-    @GetMapping("verifier/sync")
-    McR syncVerifier(String projectCode) {
-
-        List<Map> dataList = awClint.syncVerifier(projectCode);
-        log.info("syncVerifier, {}, {}", projectCode, dataList.size());
-        return McR.success(dataList);
-    }
-
     /**
      * 知识库版本管理
      */
@@ -289,13 +282,10 @@ public class TBxYDController {
      */
     @GetMapping("product/list")
     Map getProductList(@RequestParam Map param) {
-        System.out.println(JSONObject.toJSONString(param));
-//        String projectId="65f2855b5a2065ad7ad7d084";
-        String projectId=UtilMap.getString(param,"projectId");
-        String q=UtilMap.getString(param,"q");
-        String objectId=UtilMap.getString(param,"objectId");
-        List result=awClint.getProductList(projectId,q);
-        return UtilMap.map("options",result);
+        String projectId = UtilMap.getString(param, "projectId");
+        String q = UtilMap.getString(param, "q");
+        List result = awClint.getProductList(projectId, q);
+        return UtilMap.map("options", result);
     }
 
     /**
@@ -303,13 +293,58 @@ public class TBxYDController {
      */
     @GetMapping("product/version")
     Map getProductVersionList(@RequestParam Map param) {
-        System.out.println(JSONObject.toJSONString(param));
-//        String projectId="65f2855b5a2065ad7ad7d084";
-        String projectId=UtilMap.getString(param,"projectId");
-        String q=UtilMap.getString(param,"q");
-        String objectId=UtilMap.getString(param,"objectId");
-        List result=awClint.getProductList(projectId,q,objectId);
-        return UtilMap.map("options",result);
+        String projectId = UtilMap.getString(param, "projectId");
+        String q = UtilMap.getString(param, "q");
+        String objectId = UtilMap.getString(param, "objectId");
+        List result = awClint.getProductList(projectId, q, objectId);
+        return UtilMap.map("options", result);
+    }
+
+    /************************************* 宜搭结构化 *************************************/
+
+
+    @Autowired
+    private AWYDClient awydClient;
+
+    /**
+     * 提供verifier数据读取服务
+     */
+    @GetMapping("verifier/sync")
+    McR syncVerifier(String projectCode) {
+
+        List<Map> dataList = awydClient.syncVerifier(projectCode);
+        log.info("syncVerifier, {}, {}", projectCode, dataList.size());
+        return McR.success(dataList);
+    }
+
+
+    /**
+     * 导出
+     */
+    @PostMapping("export")
+    void export(@RequestBody Map data, HttpServletResponse response) {
+        List<Map> dataList = UtilMap.getList(data, "dataList");
+        String fileName = UtilMap.getString(data, "fileName");
+        String tempFileName = UtilMap.getString(data, "tempFileName");
+        UtilExcel.exportMapAndListByTemplate(response, dataList, Map.class, fileName, tempFileName);
+    }
+
+    /**
+     * 导入前处理
+     */
+    @PostMapping("beforeImportData")
+    McR beforeImportData(@RequestBody Map data, HttpServletResponse response) {
+        Map result = awydClient.checkImportData(data);
+        Boolean flag = UtilMap.getBoolean(result, "flag");
+        List<Map> resultData = UtilMap.getList(result, "data");
+        if (flag) {
+            return McR.success(resultData);
+        } else {
+            String fileName = "异常";
+            String tempFileName = "templates_xqwh_result.xlsx";
+            UtilExcel.exportMapAndListByTemplate(response, resultData, Map.class, fileName, tempFileName);
+            return null;
+        }
     }
 
     //////// test ////////
@@ -348,7 +383,7 @@ public class TBxYDController {
     @Autowired
     private McDelegate mcDelegate;
 
-    @PostMapping("test")
+    @GetMapping("test")
     McR test(HttpServletRequest request) {
 
         Map<String, ?> data = UtilServlet.getParamMap(request);
@@ -368,6 +403,9 @@ public class TBxYDController {
     McR tmp(String programIds) {
 
 //        awClint.tmp();
-        return McR.success();
+
+        List<String> tags = tbClient.queryProjectTag("66c763a2a86f837e07c418e9", tbConf.getOperatorId());
+        tags.add("111");
+        return McR.success(tags);
     }
 }

+ 17 - 7
mjava-aiwei/src/main/java/com/malk/aiwei/service/AWClint.java

@@ -100,17 +100,27 @@ public interface AWClint {
     void approveVersion(String taskId, String pCode);
 
     /**
-     * 提供verifier数据读取服务
+     * 获取主数据中产品列表
      */
-    List<Map> syncVerifier(String projectCode);
+    List<Map> getProductList(String projectId, String q);
 
-    void test();
+    /**
+     * 获取主数据中产品版本
+     */
+    List<Map> getProductList(String projectId, String q, String taskId);
 
-    void tmp();
+    /**
+     * 选择产品\版本后, 回调更新对应原文本字段, 兼容之前字段逻辑
+     */
+    void custFieldUpdate(JSONObject data);
 
-    List<Map> getProductList(String projectId,String q);
+    /**
+     * 检查项导出, 全部检查项左关联已提交数据
+     */
+    void exportCheckList(String pCode, String proType);
 
-    List<Map> getProductList(String projectId,String q,String taskId);
 
-    void custFieldUpdate(JSONObject data);
+    void test();
+
+    void tmp();
 }

+ 16 - 0
mjava-aiwei/src/main/java/com/malk/aiwei/service/AWYDClient.java

@@ -0,0 +1,16 @@
+package com.malk.aiwei.service;
+
+import java.util.List;
+import java.util.Map;
+
+public interface AWYDClient {
+
+    /**
+     * 提供verifier数据读取服务
+     */
+    List<Map> syncVerifier(String projectCode);
+
+    /************************************* 0906 产品需求导入逻辑变革, 弃用保留 *************************************/
+
+    Map checkImportData(Map data);
+}

+ 209 - 99
mjava-aiwei/src/main/java/com/malk/aiwei/service/impl/AWImplClient.java

@@ -49,7 +49,7 @@ public class AWImplClient implements AWClint {
     // 单据环境映射
     private String _matchFormUuid(String code) {
         Map<String, String> formUuid = UtilMap.empty();
-        if (UtilEnv.getActiveProfile().equals(UtilEnv.ENV_PROD)||UtilEnv.getActiveProfile().equals(UtilEnv.ENV_TEST)) {
+        if (true || UtilEnv.getActiveProfile().equals(UtilEnv.ENV_PROD) || UtilEnv.getActiveProfile().equals(UtilEnv.ENV_TEST)) {
             formUuid.put("DENTRY", "FORM-BD73A57B62EA4153B896C9BB3EA14D28GWSQ");                // 文件夹/文件版本记录
             formUuid.put("PERMISSION", "FORM-3380221DFDF84FBD8BCF503198294257TFWB");            // 文件夹权限
             formUuid.put("REVIEW", "FORM-812FD46AF391449A8F206EDB3221B38840UQ");                // 交付物审批记录
@@ -58,6 +58,7 @@ public class AWImplClient implements AWClint {
             formUuid.put("APPROVE", "FORM-A25299893F614A6EAA672514D3A76BB0QDBF");               // 交付物审批矩阵
             formUuid.put("CHECK", "FORM-1A5D4D7FBF88409B956EBE51F9342A6BKOLP");                 // 预检项
             formUuid.put("RECORD", "FORM-6E2C0D1197264B8AA23EB3FECAE7344B00BN");                // 预检项记录
+            formUuid.put("RTO", "FORM-DF879E2CC586467C97203B7F16733228Y2MN");                   // RTO检查项控
             formUuid.put("ROLE", "FORM-3C7396A12ADB48A8833EBD90089C93833R21");                  // 项目角色
             formUuid.put("ROLE_PDT", "FORM-69B6A8151F3346DCA20B0ED54F5380675LJX");              // PDT角色
             formUuid.put("CRM_LOG", "FORM-16DD578308E64763AE1539D8176CCCD0GX6F");               // crm推送日志
@@ -471,12 +472,39 @@ public class AWImplClient implements AWClint {
             } else {
                 rProject = pList.get(0);
                 String proType = UtilMap.getString(rProject, "textField_ltwcq7s6");
+                Map searchCondition = UtilMap.map("selectField_lrncf4hk, radioField_lrnddfq6", tCode, "启用");
+                /// prd 8.21 RTO 任务只需要查看 IC技术评审
+                if (tCode.contains("RTO-")) {
+                    searchCondition.put("selectField_lrnd3h0s", "IC技术检查表");
+                }
                 tList = ydService.queryFormData_all(YDParam.builder()
                         .formUuid(_matchFormUuid("CHECK"))
-                        .searchFieldJson(JSON.toJSONString(UtilMap.map("selectField_lrncf4hk, radioField_lrnddfq6", tCode, "启用")))
+                        .searchFieldJson(JSON.toJSONString(searchCondition))
                         .build());
                 // prd 多模板适配: [任务号 + 项目类型]
                 tList = tList.stream().filter(item -> tCode.equals(item.get("selectField_lrncf4hk")) && UtilMap.getList(item, "multiSelectField_ltwjre9s").contains(proType)).collect(Collectors.toList());
+                /// prd 8.21 RTO任务关联技术检查项自动化处理
+                if (tCode.contains("RTO-")) {
+                    // 按照技术领域区分, 非必填
+                    List<Map> rtoList = ydService.queryDataList_FormData(_matchFormUuid("RTO"), UtilMap.map("selectField_lrncf4hk", tCode));
+                    rtoList = rtoList.stream().filter(item -> tCode.equals(item.get("selectField_lrncf4hk"))).collect(Collectors.toList());
+                    if (rtoList.size() == 1) {
+                        Map searchMap = UtilMap.map("radioField_lrnddfq6, textField_8n5ib3y", "启用", UtilMap.getString(rtoList.get(0), "textField_8n5ib3y"));
+                        List<Map> rtoCheck = ydService.queryFormData_all(YDParam.builder()
+                                .formUuid(_matchFormUuid("CHECK"))
+                                .searchFieldJson(JSON.toJSONString(searchMap))
+                                .build());
+                        List<String> nodes = UtilMap.getList(rtoList.get(0), "multiSelectField_ltejinaz");
+                        // 匹配评审点\项目类型\数据去重
+                        for (Map rCheck : rtoCheck) {
+                            if (nodes.contains(UtilMap.getString(rCheck, "textField_rfwx8lk")) &&
+                                    UtilMap.getList(rCheck, "multiSelectField_ltwjre9s").contains(proType) &&
+                                    !tList.stream().filter(row -> rCheck.get("textField_lrnd3h0r").equals(row.get("textField_lrnd3h0r"))).findAny().isPresent()) {
+                                tList.add(rCheck);
+                            }
+                        }
+                    }
+                }
                 if (tList.size() == 0) {
                     resultTitle = "未配置预检项";
                 } else {
@@ -642,6 +670,14 @@ public class AWImplClient implements AWClint {
                 if (!formData.get("textField_ltsdsti7").equals(projectMaps.get(0).get("textField_ltsdsti7"))) {
                     formData.put("src_state", formData.get("textField_ltsdsti7"));
                 }
+                /// 8.21 项目信息\项目重要性分级, 也添加差异同步, 避免新增字段历史项目不同步问题
+                if (!formData.get("textareaField_lrj7vnxl").equals(projectMaps.get(0).get("textareaField_lrj7vnxl"))) {
+                    formData.put("src_desc", formData.get("textareaField_lrj7vnxl"));
+                }
+                if (!formData.get("textField_lwj1r7n6").equals(projectMaps.get(0).get("textField_lwj1r7n6"))) {
+                    formData.put("src_level", formData.get("textField_lwj1r7n6"));
+                }
+
                 ydParam2.setFormInstanceId(String.valueOf(projectMaps.get(0).get("instanceId")));
                 ydClient.operateData(ydParam2, YDConf.FORM_OPERATION.update); // 主表为增量更新
                 // 保留tb项目号, 避免冲重复通过模板参加项目 [供新增用]
@@ -778,16 +814,21 @@ public class AWImplClient implements AWClint {
         if (StringUtils.isNotBlank(groupName)) {
             List<Map> tagList = tbClient.queryTagList(UtilMap.map("q", groupName));
             if (tagList.size() > 0) {
-                tbClient.updateProjectTag(projectId, Arrays.asList(UtilMap.getString(tagList.get(0), "id"), staffRoleId), tbConf.getOperatorId());
+                /// 更新项目分组, 不会保留原分组, 需要兼容
+                List<String> tags = tbClient.queryProjectTag(projectId, tbConf.getOperatorId());
+                tags.add(UtilMap.getString(tagList.get(0), "id"));
+                tbClient.updateProjectTag(projectId, tags, tbConf.getOperatorId());
             }
         }
         // prd 人员变更, 自动同步更新执行人: 仅触发存在执行人 & 未完成场景 [5.10 新增项目不执行, TB任务号宜搭回写有延迟, 避免异常]
         if (!isCreate) {
             updateProjectRole(projectId, Arrays.asList("全部", "自动更新"), "", "");
         }
-        // prd 5.23 更新项目概览信息
-        if (isCreate) {
+        // prd 5.23 更新项目概览信息 8.21 项目信息\项目重要性分级, 也添加差异同步, 避免新增字段历史项目不同步问题
+        if (UtilMap.isNotBlankString(formData, "src_desc")) {
             tbClient.updateProjectStatusField(projectId, tbConf.getOperatorId(), TBConf.assembleCustomFieldName("项目描述", UtilMap.getString(formData, "textareaField_lrj7vnxl")));
+        }
+        if (UtilMap.isNotBlankString(formData, "src_level")) {
             tbClient.updateProjectStatusField(projectId, tbConf.getOperatorId(), TBConf.assembleCustomFieldName("项目重要等级", UtilMap.getString(formData, "textField_lwj1r7n6")));
         }
         // 项目添加到项目集
@@ -1262,7 +1303,7 @@ public class AWImplClient implements AWClint {
                         .formUuid("FORM-B40420AFCDB84AD69FE78D82D6D5CFD2C2D2")
                         .build();
                 // 任务号, 描述, ID(标题), 任务名称, 适用项目类型
-                Map<String, ?> compIds2 = UtilMap.map("selectField_lrncf4hk, textField_lrrnqz7w, textField_lrnd3h0r, textField_ltzl9mpc, multiSelectField_ltwjre9s", "selectField_bclg9y5, textField_k1e08ji, textField_96ikaoh, textField_lsa0d856, multiSelectField_ltwjre9s");
+                Map<String, ?> compIds2 = UtilMap.map("selectField_lrncf4hk, textField_lrrnqz7w, textField_lrnd3h0r, textField_ltzl9mpc, multiSelectField_ltwjre9s, textField_8n5ib3y, textField_rfwx8lk", "selectField_bclg9y5, textField_k1e08ji, textField_96ikaoh, textField_lsa0d856, multiSelectField_ltwjre9s, textField_8n5ib3y, textField_rfwx8lk");
                 syncCheckList(ydParam2, compIds2, "selectField_bclg9y5", "textField_96ikaoh", "IC技术检查表", "associationFormField_lrrn5csg");
                 break;
 
@@ -1678,134 +1719,203 @@ public class AWImplClient implements AWClint {
         }
     }
 
-
     /**
-     * 提供verifier数据读取服务
+     * 获取主数据中产品列表
      */
-    @Override
-    public List<Map> syncVerifier(String projectCode) {
-        List<Map> dataList = ydService.queryFormData_all(YDParam.builder()
-                .formUuid("FORM-23B67983E91C4ED3B063F9B629D6E964SGHH")
-                .searchCondition(JSON.toJSONString(UtilMap.map("textField_lt6xd8lm", projectCode)))
-                .build());
-
-        return dataList.stream().map(item -> {
-            return item;
-        }).collect(Collectors.toList());
-
-    }
-
-    @Override
-    public void test() {
-        approveVersion("659a681d44ade3345fdc0d39", "99999");
-//
-//        String pCode = "99999";
-//        String pCode = "A240407DryRun";
-//
-//        List<Map> pList = ydService.queryDataList_FormData(_matchFormUuid("PROJECT"), UtilMap.map("textField_lrj7vnxb", pCode));
-//        pList = pList.stream().filter(item -> pCode.equals(item.get("textField_lrj7vnxb"))).collect(Collectors.toList());
-//        _assembleBreakPermission(pList.get(0));
-
-//        String creatorUnionId = String.valueOf(ddClient_contacts.getUserInfoById(ddClient.getAccessToken(), "095358016629044412").get("unionid"));
-//        List<Map> allMembers = ddClient_storage.queryDentryPermissions(ddClient.getAccessToken(), "14lgGw3P8vMDNPvMC7aw11LzJ5daZ90D", creatorUnionId, null);
-//        log.info("xxxx, {}", allMembers);
-//
-//        String taskId = "65addc57055591ee7d17d807";
-//        Map taskData = _getTaskFieldMap(taskId, AWServer.TASK_APPROVE_LINK, AWServer.TASK_APPROVE_VERSION, AWServer.TASK_STAGE, AWServer.TASK_ROLE);
-//        List<Map> checkList = _getCustomFieldList(taskData, AWServer.TASK_APPROVE_LINK);
-
-//        checkList = new ArrayList<>();
-//        String url = "https://kabom7.aliwork.com/APP_H7WUJTKB448F9IBDC6C4/processDetail?formUuid=FORM-FBC1A390B4C348089020C763938A6F54RUNY&procInsId=5bd917c4-b23c-4f2f-ba4b-cef533118cdf&isAdmin=true&navConfig.layout=1180";
-//        String url = "https://kabom7.aliwork.com/APP_H7WUJTKB448F9IBDC6C4/submission/FORM-7B63BB056145452F8BC0A2C52492DE00QVBH?taskId=65addc57055591ee7d17d807";
-//        _updateApproveField(taskId, checkList, url, "技术检查项确认", "待提交", AWServer.TASK_APPROVE_LINK);
-
-    }
-
-    @Override
-    public void tmp() {
-//        this.tmp_617();
-    }
-
     @Override
     public List<Map> getProductList(String projectId, String q) {
-        // 获取主数据中产品列表
-        return getProductData(projectId,q,"textField_lhsxurnt",null);
-
+        return getProductData(projectId, q, "textField_lhsxurnt", null);
     }
 
+    /**
+     * 获取主数据中产品版本
+     */
     @Override
     public List<Map> getProductList(String projectId, String q, String taskId) {
         Map taskData = _getTaskFieldMap(taskId, AWServer.TASK_PRODUCT);
 //        Map rTask = UtilMap.getMap(taskData, "task");
         String tCode = UtilMap.getString(taskData, AWServer.TASK_PRODUCT);
         McException.assertAccessException(StringUtils.isBlank(tCode), "请先选择产品型号!");
-        // 获取主数据中产品版本
-        return getProductData(projectId,q,"textField_lo2ludkv",tCode);
+        return getProductData(projectId, q, "textField_lo2ludkv", tCode);
     }
 
+    /**
+     * 选择产品\版本后, 回调更新对应原文本字段, 兼容之前字段逻辑
+     */
     @Override
     public void custFieldUpdate(JSONObject data) {
-        List<Map> list=tbClient.queryTaskDetail(data.getString("taskId"),"","");
-        McException.assertAccessException(list==null||list.size()<1, "未匹配到任务!");
-        Map rTask =list.get(0);
-        Map<String, String> proData = getProjectCFID(UtilMap.getString(rTask,"projectId"), Arrays.asList(AWServer.SELECT_TASK_PRODUCT, AWServer.SELECT_TASK_PRODUCT_VERSION));
-        if(data.getString("customfieldId").equals(proData.get(AWServer.SELECT_TASK_PRODUCT))){
+        List<Map> list = tbClient.queryTaskDetail(data.getString("taskId"), "", "");
+        McException.assertAccessException(list == null || list.size() < 1, "未匹配到任务!");
+        Map rTask = list.get(0);
+        Map<String, String> proData = getProjectCFID(UtilMap.getString(rTask, "projectId"), Arrays.asList(AWServer.SELECT_TASK_PRODUCT, AWServer.SELECT_TASK_PRODUCT_VERSION));
+        if (data.getString("customfieldId").equals(proData.get(AWServer.SELECT_TASK_PRODUCT))) {
             // 更新自定义字段--产品型号
             Map body = null;
-            if(data.getJSONArray("customfieldValue").size()<1){
-                body=TBConf.assembleCustomFieldName(AWServer.TASK_PRODUCT);
-            }else{
-                body=TBConf.assembleCustomFieldName(AWServer.TASK_PRODUCT, data.getJSONArray("customfieldValue").getJSONObject(0).getString("title"));
+            if (data.getJSONArray("customfieldValue").size() < 1) {
+                body = TBConf.assembleCustomFieldName(AWServer.TASK_PRODUCT);
+            } else {
+                body = TBConf.assembleCustomFieldName(AWServer.TASK_PRODUCT, data.getJSONArray("customfieldValue").getJSONObject(0).getString("title"));
             }
             tbClient.updateTaskCustomField(data.getString("taskId"), tbConf.getOperatorId(), body);
-        }else if(data.getString("customfieldId").equals(proData.get(AWServer.SELECT_TASK_PRODUCT_VERSION))){
+        } else if (data.getString("customfieldId").equals(proData.get(AWServer.SELECT_TASK_PRODUCT_VERSION))) {
             // 更新自定义字段--产品版本
             Map body = null;
-            if(data.getJSONArray("customfieldValue").size()<1){
-                body=TBConf.assembleCustomFieldName(AWServer.TASK_PRODUCT_VERSION);
-            }else{
-                body=TBConf.assembleCustomFieldName(AWServer.TASK_PRODUCT_VERSION, data.getJSONArray("customfieldValue").getJSONObject(0).getString("title"));
+            if (data.getJSONArray("customfieldValue").size() < 1) {
+                body = TBConf.assembleCustomFieldName(AWServer.TASK_PRODUCT_VERSION);
+            } else {
+                body = TBConf.assembleCustomFieldName(AWServer.TASK_PRODUCT_VERSION, data.getJSONArray("customfieldValue").getJSONObject(0).getString("title"));
             }
             tbClient.updateTaskCustomField(data.getString("taskId"), tbConf.getOperatorId(), body);
         }
     }
 
-    private List<Map> getProductData(String projectId,String q,String qKey,String tCode){
+    /// 获取产品主数据
+    private List<Map> getProductData(String projectId, String q, String qKey, String tCode) {
         // 校验项目号
-        YDSearch ytbProjectId=new YDSearch("textField_lqxtykce",projectId,"TB项目编号", YDSearch.Type.TEXT_FIELD,YDSearch.Operator.EQ);
-        List<Map> tbProjectList =(List<Map>) ydClient.queryData(YDParam.builder().formUuid("FORM-141E21DF183846028E21727CE43CD1C75CLZ")
+        YDSearch ytbProjectId = new YDSearch("textField_lqxtykce", projectId, "TB项目编号", YDSearch.Type.TEXT_FIELD, YDSearch.Operator.EQ);
+        List<Map> tbProjectList = (List<Map>) ydClient.queryData(YDParam.builder().formUuid("FORM-141E21DF183846028E21727CE43CD1C75CLZ")
                 .appType("APP_R5EBUF2FPN3Y8DRF93M4").systemToken("ON566NC1VNIHPANP9TNVHB3TBIWS3E0TUZ5RLF3")
                 .searchCondition(JSONObject.toJSONString(Arrays.asList(ytbProjectId)))
                 .pageSize(10).build(), YDConf.FORM_QUERY.retrieve_list).getData();
 
-        McException.assertAccessException(tbProjectList==null||tbProjectList.size()<1, "未匹配到主数据!");
-        String pId=UtilMap.getString(UtilMap.getMap(tbProjectList.get(0),"formData"),"textField_lrj7vnxb");
+        McException.assertAccessException(tbProjectList == null || tbProjectList.size() < 1, "未匹配到主数据!");
+        String pId = UtilMap.getString(UtilMap.getMap(tbProjectList.get(0), "formData"), "textField_lrj7vnxb");
         McException.assertAccessException(StringUtils.isBlank(pId), "未匹配到主数据!");
 
-        YDSearch ydSearch=new YDSearch("textField_lha7mqbs","G","物料子类", YDSearch.Type.TEXT_FIELD,YDSearch.Operator.EQ);
-        YDSearch ydSearch2=new YDSearch("textField_lha7mqbn",pId,"项目号", YDSearch.Type.TEXT_FIELD,YDSearch.Operator.EQ);
-        YDSearch ydSearch3=new YDSearch(qKey,q,"产品料号", YDSearch.Type.TEXT_FIELD,YDSearch.Operator.LIKE);
-        List qList=Arrays.asList(ydSearch,ydSearch2,ydSearch3);
-        if(tCode!=null){
-            YDSearch ydSearch4=new YDSearch("textField_lhsxurnt",tCode,"产品料号", YDSearch.Type.TEXT_FIELD,YDSearch.Operator.EQ);
-            qList=Arrays.asList(ydSearch,ydSearch2,ydSearch3,ydSearch4);
+        YDSearch ydSearch = new YDSearch("textField_lha7mqbs", "G", "物料子类", YDSearch.Type.TEXT_FIELD, YDSearch.Operator.EQ);
+        YDSearch ydSearch2 = new YDSearch("textField_lha7mqbn", pId, "项目号", YDSearch.Type.TEXT_FIELD, YDSearch.Operator.EQ);
+        YDSearch ydSearch3 = new YDSearch(qKey, q, "产品料号", YDSearch.Type.TEXT_FIELD, YDSearch.Operator.LIKE);
+        List qList = Arrays.asList(ydSearch, ydSearch2, ydSearch3);
+        if (tCode != null) {
+            YDSearch ydSearch4 = new YDSearch("textField_lhsxurnt", tCode, "产品料号", YDSearch.Type.TEXT_FIELD, YDSearch.Operator.EQ);
+            qList = Arrays.asList(ydSearch, ydSearch2, ydSearch3, ydSearch4);
         }
-        List<Map> list =(List<Map>) ydClient.queryData(YDParam.builder().formUuid("FORM-4W8667D17CAAGFXI9VO0J9J7RFNL2QDFL7AHLJ")
+        List<Map> list = (List<Map>) ydClient.queryData(YDParam.builder().formUuid("FORM-4W8667D17CAAGFXI9VO0J9J7RFNL2QDFL7AHLJ")
                 .appType("APP_QBWQITQBSPJNYTUTNPDK").systemToken("8F966HB12J27MQJM6V4IQDYHYTPA2G4GTZGCLN1")
                 .searchCondition(JSONObject.toJSONString(qList))
                 .pageSize(100).build(), YDConf.FORM_QUERY.retrieve_list).getData();
-        List<Map> result=new ArrayList<>();
-        Map<String,String> keyMap=new HashMap<>();
-        for (Map map:list){
-            String data=UtilMap.getString(UtilMap.getMap(map,"formData"),qKey);
-            if(!StringUtils.isBlank(data)&&!keyMap.containsKey(data)){
-                result.add(UtilMap.map("title",data));
-                keyMap.put(data,data);
+        List<Map> result = new ArrayList<>();
+        Map<String, String> keyMap = new HashMap<>();
+        for (Map map : list) {
+            String data = UtilMap.getString(UtilMap.getMap(map, "formData"), qKey);
+            if (!StringUtils.isBlank(data) && !keyMap.containsKey(data)) {
+                result.add(UtilMap.map("title", data));
+                keyMap.put(data, data);
             }
         }
         return result;
     }
 
+
+    /**
+     * 检查项导出, 全部检查项左关联已提交数据 [ ppExt 已提交数据作为查询条件, 只能筛选已提交数据, 因此提供全量导出 ]
+     */
+    @Override
+    public void exportCheckList(String pCode, String proType) {
+        List<Map> checkedList = _getCheckedList(pCode);
+
+
+        // 查询全部检查项提交数据
+        List<Map> dataList = ydService.queryFormData_all(YDParam.builder()
+                .formUuid(_matchFormUuid("CHECK"))
+                .searchFieldJson(JSON.toJSONString(UtilMap.map("multiSelectField_ltwjre9s, radioField_lrnddfq6", Arrays.asList(proType), "启用")))
+                .dynamicOrder(JSON.toJSONString(UtilMap.map("selectField_lrncf4hk", "+")))
+                .build());
+        // 匹配已提交检查项生数据
+        List<Map> unionList = new ArrayList<>();
+        for (Map check : dataList) {
+            // 任务编号一致, 检查项唯一标识一致
+            List<Map> match = checkedList.stream().filter(item ->
+            {
+                Map unique = (Map) UtilMap.getList(UtilMap.getMap(item, "main"), "associationFormField_lrrnem5r_id").get(0);
+                return item.get("selectField_lqxuswzd").equals(check.get("selectField_lrncf4hk")) && check.get("textField_lrnd3h0r").equals(unique.get("title"));
+            }).collect(Collectors.toList());
+            // 多条重复提交如何处理
+            if (match.size() > 0) {
+                // match 匹配已提交件数据, match.main 为已提交数据主表内容
+                match.forEach(item -> {
+                    check.put("match", item);
+                    unionList.add(check);
+                });
+            } else {
+                unionList.add(check);
+            }
+        }
+        log.info("检查项数据: {}", unionList.size());
+    }
+
+
+    /// 查询项目已提交全部检查项数据
+    List<Map> _getCheckedList(String pCode) {
+        List<Map> dataList = ydService.queryFormData_all(YDParam.builder()
+                .formUuid(_matchFormUuid("RECORD"))
+                .searchFieldJson(JSON.toJSONString(UtilMap.map("selectField_lqxuswze", pCode)))
+                .build());
+        dataList = dataList.stream().filter(item -> pCode.equals(item.get("selectField_lqxuswze"))).collect(Collectors.toList());
+
+        List<Map> checkedList = new ArrayList<>();
+        for (Map record : dataList) {
+            // 检查项清单[明细默认只返回前50]
+            List<Map> details = UtilMap.getList(record, "tableField_lqxxgj4s");
+            if (details.size() == YDConf.PAGE_SIZE_DETAILS) {
+                details = ydService.queryDetails(YDParam.builder()
+                        .formUuid(_matchFormUuid("RECORD"))
+                        .formInstanceId(UtilMap.getString(record, "instanceId"))
+                        .tableFieldId("tableField_lqxxgj4s")
+                        .build());
+                // 过滤空数据, 无检查项目关联数据
+                details = details.stream().filter(item -> ObjectUtil.isNotNull(item) && StringUtils.isNotBlank(UtilMap.getString(item, "associationFormField_lrrnem5r_id")))
+                        .map(item -> {
+                            // 合并主笔数据
+                            item.put("main", record);
+                            item.put("associationFormField_lrrnem5r", JSON.parse(String.valueOf(JSON.parse(UtilMap.getString(item, "associationFormField_lrrnem5r_id")))));
+                            return item;
+                        }).collect(Collectors.toList());
+            }
+            checkedList.addAll(details);
+            log.info("检查项清单, {}", details.size());
+        }
+        return checkedList;
+    }
+
+
+    /************************************* ------------------- *************************************/
+
+    @Override
+    public void test() {
+
+
+        exportCheckList("A2453", "产品开发项目");
+
+//        approveVersion("659a681d44ade3345fdc0d39", "99999");
+        //
+        //        String pCode = "99999";
+        //        String pCode = "A240407DryRun";
+        //
+        //        List<Map> pList = ydService.queryDataList_FormData(_matchFormUuid("PROJECT"), UtilMap.map("textField_lrj7vnxb", pCode));
+        //        pList = pList.stream().filter(item -> pCode.equals(item.get("textField_lrj7vnxb"))).collect(Collectors.toList());
+        //        _assembleBreakPermission(pList.get(0));
+
+        //        String creatorUnionId = String.valueOf(ddClient_contacts.getUserInfoById(ddClient.getAccessToken(), "095358016629044412").get("unionid"));
+        //        List<Map> allMembers = ddClient_storage.queryDentryPermissions(ddClient.getAccessToken(), "14lgGw3P8vMDNPvMC7aw11LzJ5daZ90D", creatorUnionId, null);
+        //        log.info("xxxx, {}", allMembers);
+        //
+        //        String taskId = "65addc57055591ee7d17d807";
+        //        Map taskData = _getTaskFieldMap(taskId, AWServer.TASK_APPROVE_LINK, AWServer.TASK_APPROVE_VERSION, AWServer.TASK_STAGE, AWServer.TASK_ROLE);
+        //        List<Map> checkList = _getCustomFieldList(taskData, AWServer.TASK_APPROVE_LINK);
+
+        //        checkList = new ArrayList<>();
+        //        String url = "https://kabom7.aliwork.com/APP_H7WUJTKB448F9IBDC6C4/processDetail?formUuid=FORM-FBC1A390B4C348089020C763938A6F54RUNY&procInsId=5bd917c4-b23c-4f2f-ba4b-cef533118cdf&isAdmin=true&navConfig.layout=1180";
+        //        String url = "https://kabom7.aliwork.com/APP_H7WUJTKB448F9IBDC6C4/submission/FORM-7B63BB056145452F8BC0A2C52492DE00QVBH?taskId=65addc57055591ee7d17d807";
+        //        _updateApproveField(taskId, checkList, url, "技术检查项确认", "待提交", AWServer.TASK_APPROVE_LINK);
+
+    }
+
+    @Override
+    public void tmp() {
+        //        this.tmp_617();
+    }
+
     /// tmp: 6.18 临时修改权限
     private void tmp618() {
         // 知识库返回根节点 rootNodeId, 即根目录的 dentryUuid, 可添加整个知识库编辑权限, 通过知识库创建者赋权
@@ -1846,14 +1956,14 @@ public class AWImplClient implements AWClint {
             }
             details = details.stream().filter(row -> !"IC技术检查表".equals(row.get("selectField_lrnd3h0s"))).collect(Collectors.toList());
             details.forEach(record -> {
-//                String tmp = ((List<Map<String, String>>) JSON.parse(String.valueOf(JSON.parse(String.valueOf(record.get("associationFormField_lrrnem5r_id")))))).get(0).get("title");
-//                if (tmp.startsWith("TR")) {
-//                    record.put("selectField_lrnd3h0s", "TR评审要素表");
-//                } else if (tmp.contains("-")) {
-//                    record.put("selectField_lrnd3h0s", "IC技术检查表");
-//                } else {
-//                    record.put("selectField_lrnd3h0s", "经验库");
-//                }
+                //                String tmp = ((List<Map<String, String>>) JSON.parse(String.valueOf(JSON.parse(String.valueOf(record.get("associationFormField_lrrnem5r_id")))))).get(0).get("title");
+                //                if (tmp.startsWith("TR")) {
+                //                    record.put("selectField_lrnd3h0s", "TR评审要素表");
+                //                } else if (tmp.contains("-")) {
+                //                    record.put("selectField_lrnd3h0s", "IC技术检查表");
+                //                } else {
+                //                    record.put("selectField_lrnd3h0s", "经验库");
+                //                }
                 if ("技术评审要素表".equals(record.get("selectField_lrnd3h0s"))) {
                     record.put("selectField_lrnd3h0s", "IC技术检查表");
                 }

+ 277 - 0
mjava-aiwei/src/main/java/com/malk/aiwei/service/impl/AWYDImplClient.java

@@ -0,0 +1,277 @@
+package com.malk.aiwei.service.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.malk.aiwei.service.AWYDClient;
+import com.malk.server.aliwork.YDConf;
+import com.malk.server.aliwork.YDParam;
+import com.malk.service.aliwork.YDClient;
+import com.malk.service.aliwork.YDService;
+import com.malk.utils.UtilMap;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Service
+public class AWYDImplClient implements AWYDClient {
+
+    @Autowired
+    private YDClient ydClient;
+
+    @Autowired
+    private YDService ydService;
+
+    /**
+     * 提供verifier数据读取服务
+     */
+    @Override
+    public List<Map> syncVerifier(String projectCode) {
+        List<Map> dataList = ydService.queryFormData_all(YDParam.builder()
+                .formUuid("FORM-23B67983E91C4ED3B063F9B629D6E964SGHH")
+                .searchCondition(JSON.toJSONString(UtilMap.map("textField_lt6xd8lm", projectCode)))
+                .build());
+
+        return dataList.stream().map(item -> {
+            return item;
+        }).collect(Collectors.toList());
+    }
+
+
+    /************************************* 0906 产品需求导入逻辑变革, 弃用保留 *************************************/
+    
+    @Override
+    public Map checkImportData(Map data) {
+        List<Map> dataList = UtilMap.getList(data, "dataList");
+        String charter = UtilMap.getString(data, "charter");
+        // 根据charter查询需求库
+        List<Map> list = ydService.queryFormData_all(YDParam.builder()
+                .appType("APP_YQY0OH7953OKBTM57PLL")
+                .systemToken("PGC66MB1H2RLXMFQ7XKW4BC3BDFJ2UDM909XL18")
+                .formUuid("FORM-7A52930D0E834522AD65A4CFE2C0818F1KQO")
+                .searchFieldJson(JSONObject.toJSONString(UtilMap.map("textField_lth2h04b", charter))).build());
+        Map<String, Map> charterMap = new HashMap();
+        Map<String, String> instIdList = new HashMap<>();
+        for (int j = 0; j < list.size(); j++) {
+            Map item = list.get(j);
+            instIdList.put(UtilMap.getString(item, "textField_lt2d2x79"), UtilMap.getString(item, "instanceId"));
+            String no = getCode(UtilMap.getString(item, "textField_lt2d2x79"));
+            charterMap.put(no, item);
+            list.get(j).put("id", no);
+        }
+        Boolean flag = true;
+        Map noList = new HashMap();
+        // 数据校验
+        for (int i = 0; i < dataList.size(); i++) {
+            String errmsg = "";
+            Map item = dataList.get(i);
+            String category = UtilMap.getString(item, "selectField_lronu2g3");
+            if (StringUtils.isBlank(category)) {
+                errmsg = errmsg + "需求大类不能为空;";
+            } else {
+                category = category.split("(")[1].replace(")", "");
+                String no = noCP(UtilMap.getString(item, "textField_lt2d2x79"), category);
+                String fno = noCP(UtilMap.getString(item, "textField_m0afm8pd"), category);
+                if (!isValidVersion(no)) {
+                    errmsg = errmsg + "需求编号格式错误;";
+                }
+                if (noList.containsKey(category + no)) {
+                    errmsg = errmsg + "需求编号重复;";
+                }
+                noList.put(category + no, category + no);
+                int cj = getSize(no);
+                if (cj == 1) {
+                    dataList.get(i).put("textField_m0afm8pd", "");
+                } else {
+                    if (!isValidVersion(fno)) {
+                        errmsg = errmsg + "父需求编号格式错误;";
+                    }
+                    if (cj - 1 != getSize(fno)) {
+                        errmsg = errmsg + "父需求编号层级错误;";
+                    }
+                    if (StringUtils.isNotBlank(fno) && !noList.containsKey(category + fno)) {
+                        // 导入数据前父需求编号不存在
+                        if (!charterMap.containsKey(getCode(UtilMap.getString(item, "textField_m0afm8pd")))) {
+                            errmsg = errmsg + "父需求编号数据不存在;";
+                        }
+                    }
+                }
+                if (fno == no) {
+                    errmsg = errmsg + "需求编号于父需求编号不能相同;";
+                }
+                dataList.get(i).put("selectField_lr4y2xcj", cj + "级");
+                if (String.valueOf(item.get("multiSelectField_lw678e43")).length() > 0) {
+                    List multi = UtilMap.getList(item, "multiSelectField_lw678e43");
+                    dataList.get(i).put("multiSelectField_lw678e43_str", multi == null || multi.size() < 1 ? "" : String.join(",", multi));
+                }
+            }
+            if (errmsg != "") {
+                dataList.get(i).put("result", errmsg);
+                flag = false;
+            }
+        }
+        if (flag) {
+            for (int i = 0; i < dataList.size(); i++) {
+                Map item = dataList.get(i);
+                String no = UtilMap.getString(item, "textField_lt2d2x79");
+                String codeNo = getCode(no);
+                if (charterMap.containsKey(codeNo)) {
+                    dataList.get(i).put("associationFormField_lvy7yjq8", getAss(no, instIdList.get(no)));
+                    dataList.get(i).put("textField_lyqprdyf", codeNo); // 序号
+                } else {
+                    // 新增
+                    String category = UtilMap.getString(item, "selectField_lronu2g3");
+                    String categoryNew = category.split("(")[1].replace(")", "");
+                    no = noCP(UtilMap.getString(item, "textField_lt2d2x79"), categoryNew);
+                    String fno = "";
+                    int level = getSize(no);
+                    dataList.get(i).put("selectField_lr4y2xcj", level + "级");
+                    // 根据层级查询序号
+                    String noNew = "";
+                    // 处理结果
+                    if (level > 1) {
+                        fno = getCodeNo(categoryNew, noCP(UtilMap.getString(item, "textField_m0afm8pd"), categoryNew));
+                    }
+                    Map reMap = getMaxValue(list, level + "级", category, fno);
+                    if (reMap != null) {
+                        String id = UtilMap.getString(reMap, "id");
+                        noNew = incrementLastPart(id);
+                    } else {
+                        noNew = level == 1 ? categoryNew + "001" : fno + ".1";
+                    }
+                    codeNo = noNew;
+                    fno = getFnoValue(list, fno);
+                    String nowTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("MMddHHmmssS"));
+                    dataList.get(i).put("textField_lt2d2x79", noNew + "_" + nowTime);
+                    dataList.get(i).put("textField_m0afm8pd", fno);
+                    dataList.get(i).put("textField_lyqprdyf", codeNo); // 序号
+                    // 拼装数据并新增需求
+                    Map mapNew = dataList.get(i);
+                    mapNew.put("textField_lth2h04b", charter);
+                    mapNew.put("radioField_lroozhse", "是");
+                    mapNew.put("textField_m0m3dyk4", fno);
+                    mapNew.put("textField_lyqpt99s", codeNo);
+                    mapNew.put("radioField_m0ow50wn", "是"); // 是否草稿
+                    String id = (String) ydClient.operateData(YDParam.builder().appType("APP_YQY0OH7953OKBTM57PLL")
+                            .systemToken("PGC66MB1H2RLXMFQ7XKW4BC3BDFJ2UDM909XL18")
+                            .formUuid("FORM-7A52930D0E834522AD65A4CFE2C0818F1KQO")
+                            .formDataJson(JSONObject.toJSONString(mapNew))
+                            .build(), YDConf.FORM_OPERATION.create);
+                    dataList.get(i).put("associationFormField_lvy7yjq8", getAss(noNew + "_" + nowTime, id));
+                    mapNew.put("instanceId", id);
+                    mapNew.put("id", codeNo);
+                    list.add(mapNew);
+                }
+            }
+        }
+        return UtilMap.map("data, flag", dataList, flag);
+    }
+
+    private static String incrementLastPart(String input) {
+        // 查找最后一个点号的位置
+        int lastDotIndex = input.lastIndexOf('.');
+        // 如果没有点号,则整个字符串都需要加1
+        if (lastDotIndex == -1) {
+            String q = input.substring(0, input.length() - 3);
+            String h = input.substring(input.length() - 3);
+            return q + String.format("%03d", Integer.parseInt(h) + 1);
+        }
+        // 分割字符串
+        String prefix = input.substring(0, lastDotIndex + 1);
+        String lastPart = input.substring(lastDotIndex + 1);
+        // 对最后一部分加1
+        String incrementedLastPart = incrementPart(lastPart);
+        // 返回拼接后的结果
+        return prefix + incrementedLastPart;
+    }
+
+    private static String incrementPart(String part) {
+        // 将字符串转换为整数并加1
+        int number = Integer.parseInt(part);
+        number++;
+        // 将整数转换回字符串
+        return String.valueOf(number);
+    }
+
+    private static String getCodeNo(String category, String no) {
+        int dotIndex = no.indexOf('.');
+        String beforeDot = dotIndex == -1 ? no : no.substring(0, dotIndex);
+        String afterDot = dotIndex == -1 ? "" : no.substring(dotIndex);
+        // 对第一部分进行补零
+        String paddedBeforeDot = String.format("%03d", Integer.parseInt(beforeDot));
+        return category + paddedBeforeDot + afterDot;
+    }
+
+    private String getFnoValue(List<Map> list, String fno) {
+        if (StringUtils.isBlank(fno)) {
+            return "";
+        }
+        List<Map> list1 = list.stream()
+                .filter(map -> UtilMap.getString(map, "textField_lt2d2x79").contains(fno + "_")).collect(Collectors.toList()); // 父编号查询编号
+        if (list1 != null && list1.size() > 0) {
+            return UtilMap.getString(list1.get(0), "textField_lt2d2x79");
+        }
+        return "";
+    }
+
+    private Map getMaxValue(List<Map> list, String level, String category, String fno) {
+        // 查找符合条件的最大 id
+        List<Map> list1 = list.stream()
+                .filter(map -> UtilMap.getString(map, "selectField_lr4y2xcj").equals(level)) // 层级
+                .filter(map -> UtilMap.getString(map, "textField_lt2d2x79").contains(fno)) // 父编号查询编号
+                .filter(map -> UtilMap.getString(map, "selectField_lronu2g3").equals(category)).collect(Collectors.toList()); // 前缀
+        Optional<Map> maxMap = list1.stream()
+                .max(Comparator.comparing(map -> UtilMap.getString(map, "id")));
+        return maxMap.orElse(null);
+    }
+
+    private Object getAss(String title, String id) {
+        return Arrays.asList(UtilMap.map("appType, formUuid, formType, instanceId, title, subTitle", "APP_YQY0OH7953OKBTM57PLL", "FORM-7A52930D0E834522AD65A4CFE2C0818F1KQO", "receipt", id, title, ""));
+    }
+
+    private static int getSize(String value) {
+        return value.split("\\.").length;
+    }
+
+    private Boolean isValidVersion(String version) {
+        Pattern pattern = Pattern.compile("^([0-9]{1,3}(\\.[0-9]{1,3}){0,2})$");
+        Matcher matcher = pattern.matcher(version);
+        return matcher.matches();
+    }
+
+    private String noCP(String value, String category) {
+        if (value.contains(category)) {
+            return getCode(value).replace(category, "").replaceAll("^0+", "");
+        } else {
+            return value;
+        }
+    }
+
+    private String getCode(String pCode) {
+        if (!pCode.contains("_")) {
+            return pCode;
+        }
+        if (isNumeric(pCode.split("_")[0])) {
+            // 时间_序号
+            return pCode.split("_")[1];
+        } else if (isNumeric(pCode.split("_")[1])) {
+            // 序号_时间
+            return pCode.split("_")[0];
+        }
+        return pCode;
+    }
+
+    private boolean isNumeric(String str) {
+        Pattern pattern = Pattern.compile("^\\d+$");
+        Matcher matcher = pattern.matcher(str);
+        return matcher.matches();
+    }
+}

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

@@ -57,10 +57,10 @@ dingtalk:
   token:
   operator: "095358016629044412"   # OA管理员账号
 
-#  aliwork
-aliwork:
-  appType: "APP_H7WUJTKB448F9IBDC6C4"
-  systemToken: "DHA66081DN6GRFNC6GTRW5NIJS082ZF0UN9PLLF"
+##  aliwork
+#aliwork:
+#  appType: "APP_H7WUJTKB448F9IBDC6C4"
+#  systemToken: "DHA66081DN6GRFNC6GTRW5NIJS082ZF0UN9PLLF"
 
 # teambition
 teambition:
@@ -69,10 +69,10 @@ teambition:
   TenantId: 6034c885e71842e1e5bb5218        # 管理后台 - 企业xx - 企业ID
   OperatorId: 5e698cca21f5ad70dfba7d2b      # 公共账号, 需要有操作权限 [牧语]
 
-## aliwork - prod
-#aliwork:
-#  appType: "APP_R5EBUF2FPN3Y8DRF93M4"
-#  systemToken: "ON566NC1VNIHPANP9TNVHB3TBIWS3E0TUZ5RLF3"
+# aliwork - prod
+aliwork:
+  appType: "APP_R5EBUF2FPN3Y8DRF93M4"
+  systemToken: "ON566NC1VNIHPANP9TNVHB3TBIWS3E0TUZ5RLF3"
 #
 ## dingtalk
 #dingtalk:

+ 1 - 0
mjava-aiwei/src/main/resources/application-test.yml

@@ -43,3 +43,4 @@ teambition:
   AppSecret: jyd7DVu3MGYwzt562qPmLAaacV65FIyQ
   TenantId: 658e7239b580fdc87e4a7ca4                # 管理后台 - 企业xx - 企业ID
   OperatorId: 667e8282df3131f8e588526e              # 公共账号, 需要有操作权限 [x]
+  ApiHost: https://tbtest.awinic.com:443/gateway        # 私有部署

BIN
mjava-aiwei/src/main/resources/templates/templates_xqrk.xlsx


BIN
mjava-aiwei/src/main/resources/templates/templates_xqwh.xlsx


BIN
mjava-aiwei/src/main/resources/templates/templates_xqwh_result.xlsx


+ 14 - 18
mjava-aiwei/src/test/java/com/malk/aiwei/AwTbTest.java

@@ -1,24 +1,20 @@
 package com.malk.aiwei;
 
 import com.alibaba.fastjson.JSONObject;
-import com.malk.aiwei.server.YDSearch;
-import com.malk.server.aliwork.YDConf;
-import com.malk.server.aliwork.YDParam;
-import com.malk.server.dingtalk.DDR_New;
 import com.malk.server.teambition.TBConf;
 import com.malk.service.aliwork.YDClient;
 import com.malk.service.teambition.TBClient;
 import com.malk.utils.UtilMap;
 import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.StringUtils;
-import org.assertj.core.util.Strings;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.test.context.junit4.SpringRunner;
 
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
 
 @Slf4j
 @SpringBootTest
@@ -31,17 +27,17 @@ public class AwTbTest {
     private TBConf tbConf;
 
     @Test
-    public void test(){
-        List<String> users=Arrays.asList("5f3a250040ce230ba377bf3c","5e698cca21f5ad70dfba7d2b","616fb6f78ad4104a10515809");
-        String programId ="662a69aceda740b4e63d3976";
+    public void test() {
+        List<String> users = Arrays.asList("5f3a250040ce230ba377bf3c", "5e698cca21f5ad70dfba7d2b", "616fb6f78ad4104a10515809");
+        String programId = "662a69aceda740b4e63d3976";
 //        tbClient.createProgramMember(programId,tbConf.getOperatorId(),users);
-        List addUsers=new ArrayList();
-        for (String userId:users){
-            List resut=tbClient.queryProgramMember(programId,tbConf.getOperatorId(), UtilMap.map("userIds", userId));
+        List addUsers = new ArrayList();
+        for (String userId : users) {
+            List resut = tbClient.queryProgramMember(programId, tbConf.getOperatorId(), UtilMap.map("userIds", userId));
             if (resut.size() < 1) addUsers.add(userId);
         }
-        log.info("需要添加到项目集的userId:{}",tbClient);
-        if (addUsers.size() > 0) tbClient.createProgramMember(programId,tbConf.getOperatorId(),addUsers);
+        log.info("需要添加到项目集的userId:{}", tbClient);
+        if (addUsers.size() > 0) tbClient.createProgramMember(programId, tbConf.getOperatorId(), addUsers);
     }
 
     @Autowired
@@ -52,9 +48,8 @@ public class AwTbTest {
     //    'yida_pub_account', "selectField_lchafcgt", "selectField_lchafcgt", "selectField_lywdbrk1", 100);
 
 
-
     @Test
-    public void adad(){
+    public void adad() {
 //        YDSearch ydSearch=new YDSearch("textField_lha7mqbs","G","物料子类", YDSearch.Type.TEXT_FIELD,YDSearch.Operator.EQ);
 //        YDSearch ydSearch2=new YDSearch("textField_lha7mqbn","A2443","项目号", YDSearch.Type.TEXT_FIELD,YDSearch.Operator.EQ);
 //        List<Map> list =(List<Map>) ydClient.queryData(YDParam.builder().formUuid("FORM-4W8667D17CAAGFXI9VO0J9J7RFNL2QDFL7AHLJ")
@@ -76,7 +71,8 @@ public class AwTbTest {
 //                .build(), YDConf.FORM_QUERY.retrieve_forms);
 //        print(ddr_new);
     }
-    private void print(Object o){
+
+    private void print(Object o) {
         System.out.println(JSONObject.toJSONString(o));
     }
 

+ 2 - 0
mjava-cloudpure/src/main/java/com/malk/cloudpure/controller/TSController.java

@@ -172,6 +172,8 @@ public class TSController {
                     .appType("APP_ERBDTFS82HOVBPL3NFH0")
                     .systemToken("RRB66F91T97H1WN89QZYC47PKLZO2ZQOUMOQLP")
                     .formInstanceId(UtilMap.getString(item, "formInstanceId"))
+                    .useLatestVersion(true)
+                    .updateFormDataJson(JSON.toJSONString(new HashMap<>()))
                     .build(), YDConf.FORM_OPERATION.update);
         });
     }

+ 3 - 1
mjava-hake/src/main/java/com/malk/hake/controller/HKController.java

@@ -66,7 +66,9 @@ public class HKController {
 
         Map data = UtilServlet.getParamMap(request);
         log.info("审批回调, {}", JSON.toJSONString(data));
-        hkClient.callbackProcess(data);
+        if (!"Y".equals(data.get("Status"))) { // 询价\报价
+            hkClient.callbackProcess(data);
+        }
         return McR.success();
     }
 

+ 54 - 0
mjava-ruisi/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-ruisi</artifactId>
+    <description>瑞思COS 投入对接企业账号</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-ruisi/src/main/java/com/malk/ruisi/Boot.java

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

+ 58 - 0
mjava-ruisi/src/main/java/com/malk/ruisi/controller/CosController.java

@@ -0,0 +1,58 @@
+package com.malk.ruisi.controller;
+
+/**
+ * 错误抛出与拦截详见 CatchException
+ */
+
+import com.malk.ruisi.service.RSService;
+import com.malk.server.common.McException;
+import com.malk.server.common.McR;
+import com.malk.utils.UtilServlet;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.Map;
+
+@Slf4j
+@RestController
+@RequestMapping
+public class CosController {
+
+    @Autowired
+    private RSService rsService;
+
+    /**
+     * 创建投资人用户
+     */
+    @PostMapping("user/sync")
+    McR syncUser() {
+        
+        log.info("syncUser");
+        rsService.syncDingTalk_exclusive();
+        return McR.success();
+    }
+
+    /**
+     * 重置密码流程
+     */
+    @PostMapping("reset")
+    McR resetPwd(HttpServletRequest request) {
+
+        Map data = UtilServlet.getParamMap(request);
+        log.info("reset, {}", data);
+
+        McException.assertParamException_Null(data, "userId", "password");
+        rsService.resetPwd(data);
+        return McR.success();
+    }
+
+    @PostMapping("test")
+    McR test() {
+
+        return McR.success();
+    }
+}

+ 35 - 0
mjava-ruisi/src/main/java/com/malk/ruisi/schedule/RSScheduleTask.java

@@ -0,0 +1,35 @@
+package com.malk.ruisi.schedule;
+
+import com.malk.ruisi.service.RSService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.scheduling.annotation.Scheduled;
+
+/**
+ * @EnableScheduling 开启定时任务 [配置参考McScheduleTask]
+ */
+@Slf4j
+@Configuration
+@EnableScheduling
+@ConditionalOnProperty(name = {"spel.scheduling"})
+public class RSScheduleTask {
+
+    @Autowired
+    private RSService rsService;
+
+    /**
+     * 每天凌晨5点同步
+     */
+    @Scheduled(cron = "0 0 5 * * ? ")
+    public void syncDingTalkFailedList() {
+        try {
+            rsService.syncDingTalk_exclusive();
+        } catch (Exception e) {
+            // 记录错误信息
+            e.printStackTrace();
+        }
+    }
+}

+ 16 - 0
mjava-ruisi/src/main/java/com/malk/ruisi/service/RSService.java

@@ -0,0 +1,16 @@
+package com.malk.ruisi.service;
+
+import java.util.Map;
+
+public interface RSService {
+
+    /**
+     * 同步钉钉企业账号
+     */
+    void syncDingTalk_exclusive();
+
+    /**
+     * 重置企业账号密码
+     */
+    void resetPwd(Map data);
+}

+ 85 - 0
mjava-ruisi/src/main/java/com/malk/ruisi/service/impl/RSImplService.java

@@ -0,0 +1,85 @@
+package com.malk.ruisi.service.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.malk.ruisi.service.RSService;
+import com.malk.server.aliwork.YDConf;
+import com.malk.server.aliwork.YDParam;
+import com.malk.server.common.McException;
+import com.malk.service.aliwork.YDClient;
+import com.malk.service.aliwork.YDService;
+import com.malk.service.dingtalk.DDClient;
+import com.malk.service.dingtalk.DDClient_Contacts;
+import com.malk.utils.UtilMap;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+@Service
+@Slf4j
+public class RSImplService implements RSService {
+
+    @Autowired
+    private YDService ydService;
+
+    @Autowired
+    private YDClient ydClient;
+
+    @Autowired
+    private DDClient_Contacts ddClient_contacts;
+
+    @Autowired
+    private DDClient ddClient;
+
+    @Autowired
+    private static final long DEPT_ID = 933074211L; // 合作加盟校区
+
+
+    /// 创建企业账号: loginI/userId 都为 SHR 工号
+    private void createExclusiveUser(String loginId, String name) {
+
+        final String PASS_WORD = "tzr@111111";
+
+        Map info = UtilMap.map("userid", loginId);
+        ddClient_contacts.createUser_dingTalk(ddClient.getAccessToken(), loginId, PASS_WORD, name, Arrays.asList(DEPT_ID), info);
+    }
+
+    /**
+     * 同步钉钉企业账号
+     */
+    @Override
+    public void syncDingTalk_exclusive() {
+
+        List<Map> dataList = ydService.queryFormData_all(YDParam.builder()
+                .formUuid("FORM-11B80FC621CA4DB9A35364CFBFF7287538KR")
+                .build());
+        dataList.forEach(data -> {
+            if (!"是".equals(UtilMap.getString(data, "radioField_m0hlup9w"))) {
+                String userId = UtilMap.getString(data, "textField_lztc6k3k");
+                String message = "";
+                try {
+                    this.createExclusiveUser(userId, UtilMap.getString(data, "textField_lxsm8xow"));
+                } catch (McException e) {
+                    message = e.getMessage();
+                    log.error(e.getMessage(), e);
+                }
+                ydClient.operateData(YDParam.builder()
+                        .formInstanceId(UtilMap.getString(data, "instanceId"))
+                        .useLatestVersion(true)
+                        .updateFormDataJson(JSON.toJSONString(UtilMap.map("radioField_m0hlup9w, employeeField_m0hlup9v, textareaField_m0hs4k90", "是", Arrays.asList(userId), message)))
+                        .build(), YDConf.FORM_OPERATION.update);
+            }
+        });
+    }
+    
+    /**
+     * 重置企业账号密码
+     */
+    @Override
+    public void resetPwd(Map data) {
+        ddClient_contacts.updateUser_dingTalk(ddClient.getAccessToken(), UtilMap.getString(data, "userId"), Arrays.asList(DEPT_ID), UtilMap.map("init_password", UtilMap.getString(data, "password")));
+    }
+}

+ 64 - 0
mjava-ruisi/src/main/resources/application-dev.yml

@@ -0,0 +1,64 @@
+# 环境配置
+server:
+  port: 9001
+  servlet:
+    context-path: /api/ruisi
+
+# 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: 3079562924
+  appKey: dingprswtas7kluqst2c
+  appSecret: ukquGx_DjznsTQtKQtFFNutn1NFhSgL9ZbTfCtl_9mJYWacFYu--vj_zThTxjsYN
+  corpId: dingccd7fff754e440cf24f2f5cc6abecb85
+  aesKey:
+  token:
+  operator:           # OA管理员账号 [首字符若为0需要转一下字符串]
+
+# aliwork
+aliwork:
+  appType: APP_VCTRP6227CC8368NDOID
+  systemToken: 5H9662C1X8XJLFFCE841M5VBEBQ73DM5IBPULPI3
+

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

@@ -0,0 +1,38 @@
+# 环境配置
+server:
+  port: 9031
+  servlet:
+    context-path: /api/ruisi
+
+# 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: 3079562924
+  appKey: dingprswtas7kluqst2c
+  appSecret: ukquGx_DjznsTQtKQtFFNutn1NFhSgL9ZbTfCtl_9mJYWacFYu--vj_zThTxjsYN
+  corpId: dingccd7fff754e440cf24f2f5cc6abecb85
+  aesKey:
+  token:
+  operator:           # OA管理员账号 [首字符若为0需要转一下字符串]
+
+# aliwork
+aliwork:
+  appType: APP_VCTRP6227CC8368NDOID
+  systemToken: 5H9662C1X8XJLFFCE841M5VBEBQ73DM5IBPULPI3

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

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

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

@@ -96,7 +96,6 @@ public abstract class BaseDto {
         return formData;
     }
 
-
     /**
      * Map时间格式化, 直接从数据库取值后Map会有市区差, 方法1见BasePo, @Temporal & @JsonFormat 注解
      * -

+ 3 - 0
mjava/src/main/java/com/malk/schedule/McScheduleTask.java

@@ -29,6 +29,9 @@ import org.springframework.scheduling.annotation.EnableScheduling;
  * @ConditionalOnProperty,可多个参数,支持与,若获取值为空识别为false,若有值则将该值与havingValue指定的值进行比较,匹配结果为bool。不支持或
  */
 
+
+// todo L 不识别, 启动报错
+
 @Slf4j
 @Configuration
 @EnableScheduling

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

@@ -33,6 +33,13 @@ public class YDConf {
      */
     public static final Integer PAGE_SIZE_LIMIT = 100;
 
+
+    /**
+     * 子表超过50分页查询数量
+     */
+    public static final Integer PAGE_SIZE_DETAILS = 50;
+
+
     /**
      * 接口访问账号 [不能触发待办与消息通知, 业务规则亦不能]
      * -
@@ -64,6 +71,7 @@ public class YDConf {
         retrieve_changed,    // 变更记录
         retrieve_definition, // 表单定义
 
+        retrieve_forms, // 表单列表
     }
 
     /**
@@ -71,8 +79,9 @@ public class YDConf {
      */
     public enum FORM_OPERATION {
         create,
-        delete,             // 传入为body, 文档为param
+        delete,                     // 传入为body, 文档为param
         update,
+        upsert,                     // fixme: 不支持新增字段更新, 若有可先更新版本后执行 [无版本和更新json参数]
         multi_create,               // 批量操作
         delete_batch,               // 批量删除
         multi_update,               // 批量更新

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

@@ -31,6 +31,7 @@ public class VenR extends BaseDto {
     public static final String RC_FXK = "com.malk.server.fxiaoke.FXKR ";
     public static final String RC_XBB = "com.malk.server.xbongbong.XBBR";
     public static final String RC_VK = "com.malk.server.vika.VKR";
+    public static final String RC_TB = "com.malk.server.teambition.TBR";
 
     /**
      * 通用post请求

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

@@ -62,6 +62,9 @@ public class YDClientImpl implements YDClient {
             case update:
                 ddr_new = (DDR_New) UtilHttp.doPut(getRequestUrl("/forms/instances"), ddClient.initTokenHeader(), bodys, DDR_New.class);
                 break;
+            case upsert:
+                ddr_new = (DDR_New) UtilHttp.doPost(this.getRequestUrl("/forms/instances/insertOrUpdate"), this.ddClient.initTokenHeader(), bodys, DDR_New.class);
+
             case delete:
                 ddr_new = (DDR_New) UtilHttp.doDelete(getRequestUrl("/forms/instances"), ddClient.initTokenHeader(), bodys, DDR_New.class);
                 break;
@@ -124,6 +127,9 @@ public class YDClientImpl implements YDClient {
             case retrieve_changed:
                 ddr_new = DDR_New.doPost(getRequestUrl("/forms/operationsLogs/query"), ddClient.initTokenHeader(), null, param);
                 break;
+            case retrieve_forms:
+                ddr_new = DDR_New.doGet(getRequestUrl("/forms"), ddClient.initTokenHeader(), param);
+                break;
         }
         return ddr_new;
     }

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

@@ -74,7 +74,7 @@ public class YDServiceImpl implements YDService {
 
     // 递归查询 todo 如果查询中, totalCount 发生变化, 就会进入死循环
     private List<Map> _queryDetails(YDParam ydParam, List<Map> details) {
-        ydParam.setPageSize(50);
+        ydParam.setPageSize(YDConf.PAGE_SIZE_DETAILS);
         DDR_New ddr_new = ydClient.queryData(ydParam, YDConf.FORM_QUERY.retrieve_details);
         details.addAll((List<Map>) ddr_new.getData());
         if (ddr_new.getTotalCount() != details.size()) {

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

@@ -248,6 +248,11 @@ public class DDImplClient_Contacts implements DDClient_Contacts {
         return (Map) DDR.doPost("https://oapi.dingtalk.com/topapi/v2/user/create", null, param, body).getResult();
     }
 
+    /**
+     * 更新钉钉自建企业账号
+     *
+     * @apiNote https://open.dingtalk.com/document/orgapp/update-dedicated-accounts-information
+     */
     @Override
     public Map updateUser_dingTalk(String access_token, String userId, List<Long> dept_id_list, Map body_ext) {
         Map param = UtilMap.map("access_token", access_token);

+ 11 - 2
mjava/src/main/java/com/malk/service/teambition/TBClient.java

@@ -74,6 +74,15 @@ public interface TBClient {
      */
     Map projectUpdate(String projectId, Map<String, String> data, String operatorId);
 
+
+    /**
+     * 查看项目的项目分组 [ fixme 更新项目分组, 不会保留原分组, 若兼容需要先查询 ]
+     *
+     * @apiNote https://open.teambition.com/docs/apis/6321c6d0912d20d3b5a49a2e
+     */
+    List<String> queryProjectTag(String projectId, String operatorId);
+
+
     /**
      * 更新项目的项目分组 [ ppExt: 若修改分组相同, 不返回204, 会报错400, 已兼容 ]
      *
@@ -284,14 +293,14 @@ public interface TBClient {
      *
      * @apiNote https://open.teambition.com/docs/apis/66693d96912d20d3b5ee560b
      */
-    Map createProgramMember(String programId , String operatorId, List<String> users);
+    Map createProgramMember(String programId, String operatorId, List<String> users);
 
     /**
      * 查询项目集内成员
      *
      * @apiNote https://open.teambition.com/docs/apis/66693d96912d20d3b5ee5737
      */
-    List<Map> queryProgramMember(String programId , String operatorId, Map body);
+    List<Map> queryProgramMember(String programId, String operatorId, Map body);
 
     /**
      * 查询全部数据 [函数回调]

+ 7 - 1
mjava/src/main/java/com/malk/service/teambition/impl/TBClientImpl.java

@@ -121,6 +121,12 @@ public class TBClientImpl implements TBClient {
         return (List<Map>) tbr.getResult();
     }
 
+    @Override
+    public List<String> queryProjectTag(String projectId, String operatorId) {
+        TBR tbr = (TBR) UtilHttp.doGet(tbConf.getApiHost() + "/v3/project/" + projectId + "/project-tag", initHeaderToken(operatorId), null, TBR.class);
+        return (List<String>) tbr.getResult();
+    }
+
     @Override
     public Map projectUpdate(String projectId, Map<String, String> data, String operatorId) {
         TBR tbr = (TBR) UtilHttp.doPut(tbConf.getApiHost() + "/v3/project/" + projectId, initHeaderToken(operatorId), data, TBR.class);
@@ -389,7 +395,7 @@ public class TBClientImpl implements TBClient {
 
     @Override
     public Map createProgramMember(String programId, String operatorId, List<String> users) {
-        Map body=UtilMap.map("userIds",users);
+        Map body = UtilMap.map("userIds", users);
         TBR tbr = (TBR) UtilHttp.doPost(tbConf.getApiHost() + "/v3/program/" + programId + "/member/create", initHeaderToken(operatorId), body, TBR.class);
         return (Map) tbr.getResult();
     }

+ 15 - 0
mjava/src/main/java/com/malk/test/TmpController.java

@@ -0,0 +1,15 @@
+package com.malk.test;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.annotation.Profile;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@Slf4j
+@Profile({"dev", "test"})
+@RestController
+@RequestMapping("/tmp")
+public class TmpController {
+    
+
+}

+ 14 - 0
mjava/src/main/java/com/malk/utils/UtilExcel.java

@@ -244,4 +244,18 @@ public class UtilExcel {
         workBook.finish();
     }
 
+    /**
+     * 列表与主表进行填充 [格式: 模板主表 {字段}, 列表 {.字段}]
+     */
+    @SneakyThrows
+    public static void exportMapAndListByTemplate(HttpServletResponse response, List dataList, Class dtoClass, @Nullable String fileName, String templateName) {
+        InputStream inputStream = UtilFile.readPackageResource("templates/" + templateName);
+        UtilExcel.setResponseHeader(response, fileName, ".xlsx");
+        ExcelWriter workBook = EasyExcel.write(response.getOutputStream(), dtoClass).withTemplate(inputStream).build();
+        WriteSheet sheet = EasyExcel.writerSheet().build();
+        // 先单组数据填充,再多组数据填充
+        workBook.fill(dataList, sheet);
+        workBook.finish();
+    }
+
 }

+ 11 - 0
mjava/src/main/java/com/malk/utils/UtilList.java

@@ -85,4 +85,15 @@ public abstract class UtilList {
             return data;
         }).collect(Collectors.toList());
     }
+
+    /// 判定集合是否包含另一个集合任一元素
+    public static boolean isContainsOne(List<String> oneList, List<String> otherList) {
+        for (String one : otherList) {
+            boolean contains = oneList.contains(one);
+            if (contains) {
+                return true;
+            }
+        }
+        return false;
+    }
 }

+ 1 - 0
pom.xml

@@ -31,6 +31,7 @@
         <module>mjava-dongfangxinhua</module>
         <module>mjava-aiwei</module>
         <module>mjava-lemeng</module>
+        <module>mjava-ruisi</module>
     </modules>
     <packaging>pom</packaging>