From 8356bc01796536e03beb7d5ea3bd4191aa323d8a Mon Sep 17 00:00:00 2001
From: PoffyZhang <99775271@qq.com>
Date: Fri, 21 Jul 2023 16:00:59 +0800
Subject: [PATCH] =?UTF-8?q?=E5=AF=B9=E6=AF=94=20=E5=8F=98=E6=9B=B4?=
=?UTF-8?q?=E5=89=8D=E5=90=8E=E7=9A=84=E9=A1=B9=E7=9B=AE=E5=AD=97=E6=AE=B5?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../ningdatech/pmapi/common/compare/Compare.java | 22 +++
.../pmapi/common/compare/CompareNode.java | 47 ++++++
.../pmapi/common/compare/CompareUtils.java | 181 +++++++++++++++++++++
.../pmapi/projectlib/manage/ProjectLibManage.java | 61 ++++++-
.../pmapi/todocenter/manage/TodoCenterManage.java | 2 +
.../model/vo/ProcessProgressDetailVo.java | 5 +
6 files changed, 310 insertions(+), 8 deletions(-)
create mode 100644 pmapi/src/main/java/com/ningdatech/pmapi/common/compare/Compare.java
create mode 100644 pmapi/src/main/java/com/ningdatech/pmapi/common/compare/CompareNode.java
create mode 100644 pmapi/src/main/java/com/ningdatech/pmapi/common/compare/CompareUtils.java
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/common/compare/Compare.java b/pmapi/src/main/java/com/ningdatech/pmapi/common/compare/Compare.java
new file mode 100644
index 0000000..0a56775
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/common/compare/Compare.java
@@ -0,0 +1,22 @@
+package com.ningdatech.pmapi.common.compare;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * 字段标记注解
+ *
+ * @author zpf
+ * @since 2023/07/21
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Compare {
+
+ /**
+ * 字段名称
+ */
+ String value();
+}
\ No newline at end of file
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/common/compare/CompareNode.java b/pmapi/src/main/java/com/ningdatech/pmapi/common/compare/CompareNode.java
new file mode 100644
index 0000000..737331d
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/common/compare/CompareNode.java
@@ -0,0 +1,47 @@
+package com.ningdatech.pmapi.common.compare;
+
+/**
+ * @author zpf
+ * @since 2023/07/21
+ */
+public class CompareNode {
+
+ /**
+ * 字段
+ */
+ private String fieldKey;
+
+ /**
+ * 字段值
+ */
+ private Object fieldValue;
+
+ /**
+ * 字段名称
+ */
+ private String fieldName;
+
+ public String getFieldKey() {
+ return fieldKey;
+ }
+
+ public void setFieldKey(String fieldKey) {
+ this.fieldKey = fieldKey;
+ }
+
+ public Object getFieldValue() {
+ return fieldValue;
+ }
+
+ public void setFieldValue(Object fieldValue) {
+ this.fieldValue = fieldValue;
+ }
+
+ public String getFieldName() {
+ return fieldName;
+ }
+
+ public void setFieldName(String fieldName) {
+ this.fieldName = fieldName;
+ }
+}
\ No newline at end of file
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/common/compare/CompareUtils.java b/pmapi/src/main/java/com/ningdatech/pmapi/common/compare/CompareUtils.java
new file mode 100644
index 0000000..190eded
--- /dev/null
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/common/compare/CompareUtils.java
@@ -0,0 +1,181 @@
+package com.ningdatech.pmapi.common.compare;
+
+import com.alibaba.fastjson.JSONObject;
+
+import java.lang.reflect.Field;
+import java.util.*;
+
+/**
+ * 使用须知:
+ * (1)该工具类主要用于两个同类对象的属性值比较;
+ * (2)使用本工具类前,请将对应的类属性上打上 @Compare("xxx") 注解,其中xxx为字段的表达名称;
+ * (3)为了比较灵活,只有打了该注解才会进行比较,不打的字段则不会进行比较
+ * (4)比较后,只会返回有变化的字段,无变化的字符则不返回
+ *
+ * @author zpf
+ * @since 2023/07/21
+ */
+public class CompareUtils {
+
+ private static final String COMMA = ",";
+
+ /**
+ * 属性比较
+ *
+ * @param source 源数据对象
+ * @param target 目标数据对象
+ * @return 对应属性值的比较变化
+ */
+ public String compare(T source, T target) {
+ return compare(source, target, null);
+ }
+
+
+ /**
+ * 属性比较
+ *
+ * @param source 源数据对象
+ * @param target 目标数据对象
+ * @param ignoreCompareFields 忽略比较的字段
+ * @return 对应属性值的比较变化
+ */
+ public String compare(T source, T target, List ignoreCompareFields) {
+ if (Objects.isNull(source) && Objects.isNull(target)) {
+ return "";
+ }
+ Map sourceMap = this.getFiledValueMap(source);
+ Map targetMap = this.getFiledValueMap(target);
+ if (sourceMap.isEmpty() && targetMap.isEmpty()) {
+ return "";
+ }
+ // 如果源数据为空,则只显示目标数据,不显示属性变化情况
+ if (sourceMap.isEmpty()) {
+ return doEmpty(targetMap, ignoreCompareFields);
+ }
+ // 如果源数据为空,则显示属性变化情况
+ String s = doCompare(sourceMap, targetMap, ignoreCompareFields);
+ if (!s.endsWith(COMMA)) {
+ return s;
+ }
+ return s.substring(0, s.length() - 1);
+ }
+
+ public JSONObject compareToJson(T source, T target, List ignoreCompareFields) {
+ JSONObject res = new JSONObject();
+ if (Objects.isNull(source) && Objects.isNull(target)) {
+ return res;
+ }
+ Map sourceMap = this.getFiledValueMap(source);
+ Map targetMap = this.getFiledValueMap(target);
+ if (sourceMap.isEmpty() && targetMap.isEmpty()) {
+ return res;
+ }
+ // 如果源数据为空,则只显示目标数据,不显示属性变化情况
+ if (sourceMap.isEmpty()) {
+ return res;
+ }
+
+ return doCompareJson(sourceMap, targetMap, ignoreCompareFields);
+ }
+
+ private String doEmpty(Map targetMap, List ignoreCompareFields) {
+ StringBuilder sb = new StringBuilder();
+ Collection values = targetMap.values();
+ int size = values.size();
+ int current = 0;
+ for (CompareNode node : values) {
+ current++;
+ Object o = Optional.ofNullable(node.getFieldValue()).orElse("");
+ if (Objects.nonNull(ignoreCompareFields) && ignoreCompareFields.contains(node.getFieldKey())) {
+ continue;
+ }
+ if (o.toString().length() > 0) {
+ sb.append("[" + node.getFieldName() + ":" + o + "]");
+ if (current < size) {
+ sb.append(COMMA);
+ }
+ }
+ }
+ return sb.toString();
+ }
+
+ private String doCompare(Map sourceMap, Map targetMap, List ignoreCompareFields) {
+ StringBuilder sb = new StringBuilder();
+ Set keys = sourceMap.keySet();
+ int size = keys.size();
+ int current = 0;
+ for (String key : keys) {
+ current++;
+ CompareNode sn = sourceMap.get(key);
+ CompareNode tn = targetMap.get(key);
+ if (Objects.nonNull(ignoreCompareFields) && ignoreCompareFields.contains(sn.getFieldKey())) {
+ continue;
+ }
+ String sv = Optional.ofNullable(sn.getFieldValue()).orElse("").toString();
+ String tv = Optional.ofNullable(tn.getFieldValue()).orElse("").toString();
+ // 只有两者属性值不一致时, 才显示变化情况
+ if (!sv.equals(tv)) {
+ sb.append(String.format("[%s:%s -> %s]", sn.getFieldName(), sv, tv));
+ if (current < size) {
+ sb.append(COMMA);
+ }
+ }
+ }
+ return sb.toString();
+ }
+
+ private JSONObject doCompareJson(Map sourceMap, Map targetMap, List ignoreCompareFields) {
+ JSONObject res = new JSONObject();
+ Set keys = sourceMap.keySet();
+ int size = keys.size();
+ int current = 0;
+ for (String key : keys) {
+ current++;
+ CompareNode sn = sourceMap.get(key);
+ CompareNode tn = targetMap.get(key);
+ if (Objects.nonNull(ignoreCompareFields) && ignoreCompareFields.contains(sn.getFieldKey())) {
+ continue;
+ }
+ String sv = Optional.ofNullable(sn.getFieldValue()).orElse("").toString();
+ String tv = Optional.ofNullable(tn.getFieldValue()).orElse("").toString();
+ // 只有两者属性值不一致时, 才显示变化情况
+ if (!sv.equals(tv)) {
+ JSONObject valueChange = new JSONObject();
+ valueChange.put("old",sv);
+ valueChange.put("new",tv);
+ res.put(sn.getFieldName(),valueChange);
+ }
+ }
+ return res;
+ }
+
+ private Map getFiledValueMap(T t) {
+ if (Objects.isNull(t)) {
+ return Collections.emptyMap();
+ }
+ Field[] fields = t.getClass().getDeclaredFields();
+ if (Objects.isNull(fields) || fields.length == 0) {
+ return Collections.emptyMap();
+ }
+ Map map = new LinkedHashMap();
+ for (Field field : fields) {
+ Compare compareAnnotation = field.getAnnotation(Compare.class);
+ if (Objects.isNull(compareAnnotation)) {
+ continue;
+ }
+ field.setAccessible(true);
+ try {
+ String fieldKey = field.getName();
+ CompareNode node = new CompareNode();
+ node.setFieldKey(fieldKey);
+ node.setFieldValue(field.get(t));
+ node.setFieldName(compareAnnotation.value());
+ map.put(field.getName(), node);
+ } catch (IllegalArgumentException | IllegalAccessException e) {
+ e.printStackTrace();
+ }
+ }
+ return map;
+ }
+
+}
\ No newline at end of file
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/projectlib/manage/ProjectLibManage.java b/pmapi/src/main/java/com/ningdatech/pmapi/projectlib/manage/ProjectLibManage.java
index 9299e64..e5bb1d2 100644
--- a/pmapi/src/main/java/com/ningdatech/pmapi/projectlib/manage/ProjectLibManage.java
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/projectlib/manage/ProjectLibManage.java
@@ -14,6 +14,7 @@ import com.ningdatech.basic.model.PageVo;
import com.ningdatech.basic.util.CollUtils;
import com.ningdatech.file.entity.File;
import com.ningdatech.file.service.FileService;
+import com.ningdatech.pmapi.common.compare.CompareUtils;
import com.ningdatech.pmapi.common.constant.BizConst;
import com.ningdatech.pmapi.common.constant.CommonConst;
import com.ningdatech.pmapi.common.constant.RegionConst;
@@ -1121,6 +1122,35 @@ public class ProjectLibManage {
}
/**
+ * 判断 当前项目是不是被驳回 或者 退回过
+ * @param projectId
+ * @return
+ */
+ public Boolean isChangeRecord(Long projectId) {
+ //1.先判断下 项目存不存在
+ Project project = projectService.getById(projectId);
+ if(Objects.isNull(project)){
+ return Boolean.FALSE;
+ }
+
+ //2.要判断 项目在当前状态 有没有被驳回和退回过
+ //当前项目状态流程的 实例 看看是不是有2个以上 有2个说明 有退回 驳回
+ List pis = projectInstService.list(Wrappers.lambdaQuery(ProjectInst.class)
+ .eq(ProjectInst::getProjectId, projectId)
+ .orderByDesc(ProjectInst::getInstType)
+ .last("limit 2"));
+ if(CollUtil.isEmpty(pis)){
+ return Boolean.FALSE;
+ }
+ if( pis.size() < 2 ||
+ !pis.get(0).getInstType().equals(pis.get(1).getInstType())) {
+ return Boolean.FALSE;
+ }
+
+ return Boolean.TRUE;
+ }
+
+ /**
* 查看 项目的 变更记录(驳回 重新发起的 和上个版本的变更字段)
* @param projectId
* @return
@@ -1132,20 +1162,35 @@ public class ProjectLibManage {
Project project = projectService.getById(projectId);
VUtils.isTrue(Objects.isNull(project)).throwMessage("项目不存在");
+
//2.要判断 项目在当前状态 有没有被驳回和退回过
//当前项目状态流程的 实例 看看是不是有2个以上 有2个说明 有退回 驳回
- List pis = projectInstService.list(Wrappers.lambdaQuery(ProjectInst.class)
- .eq(ProjectInst::getProjectId, projectId)
- .orderByDesc(ProjectInst::getInstType)
- .last("limit 2"));
- VUtils.isTrue(CollUtil.isEmpty(pis)).throwMessage("该项目没有审批流");
- VUtils.isTrue( pis.size() < 2 ||
- !pis.get(0).getInstType().equals(pis.get(1).getInstType()))
- .throwMessage("该项目在当前流程没有被驳回 撤回过");
+ Boolean isChangeRecord = isChangeRecord(projectId);
+ if(!isChangeRecord){
+ return res;
+ }
//3. 去对比 当前版本和上个版本 的字段对比
String projectCode = project.getProjectCode();
+ List twoVersions = projectService.list(Wrappers.lambdaQuery(Project.class)
+ .eq(Project::getProjectCode, projectCode)
+ .orderByDesc(Project::getVersion)
+ .last("limit 2"));
+ if(CollUtil.isEmpty(twoVersions) || twoVersions.size() < 2){
+ return res;
+ }
+
+ return checkTwoProjectChanges(res,twoVersions);
+ }
+ /**
+ * 列出 2个版本项目的 不同字段
+ * @param res
+ * @param twoVersions
+ * @return
+ */
+ private JSONObject checkTwoProjectChanges(JSONObject res, List twoVersions) {
+ res = new CompareUtils().compareToJson(twoVersions.get(0), twoVersions.get(1),null);
return res;
}
}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/todocenter/manage/TodoCenterManage.java b/pmapi/src/main/java/com/ningdatech/pmapi/todocenter/manage/TodoCenterManage.java
index 762c4b0..be00450 100644
--- a/pmapi/src/main/java/com/ningdatech/pmapi/todocenter/manage/TodoCenterManage.java
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/todocenter/manage/TodoCenterManage.java
@@ -563,6 +563,8 @@ public class TodoCenterManage {
res.setCanWithdraw(withDrawHandle.checkCanWithdraw(instanceId,progressInstanceDetail,request.getTaskId()));
res.setIsHighLine(isHighLine);
passHandle.checkCanPassOrSeal(request.getInstanceId(),request.getTaskId(),employeeCode,res);
+ //是不是被 驳回|退回
+ res.setIsChange(projectLibManage.isChangeRecord(projectId));
return res;
}
diff --git a/pmapi/src/main/java/com/ningdatech/pmapi/todocenter/model/vo/ProcessProgressDetailVo.java b/pmapi/src/main/java/com/ningdatech/pmapi/todocenter/model/vo/ProcessProgressDetailVo.java
index 59bf2cf..97fe111 100644
--- a/pmapi/src/main/java/com/ningdatech/pmapi/todocenter/model/vo/ProcessProgressDetailVo.java
+++ b/pmapi/src/main/java/com/ningdatech/pmapi/todocenter/model/vo/ProcessProgressDetailVo.java
@@ -58,4 +58,9 @@ public class ProcessProgressDetailVo {
* 当前审批人 是不是流程配置里的 上级条线主管
*/
private Boolean isHighLine = Boolean.FALSE;
+
+ /**
+ * 当前项目 是不是被 驳回|退回过
+ */
+ private Boolean isChange = Boolean.FALSE;
}