Pārlūkot izejas kodu

业务招待制度、业务招待清单、业务招待申请单推送国资委

dingsixi 2 nedēļas atpakaļ
vecāks
revīzija
2fab98e3a3

+ 122 - 39
base/nckd-base-common/src/main/java/nckd/base/common/utils/GzwCommonUtils.java

@@ -2,11 +2,17 @@ package nckd.base.common.utils;
 
 import com.alibaba.fastjson.JSONObject;
 import kd.bos.bos.servicehelper.ServiceFactory;
+import kd.bos.cache.CacheFactory;
+import kd.bos.cache.TempFileCache;
 import kd.bos.dataentity.entity.DynamicObject;
 import kd.bos.exception.KDBizException;
 import kd.bos.fileservice.FileService;
 import kd.bos.fileservice.FileServiceFactory;
+import kd.bos.fileservice.extension.FileServiceExtFactory;
+import kd.bos.form.IFormView;
+import kd.bos.mvc.SessionManager;
 import kd.bos.servicehelper.workflow.WorkflowServiceHelper;
+import kd.bos.url.UrlService;
 import kd.bos.workflow.component.approvalrecord.IApprovalRecordGroup;
 import kd.bos.workflow.component.approvalrecord.IApprovalRecordItem;
 import kd.bos.workflow.engine.TaskService;
@@ -20,7 +26,9 @@ import org.apache.commons.lang3.ObjectUtils;
 import org.apache.commons.lang3.StringUtils;
 
 import java.io.*;
+import java.lang.reflect.Field;
 import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.util.*;
