Procházet zdrojové kódy

feat(performance): 完善绩效排名管理功能

- 启用未参与排名条目的缓存与恢复机制
- 优化保存操作,确保非排名数据不丢失
- 增加步骤切换时的未保存提示与处理逻辑
- 改进条目过滤与界面更新逻辑
- 提升数据同步与展示的一致性
wyc před 23 hodinami
rodič
revize
19b594e2d6

+ 112 - 20
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/form/performance/PerfRankMgmtFormPlugin.java

@@ -1,12 +1,20 @@
 package nckd.jxccl.hr.psms.plugin.form.performance;
 
+import com.google.common.collect.Lists;
+import kd.bos.bill.BillShowParameter;
+import kd.bos.bill.OperationStatus;
 import kd.bos.common.enums.EnableEnum;
 import kd.bos.dataentity.OperateOption;
 import kd.bos.dataentity.RefObject;
 import kd.bos.dataentity.entity.DynamicObject;
 import kd.bos.dataentity.entity.DynamicObjectCollection;
+import kd.bos.dataentity.metadata.IDataEntityProperty;
 import kd.bos.dataentity.metadata.dynamicobject.DynamicObjectType;
+import kd.bos.dataentity.serialization.DataEntitySerializer;
+import kd.bos.dataentity.serialization.DataEntitySerializerOption;
+import kd.bos.dtx.util.DynamicObjectSerializeUtil;
 import kd.bos.entity.EntityMetadataCache;
+import kd.bos.entity.MainEntityType;
 import kd.bos.entity.QueryEntityType;
 import kd.bos.entity.constant.StatusEnum;
 import kd.bos.entity.datamodel.IDataModel;
@@ -19,10 +27,12 @@ import kd.bos.entity.datamodel.events.PropertyChangedArgs;
 import kd.bos.entity.filter.CompareTypeEnum;
 import kd.bos.entity.filter.FilterValue;
 import kd.bos.entity.filter.SimpleFilterRow;
+import kd.bos.entity.operate.result.OperationResult;
 import kd.bos.entity.property.entryfilter.EntryQueryParam;
 import kd.bos.form.ConfirmCallBackListener;
 import kd.bos.form.ConfirmTypes;
 import kd.bos.form.IClientViewProxy;
+import kd.bos.form.IPageCache;
 import kd.bos.form.MessageBoxOptions;
 import kd.bos.form.MessageBoxResult;
 import kd.bos.form.container.Wizard;
@@ -100,7 +110,7 @@ public class PerfRankMgmtFormPlugin extends AbstractFormPlugin implements Wizard
 
     @Override
     public void afterBindData(EventObject e) {
-//        sortEntry();
+        sortEntry();
         this.getView().updateView(PerfRankMgmtConstant.NCKD_PERFRANKMGMTENTRY);
         // 该单据不需要审批,默认为暂存状态
         this.getModel().setValue(FormConstant.STATUS, StatusEnum.A.toString());
@@ -124,6 +134,7 @@ public class PerfRankMgmtFormPlugin extends AbstractFormPlugin implements Wizard
                 }*/
                 DynamicObjectCollection entryEntityCols = this.getModel().getDataEntity(true).getDynamicObjectCollection(PerfRankMgmtConstant.NCKD_PERFRANKMGMTENTRY);
                 entryEntityCols.removeIf(obj -> obj.getBoolean(PerfRankMgmtConstant.NCKD_ISRANKING));
+                this.getView().updateView(PerfRankMgmtConstant.NCKD_PERFRANKMGMTENTRY);
             }
             setStepStatus(0,Steps.FINISH);
             setStepStatus(1,Steps.PROCESS);
