Просмотр исходного кода

feat(performance): 添加绩效考核打印功能和员工任职信息查询优化

- 新增 JOINWORKTIME_KEY 常量定义
- 实现查询员工最新任职经历信息(含不在岗)功能,包括详细的查询逻辑和分组处理
- 添加绩效批量打印列表插件,支持选中行打印功能
- 创建绩效详情打印插件,实现过滤勾选行打印逻辑
- 优化绩效详情报表查询,增加批量查询数量限制和数据过滤处理
- 在绩效管理保存操作中添加数据迁移支持和员工任职关系查询集成
wyc 5 дней назад
Родитель
Сommit
4094e94f9d

+ 2 - 0
code/base/nckd-jxccl-base-common/src/main/java/nckd/jxccl/base/common/constant/FormConstant.java

@@ -463,6 +463,8 @@ public class FormConstant {
     public static final String PHONE_KEY = "phone";
     /** 参加工作日期 */
     public static final String NCKD_JOINWORKTIME = "nckd_joinworktime";
+    /** 参加工作日期 */
+    public static final String JOINWORKTIME_KEY = "joinworktime";
     /** 出生日期 */
     public static final String BIRTHDAY = "birthday";
     /** 性别 */

+ 75 - 1
code/base/nckd-jxccl-base-helper/src/main/java/nckd/jxccl/base/hrpi/helper/EmpPosOrgRelHelper.java

@@ -102,7 +102,42 @@ public class EmpPosOrgRelHelper {
     }
 
     /**
-     * 根据多个员工ID查询最新的任职经历信息
+     * 根据多个员工ID查询最新的任职经历信息(含不在岗)
+     *
+     * @param employeeIds 员工ID集合
+     * @return 员工的任职经历信息数组
+     * @author W.Y.C
+     * @date: 2025/11/04 16:02
+     */
+    public static Map<Long, DynamicObject> queryEmpPosOrgRelWithOutPostByEmployeesMap(Collection<Long> employeeIds) {
+        DynamicObject[] dynamicObjects = queryEmpPosOrgRelByEmployeesWithOutPost(employeeIds, null);
+        // 按员工ID分组,并取每个员工的最新记录(按开始日期)
+        Map<Long, List<DynamicObject>> grouped = new HashMap<>();
+        for (DynamicObject obj : dynamicObjects) {
+            Long empId = obj.getLong(String.join(".", FormConstant.EMPLOYEE_KEY, FormConstant.ID_KEY));
+            grouped.computeIfAbsent(empId, k -> new ArrayList<>()).add(obj);
+        }
+
+        // 从每组中选取开始日期最新的记录
+        Map<Long, DynamicObject> result = new HashMap<>();
+        for (Map.Entry<Long, List<DynamicObject>> entry : grouped.entrySet()) {
+            List<DynamicObject> records = entry.getValue();
+            DynamicObject latestRecord = records.stream()
+                    .max((o1, o2) -> {
+                        Date date1 = o1.getDate(FormConstant.STARTDATE);
+                        Date date2 = o2.getDate(FormConstant.STARTDATE);
+                        return date1.compareTo(date2);
+                    })
+                    .orElse(null);
+            result.put(entry.getKey(), latestRecord);
+        }
+
+        return result;
+
+    }
+
+    /**
+     * 根据多个员工ID查询最新的任职经历信息(含不在岗)
      *
      * @param employeeIds 员工ID集合
      * @return 员工的任职经历信息数组
@@ -135,6 +170,7 @@ public class EmpPosOrgRelHelper {
         return result;
 
     }
+
     /**
      * 根据多个员工ID查询最新的任职经历信息(含历史)
      *
@@ -222,6 +258,44 @@ public class EmpPosOrgRelHelper {
         return BusinessDataServiceHelper.load(FormConstant.HRPI_EMPPOSORGREL, selectProperties, new QFilter[]{queryFilter}, order);
     }
 
+    /**
+     * 获取员工最新有效任职经历(含不在岗)
+     * 查询条件包括:
+     * 1. 员工ID在指定范围内
+     * 2. 是最新记录(IS_SEQLATESTRECORD=YES)
+     * 3. 未删除(IS_DELETED=NO)
+     * 4. 是主任职(IS_PRIMARY=YES)
+     *
+     * @param employeeIds 员工ID集合
+     * @param otherFilter 其他查询条件(可选)
+     * @return 员工的任职经历信息数组
+     * @author W.Y.C
+     * @date: 2025/11/04 16:02
+     */
+    public static DynamicObject[] queryEmpPosOrgRelByEmployeesWithOutPost(Collection<Long> employeeIds, QFilter otherFilter) {
+        // 构建基础查询条件
+
+        QFilter queryFilter = new QFilter(FormConstant.EMPLOYEE_KEY, QCP.in, employeeIds)
+                .and(FormConstant.IS_SEQLATESTRECORD, QCP.equals, EnableEnum.YES.getCode())
+                .and(FormConstant.IS_DELETED, QCP.equals, EnableEnum.NO.getCode())
+                .and(FormConstant.IS_PRIMARY, QCP.equals, EnableEnum.YES.getCode())
+                .and(FormConstant.STARTDATE, QCP.less_equals, new Date())
+                .and(FormConstant.ENDDATE, QCP.large_equals, new Date())
+                .and(FormConstant.ISCURRENTDATA, QCP.equals, EnableEnum.YES.getCode());
+
+        // 添加额外查询条件(如果有)
+        if (otherFilter != null) {
+            queryFilter.and(otherFilter);
+        }
+
+        // 构建查询字段和排序规则
+        String selectProperties = selectProperties().buildSelect();
+        String order = selectProperties().buildOrder();
+
+        // 执行查询并返回结果
+        return BusinessDataServiceHelper.load(FormConstant.HRPI_EMPPOSORGREL, selectProperties, new QFilter[]{queryFilter}, order);
+    }
+
     /**
      * 获取员工有效任职经历(含历史)
      * 查询条件包括:

+ 26 - 1
code/opmc/nckd-jxccl-opmc/src/main/java/nckd/jxccl/opmc/pm/plugin/form/print/PerfBatchPrintListPlugin.java

@@ -5,6 +5,8 @@ import com.alibaba.fastjson.JSONObject;
 import kd.bos.dataentity.entity.DynamicObject;
 import kd.bos.dataentity.entity.DynamicObjectCollection;
 import kd.bos.dataentity.utils.StringUtils;
+import kd.bos.entity.datamodel.ListSelectedRow;
+import kd.bos.entity.datamodel.ListSelectedRowCollection;
 import kd.bos.entity.datamodel.events.PackageDataEvent;
 import kd.bos.entity.report.ReportColumn;
 import kd.bos.entity.report.ReportQueryParam;
@@ -13,8 +15,14 @@ import kd.bos.form.FormShowParameter;
 import kd.bos.form.ShowType;
 import kd.bos.form.control.Toolbar;
 import kd.bos.form.control.events.ItemClickEvent;
+import kd.bos.form.events.BeforeDoOperationEventArgs;
 import kd.bos.form.events.ClosedCallBackEvent;
 import kd.bos.form.events.PreOpenFormEventArgs;
+import kd.bos.form.operate.AbstractOperate;
+import kd.bos.form.operate.FormOperate;
+import kd.bos.form.operate.printop.PrintPreview;
+import kd.bos.form.operate.printop.SelectTplPrint;
+import kd.bos.list.IListView;
 import kd.bos.report.ReportList;
 import kd.bos.report.plugin.AbstractReportFormPlugin;
 import kd.sdk.plugin.Plugin;
@@ -114,7 +122,24 @@ public class PerfBatchPrintListPlugin extends AbstractReportFormPlugin implement
             }
 
         }
+    }
 
-
+    @Override
+    public void beforeDoOperation(BeforeDoOperationEventArgs args) {
+        AbstractOperate operate = (AbstractOperate) args.getSource();
+        String operateKey = operate.getOperateKey();
+        if ("selecttplprint".equals(operateKey)) {
+            ReportList reportList = this.getView().getControl(FormConstant.REPORTLISTAP);
+            int[] selectedRowIndexes = reportList.getEntryState().getSelectedRows();
+            if(selectedRowIndexes != null && selectedRowIndexes.length > 0) {
+                List<Integer> seqList = new   ArrayList<>();
+                for (int selectedRowIndex : selectedRowIndexes) {
+                    DynamicObject rowData = reportList.getReportModel().getRowData(selectedRowIndex);
+                    seqList.add(rowData.getInt("fseq"));
+                }
+                SelectTplPrint operation = (SelectTplPrint) args.getSource();
+                operation.getParameter().put("extParam123", seqList);
+            }
+        }
     }
 }

+ 56 - 0
code/opmc/nckd-jxccl-opmc/src/main/java/nckd/jxccl/opmc/pm/plugin/form/print/PerfDetailPrintPlugin.java

@@ -0,0 +1,56 @@
+package nckd.jxccl.opmc.pm.plugin.form.print;
+
+import kd.bos.print.core.data.DataRowSet;
+import kd.bos.print.core.data.field.CollectionField;
+import kd.bos.print.core.data.field.Field;
+import kd.bos.print.core.plugin.AbstractPrintPlugin;
+import kd.bos.print.core.plugin.event.AfterLoadDataEvent;
+import kd.sdk.plugin.Plugin;
+import nckd.jxccl.base.common.constant.FormConstant;
+import nckd.jxccl.base.common.utils.ConvertUtil;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+* 绩效结果打印
+* @author W.Y.C
+* @date 2026/1/6 15:15
+* @version 1.0
+*/
+public class PerfDetailPrintPlugin extends AbstractPrintPlugin implements Plugin {
+
+    @Override
+    public void afterLoadData(AfterLoadDataEvent evt) {
+        List<Integer> seqs = ConvertUtil.toList(this.getExtParam());
+        if (seqs == null || seqs.isEmpty()) {
+            return;
+        }
+        // 获取当前打印的数据集并准备过滤后的集合
+        // 2. 获取当前打印的数据集
+        List<DataRowSet> dataRowSets = evt.getDataRowSets();
+        List<DataRowSet> filteredDataRowSets = new ArrayList<>();
+        for (DataRowSet dataRowSet : dataRowSets) {
+            CollectionField entryField = (CollectionField) dataRowSet.getField("reportEntry");
+            List<DataRowSet> entryRows = entryField.getValue();
+            List<DataRowSet> filteredEntryRows = new ArrayList<>();
+            for (DataRowSet entryRow : entryRows) {
+                Integer seq = ConvertUtil.toInt(entryRow.getField(FormConstant.SEQ_KEY).getValue());
+                // 判断该分录行是否在用户勾选的列表中
+                if (seqs.contains(seq)) {
+                    filteredEntryRows.add(entryRow); // 保留被勾选的行
+                }
+            }
+            // 用过滤后的分录数据替换原数据
+            if (!filteredEntryRows.isEmpty()) {
+                DataRowSet newDataRowSet = dataRowSet.deepCopy(); // 深拷贝,避免影响原数据
+                newDataRowSet.put("reportEntry", new CollectionField(filteredEntryRows));
+                filteredDataRowSets.add(newDataRowSet);
+            }
+
+        }
+        // 将过滤后的数据集设置回事件,实现只打印勾选行
+        evt.setDataRowSets(filteredDataRowSets);
+    }
+}

+ 13 - 6
code/opmc/nckd-jxccl-opmc/src/main/java/nckd/jxccl/opmc/pm/plugin/form/print/PrintPerfDetailReportListDataPlugin.java

@@ -67,7 +67,7 @@ public class PrintPerfDetailReportListDataPlugin extends AbstractReportListDataP
             qFilter.and(dataRule);
         }
         IReportBatchQueryInfo byBatchInfo = queryParam.byBatchInfo();