@@ -32,6 +40,28 @@ import java.util.*;
  */
 public class GzwCommonUtils {
 
+    /**
+     * @param sysCtrlParameter 系统参数
+     * @param zipFile          zip文件
+     * @return API响应参数
+     */
+    public static Map<String, Object> pushGzwApi(Map<String, Object> sysCtrlParameter, File zipFile) {
+        //环境地址
+        String address = (String) sysCtrlParameter.get("nckd_gzw_address");
+        //请求路径
+        String path = (String) sysCtrlParameter.get("nckd_gzw_path");
+        String url = address + path;
+        //接口代号
+        String apiCode = (String) sysCtrlParameter.get("nckd_apicode");
+        //版本
+        String ver = (String) sysCtrlParameter.get("nckd_ver");
+        //客户端标识
+        String user = (String) sysCtrlParameter.get("nckd_user");
+        //客户端密码
+        String password = (String) sysCtrlParameter.get("nckd_password");
+        return HttpUtils.uploadFile(url, zipFile, apiCode, user, password, ver, zipFile.getName());
+    }
+
     /**
      * File文件夹相对路径
      */
@@ -107,22 +137,21 @@ public class GzwCommonUtils {
     }
 
     /**
-     *
      * 将单据审批记录转换成XML参数
      *
-     * @param bill 单据
-     * @param auditResMap 业务审批记录资源代号信息
-     * @param dataFlag 数据标识
-     * @param org 单据组织
+     * @param bill         单据
+     * @param auditResMap  业务审批记录资源代号信息
+     * @param dataFlag     数据标识
+     * @param org          单据组织
      * @param auditResCode 业务审批记录资源代号
-     * @param xmlMap 单据XML参数
+     * @param xmlMap       单据XML参数
      */
     public static void getBillApprovalRecordsData(DynamicObject bill, Map<String, String> auditResMap, String dataFlag,
                                                   DynamicObject org, String auditResCode, Map<String, Object> xmlMap) {
 
         //获取单据审批记录
         List<IApprovalRecordGroup> approvalRecords = WorkflowServiceHelper.getApprovalRecords(bill.getDynamicObjectType().getName(), bill.getPkValue().toString(), false);
-        if(ObjectUtils.isEmpty(approvalRecords)){
+        if (ObjectUtils.isEmpty(approvalRecords)) {
             return;
         }
 
@@ -139,13 +168,13 @@ public class GzwCommonUtils {
             Map<String, Object> map = approvalRecordForFormat.get(i);
 
             LinkedHashMap<String, Object> data = new LinkedHashMap<>();
-            data.put("uuid",map.get("activityid"));
-            data.put("biz_uuid",bill.getString(BaseFieldConst.ID));
-            data.put("node_name",map.get("activityname"));
-            data.put("handler",map.get("assignee"));
-            data.put("handle_status",map.get("result"));
-            data.put("handle_time",map.get("formatstrtime"));
-            data.put("handle_opinion",map.get("message"));
+            data.put("uuid", map.get("activityid"));
+            data.put("biz_uuid", bill.getString(BaseFieldConst.ID));
+            data.put("node_name", map.get("activityname"));
+            data.put("handler", map.get("assignee"));
+            data.put("handle_status", map.get("result"));
+            data.put("handle_time", map.get("formatstrtime"));
+            data.put("handle_opinion", map.get("message"));
             data.putAll(fixedData);
             existingAttachData.add(data);
         }
@@ -168,7 +197,8 @@ public class GzwCommonUtils {
      */
     public static void getBillAttrDataAndFile(Map<String, List<Map<String, Object>>> billAttrMap, DynamicObject bill,
                                               Map<String, String> attrResMap, String dataFlag, DynamicObject org,
-                                              List<File> allAttachFiles, String attrResCode, Map<String, Object> xmlMap) {
+                                              List<File> allAttachFiles, String attrResCode, Map<String, Object> xmlMap,
+                                              String attachmentServer) {
         // 获取当前单据附件信息
         List<Map<String, Object>> billAttachments = billAttrMap.getOrDefault(
                 bill.getString("id"),
@@ -184,7 +214,7 @@ public class GzwCommonUtils {
 
         //将单据附件信息转成动态参数及File文件
         GzwCommonUtils.getBillAttrDataAndFile(billAttachments, allAttachFiles, existingAttachData,
-                GzwCommonUtils.getFixedData(attrResMap, org, dataFlag));
+                GzwCommonUtils.getFixedData(attrResMap, org, dataFlag), attachmentServer);
 
         //更新附件XML参数
         xmlMap.put(attrResCode, existingAttachData);
@@ -200,7 +230,7 @@ public class GzwCommonUtils {
     public static void getBillAttrDataAndFile(List<Map<String, Object>> attachments,
                                               List<File> billAttrFileList,
                                               List<LinkedHashMap<String, Object>> attrDataList,
-                                              Map<String, Object> fixedData) {
+                                              Map<String, Object> fixedData, String attachmentServer) {
         if (attachments.isEmpty()) {
             return;
         }
@@ -211,11 +241,11 @@ public class GzwCommonUtils {
             //将单据附件转为File对象
             File file = generateBillAttrToFile(fileMap, attachmentFileService);
             //重新设置附件信息名称 文件名称添加MD5前缀
-//            fileMap.put("name",file.getName());
+            fileMap.put("name",file.getName());
             billAttrFileList.add(file);
 
             //附件动态参数
-            LinkedHashMap<String, Object> attrMapData = createBillAttrData(fileMap);
+            LinkedHashMap<String, Object> attrMapData = createBillAttrData(fileMap, attachmentServer);
             attrMapData.putAll(fixedData);
             attrDataList.add(attrMapData);
 
@@ -226,12 +256,13 @@ public class GzwCommonUtils {
      * @param fileMap 单据附件信息
      * @return 创建单据附件信息动态参数
      */
-    public static LinkedHashMap<String, Object> createBillAttrData(Map<String, Object> fileMap) {
+    public static LinkedHashMap<String, Object> createBillAttrData(Map<String, Object> fileMap, String attachmentServer) {
         LinkedHashMap<String, Object> attrMap = new LinkedHashMap<>();
         attrMap.put("uuid", fileMap.get("uid"));
         attrMap.put("biz_uuid", fileMap.get("billPkId"));
         attrMap.put("file_name", fileMap.get("name"));
-        attrMap.put("file_path", fileMap.get("relativeUrl"));
+        //TODO mc参数未配置正确
+        attrMap.put("file_path", attachmentServer + fileMap.get("url").toString().split("path=")[1]);
         attrMap.put("file_type", fileMap.get("type"));
         attrMap.put("create_time", DateUtil.date2str((Date) fileMap.get("lastModified"), DateUtil.DATE_TIME_FORMAT_YYYY_MM_DD_HH_MI_SS));
 
@@ -245,17 +276,14 @@ public class GzwCommonUtils {
      */
     public static File generateBillAttrToFile(Map<String, Object> fileMap, FileService attachmentFileService) {
         String fileName = (String) fileMap.get("name");
-        // 获取对路径
+        // 获取对路径
         String relativeUrl = (String) fileMap.get("relativeUrl");
 
-        //MD5
-        String md5 = calculateMD5(relativeUrl);
-        ByteArrayOutputStream out = new ByteArrayOutputStream();
-        attachmentFileService.download(relativeUrl, out, null);
-        InputStream in = new ByteArrayInputStream(out.toByteArray());
+        //读取两次,单向流第二次读取都是空数据
+        String md5 = calculateMD5(attachmentFileService.getInputStream(relativeUrl));
         File file = null;
         try {
-            file = inputStreamToFile(in, FILEPATH + md5 + "_" + fileName);
+            file = inputStreamToFile(attachmentFileService.getInputStream(relativeUrl), FILEPATH + md5 + "_" + fileName);
         } catch (Exception e) {
             throw new KDBizException("附件上传异常" + e.getMessage());
         }
@@ -288,8 +316,10 @@ public class GzwCommonUtils {
      * @return 获取数据标识( 1  表示新增,2 表示修改,3  表示删除 ),默认为 1
      */
     public static String getDataFlag(String operationKey, DynamicObject obj) {
-        //删除 = 3 ,非删除从数据库取出来得数据则是修改=2,不是从数据库取出的则是新增 = 1
-        return operationKey.equals(OperationKeyConst.DELETE) ? "3" : obj.getDataEntityState().getFromDatabase() ? "2" : "1";
+        //删除 = 3 ,非删除从数据库取出来得数据则是修改=2,不是从数据库取出的则是新增 = 1 。 根据数据判断
+//        return operationKey.equals(OperationKeyConst.DELETE) ? "3" : obj.getDataEntityState().getFromDatabase() ? "2" : "1";
+        //删除 = 3,非删除是否推送国资委为false = 新增 ,true为修改。根据字段值判断
+        return operationKey.equals(OperationKeyConst.DELETE) ? "3" : obj.getBoolean("nckd_ispush") ? "2" : "1";
     }
 
     /**
@@ -423,24 +453,24 @@ public class GzwCommonUtils {
     }
 
     /**
-     * @param filePath 文件路径
+     * @param inputStream 文件路径
      * @return md5
      */
-    public static String calculateMD5(String filePath) {
-        try (InputStream fis = new FileInputStream(filePath)) {
-            //  获取 MD5 MessageDigest  实例
+    public static String calculateMD5(InputStream inputStream) {
+        try {
+            // 获取 MD5 MessageDigest 实例
             MessageDigest digest = MessageDigest.getInstance("MD5");
 
-            //  用于保存读取的字节数
+            // 用于保存读取的字节数
             byte[] byteArray = new byte[1024];
             int bytesCount;
 
-            //  读取文件内容,并更新摘要信息
-            while ((bytesCount = fis.read(byteArray)) != -1) {
+            // 读取流内容,并更新摘要信息
+            while ((bytesCount = inputStream.read(byteArray)) != -1) {
                 digest.update(byteArray, 0, bytesCount);
             }
 
-            //  获取文件的 MD5 值,返回的是字节数组,转换成 16 进制数表示byte[] bytes = digest.digest();
+            // 获取 MD5 值,返回的是字节数组,转换成 16 进制数表示
             byte[] bytes = digest.digest();
             StringBuilder sb = new StringBuilder();
             for (byte b : bytes) {
@@ -448,7 +478,7 @@ public class GzwCommonUtils {
             }
             return sb.toString().toUpperCase();
         } catch (NoSuchAlgorithmException | IOException e) {
-            throw new KDBizException("文件名称生成MD5失败:" + e);
+            throw new KDBizException("生成MD5失败:" + e);
         }
     }
 
@@ -544,4 +574,57 @@ public class GzwCommonUtils {
         return wfService.getTaskService();
     }
 
+    /**
+     * 后台操作插件获取表单IFormView下载File文件
+     *
+     * @param zipFile zip文件
+     */
+    public static void download(File zipFile) {
+        IFormView view = getView();
+        if (null == view) {
+            return;
+        }
+        //注册文件服务
+        TempFileCache cache = CacheFactory.getCommonCacheFactory().getTempFileCache();
+        try {
+            String tempUrl = cache.saveAsFullUrl(zipFile.getName(), Files.readAllBytes(zipFile.toPath()), 60 * 60 * 4);
+            view.download(tempUrl);
+        } catch (IOException ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+
+    /**
+     * @return 返回表单视图(可能为null)
+     */
+    public static IFormView getView() {
+        // 获取单据页面视图
+        SessionManager sm = SessionManager.getCurrent();
+        Field field = null;
+        try {
+            //获取私有参数
+            field = sm.getClass().getDeclaredField("ipageCache");
+        } catch (NoSuchFieldException ex) {
+            throw new RuntimeException(ex);
+        }
+        field.setAccessible(true);
+        Map<?, ?> sessions = null;
+        try {
+            //获取私有参数值
+            sessions = (Map<?, ?>) field.get(sm);
+        } catch (IllegalAccessException ex) {
+            throw new RuntimeException(ex);
+        }
+        //审批流程无法获取
+        if(ObjectUtils.isEmpty(sessions)){
+            return null;
+        }
+        //取第一个视图,随便取的,不知道是不是当前页面操作的视图,其他场景使用自己考虑,只用来操作插件下载文件
+        IFormView formView = sm.getView(sessions.keySet().iterator().next().toString());
+//        if (formView == null) {
+//            throw new KDException("获取视图失败");
+//        }
+        return formView;
+    }
+
 }

+ 96 - 0
base/nckd-base-common/src/main/java/nckd/base/common/utils/HttpUtils.java

@@ -15,6 +15,20 @@ import java.nio.charset.StandardCharsets;
 import java.security.SecureRandom;
 import java.security.cert.X509Certificate;
 import java.util.Map;
+import org.apache.http.HttpEntity;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.ContentType;
+import org.apache.http.entity.mime.MultipartEntityBuilder;
+import org.apache.http.entity.mime.content.FileBody;
+import org.apache.http.entity.mime.content.StringBody;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.util.EntityUtils;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.regex.Pattern;
 
 /**
  * @description:http请求完整工具类
@@ -23,6 +37,88 @@ import java.util.Map;
  */
 public class HttpUtils {
 
+    /**
+     *
+     * @param password
+     * @return 判断是否包含特殊字符 用户密码
+     */
+    public static boolean containsSpecialChars(String password) {
+        if (password == null) return false;
+        // 检查是否包含URL需要编码的字符
+        Pattern pattern = Pattern.compile("[+&=%#?]");
+        return pattern.matcher(password).find();
+    }
+
+    /**
+     *
+     * @param url 请求路径
+     * @param zipFile zip文件
+     * @param resCode 接口代号
+     * @param username 用户名
+     * @param password 用户名密码
+     * @param ver 版本号
+     * @param filename 文件名称
+     * @return 推送国资委数据采集平台
+     */
+    public static Map<String,Object> uploadFile(String url, File zipFile, String resCode,
+                             String username, String password,String ver,
+                             String filename)  {
+
+        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
+
+            // 构建基础URL(包含RESCODE, Ver, USER)
+            String baseUrl = String.format("%s?RESCODE=%s&Ver=%s&USER=%s",
+                    url,
+                    URLEncoder.encode(resCode, "UTF-8"),
+                    URLEncoder.encode(ver, "UTF-8"),
+                    URLEncoder.encode(username, "UTF-8"));
+
+            //判断是否包含特殊字符 用户密码
+            boolean passwordInBody = containsSpecialChars(password);
+            String finalUrl = baseUrl;
+
+            // 如果密码没有特殊字符,添加到URL中
+            if (!passwordInBody && password != null) {
+                finalUrl = baseUrl + "&PASSWORD=" + URLEncoder.encode(password, "UTF-8");
+            }
+
+            HttpPost httpPost = new HttpPost(finalUrl);
+
+            // 构建 multipart/form-data 请求体
+            MultipartEntityBuilder builder = MultipartEntityBuilder.create();
+
+            // 1. file参数 (Body, binary)
+            if (zipFile != null && zipFile.exists()) {
+                builder.addPart("file", new FileBody(zipFile,
+                        ContentType.APPLICATION_OCTET_STREAM,
+                        zipFile.getName()));
+            }
+
+            // 2. 如果密码有特殊字符,放入Body中
+            if (passwordInBody && password != null) {
+                builder.addPart("PASSWORD",
+                        new StringBody(password, ContentType.TEXT_PLAIN));
+            }
+
+            // 设置请求体
+            HttpEntity multipart = builder.build();
+            httpPost.setEntity(multipart);
+
+            // 3. 设置Headers中的filename
+            httpPost.setHeader("filename", filename);
+
+            try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
+                HttpEntity responseEntity = response.getEntity();
+                if (responseEntity != null) {
+                    return JSONObject.parseObject(EntityUtils.toString(responseEntity, "UTF-8"),Map.class);
+                }
+                return null;
+            }
+        } catch (Exception e) {
+            throw new KDBizException("上传文件失败:"+ e);
+        }
+    }
+
 
     /**
      * 发送POST请求(JSON格式)

+ 46 - 3
nckd-fi/src/main/java/nckd/fi/er/opplugin/GzwPushOpPlugin.java

@@ -1,18 +1,35 @@
 package nckd.fi.er.opplugin;
 
+import kd.bos.base.BaseShowParameter;
+import kd.bos.bill.BillShowParameter;
+import kd.bos.cache.CacheFactory;
+import kd.bos.cache.TempFileCache;
 import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.entity.MainEntityType;
 import kd.bos.entity.plugin.AbstractOperationServicePlugIn;
 import kd.bos.entity.plugin.PreparePropertysEventArgs;
 import kd.bos.entity.plugin.args.EndOperationTransactionArgs;
+import kd.bos.exception.KDBizException;
+import kd.bos.exception.KDException;
+import kd.bos.form.FormShowParameter;
+import kd.bos.form.IFormView;
+import kd.bos.mvc.FormConfigFactory;
+import kd.bos.mvc.SessionManager;
 import kd.bos.servicehelper.AttachmentServiceHelper;
+import kd.bos.servicehelper.MetadataServiceHelper;
 import kd.bos.servicehelper.workflow.WorkflowServiceHelper;
 import kd.bos.workflow.component.approvalrecord.IApprovalRecordGroup;
 import nckd.base.common.utils.GzwCommonUtils;
 import nckd.base.common.utils.GzwSyncBillUtils;
+import nckd.base.common.utils.HttpUtils;
 import nckd.base.common.utils.ParamUtils;
 import nckd.base.common.config.ResCodeConfig;
+import org.apache.commons.lang3.ObjectUtils;
 
 import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.nio.file.Files;
 import java.util.*;
 import java.util.stream.Collectors;
 
@@ -45,6 +62,11 @@ public abstract class GzwPushOpPlugin extends AbstractOperationServicePlugIn {
 
         // 获取费控系统参数
         Map<String, Object> sysCtrlParameter = ParamUtils.getSysCtrlParameter(ParamUtils.EM);
+        String pushState = (String) sysCtrlParameter.get("nckd_gzwpushstate");
+        //关闭推送
+        if (pushState.equals("GBTS")) {
+            return;
+        }
 
         // 获取接口代号和版本号
         String ver = (String) sysCtrlParameter.get("nckd_ver");
@@ -60,6 +82,9 @@ public abstract class GzwPushOpPlugin extends AbstractOperationServicePlugIn {
         Map<String, String> auditResMap = GzwCommonUtils.getResMap(GzwSyncBillUtils.BIZ_APPROVE_RECORD, (String) sysCtrlParameter.get("nckd_res"));
         //业务审批记录资源代号
         String auditResCode = auditResMap.get("nckd_rescode");
+        //文件服务器
+        String attachmentServer = (String) sysCtrlParameter.get("nckd_attachmentserver");
+
 
         // 获取所有单据附件
         Object[] ids = Arrays.stream(bills).map(it -> it.getString("id")).toArray();
@@ -106,10 +131,10 @@ public abstract class GzwPushOpPlugin extends AbstractOperationServicePlugIn {
                 }
 
                 //将单据附件信息转成XML参数及File文件
-                GzwCommonUtils.getBillAttrDataAndFile(billAttrMap, bill, attrResMap, dataFlag, org, allAttachFiles, attrResCode, xmlMap);
+                GzwCommonUtils.getBillAttrDataAndFile(billAttrMap, bill, attrResMap, dataFlag, org, allAttachFiles, attrResCode, xmlMap,attachmentServer);
 
                 //将单据审批记录转成XML参数
-                GzwCommonUtils.getBillApprovalRecordsData(bill,auditResMap,dataFlag,org,auditResCode,xmlMap);
+                GzwCommonUtils.getBillApprovalRecordsData(bill, auditResMap, dataFlag, org, auditResCode, xmlMap);
             }
 
             // 生成ZIP文件
@@ -117,10 +142,28 @@ public abstract class GzwPushOpPlugin extends AbstractOperationServicePlugIn {
             if (zipFile == null) {
                 return;
             }
-            // TODO 相同组织内的数据一起推送 推送并记录日志
+
+
+            if (pushState.equals("ZCTS")) {
+                //TODO 异步执行生成推送日志
+                // 推送国资委数据采集平台
+                Map<String, Object> respMap = GzwCommonUtils.pushGzwApi(sysCtrlParameter, zipFile);
+                String serviceFlag = (String)respMap.get("serviceFlag");
+                if(serviceFlag.equals("0")){
+                    throw new KDBizException("推送国资委接口失败:"+respMap.get("msg"));
+                }
+                //TODO 推送成功回写单据推送状态
+            } else if (pushState.equals("XZWJ")) {
+                //后台操作插件获取表单IFormView下载File文件
+                GzwCommonUtils.download(zipFile);
+            }
+
+            //删除zip文件
+            zipFile.delete();
         }
     }
 
+
     /**
      * 转换指定数据集的数据
      */