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; }