-        byBatchInfo.setCountPerBatch(2000);
+        byBatchInfo.setCountPerBatch(3000);
         return QueryServiceHelper.queryDataSet(this.getClass().getName(),PerfManagerFormConstant.PERFMANAGER_ENTITYID, queryFieldBuilder.buildSelect(), new QFilter[]{qFilter}, queryFieldBuilder.buildOrder(),1000000);
     }
 
@@ -103,7 +103,6 @@ public class PrintPerfDetailReportListDataPlugin extends AbstractReportListDataP
             qFilter.and(new QFilter(FormConstant.ID_KEY, QCP.in, idsOfCurrentBatch));
         }
         qFilter.and(String.join(".", FormConstant.HRPI_EMPPOSORGREL, FormConstant.POS_STATUS,FormConstant.POST_STATE_CLS, FormConstant.NUMBER_KEY),QCP.equals,"1010_S");
-
         // 处理快速过滤条件
         processFastFilter(reportQueryParam, qFilter);
 
@@ -116,7 +115,6 @@ public class PrintPerfDetailReportListDataPlugin extends AbstractReportListDataP
         if(dataRule != null){
             qFilter.and(dataRule);
         }
-
         // 执行基础查询
         QueryEntityType queryEntityType = (QueryEntityType) EntityMetadataCache.getDataEntityType("printperfquery");
         DataSet dataSet = HRQueryEntityHelper.getInstance().getQueryDataSet(queryEntityType,queryFieldBuilder.buildSelect(), new QFilter[]{qFilter}, null);
