|
|
@@ -2,6 +2,9 @@ package nckd.jxccl.opmc.pm.plugin.form.print;
|
|
|
|
|
|
import kd.bos.algo.DataSet;
|
|
|
import kd.bos.algo.GroupbyDataSet;
|
|
|
+import kd.bos.algo.JoinType;
|
|
|
+import kd.bos.algo.Row;
|
|
|
+import kd.bos.common.enums.EnableEnum;
|
|
|
import kd.bos.dataentity.entity.LocaleString;
|
|
|
import kd.bos.entity.EntityMetadataCache;
|
|
|
import kd.bos.entity.QueryEntityType;
|
|
|
@@ -11,22 +14,30 @@ import kd.bos.entity.report.AbstractReportColumn;
|
|
|
import kd.bos.entity.report.AbstractReportListDataPlugin;
|
|
|
import kd.bos.entity.report.DynamicReportColumnEvent;
|
|
|
import kd.bos.entity.report.FastFilter;
|
|
|
+import kd.bos.entity.report.IReportBatchQueryInfo;
|
|
|
import kd.bos.entity.report.ReportColumn;
|
|
|
import kd.bos.entity.report.ReportQueryParam;
|
|
|
import kd.bos.mvc.list.ListDataProvider;
|
|
|
import kd.bos.orm.query.QCP;
|
|
|
import kd.bos.orm.query.QFilter;
|
|
|
+import kd.bos.servicehelper.QueryServiceHelper;
|
|
|
import kd.hr.hbp.business.servicehelper.HRQueryEntityHelper;
|
|
|
+import kd.hr.hbp.common.cache.HRPageCache;
|
|
|
import kd.sdk.plugin.Plugin;
|
|
|
+import nckd.jxccl.base.common.algo.GroupMaxStrFunction;
|
|
|
import nckd.jxccl.base.common.constant.FormConstant;
|
|
|
import nckd.jxccl.base.common.utils.DateUtil;
|
|
|
import nckd.jxccl.base.common.utils.QueryFieldBuilder;
|
|
|
import nckd.jxccl.opmc.pm.common.PerfManagerFormConstant;
|
|
|
|
|
|
import java.time.LocalDate;
|
|
|
+import java.time.LocalDateTime;
|
|
|
import java.util.Date;
|
|
|
+import java.util.HashSet;
|
|
|
import java.util.List;
|
|
|
import java.util.Map;
|
|
|
+import java.util.Set;
|
|
|
+import java.util.UUID;
|
|
|
|
|
|
/**
|
|
|
* 年度绩效结果明细-报表取数插件
|
|
|
@@ -42,6 +53,7 @@ public class PrintPerfDetailReportListDataPlugin extends AbstractReportListDataP
|
|
|
super.getDynamicColumns(event);
|
|
|
}
|
|
|
|
|
|
+
|
|
|
@Override
|
|
|
public DataSet query(ReportQueryParam reportQueryParam, Object o) throws Throwable {
|
|
|
|
|
|
@@ -55,6 +67,8 @@ public class PrintPerfDetailReportListDataPlugin extends AbstractReportListDataP
|
|
|
|
|
|
int currentYear = LocalDate.now().getYear() - 1; // 不包含今年
|
|
|
Date endDate = DateUtil.toDate(LocalDate.of(currentYear, 1, 1));
|
|
|
+
|
|
|
+
|
|
|
//查询最近5年的数据
|
|
|
/*QFilter qFilter = new QFilter(PerfManagerFormConstant.NCKD_BEGINYEAR, QCP.less_equals, endDate)
|
|
|
.and(new QFilter(PerfManagerFormConstant.NCKD_ENDYEAR, QCP.large_equals, beginDate));*/
|
|
|
@@ -69,13 +83,17 @@ public class PrintPerfDetailReportListDataPlugin extends AbstractReportListDataP
|
|
|
// 执行基础查询
|
|
|
QueryEntityType queryEntityType = (QueryEntityType) EntityMetadataCache.getDataEntityType("annualperfdetailquery");
|
|
|
DataSet dataSet = HRQueryEntityHelper.getInstance().getQueryDataSet(queryEntityType,queryFieldBuilder.buildSelect(), new QFilter[]{qFilter}, null);
|
|
|
-
|
|
|
- dataSet.print( true);
|
|
|
+ DataSet dataSetCopy = dataSet.copy();
|
|
|
+ Set<Long> personIds = new HashSet();
|
|
|
+ while (dataSetCopy.hasNext()) {
|
|
|
+ Row next = dataSetCopy.next();
|
|
|
+ Long personId = next.getLong(String.join(".", FormConstant.NCKD_PERSON, FormConstant.ID_KEY));
|
|
|
+ personIds.add(personId);
|
|
|
+ }
|
|
|
|
|
|
//过滤调实际结束实际之外的年份分录
|
|
|
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)");
|
|
|
- withYearFields.print(true);
|
|
|
|
|
|
// 动态添加年份字段;行转列
|
|
|
int tempIndex = 1;
|
|
|
@@ -86,7 +104,6 @@ public class PrintPerfDetailReportListDataPlugin extends AbstractReportListDataP
|
|
|
);
|
|
|
tempIndex++;
|
|
|
}
|
|
|
- withYearFields.print(true);
|
|
|
|
|
|
// 按分组字段聚合
|
|
|
GroupbyDataSet groupbyDataSet = withYearFields.groupBy(new String[]{
|
|
|
@@ -116,8 +133,145 @@ public class PrintPerfDetailReportListDataPlugin extends AbstractReportListDataP
|
|
|
}
|
|
|
IAppCache nckdPm = AppCache.get("nckd_pm");
|
|
|
|
|
|
+ DataSet annualPerfDetailQueryDataSet = groupbyDataSet.finish();
|
|
|
+
|
|
|
+// 获取近5年的岗位信息
|
|
|
+ DataSet positionDateSet = getPositions(fiveYearsAgo, currentYear,personIds);
|
|
|
+ String[] mainTableFieldNames = annualPerfDetailQueryDataSet.getRowMeta().getFieldNames();
|
|
|
+ String[] pivotFieldNames = positionDateSet.getRowMeta().getFieldNames();
|
|
|
+ annualPerfDetailQueryDataSet = annualPerfDetailQueryDataSet.join(positionDateSet, JoinType.LEFT)
|
|
|
+ .on(String.join(".", FormConstant.NCKD_PERSON, FormConstant.ID_KEY), String.join(".", FormConstant.EMPLOYEE_KEY, FormConstant.ID_KEY))
|
|
|
+ .select(mainTableFieldNames, pivotFieldNames).finish();
|
|
|
+
|
|
|
+ DataSet perfRankMgmtDataSet = getPerfRankMgmt(personIds, fiveYearsAgo, currentYear);
|
|
|
+
|
|
|
+ mainTableFieldNames = annualPerfDetailQueryDataSet.getRowMeta().getFieldNames();
|
|
|
+ pivotFieldNames = perfRankMgmtDataSet.getRowMeta().getFieldNames();
|
|
|
+ java.util.List<String> filteredFieldNames = new java.util.ArrayList<>();
|
|
|
+ for (String fieldName : pivotFieldNames) {
|
|
|
+ if (!"nckd_person.id".equals(fieldName)) {
|
|
|
+ filteredFieldNames.add(fieldName);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ pivotFieldNames = filteredFieldNames.toArray(new String[0]);
|
|
|
+ return annualPerfDetailQueryDataSet.join(perfRankMgmtDataSet, JoinType.LEFT)
|
|
|
+ .on(String.join(".", FormConstant.NCKD_PERSON, FormConstant.ID_KEY), String.join(".", FormConstant.NCKD_PERSON, FormConstant.ID_KEY))
|
|
|
+ .select(mainTableFieldNames, pivotFieldNames).finish();
|
|
|
+ }
|
|
|
+
|
|
|
+ private static DataSet getPerfRankMgmt(Set<Long> personIds, int beginYear, int endYear) {
|
|
|
+ // 年度绩效排名管理
|
|
|
+ QueryFieldBuilder perfRankMgmtFieldBuilder = QueryFieldBuilder.create()
|
|
|
+ .addIdNumberName(FormConstant.NCKD_PERSON)
|
|
|
+ .add("nckd_toprank")
|
|
|
+ .addGroup(new String[]{"nckd_perfrankmgmt"},"nckd_topranks","nckd_theyear");
|
|
|
+ QFilter perfRankMgmtFilter = new QFilter("nckd_isranking", "=", EnableEnum.YES.getCode())
|
|
|
+ .and(FormConstant.NCKD_PERSON, QCP.in, personIds)
|
|
|
+ .and("nckd_perfrankmgmt.nckd_theyear",QCP.large_equals, beginYear)
|
|
|
+ .and("nckd_perfrankmgmt.nckd_theyear",QCP.less_equals, endYear);
|
|
|
+ DataSet perfRankMgmtDataSet = QueryServiceHelper.queryDataSet("PrintPerfDetailReportListDataPlugin_perfRank", "nckd_perfrankmgmtentry", perfRankMgmtFieldBuilder.buildSelect(), new QFilter[]{perfRankMgmtFilter}, perfRankMgmtFieldBuilder.buildOrder(), 10000);
|
|
|
+ int tempIndex = 1;
|
|
|
+ for (int year = beginYear; year <= endYear; year++) {
|
|
|
+ //排名
|
|
|
+ String toprankField = "CASE WHEN nckd_perfrankmgmt.nckd_theyear = "+year+" THEN nckd_toprank ELSE null END";
|
|
|
+ perfRankMgmtDataSet = perfRankMgmtDataSet.addField(toprankField, "perfrankmgmt_topran_temp_" + tempIndex);
|
|
|
+ //总人数
|
|
|
+ String topranksField = "CASE WHEN nckd_perfrankmgmt.nckd_theyear = "+year+" THEN nckd_perfrankmgmt.nckd_topranks ELSE null END";
|
|
|
+ perfRankMgmtDataSet = perfRankMgmtDataSet.addField(topranksField, "perfrankmgmt_topranks_temp_" + tempIndex);
|
|
|
+ tempIndex++;
|
|
|
+ }
|
|
|
+ GroupbyDataSet groupbyDataSet = perfRankMgmtDataSet.groupBy(new String[]{String.join(".", FormConstant.NCKD_PERSON, FormConstant.ID_KEY)});
|
|
|
+ tempIndex = 1;
|
|
|
+ for (int year = beginYear; year <= endYear; year++) {
|
|
|
+ groupbyDataSet.max("perfrankmgmt_topran_temp_"+tempIndex, "perfrank_topran_"+tempIndex);
|
|
|
+ groupbyDataSet.max("perfrankmgmt_topranks_temp_"+tempIndex, "perfrank_topranks_"+tempIndex);
|
|
|
+ tempIndex++;
|
|
|
+ }
|
|
|
+ return groupbyDataSet.finish();
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取近N年的岗位信息
|
|
|
+ * 用于查询每个员工在指定年份范围内每年年底(12月31日)所在的有效岗位
|
|
|
+ * 当一个员工在同一年有多个有效岗位时,选择结束日期最晚的那个岗位
|
|
|
+ *
|
|
|
+ * @param beginYear 起始年份(包含)
|
|
|
+ * @param endYear 结束年份(包含)
|
|
|
+ * @return 包含每个员工每年岗位信息的数据集
|
|
|
+ */
|
|
|
+ private DataSet getPositions(int beginYear,int endYear,Set<Long> personIds){
|
|
|
+ // 查询全职任职关系,获取员工、岗位、任职起止时间等信息
|
|
|
+ QueryFieldBuilder queryFieldBuilder = QueryFieldBuilder.create()
|
|
|
+ .add(FormConstant.STARTDATE) // 任职开始日期
|
|
|
+ .add(FormConstant.ENDDATE) // 任职结束日期
|
|
|
+ .addIdNumberName(FormConstant.POSITION_KEY) // 岗位信息(ID、编码、名称)
|
|
|
+ .addIdNumberNameWithExtras(new String[]{FormConstant.EMPLOYEE_KEY},FormConstant.EMP_NUMBER_KEY) // 员工信息(ID、编码、姓名)+ 工号
|
|
|
+ .orderDesc(FormConstant.EMPLOYEE_KEY,FormConstant.STARTDATE); // 按员工ID和开始日期降序排列
|
|
|
+ // 筛选条件:只查询全职任职(IS_PRIMARY = YES)
|
|
|
+ QFilter qFilter = new QFilter(FormConstant.IS_PRIMARY,QCP.equals, EnableEnum.YES.getCode());
|
|
|
+ if(!personIds.isEmpty()){
|
|
|
+ qFilter = new QFilter(FormConstant.EMPLOYEE_KEY,QCP.in,personIds.toArray());
|
|
|
+ }
|
|
|
+ DataSet dataSet = QueryServiceHelper.queryDataSet("PrintPerfDetailReportListDataPlugin_EMPREL", FormConstant.HRPI_EMPPOSORGREL, queryFieldBuilder.buildSelect(), new QFilter[]{qFilter}, queryFieldBuilder.buildOrder(), 1000000);
|
|
|
+
|
|
|
+ int tempIndex = 1;
|
|
|
+ // 遍历指定年份范围,为每一年生成对应的岗位查询字段
|
|
|
+ for (int year = beginYear; year <= endYear; year++) {
|
|
|
+ // 获取每年12-31 23:59:59作为目标日期,用于判断该员工当年年底的岗位状态
|
|
|
+ Date targetDate = DateUtil.toDate(LocalDateTime.of(year, 12, 31, 23, 59, 59));
|
|
|
+ String targetDateStr = DateUtil.format(targetDate, DateUtil.NORM_DATE_PATTERN); // 使用日期格式而非日期时间格式
|
|
|
+
|
|
|
+ // 创建复合字段:如果在目标日期员工处于有效任职状态,则生成"结束日期|岗位名称"格式的字符串
|
|
|
+ // 这样使用GroupMaxStrFunction时,会根据结束日期选择最晚的那个任职记录
|
|
|
+ //为什么用“00000000000000|”,不用null。因为当GroupMaxStrFunction进行字符串比较时,有效的日期值(如'20231231235959|经济技术部部长')会比'00000000000000|'大,从而被正确选择
|
|
|
+ String combinedField = "CASE WHEN " + FormConstant.STARTDATE + " <= to_date('" + targetDateStr + "','yyyy-MM-dd') " +
|
|
|
+ "AND " + FormConstant.ENDDATE + " >= to_date('" + targetDateStr + "','yyyy-MM-dd') " +
|
|
|
+ "THEN CONCAT(TO_CHAR(" + FormConstant.ENDDATE + ", 'YYYYMMDDHHmmss'), '|', " +
|
|
|
+ String.join(".", FormConstant.POSITION_KEY, FormConstant.NAME_KEY) + ") ELSE '00000000000000|' END";
|
|
|
+
|
|
|
+ // 添加岗位复合字段(包含结束日期和岗位名称)
|
|
|
+ dataSet = dataSet.addField(combinedField, "position_temp_" + tempIndex);
|
|
|
+
|
|
|
+ // 同时创建仅包含日期部分的字段,用于后续解析时去除日期部分,只保留岗位名称
|
|
|
+ String dateField = "CASE WHEN " + FormConstant.STARTDATE + " <= to_date('" + targetDateStr + "','yyyy-MM-dd') " +
|
|
|
+ "AND " + FormConstant.ENDDATE + " >= to_date('" + targetDateStr + "','yyyy-MM-dd') " +
|
|
|
+ "THEN CONCAT(TO_CHAR(" + FormConstant.ENDDATE + ", 'YYYYMMDDHHmmss'),'|') ELSE '00000000000000|' END";
|
|
|
+ dataSet = dataSet.addField(dateField, "position_date_" + tempIndex);
|
|
|
+
|
|
|
+// dataSet = dataSet.addField("'"+year+"'", "position_year_" + tempIndex);
|
|
|
+ tempIndex++;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 行转列处理:按员工ID分组,使用GroupMaxStrFunction获取每个员工每年结束日期最晚的任职记录
|
|
|
+ tempIndex = 1;
|
|
|
+ GroupMaxStrFunction groupMaxStr = new GroupMaxStrFunction();
|
|
|
+ // 按员工ID进行分组聚合
|
|
|
+ GroupbyDataSet groupbyDataSet = dataSet.groupBy(new String[]{String.join(".", FormConstant.EMPLOYEE_KEY, FormConstant.ID_KEY)});
|
|
|
+ // 对每一年的数据进行聚合,获取结束日期最晚的任职记录
|
|
|
+ for (int year = beginYear; year <= endYear; year++) {
|
|
|
+ // 获取岗位复合字段的最大值(即结束日期最晚的记录)
|
|
|
+ groupbyDataSet.agg(new GroupMaxStrFunction(),"position_temp_"+tempIndex, "position_max_"+tempIndex);
|
|
|
+ // 同时获取日期字段的最大值,用于后续解析
|
|
|
+ groupbyDataSet.agg(groupMaxStr,"position_date_"+tempIndex, "position_date_max_"+tempIndex);
|
|
|
+ tempIndex++;
|
|
|
+ }
|
|
|
DataSet result = groupbyDataSet.finish();
|
|
|
- result.print( true);
|
|
|
+
|
|
|
+ // 解析复合字段,提取真正的岗位名称
|
|
|
+ // 通过去除日期部分(YYYYMMDDHHmmss|)来获取原始的岗位名称
|
|
|
+ tempIndex = 1;
|
|
|
+ for (int year = beginYear; year <= endYear; year++) {
|
|
|
+ final int currentYearIndex = year - beginYear + 1;
|
|
|
+ result = result.addField(
|
|
|
+ // 如果岗位字段有效(不为默认值'00000000000000|'),则去除日期部分,只保留岗位名称
|
|
|
+ "CASE WHEN position_max_" + tempIndex + " IS NOT NULL AND position_max_" + tempIndex + " != '00000000000000|' THEN " +
|
|
|
+ "REPLACE(position_max_" + tempIndex + ",position_date_max_"+tempIndex+",'') " + // 去除日期部分,得到岗位名称
|
|
|
+ "ELSE null END",
|
|
|
+ "position_" + tempIndex // 最终的岗位名称字段
|
|
|
+ );
|
|
|
+ tempIndex++;
|
|
|
+ }
|
|
|
return result;
|
|
|
}
|
|
|
|