wzy недель назад: 2
Родитель
Сommit
97e5083655

+ 21 - 0
mjava-zhongche/src/main/java/com/malk/zhongche/config/StartupRunner.java

@@ -0,0 +1,21 @@
+package com.malk.zhongche.config;
+
+import com.malk.zhongche.service.McProjectService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.ApplicationArguments;
+import org.springframework.boot.ApplicationRunner;
+import org.springframework.stereotype.Component;
+
+@Component
+public class StartupRunner implements ApplicationRunner {
+
+    @Autowired
+    private McProjectService mcProjectService;
+
+    @Override
+    public void run(ApplicationArguments args) throws Exception {
+        mcProjectService.init();
+//        System.out.println("项目启动完毕,可以根据启动参数执行相应操作!");
+//        args.getOptionNames().forEach(System.out::println); // 打印所有选项参数名
+    }
+}

+ 6 - 0
mjava-zhongche/src/main/java/com/malk/zhongche/controller/ZhongcheController.java

@@ -32,4 +32,10 @@ public class ZhongcheController {
     public McR updateParentTaskType(@RequestBody Map map){
         return zhongcheService.updateParentTaskType(map);
     }
+
+    //上传附件完成任务
+    @PostMapping("/finishTask")
+    public McR finishTask(@RequestBody Map map){
+        return zhongcheService.finishTask(map);
+    }
 }

+ 7 - 0
mjava-zhongche/src/main/java/com/malk/zhongche/service/McProjectService.java

@@ -0,0 +1,7 @@
+package com.malk.zhongche.service;
+
+public interface McProjectService {
+
+    void init();
+
+}

+ 1 - 0
mjava-zhongche/src/main/java/com/malk/zhongche/service/ZhongcheService.java

@@ -13,4 +13,5 @@ public interface ZhongcheService {
 
     void updateLastTaskSfc();
 
+    McR finishTask(Map map);
 }

+ 29 - 0
mjava-zhongche/src/main/java/com/malk/zhongche/service/impl/McProjectServiceImpl.java

@@ -0,0 +1,29 @@
+package com.malk.zhongche.service.impl;
+
+import com.malk.core.McProject;
+import com.malk.server.aliwork.YDConf;
+import com.malk.server.aliwork.YDParam;
+import com.malk.server.dingtalk.DDR_New;
+import com.malk.service.aliwork.YDClient;
+import com.malk.utils.PublicUtil;
+import com.malk.utils.UtilMap;
+import com.malk.zhongche.service.McProjectService;
+import lombok.extern.slf4j.Slf4j;
+import org.slf4j.MDC;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Slf4j
+@Service
+public class McProjectServiceImpl implements McProjectService {
+    @Override
+    public void init() {
+        MDC.put("MDC_KEY_PID","1001");
+        McProject.addYida("1001",new String[] {"APP_SL9V2KUH6GBEISLNXXTJ","HOE66T71Z9H2PLVHM6EU85Q7H2AJ2YV2GRKKMWL1"});//对接TB
+        McProject.addYida("1002",new String[] {"APP_F90E02RA0Y7DJ5KLZ1W9","0YE66JA1RXGTAAJC7TJP09R8QELM3QPG7YW7MY6"});//车辆档案管理
+    }
+}

+ 206 - 3
mjava-zhongche/src/main/java/com/malk/zhongche/service/impl/ZhongcheServiceImpl.java

@@ -1,5 +1,6 @@
 package com.malk.zhongche.service.impl;
 
+import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.auth0.jwt.JWT;
 import com.auth0.jwt.algorithms.Algorithm;
@@ -7,6 +8,7 @@ import com.malk.server.aliwork.YDConf;
 import com.malk.server.aliwork.YDParam;
 import com.malk.server.common.McR;
 import com.malk.server.teambition.TBConf;
+import com.malk.server.teambition.TBR;
 import com.malk.service.aliwork.YDClient;
 import com.malk.service.dingtalk.DDClient;
 import com.malk.service.dingtalk.DDClient_Contacts;
@@ -18,9 +20,17 @@ import com.malk.zhongche.service.ZhongcheService;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.logging.log4j.util.Strings;
+import org.slf4j.MDC;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 
+import java.io.*;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.text.SimpleDateFormat;
 import java.time.Instant;
 import java.time.ZoneId;