@@ -127,7 +125,9 @@ public class PrintPerfDetailReportListDataPlugin extends AbstractReportListDataP
             Long personId = next.getLong(String.join(".", FormConstant.NCKD_PERSON, FormConstant.ID_KEY));
             personIds.add(personId);
         }
-
+        if(personIds.isEmpty()){
+            return dataSet;
+        }
         //过滤调实际结束实际之外的年份分录
         DataSet withYearFields = dataSet.filter("year("+String.join(".", PerfManagerFormConstant.PERFMANAGERENTRY, PerfManagerFormConstant.NCKD_APPRAISALYEAR) +") " +
                 "<= year(CASE WHEN nckd_actendyear is not null THEN nckd_actendyear ELSE "+PerfManagerFormConstant.NCKD_ENDYEAR+" end)");
@@ -137,8 +137,8 @@ public class PrintPerfDetailReportListDataPlugin extends AbstractReportListDataP
         for (int year = fiveYearsAgo; year <= currentYear; year++) {
             withYearFields = withYearFields.addField(
                     "CASE WHEN year(" + String.join(".", PerfManagerFormConstant.PERFMANAGERENTRY, PerfManagerFormConstant.NCKD_APPRAISALYEAR) + ") = " + year + " THEN " + String.join(".", PerfManagerFormConstant.PERFMANAGERENTRY, PerfManagerFormConstant.NCKD_APPRAISALRESULT,FormConstant.ID_KEY)+ " ELSE null END",
-                    "temp_" + tempIndex
-            );
+                    "temp_" + tempIndex);
+            withYearFields = withYearFields.addField(year+"","temp_year_" + tempIndex);
             tempIndex++;
         }
 
