Browse Source

因钉钉审批详情返回数据结构修改, 更新接口方法, 重大改动

wuweihao 1 year ago
parent
commit
9c5042d3b2

+ 9 - 1
pom.xml

@@ -23,7 +23,7 @@
 
 	<properties>
 		<shiro.version>1.2.4</shiro.version>
-		<java.version>1.7</java.version>
+		<java.version>1.8</java.version>
 	</properties>
 
 	<!-- Add typical dependencies for a web application -->
@@ -181,6 +181,14 @@
 		    <artifactId>xmlworker</artifactId>
 		    <version>5.5.11</version>
 		</dependency>
+
+		<!-- 工具类 2024-03-06 by owen  -->
+		<dependency>
+			<groupId>cn.hutool</groupId>
+			<artifactId>hutool-all</artifactId>
+			<version>5.3.3</version>
+		</dependency>
+
 	</dependencies>
 
 	<build>

+ 3 - 17
src/main/java/com/fourdage/dingding/controller/ExaminationController.java

@@ -78,6 +78,7 @@ public class ExaminationController extends BaseController{
 	@RequestMapping(value = {"/list"}, method = RequestMethod.GET)
 	@ResponseBody
 	public Map<String, Object> list(String datetime, String applyDate, String processCodeId, String businessNum, String companyId){
+    	logger.info("run list");
 		
 		Map<String, Object> result = new HashMap<>();
 		try {
@@ -122,16 +123,7 @@ public class ExaminationController extends BaseController{
 			}
 			
 			dingDingUtil.getProcesses(processes, vo);
-			/*List<ProcessInstance> instances = new ArrayList<>();
-			if (StringUtils.isNotEmpty(deptId) && !"1".equals(deptId) && processes != null && processes.size() > 0){
-				for (ProcessInstance processInstance : processes){
-					if (deptId.equals(processInstance.getOriginatorDeptId())){
-						instances.add(processInstance);
-					}
-				}
-			}else{
-				instances.addAll(processes);
-			}*/
+
 			result.put("code", 0);
 			result.put("msg", "");
 			result.put("count", processes.size());
@@ -169,17 +161,11 @@ public class ExaminationController extends BaseController{
     			dirFile.mkdir();
     		}
     		File file = new File(filePathName);
-//    		if (file.exists()){
-//    			return JsonResult.success(fileName + ".html");
-//    		}else{
-//    			//设置输出文件
-//    			file.createNewFile();
-//    		}
 
 			// 2023-09-19 覆盖旧文件
 			file.createNewFile();
     		
-    		htmlPdfUtil.generateHTMLFile(dingDingUtil.getAccessToken(), processInstanceId, fileName);
+    		htmlPdfUtil.generateHTMLFile_2(dingDingUtil.getAccessToken(), processInstanceId, fileName);
         	return JsonResult.success(fileName + ".html");
         } catch (Exception e) {
         	logger.error("系统异常:", e);

+ 18 - 0
src/main/java/com/fourdage/dingding/util/DingDingUtil.java

@@ -4,12 +4,18 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.http.HttpRequest;
+import cn.hutool.http.HttpResponse;
+import cn.hutool.http.HttpUtil;
 import org.apache.commons.lang.StringUtils;
 import org.apache.shiro.SecurityUtils;
 import org.apache.shiro.subject.Subject;
 import org.joda.time.DateTime;
 import org.joda.time.format.DateTimeFormat;
 import org.joda.time.format.DateTimeFormatter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.cache.ehcache.EhCacheCacheManager;
 import org.springframework.stereotype.Repository;
@@ -27,8 +33,11 @@ import com.fourdage.system.service.IDataDictionaryService;
 import net.sf.ehcache.Cache;
 import net.sf.ehcache.Element;
 
+
 @Repository
 public class DingDingUtil {
+
+	private Logger logger = LoggerFactory.getLogger(getClass());
 	
 	@Autowired
 	private IDataDictionaryService dataDictionaryService;
@@ -100,6 +109,7 @@ public class DingDingUtil {
     }
 	
 	public List<ProcessInstance> getProcesses(List<ProcessInstance> processes, DingDingSearchBean searchBean){
+		logger.info("run getProcesses");
     	
     	DateTimeFormatter format = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
     	
@@ -237,4 +247,12 @@ public class DingDingUtil {
 		System.out.println(util.getAccessToken());
 	}
 
+	public void getWorkflowInfo(String accessToken, String processInstanceId){
+		String api = StrUtil.format("https://api.dingtalk.com/v1.0/workflow/processInstances?processInstanceId={}", processInstanceId);
+		HttpResponse response = HttpUtil.createGet(api).header("x-acs-dingtalk-access-token", accessToken).execute();
+		logger.info("钉钉返回值:{}", response.body());
+
+
+	}
+
 }

+ 377 - 16
src/main/java/com/fourdage/dingding/util/HtmlPdfUtil.java

@@ -11,13 +11,24 @@ import java.io.InputStreamReader;
 import java.io.OutputStreamWriter;
 import java.math.BigDecimal;
 import java.nio.charset.Charset;
+import java.time.OffsetDateTime;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+import java.util.Arrays;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.http.HttpRequest;
+import cn.hutool.http.HttpResponse;
+import cn.hutool.http.HttpUtil;
 import org.apache.commons.lang.StringUtils;
 import org.apache.shiro.SecurityUtils;
 import org.apache.shiro.subject.Subject;
 import org.joda.time.DateTime;
+import org.joda.time.LocalDateTime;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -60,7 +71,7 @@ public class HtmlPdfUtil {
 	
 	private String blankCode = "            &nbsp;&nbsp;";
 	
-	public void generateHTMLFile(String accessToken, String processInstanceId, String fileName) {
+	public void generateHTMLFile_1(String accessToken, String processInstanceId, String fileName) {
 		logger.info("run generateHTMLFile");
 //		FileWriter out = null;
 		OutputStreamWriter out = null;
@@ -68,12 +79,31 @@ public class HtmlPdfUtil {
 			String title = "";
 			String businessId = "";
 			logger.info("请求参数,processInstanceId:{}, accessToken:{}", processInstanceId, accessToken);
+//			dingdingUtil.getWorkflowInfo(accessToken, processInstanceId);
+
+//				String body = HttpUtil.
+//					createGet(StrUtil.format("http://127.0.0.1:8001//api/dingTalk/getWorkflowInfo/{}", processInstanceId))
+//					.execute().body();
+//				logger.info("服务返回值:{}", body);
+//
+//			JSONObject parseJson = JSONObject.parseObject(body);
+//
+//			Integer code = parseJson.getInteger("code");
+//			if (code != 0){
+//				logger.error("服务返回异常");
+//				return;
+//			}
+//
+//			JSONObject jsonResult = parseJson.getJSONObject("data");
+
+
 			JSONObject jsonResult = dingdingUtil.getDingDingJSONResult(processInstanceId, accessToken);
 			logger.info("钉钉返回数据: {}", jsonResult);
 			if (jsonResult.getBoolean("success")){
-				DataDictionary corp = dataDictionaryService.findByCodeAndDataKey("corp_code", dingdingUtil.getRegion());
-				
+//				DataDictionary corp = dataDictionaryService.findByCodeAndDataKey("corp_code", dingdingUtil.getRegion());
+
 				JSONObject result = jsonResult.getJSONObject("process_instance");
+				logger.info("result:{}", result);
 				//企业名称
 //				String corpName = corp.getDataValue();
 				String corpName = "四维时代 & 中德人工智能研究院";
@@ -94,7 +124,7 @@ public class HtmlPdfUtil {
 				title = titlesArr[1];
 				//申请人部门
 				String org = result.getString("originator_dept_name");
-				
+
 				PdfVO vo = new PdfVO();
 				vo.setCorpName(corpName);
 				vo.setApplyDate(applyDate);
@@ -103,10 +133,11 @@ public class HtmlPdfUtil {
 				vo.setTitle(title);
 				vo.setOrg(org);
 				vo.setStatus(dingdingUtil.getStatus(result.getString("status")));
-				vo.setForm(generateForm(result).toString());
-				vo.setOperations(generateOperators(accessToken, result).toString());
+				// 内容 html
+				vo.setForm(generateForm_1(result).toString());
+				vo.setOperations(generateOperators_1(accessToken, result).toString());
 				vo.setPrintDate(new DateTime().toString("yyyy-MM-dd HH:mm"));
-				
+
 				Subject subject = SecurityUtils.getSubject();
 	            Object principal = subject.getPrincipal();
 	            String userName = "";
@@ -114,11 +145,11 @@ public class HtmlPdfUtil {
 	            	userName = ((User) principal).getNickName();
 	            }
 	            vo.setPrinter(userName);
-				
+
 				Configuration configuration = new Configuration();
 				configuration.setDirectoryForTemplateLoading(new File(path));
 				configuration.setDefaultEncoding("UTF-8");
-				// 获取或创建一个模版。  
+				// 获取或创建一个模版。
 				Template template = configuration.getTemplate("pdf.ftl");
 				//设置输出流
 				File file = new File(path + fileName + ".html");
@@ -140,7 +171,128 @@ public class HtmlPdfUtil {
             }
     	}
 	}
-	
+
+
+	/**
+	 * 报销申请返回的数据结构变了, 使用新接口
+	 * @param accessToken
+	 * @param processInstanceId
+	 * @param fileName
+	 */
+	public void generateHTMLFile_2(String accessToken, String processInstanceId, String fileName) {
+		logger.info("run generateHTMLFile_2");
+		OutputStreamWriter out = null;
+		try {
+			String title = "";
+			String businessId = "";
+			logger.info("请求参数,processInstanceId:{}, accessToken:{}, fileName:{}", processInstanceId, accessToken, fileName);
+
+			// 2024-03-07 by owen, 旧接口的报销申请返回的数据结构变了,使用了钉钉工时提醒应用的appkey 对应的接口
+			String body = HttpUtil.
+					createGet(StrUtil.format("http://project.4dage.com:8003/api/dingTalk/getWorkflowInfo/{}", processInstanceId))
+					.execute().body();
+			logger.info("服务返回值:{}", body);
+
+			JSONObject parseJson = JSONObject.parseObject(body);
+
+			Integer code = parseJson.getInteger("code");
+			if (code != 0){
+				logger.error("服务返回异常");
+				return;
+			}
+
+			JSONObject jsonResult = parseJson.getJSONObject("data");
+
+
+			logger.info("钉钉返回数据: {}", jsonResult);
+			if (jsonResult.getBoolean("success")){
+
+				JSONObject result = jsonResult.getJSONObject("result");
+				logger.info("result:{}", result);
+				//企业名称
+				String corpName = "四维时代 & 中德人工智能研究院";
+				//申请日期
+				String applyDate = result.getString("createTime");
+				applyDate = convertTime(applyDate);
+
+				//审批编码
+				businessId = result.getString("businessId");
+				String[] titlesArr = null;
+				String titleStr = result.getString("title");
+				if(titleStr.contains("的")){
+					titlesArr = titleStr.split("的");
+				}
+				if(titleStr.contains("'s")){
+					titlesArr = titleStr.split("'s");
+				}
+				String applyUserName = titlesArr[0];
+				//申请人
+				//模板名称
+				title = titlesArr[1];
+				//申请人部门
+				String org = result.getString("originatorDeptName");
+
+				PdfVO vo = new PdfVO();
+				vo.setCorpName(corpName);
+				vo.setApplyDate(applyDate);
+				vo.setBusinessId(businessId);
+				vo.setApplyUserName(applyUserName);
+				vo.setTitle(title);
+				vo.setOrg(org);
+				vo.setStatus(dingdingUtil.getStatus(result.getString("status")));
+				// 处理报销明细等
+				vo.setForm(generateForm_2(result, title).toString());
+				// 处理审批人详情
+				vo.setOperations(generateOperators_2(accessToken, result).toString());
+				vo.setPrintDate(new DateTime().toString("yyyy-MM-dd HH:mm"));
+
+				Subject subject = SecurityUtils.getSubject();
+				Object principal = subject.getPrincipal();
+				String userName = "";
+				if (principal != null) {
+					userName = ((User) principal).getNickName();
+				}
+				vo.setPrinter(userName);
+
+				Configuration configuration = new Configuration();
+				configuration.setDirectoryForTemplateLoading(new File(path));
+				configuration.setDefaultEncoding("UTF-8");
+				// 获取或创建一个模版。
+				Template template = configuration.getTemplate("pdf.ftl");
+				//设置输出流
+				File file = new File(path + fileName + ".html");
+//				out = new FileWriter(file);
+				//设置文件输入流编码,不然生成的html文件会中文乱码
+				out = new OutputStreamWriter(new FileOutputStream(file),"UTF-8");
+				//模板输出静态文件
+				template.process(vo, out);
+			}
+		}catch (Exception e) {
+			logger.error("系统异常:", e);
+		} finally {
+			if(null != out) {
+				try {
+					out.close();
+				} catch (IOException e) {
+					e.printStackTrace();
+				}
+			}
+		}
+	}
+
+	private String convertTime(String time){
+		// 使用ISO_INSTANT日期时间格式化器解析ISO 8601格式的字符串
+		OffsetDateTime offsetDateTime = OffsetDateTime.parse(time);
+
+		// 创建自定义的日期时间格式化器,并指定时区为UTC
+		DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(ZoneId.of("UTC"));
+
+		// 使用格式化器格式化OffsetDateTime
+		String formattedDateTime = offsetDateTime.format(formatter);
+
+		return formattedDateTime;
+	}
+
 	public String generateHtmlAndPDF(String accessToken, String processInstanceId, String processCodeName) {
 		logger.info("run generateHtmlAndPDF");
     	String fileName = "";	
@@ -161,7 +313,7 @@ public class HtmlPdfUtil {
     		fileName = result.getString("title") + result.getString("business_id");
     		String filePathName = path + processCodeName + "/" + fileName;
     		//生成HTML文件
-    		generateHTMLFile(accessToken, processInstanceId, processCodeName + "/" + fileName);
+    		generateHTMLFile_2(accessToken, processInstanceId, processCodeName + "/" + fileName);
     		//生成pdf文件
     		generatePdfFile(filePathName);
     		
@@ -250,7 +402,7 @@ public class HtmlPdfUtil {
     	}
 	}
 	
-	private StringBuffer generateOperators(String accessToken, JSONObject result) {
+	private StringBuffer generateOperators_1(String accessToken, JSONObject result) {
 		JSONArray userArray = result.getJSONObject("operation_records").getJSONArray("operation_records_vo");
 		StringBuffer userSB = null;
 		if (userArray != null && userArray.size() > 0){
@@ -290,9 +442,65 @@ public class HtmlPdfUtil {
 		}
 		return userSB;
 	}
+
+	/**
+	 * 2024-03-07 因钉钉返回数据结构变动,用此方法
+	 * 处理审批人详情
+	 * @param accessToken
+	 * @param result
+	 * @return
+	 */
+	private StringBuffer generateOperators_2(String accessToken, JSONObject result) {
+		JSONArray userArray = result.getJSONArray("operationRecords");
+		StringBuffer userSB = null;
+		if (userArray != null && userArray.size() > 0){
+			userSB = new StringBuffer("<tr><td rowspan=\"").append(userArray.size()-1).append("\">审批人</td>");
+			for (int i = 0; i < userArray.size(); i++){
+				JSONObject ob = (JSONObject) userArray.get(i);
+				String type = ob.getString("type");
+				if ("START_PROCESS_INSTANCE".equals(type)){
+					continue;
+				}
+				if (i == 1){
+					userSB.append("<td>");
+				}else{
+					userSB.append("<tr><td>");
+				}
+
+				//获取用户信息
+				Map<String, Object> tokenMap = new HashMap<String, Object>();
+				tokenMap.put("access_token", accessToken);
+				tokenMap.put("userid", ob.getString("userId"));
+				String userStr = HttpHelper.sendGetByHttpUrlConnection("https://oapi.dingtalk.com/user/get", tokenMap, "UTF-8");
+//				logger.info("userStr:{}", userStr);
+				JSONObject userObject = JSON.parseObject(userStr);
+				userSB.append(userObject.getString("name")).append(blankCode);
+
+				String remark = ob.getString("remark");
+				String resultStr = ob.getString("result");
+				//获取操作结果
+				if ("EXECUTE_TASK_NORMAL".equals(type)){
+					userSB.append(dingdingUtil.getTaskResult(resultStr));
+					if (StringUtils.isNotEmpty(remark)){
+						userSB.append("(").append(remark).append(")").append(blankCode);
+					}
+					userSB.append(blankCode);
+				}else if ("ADD_REMARK".equals(type)){
+					userSB.append("添加评论(").append(remark).append(")").append(blankCode);
+				}else {
+					userSB.append(dingdingUtil.getTaskResult(resultStr)).append(blankCode);
+				}
+				String date = ob.getString("date");
+				date = convertTime(date);
+
+				userSB.append(date == null ? "" : date).append("</td></tr>");
+			}
+		}
+		return userSB;
+	}
 	
-	private StringBuffer generateForm(JSONObject result) {
-		logger.info("run generateForm");
+	private StringBuffer generateForm_1(JSONObject result) {
+		logger.info("run generateForm_1");
 		logger.info("输入参数:{}", result);
 
 		JSONArray formArray = result.getJSONObject("form_component_values").getJSONArray("form_component_value_vo");
@@ -413,6 +621,159 @@ public class HtmlPdfUtil {
 		return formSB;
 	}
 
+
+	/**
+	 * 2024-03-07 因钉钉返回数据结构变动,用此方法
+	 * 处理单位, 报销明细,原借款(元),合计报销金额(元)
+	 * @param result
+	 * @return
+	 */
+	private StringBuffer generateForm_2(JSONObject result, String title) {
+		logger.info("run generateForm_2");
+//		logger.info("输入参数:{}", result);
+
+		// 报销详情
+		JSONArray formArray = result.getJSONArray("formComponentValues");
+		logger.info("formArray:{}", formArray);
+
+
+		// 2023-09-18 获取付款金额
+		JSONObject hasPay = getHasPay(formArray);
+		if (hasPay.getBooleanValue("hasAdd")){
+			formArray.add(7, hasPay);
+		}
+
+		StringBuffer formSB = null;
+
+		List<String> constantType = Arrays.asList("单位", "报销明细","原借款(元)", "合计报销金额(元)");
+		if (formArray != null && formArray.size() > 0){
+			formSB = new StringBuffer();
+			for (Object o : formArray){
+				JSONObject ob = (JSONObject) o;
+
+				// 图片、附件、说明的行不显示
+				String name = ob.getString("name");
+
+				// 过滤不显示类型
+				if ("报销申请".equals(title)){
+					if (!constantType.contains(name)){
+						continue;
+					}
+				}
+
+				if ("图片".equals(name)
+						|| "附件".equals(name)
+						|| "说明".equals(name)
+						|| "预计付款日期".equals(name)
+						|| "支出类别".equals(name)
+						|| "归属人".equals(name)
+						|| "发票".equals(name)
+//						|| "备注".equals(name)
+						|| "项目".equals(name)
+						|| "客户".equals(name)
+						|| "供应商".equals(name)
+						|| "企业账户".equals(name)
+						|| "null".equals(name)
+						|| null == name){
+					continue;
+				}
+
+
+
+				// 处理表单中表单名是否是json对象,如[开始时间、结束时间]
+				if (dingdingUtil.isJSONValid(name)){
+					JSONArray array = JSON.parseArray(name);
+					if (array != null){
+						formSB.append("<tr><td>");
+						for (int i = 0; i < array.size(); i++){
+							formSB.append(array.get(i)).append(i == array.size() - 1 ? "" : "/");
+						}
+						formSB.append("</td><td>");
+					}
+				}else{
+					formSB.append("<tr><td>").append(name).append("</td><td>");
+				}
+				//处理表单中表单名对应的表单值,空值不显示
+				String value = ob.getString("value");
+				if ("null".equals(value) || StrUtil.isBlank(value)){
+					formSB.append("");
+					//处理表单值是否是json对象
+				}else if (dingdingUtil.isJSONValid(value)){
+
+
+
+					JSONArray array = JSON.parseArray(value);
+					for (int i = 0; i < array.size(); i++){
+						if (array.get(i) instanceof String || array.get(i) instanceof Integer || array.get(i) instanceof BigDecimal){
+							formSB.append(array.get(i)).append(i == array.size() - 1 ? "" : blankCode);
+						}
+						else {
+							JSONObject objecte = (JSONObject)array.get(i);
+							JSONArray rowValue = objecte.getJSONArray("rowValue");
+							if (rowValue != null){
+								for (Object rowObj : rowValue){
+									JSONObject row = (JSONObject)rowObj;
+									formSB.append("<p>");
+									if (dingdingUtil.isJSONValid(row.getString("label"))){
+										JSONArray labelArray = JSON.parseArray(row.getString("label"));
+										if (labelArray != null){
+											for (int j = 0; j < labelArray.size(); j++){
+												formSB.append(labelArray.get(j)).append(j == labelArray.size() - 1 ? "" : "/");
+											}
+										}
+									}else if ("说明".equals(row.getString("label"))
+											|| "null".equals(row.getString("label"))
+											|| null == row.getString("label")){
+										formSB.append("</p>");
+										continue;
+									}else{
+										formSB.append(row.getString("label"));
+									}
+									formSB.append(":");
+									if (dingdingUtil.isJSONValid(row.getString("value"))){
+										JSONArray valueArray = JSON.parseArray(row.getString("value"));
+										if (valueArray != null){
+											for (int j = 0; j < valueArray.size(); j++){
+												formSB.append(valueArray.get(j)).append(j == valueArray.size() - 1 ? "" : "/");
+											}
+										}
+									}else{
+										formSB.append(row.getString("value")).append(blankCode);
+									}
+									formSB.append("</p>");
+								}
+							}
+						}
+						if (i != array.size() - 1){
+							formSB.append("<p>&nbsp;&nbsp;</p>");
+						}
+					}
+
+				}else{
+					formSB.append(value);
+				}
+				formSB.append("</td></tr>");
+			}
+		}
+		return formSB;
+	}
+
+
+	// 获取报销明细
+	private String formComponentValuesByTableField(JSONArray formArray){
+		for (Object o : formArray) {
+			JSONObject parseObject = JSONObject.parseObject(o.toString());
+			if (!"TableField".equals(parseObject.getString("componentType"))){
+				continue;
+			}
+
+			JSONArray value = parseObject.getJSONArray("value");
+
+		}
+
+		return null;
+	}
+
 	private JSONObject getHasPay(JSONArray formArray) {
 		String subValue = "0";
 		boolean hasAdd = false;
@@ -483,11 +844,11 @@ public class HtmlPdfUtil {
 			.append("<tr><td>申请人部门</td><td>").append(org).append("</td></tr>");
 			
 			//表单内容,循环生成表单内容
-			StringBuffer formSB = generateForm(result);
+			StringBuffer formSB = generateForm_1(result);
 			sb.append(formSB);
 			
 			//审批人
-			StringBuffer userSB = generateOperators(accessToken, result);
+			StringBuffer userSB = generateOperators_1(accessToken, result);
 			sb.append(userSB).append("</table>");
 			
 			if ("download".equals(type)){