@@ -46,6 +56,9 @@ public class ZhongcheServiceImpl implements ZhongcheService {
     @Autowired
     private TBConf tbConf;
 
+    @Value("${file.path}")
+    private String filePath;
+
     @Override
     public McR getTaskInfo(String taskId,String projectId) {
         Map taskInfo = tbClient.queryTaskDetail(taskId,null,null).get(0);
@@ -126,6 +139,8 @@ public class ZhongcheServiceImpl implements ZhongcheService {
 
     @Override
     public McR updateTaskDelayInfo(Map map) {
+        MDC.put("MDC_KEY_PID","1001");
+
         String formInstId = UtilMap.getString(map, "formInstId");
 
         Map formData = ydClient.queryData(YDParam.builder()
@@ -199,7 +214,7 @@ public class ZhongcheServiceImpl implements ZhongcheService {
 
         Map map2 = tbClient.updateTaskCustomField(taskId, tbConf.getOperatorId(), body2);
 
-        log.info("map1:{}",JSONObject.toJSONString(map1));
+        log.info("map2:{}",JSONObject.toJSONString(map2));
 
         return McR.success();
     }
@@ -230,8 +245,8 @@ public class ZhongcheServiceImpl implements ZhongcheService {
                 String id = UtilMap.getString(resultMap, "id");
 
                 switch (name){
-                    case "任务企业":sfcId2 = id;break;
-                    case "末级任务(企业)":sfcId3 = id;break;
+                    case "任务企业":sfcId2 = id;break;
+                    case "末级任务企业":sfcId3 = id;break;
                     default:break;
                 }
             }
@@ -292,6 +307,192 @@ public class ZhongcheServiceImpl implements ZhongcheService {
         }
     }
 
+    @Override
+    public McR finishTask(Map map) {
+        MDC.put("MDC_KEY_PID","1002");
+
+        String formInstId = UtilMap.getString(map, "formInstId");
+
+        Map formData = ydClient.queryData(YDParam.builder()
+                .formInstanceId(formInstId)
+                .build(), YDConf.FORM_QUERY.retrieve_id).getFormData();
+
+        String taskId = UtilMap.getString(formData, "textField_mkkrgg8y");
+        String projectId = UtilMap.getString(formData, "textField_mkkrgg8u");
+
+        if (Objects.nonNull(formData.get("attachmentField_mpzbe3w8"))){
+            List<Map> addValues = new ArrayList<>();
+
+            List<Map> fileList = (List<Map>) JSONArray.parse(String.valueOf(formData.get("attachmentField_mpzbe3w8")));
+            for (Map fileMap : fileList) {
+                String ydDownloadUrl = fileMap.get("downloadUrl").toString();
+                String fileName = fileMap.get("name").toString();
+
+                try {
+                    //下载宜搭附件
+                    downloadYdFile(ydDownloadUrl, filePath + fileName);
+                    System.out.println("文件下载成功!");
+
+                    //TB文件创建文件上传凭证
+                    Path path = Paths.get(filePath + fileName);
+                    String mimeType = Files.probeContentType(path);
+                    System.out.println(mimeType); // application/pdf
+
+                    File file = new File(fileName);
+                    long fileSize = file.length();
+
+                    Map body = new HashMap();
+                    body.put("scope", "task:"+taskId+"/attachment");
+                    body.put("fileSize", fileSize);
+                    body.put("fileType", mimeType);
+                    body.put("fileName", fileName);
+                    body.put("category", "attachment");
+
+                    TBR tbr = (TBR) UtilHttp.doPost("https://open.teambition.com/api/v3/awos/upload-token", initHeaderToken(), null, body, TBR.class);
+                    Map result = (Map) tbr.getResult();
+                    String uploadUrl = UtilMap.getString(result, "uploadUrl");
+                    String token = UtilMap.getString(result, "token");
+
+                    //上传文件
+                    uploadFile(filePath + fileName, uploadUrl, mimeType);
+
+                    Map value = new HashMap();
+                    value.put("title",fileName);
+                    value.put("metaString",JSONObject.toJSONString(UtilMap.map("fileToken",token)));
+
+                    addValues.add(value);
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+
+            //更新tb任务附件
+            Map body = new HashMap();
+            body.put("customfieldId", "67e372b0142aea12588c2d22");
+            body.put("addValues",addValues);
+
+            Map map2 = tbClient.updateTaskCustomField(taskId, tbConf.getOperatorId(), body);
+            log.info("map2:{}",JSONObject.toJSONString(map2));
+
+            //查询任务所在工作流的任务状态列表
+            TBR tbr = (TBR) UtilHttp.doGet("https://open.teambition.com/api/v3/task/" + taskId + "/tfs", initHeaderToken(), null, TBR.class);
+
+            List<Map> tfsList = (List<Map>) tbr.getResult();
+
+            for (Map tfsMap : tfsList) {
+                String tfsName = UtilMap.getString(tfsMap, "name");
+
+                if ("已完成".equals(tfsName)){
+                    String tfsId = UtilMap.getString(tfsMap, "id");
+                    //完成tb任务
+                    tbClient.updateTaskFlowStatus(taskId, tbConf.getOperatorId(), tfsId,null);
+                }
+            }
+        }
+
+        return McR.success();
+    }
+
+    /**
+     * 上传文件(核心方法)
+     * @param filePath 本地文件路径(如"2.png")
+     * @param uploadUrl 接口地址(如Postman中的PUT URL)
+     * @param contentType 文件类型(如"image/png",可留空由服务端自动识别)
+     * @return 服务端响应内容
+     */
+    public static String uploadFile(String filePath, String uploadUrl, String contentType) throws IOException {
+        File file = new File(filePath);
+        if (!file.exists()) {
+            throw new FileNotFoundException("文件不存在:" + filePath);
+        }
+
+        // 1. 创建URL并打开连接
+        URL url = new URL(uploadUrl);
+        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+
+        try {
+            // 2. 配置请求属性(必须为PUT,允许写入请求体)
+            conn.setRequestMethod("PUT");
+            conn.setDoOutput(true);
+            conn.setDoInput(true);
+            conn.setConnectTimeout(30000); // 连接超时30秒
+            conn.setReadTimeout(30000);    // 读取超时30秒
+
+            // 3. 设置请求头(关键:Content-Type需与文件类型匹配)
+//            if (contentType != null && !contentType.isEmpty()) {
+//                conn.setRequestProperty("Content-Type", contentType);
+//            }
+            // 可选:添加其他头信息(如鉴权Token)
+            // conn.setRequestProperty("Authorization", "Bearer your_token");
+
+            // 4. 读取文件并写入请求体(分块读取,避免大文件内存溢出)
+            try (FileInputStream fis = new FileInputStream(file);
+                 OutputStream os = conn.getOutputStream()) {
+
+                byte[] buffer = new byte[4096]; // 4KB缓冲区
+                int bytesRead;
+                long totalBytes = 0;
+
+                while ((bytesRead = fis.read(buffer)) != -1) {
+                    os.write(buffer, 0, bytesRead);
+                    totalBytes += bytesRead;
+                    // 可选:打印上传进度(每1MB打印一次)
+                    if (totalBytes % (1024 * 1024) == 0) {
+                        System.out.println("已上传:" + (totalBytes / (1024 * 1024)) + " MB");
+                    }
+                }
+            }
+
+            // 5. 获取响应码并读取响应内容
+            int responseCode = conn.getResponseCode();
+            System.out.println("响应码:" + responseCode);
+
+            // 读取响应内容(服务端返回的数据)
+            try (BufferedReader in = new BufferedReader(
+                    new InputStreamReader(conn.getInputStream()))) {
+                StringBuilder response = new StringBuilder();
+                String line;
+                while ((line = in.readLine()) != null) {
+                    response.append(line);
+                }
+                return response.toString();
+            }
+
+        } finally {
+            // 6. 断开连接(确保资源释放)
+            conn.disconnect();
+        }
+    }
+
+    //下载宜搭附件
+    private void downloadYdFile(String fileURL, String savePath) throws IOException {
+        //若是宜搭附件url 则需获得附件临时免登地址
+        fileURL = ydClient.convertTemporaryUrl(fileURL);
+
+        URL url = new URL(fileURL);
+        HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
+        int responseCode = httpConn.getResponseCode();
+
+        // 检查HTTP响应代码是否为200
+        if (responseCode == HttpURLConnection.HTTP_OK) {
+            InputStream inputStream = httpConn.getInputStream();
+            FileOutputStream outputStream = new FileOutputStream(savePath);
+
+            byte[] buffer = new byte[4096];
+            int bytesRead = -1;
+
+            while ((bytesRead = inputStream.read(buffer)) != -1) {
+                outputStream.write(buffer, 0, bytesRead);
+            }
+
+            outputStream.close();
+            inputStream.close();
+        } else {
+            System.out.println("无法下载文件。HTTP响应代码: " + responseCode);
+        }
+        httpConn.disconnect();
+    }
+
     private Map getRootTask(String taskId) {
         Map taskInfo = tbClient.queryTaskDetail(taskId, null, null).get(0);
 
@@ -353,6 +554,8 @@ public class ZhongcheServiceImpl implements ZhongcheService {
         header.put("Authorization", getAccessToken());
         header.put("X-Tenant-Id", tbConf.getTenantId());
         header.put("X-Tenant-Type", "organization");
+        header.put("X-Operator-Id", tbConf.getOperatorId());
+
         return header;
     }
 

+ 3 - 0
mjava-zhongche/src/main/resources/application-dev.yml

@@ -30,3 +30,6 @@ teambition:
   AppSecret: X77qcnv2AICiv70R41YZxGVFXRrFGCta
   OperatorId: 67ce737aaec2f7379c7bbf6f
   TenantId: 658a6467d87ead477d2d3f9d
+
+file:
+  path: d:\\

+ 3 - 0
mjava-zhongche/src/main/resources/application-prod.yml

@@ -30,3 +30,6 @@ teambition:
   AppSecret: X77qcnv2AICiv70R41YZxGVFXRrFGCta
   OperatorId: 67ce737aaec2f7379c7bbf6f
   TenantId: 658a6467d87ead477d2d3f9d
+
+file:
+  path: /home/server/zhongche/files/

+ 1 - 1
mjava-zhongche/src/main/resources/application.yml

@@ -1,6 +1,6 @@
 spring:
   profiles:
-    active: dev
+    active: prod
   servlet:
     multipart:
       max-file-size: 100MB