@@ -164,11 +164,16 @@ public class PrintPerfDetailReportListDataPlugin extends AbstractReportListDataP
                 String.join(".", PerfManagerFormConstant.DOCSTAMP_ENTITYID, PerfManagerFormConstant.NCKD_STAMPTIME),
                 String.join(".", PerfManagerFormConstant.DOCSTAMP_ENTITYID, PerfManagerFormConstant.NCKD_FILEISSUETIME),
                 String.join(".", PerfManagerFormConstant.HRPI_EMPPOSORGREL, PerfManagerFormConstant.POSITION_KEY, FormConstant.ID_KEY),
+                String.join(".", PerfManagerFormConstant.HRPI_PERSERLEN, PerfManagerFormConstant.FIRSTJOINCOMDATE_KEY),
+                String.join(".", PerfManagerFormConstant.HRPI_PERSERLEN, PerfManagerFormConstant.JOINCOMDATE_KEY),
+                String.join(".", PerfManagerFormConstant.HRPI_PERSERLEN, PerfManagerFormConstant.JOINWORKTIME_KEY),
         });
         int tempIndex1 = 1;
         for (int year = fiveYearsAgo; year <= currentYear; year++) {
             groupbyDataSet
                     .max("temp_"+tempIndex1, tempIndex1+"_result");
+            groupbyDataSet
+                    .max("temp_year_"+tempIndex1, "year_"+tempIndex1);
             tempIndex1++;
         }
         //职称/技能使用逗号分拼接