@@ -306,6 +317,12 @@ public class PerfRankMgmtFormPlugin extends AbstractFormPlugin implements Wizard
         } else if(Arrays.asList(FormConstant.SAVE_OP, FormConstant.SUBMIT_OP).contains(itemKey)){
             //保存或提交先计算一遍
             calcRankCount();
+            IPageCache pageCache = this.getView().getPageCache();
+            if(pageCache.get("removedEntries") != null && ConvertUtil.toBoolean(pageCache.get("removedEntries"))){
+                //告诉OP需要加载被删除的分录(不参与排名)
+                FormOperate formOperate = (FormOperate) args.getSource();
+                formOperate.getOption().setVariableValue("removedEntries", "true");
+            }
         } else if(FormConstant.DELETEENTRY_OP.equalsIgnoreCase(itemKey)){
             //校验人员考评,若考评周期已结束,则禁止删除。
             EntryGrid entryGrid = getView().getControl(PerfRankMgmtConstant.NCKD_PERFRANKMGMTENTRY);
@@ -417,6 +434,19 @@ public class PerfRankMgmtFormPlugin extends AbstractFormPlugin implements Wizard
 //                getModel().updateEntryCache(entryEntities);
                 getView().updateView(PerfRankMgmtConstant.NCKD_PERFRANKMGMTENTRY);
             }
+        }else if("update".equalsIgnoreCase(evt.getCallBackId())){
+            if (evt.getResult() == MessageBoxResult.Yes) {
+                OperationResult operationResult = this.getView().invokeOperation(FormConstant.SAVE_OP);
+                if (operationResult != null && operationResult.isSuccess()) {
+                    DynamicObject dataEntity = this.getModel().getDataEntity(true);
+                    dataEntity.getDataEntityState().setFromDatabase( true);
+                    String stepValueStr = this.getPageCache().get("stepValue");
+                    if (StringUtils.isNotBlank(stepValueStr)) {
+                        int stepValue = ConvertUtil.toInt(stepValueStr);
+                        update(stepValue);
+                    }
+                }
+            }
         }
     }
 
@@ -543,23 +573,14 @@ public class PerfRankMgmtFormPlugin extends AbstractFormPlugin implements Wizard
             if(afterDoOperationEventArgs.getOperationResult() != null && afterDoOperationEventArgs.getOperationResult().isSuccess()){
                 String wizadap = this.getView().getPageCache().get(FormConstant.NCKD_WIZARDAP);
                 if(StringUtils.isBlank(wizadap) || "0".equals(wizadap)){
-/*                    setStepStatus(0,Steps.FINISH);
+                    setStepStatus(0,Steps.FINISH);
                     setStepStatus(1,Steps.PROCESS);
-                    //控制显示隐藏
-                    importResultStep();
-                    this.getView().updateView(PerfRankMgmtConstant.NCKD_STEP);*/
-                    this.getView().getPageCache().put(PerfRankMgmtConstant.NCKD_STEP, "1");
-                    this.getView().invokeOperation(FormConstant.REFRESH_OP);
-
-/*                    //控制显示隐藏
-                    importResultStep();
-                    applyRankingFilter(true);*/
-
-
-
+                    this.getView().updateView(PerfRankMgmtConstant.NCKD_STEP);
                 }else {
                     this.getView().showSuccessNotification("同步考核周期成功。");
                 }
+                //控制显示隐藏
+                importResultStep();
             }
         }
         if(Arrays.asList(FormConstant.DELETEENTRY_OP, PerfRankMgmtConstant.GETRANKLIST_OP).contains(itemKey)){
@@ -579,9 +600,39 @@ public class PerfRankMgmtFormPlugin extends AbstractFormPlugin implements Wizard
             this.getView().setEnable(Boolean.FALSE, i, PerfRankMgmtConstant.NCKD_ISRANKING);
         }
 
+        DynamicObjectCollection entryEntityCols = this.getModel().getDataEntity(true).getDynamicObjectCollection(PerfRankMgmtConstant.NCKD_PERFRANKMGMTENTRY);
+        // 暂存被过滤掉的条目而不是直接删除
+        List<DynamicObject> removedEntries = entryEntityCols.stream()
+                .filter(obj -> !obj.getBoolean(PerfRankMgmtConstant.NCKD_ISRANKING))
+                .collect(Collectors.toList());
+        entryEntityCols.removeIf(obj -> !obj.getBoolean(PerfRankMgmtConstant.NCKD_ISRANKING));
+        if(!removedEntries.isEmpty()){
+            this.getView().getPageCache().put("removedEntries","true");
+        }else{
+            this.getView().getPageCache().put("removedEntries","false");
+        }
+        this.getView().updateView(PerfRankMgmtConstant.NCKD_PERFRANKMGMTENTRY);
+
     }
 
     private void generatePersonList() {
+
+        IPageCache pageCache = this.getView().getPageCache();
+        if(pageCache.get("removedEntries") != null && ConvertUtil.toBoolean(pageCache.get("removedEntries"))) {
+            Long id = ConvertUtil.toLong(this.getModel().getValue(FormConstant.ID_KEY));
+            if (id != null && id > 0) {
+                MainEntityType perfRankMgmtEntityType = EntityMetadataCache.getDataEntityType(PerfRankMgmtConstant.NCKD_PERFRANKMGMT_ENTITYID);
+                DynamicObject dbPerfRankMgmt = BusinessDataServiceHelper.loadSingle(id, perfRankMgmtEntityType);
+                DynamicObjectCollection dynamicObjectCollection = dbPerfRankMgmt.getDynamicObjectCollection(PerfRankMgmtConstant.NCKD_PERFRANKMGMTENTRY);
+                List<DynamicObject> removedEntries = dynamicObjectCollection.stream()
+                        .filter(obj -> !obj.getBoolean(PerfRankMgmtConstant.NCKD_ISRANKING))
+                        .collect(Collectors.toList());
+                DynamicObjectCollection entryEntityCols = this.getModel().getDataEntity(true).getDynamicObjectCollection(PerfRankMgmtConstant.NCKD_PERFRANKMGMTENTRY);
+                entryEntityCols.addAll(removedEntries);
+                this.getView().updateView(PerfRankMgmtConstant.NCKD_PERFRANKMGMTENTRY);
+                this.getView().getPageCache().put("removedEntries", "false");
+            }
+        }
         this.getModel().setValue(PerfRankMgmtConstant.NCKD_STEP,0);
         this.getView().setVisible(true, FormConstant.NUMBER_KEY, PerfRankMgmtConstant.NCKD_GETRANKLIST,"nckd_advconbaritemap2","nckd_advconbaritemap3");
         this.getView().setVisible(false, PerfRankMgmtConstant.NCKD_TOPRANKS, PerfRankMgmtConstant.NCKD_ALLOWANCERANKS, PerfRankMgmtConstant.NCKD_FAILS, PerfRankMgmtConstant.NCKD_BASICS, PerfRankMgmtConstant.NCKD_EXCELLENTS, "nckd_advconbaritemap6","nckd_advconbaritemap");
@@ -590,6 +641,7 @@ public class PerfRankMgmtFormPlugin extends AbstractFormPlugin implements Wizard
             this.getView().setEnable(Boolean.TRUE, i, FormConstant.NCKD_PERSON);
             this.getView().setEnable(Boolean.TRUE, i, PerfRankMgmtConstant.NCKD_ISRANKING);
         }