@@ -176,6 +181,7 @@ public class PrintPerfDetailReportListDataPlugin extends AbstractReportListDataP
         groupbyDataSet.agg(new DistinctConcatFunction(),"nckd_hrpi_empskill.nckd_qualiname","qualinames");
 
         DataSet annualPerfDetailQueryDataSet = groupbyDataSet.finish();
+        annualPerfDetailQueryDataSet.print(true);
         String[] mainTableFieldNames = annualPerfDetailQueryDataSet.getRowMeta().getFieldNames();
         // 创建新数组,长度比原数组多1
         String[] newMainTableFieldNames = new String[mainTableFieldNames.length + 1];
@@ -371,6 +377,7 @@ public class PrintPerfDetailReportListDataPlugin extends AbstractReportListDataP
                 .add(String.join(".", FormConstant.NCKD_PERSON, FormConstant.BIRTHDAY))
                 .add(String.join(".", FormConstant.NCKD_PERSON, FormConstant.GENDER,FormConstant.NAME_KEY))
                 .add(String.join(".", FormConstant.HRPI_PEREDUEXP, FormConstant.EDUCATION_KEY,FormConstant.NAME_KEY))
+                .addGroup(new String[]{FormConstant.HRPI_PERSERLEN},FormConstant.FIRSTJOINCOMDATE_KEY,FormConstant.JOINCOMDATE_KEY,FormConstant.JOINWORKTIME_KEY)
                 .addIdNumberName(FormConstant.HRPI_EMPENTREL,FormConstant.LABOR_REL_STATUS)
                 .addIdNumberName(FormConstant.HRPI_EMPPOSORGREL,FormConstant.ADMINORG,FormConstant.NCKD_FIRSTORG)
                 .addIdNumberName(FormConstant.HRPI_EMPPOSORGREL,FormConstant.ADMINORG,FormConstant.NCKD_SECONDORG)

+ 44 - 9
code/opmc/nckd-jxccl-opmc/src/main/java/nckd/jxccl/opmc/pm/plugin/operate/cycle/PerfManagerSaveOpPlugin.java

@@ -262,19 +262,20 @@ public class PerfManagerSaveOpPlugin extends AbstractOperationServicePlugIn impl
                                     // 判断周期是否重叠并获取重叠信息,已结束周期使用实际结束时间
                                     String overlapInfo = getCycleOverlapInfo(beginYear, endYear, null, dbBeginYear, dbEndYear, dbActEndYear);
                                     if (StringUtils.isNotBlank(overlapInfo)) {
-                                        /*addFatalErrorMessage(rowDataEntity,
+                                        addFatalErrorMessage(rowDataEntity,
                                                 StrFormatter.format("人员【{}】的考核周期与已有周期在{}重叠,请检查!",
-                                                        personName, overlapInfo));*/
+                                                        personName, overlapInfo));
                                     }
                                 }
-                            }
 