+
     }
 
     /**
@@ -820,30 +872,70 @@ public class PerfRankMgmtFormPlugin extends AbstractFormPlugin implements Wizard
 
     @Override
     public void update(StepEvent stepEvent) {
+        BillShowParameter bsp = (BillShowParameter) this.getView().getFormShowParameter();
+        boolean isUpdate = true;
+        if (bsp.getStatus() == OperationStatus.EDIT) {
+            DynamicObject dataEntity = this.getModel().getDataEntity(true);
+            boolean hasChanged = false;
+            List<IDataEntityProperty> iDataEntityProperties = dataEntity.getDataEntityState().GetDirtyProperties();
+            ArrayList<String> fields = Lists.newArrayList(PerfRankMgmtConstant.NCKD_STEP,FormConstant.STATUS);
+            for (IDataEntityProperty iDataEntityProperty : iDataEntityProperties) {
+                if (fields.stream().noneMatch(ignoreField -> ignoreField.equalsIgnoreCase(iDataEntityProperty.getName()))) {
+                    hasChanged = true;
+                }
+            }
+            if(!hasChanged) {
+                DynamicObjectCollection entityColl = dataEntity.getDynamicObjectCollection(PerfRankMgmtConstant.NCKD_PERFRANKMGMTENTRY);
+                for (DynamicObject dynamicObject : entityColl) {
+                    List<IDataEntityProperty> iDataEntityProperties1 = dynamicObject.getDataEntityState().GetDirtyProperties();
+                    if (!iDataEntityProperties1.isEmpty()) {
+                        hasChanged = true;
+                    }
+                }
+            }
+            if(hasChanged){
+                isUpdate = false;
+                this.getPageCache().put("stepValue", stepEvent.getValue()+"");
+                this.getView().showConfirm(
+                        "您当前有未保存的变更,切换步骤前需要保存。",
+                        "✅ 点击“确认”将先保存当前信息,再切换步骤\n❌ 点击“取消”则放弃保存,停留在本步骤。\n\n是否需要继续?",
+                        MessageBoxOptions.OKCancel,
+                        ConfirmTypes.Delete,
+                        new ConfirmCallBackListener("update", this));
+
+            }
+        }
+
+        if (isUpdate) {
+            update(stepEvent.getValue());
+        }
+    }
+
+    private void update(int stepValue){
         Wizard wizard = this.getControl(FormConstant.NCKD_WIZARDAP);
-        if(stepEvent.getValue() == 0){
+        if (stepValue == 0) {
             generatePersonList();
             setStepStatus(0, Steps.PROCESS);
 
             //步骤为:导入考核结果时只显示参与排名的人员
 //            applyRankingFilter(false);
 
-        }else{
+        } else {
             //校验有没有保存
-            DynamicObject dataEntity = this.getModel().getDataEntity();
+            DynamicObject dataEntity = this.getModel().getDataEntity(true);
             Object pkValue = dataEntity.getPkValue();
-            if(pkValue == null || pkValue.toString().equals("0")){
+            if (pkValue == null || pkValue.toString().equals("0")) {
                 this.getView().showTipNotification("请先生成名单并保存后再进行下一步!");
-            }else {
+            } else {
                 importResultStep();
                 setStepStatus(1, Steps.PROCESS);
 
+
                 //步骤为:导入考核结果时只显示参与排名的人员
 //                applyRankingFilter(true);
             }
         }
         this.getView().updateView(PerfRankMgmtConstant.NCKD_STEP);
-
     }
 
     /**

+ 45 - 0
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/operate/performance/PerfRankMgmtSaveOpPlugin.java

@@ -4,6 +4,7 @@ import kd.bos.common.enums.EnableEnum;
 import kd.bos.dataentity.OperateOption;
 import kd.bos.dataentity.entity.DynamicObject;
 import kd.bos.dataentity.entity.DynamicObjectCollection;
+import kd.bos.entity.EntityMetadataCache;
 import kd.bos.entity.MainEntityType;
 import kd.bos.entity.operate.OperateOptionConst;
 import kd.bos.entity.operate.result.IOperateInfo;
@@ -24,6 +25,7 @@ import kd.bos.servicehelper.operation.SaveServiceHelper;
 import kd.sdk.plugin.Plugin;
 import nckd.jxccl.base.common.constant.FormConstant;
 import nckd.jxccl.base.common.exception.ValidationException;
+import nckd.jxccl.base.common.utils.ConvertUtil;
 import nckd.jxccl.base.common.utils.DateUtil;
 import nckd.jxccl.base.common.utils.QueryFieldBuilder;
 import nckd.jxccl.base.common.utils.StrFormatter;
@@ -98,6 +100,27 @@ public class PerfRankMgmtSaveOpPlugin extends AbstractOperationServicePlugIn imp
             }
         }
 
+        Boolean removedEntries = ConvertUtil.toBoolean(this.getOption().getVariableValue("removedEntries",StringUtils.EMPTY),Boolean.FALSE);
+        Map<Long, List<DynamicObject>> nonRankingEntriesMap = new HashMap<>();
+        if(removedEntries){
+            MainEntityType perfRankMgmtEntityType = EntityMetadataCache.getDataEntityType(PerfRankMgmtConstant.NCKD_PERFRANKMGMT_ENTITYID);
+            DynamicObject[] load = BusinessDataServiceHelper.load(ids.toArray(), perfRankMgmtEntityType);
+            // 由于前端第二步不显示未参与排名的数据,保存时需要重新加载出未参与排名的数据,避免保存时未参与排名的数据丢失
+            nonRankingEntriesMap = Arrays.stream(load)
+                    .filter(Objects::nonNull)
+                    .collect(Collectors.groupingBy(
+                            obj -> obj.getLong(FormConstant.ID_KEY),
+                            Collectors.collectingAndThen(
+                                    Collectors.toList(),
+                                    list -> list.stream()
+                                            .flatMap(obj -> obj.getDynamicObjectCollection(PerfRankMgmtConstant.NCKD_PERFRANKMGMTENTRY).stream())
+                                            .filter(entry -> !entry.getBoolean(PerfRankMgmtConstant.NCKD_ISRANKING))
+                                            .collect(Collectors.toList())
+                            )
+                    ));
+
+        }
+
         Map<Long, List<DynamicObject>> dbEntryMap = new HashMap<>();
         if(!ids.isEmpty()) {
             // 获取数据库中存在的人员ID列表
@@ -121,7 +144,29 @@ public class PerfRankMgmtSaveOpPlugin extends AbstractOperationServicePlugIn imp
 
 
         for (DynamicObject dataEntity : e.getDataEntities()) {
+            long id = dataEntity.getLong(FormConstant.ID_KEY);
+            if(removedEntries && id > 0 && !nonRankingEntriesMap.isEmpty()){
+                List<DynamicObject> nonRankingEntries = nonRankingEntriesMap.get(id);
+                if(nonRankingEntries != null && !nonRankingEntries.isEmpty()){
+                    DynamicObjectCollection entryCollection = dataEntity.getDynamicObjectCollection(PerfRankMgmtConstant.NCKD_PERFRANKMGMTENTRY);
+                    // 获取当前列表中已有的所有条目ID
+                    Set<Long> existingIds = entryCollection.stream()
+                            .map(entry -> entry.getLong(FormConstant.ID_KEY))
+                            .filter(obj -> true)
+                            .collect(Collectors.toSet());
+
+                    // 只添加不存在的数据
+                    List<DynamicObject> entriesToAdd = nonRankingEntries.stream()
+                            .filter(entry -> {
+                                Long entryId = entry.getLong(FormConstant.ID_KEY);
+                                return !existingIds.contains(entryId);
+                            })
+                            .collect(Collectors.toList());
+
+                    entryCollection.addAll(entriesToAdd);
+                }
 
+            }
             //事务开始前先查询数据库中的排名名单,找出哪些是此次被删除的人员(删除的人员同步删除人员考评的考核结果)
             List<DynamicObject> dbEntryList = dbEntryMap.get(dataEntity.getLong(FormConstant.ID_KEY));
             List<Long> dbPersonIds = Optional.ofNullable(dbEntryList)