-                            //判断beginYear和dbBeginYear的年份是否相同
-                            if (isSameYear(beginYear, dbBeginYear)) {
-                                /*addFatalErrorMessage(rowDataEntity,
-                                        StrFormatter.format("人员【{}】已经存在周期开始年份【{}】的周期,无需进行创建。",
-                                                personName,
-                                                beginYear.getYear()));*/
+
+                                //判断beginYear和dbBeginYear的年份是否相同
+                                if (isSameYear(beginYear, dbBeginYear)) {
+                                    addFatalErrorMessage(rowDataEntity,
+                                            StrFormatter.format("人员【{}】已经存在周期开始年份【{}】的周期,无需进行创建。",
+                                                    personName,
+                                                    beginYear.getYear()));
+                                }
                             }
                         }
 
@@ -501,6 +502,31 @@ public class PerfManagerSaveOpPlugin extends AbstractOperationServicePlugIn impl
         //事务开始之后将其他考核周期设置为非最新
         PerfManagerHelper.markAsNotCurrentNewest(personBeginYearMap.keySet().toArray(new Long[0]));
 
+        boolean dataMigration;
+        Object invoker = this.getOption().getVariables().get(FormConstant.HR_INVOKER_PARAM_INVOKER);
+        if(ObjectUtils.isEmpty(invoker)){
+            Object invoker1 = this.getOption().getVariables().get("hr_hrdmvalidatetag_of_datasource");
+            Object invoker2 = this.getOption().getVariables().get("hr_hrdmsynctag_of_datasource");
+            if(!ObjectUtils.isEmpty(invoker1) || !ObjectUtils.isEmpty(invoker2)){
+                dataMigration = true;
+            } else {
+                dataMigration = false;
+            }
+        } else{
+            dataMigration = FormConstant.DATA_MIGRATION.equalsIgnoreCase(invoker.toString());
+        }
+        Map<Long, DynamicObject> empPosOrgRelMap = new HashMap<>();
+        if(dataMigration){
+            List<Long> personIds = new ArrayList<>();
+            for (DynamicObject dataEntity : e.getDataEntities()) {
+                DynamicObject person = dataEntity.getDynamicObject(FormConstant.NCKD_PERSON);
+                if(person != null){
+                    personIds.add(person.getLong(FormConstant.ID_KEY));
+                }
+            }
+            empPosOrgRelMap = EmpPosOrgRelHelper.queryEmpPosOrgRelWithOutPostByEmployeesMap(personIds);
+        }
+
         Boolean isCycleGenerate = ConvertUtil.toBoolean(this.getOption().getVariableValue("cyclegenerate",StringUtils.EMPTY),Boolean.FALSE);
         Boolean isUpdate = ConvertUtil.toBoolean(this.getOption().getVariableValue("isUpdate",StringUtils.EMPTY),Boolean.FALSE);
         List<DynamicObject> updatePerManager = new ArrayList<>();
@@ -509,7 +535,16 @@ public class PerfManagerSaveOpPlugin extends AbstractOperationServicePlugIn impl
         for (DynamicObject dataEntity : e.getDataEntities()) {
             long id = dataEntity.getLong(FormConstant.ID_KEY);
             DynamicObject person = dataEntity.getDynamicObject(FormConstant.NCKD_PERSON);
+            if(dataMigration) {
+                long personId = person.getLong(FormConstant.ID_KEY);
+                DynamicObject empPosOrgRel = empPosOrgRelMap.get(personId);
+                dataEntity.set(FormConstant.NCKD_EMPPOSORGREL,empPosOrgRel);
+            }
             DynamicObject empPosOrgRel = dataEntity.getDynamicObject(FormConstant.NCKD_EMPPOSORGREL);
+            if(empPosOrgRel == null){
+                continue;
+            }
+
             person = person == null ? empPosOrgRel.getDynamicObject(FormConstant.EMPLOYEE_KEY) : person;
             dataEntity.set(FormConstant.NCKD_PERSON, person);
             LocalDateTime beginYear = DateUtil.toLocalDateTime(dataEntity.getDate(PerfManagerFormConstant.NCKD_BEGINYEAR));