2 Commits 3fc9f3b6e5 ... 0f1763d939

Autor SHA1 Mensaje Fecha
  彭佳杰 0f1763d939 Merge remote-tracking branch 'origin/master' hace 6 días
  彭佳杰 f65b538ed8 绩效结果导入功能 hace 6 días

+ 81 - 0
code/opmc/nckd-jxccl-opmc/src/main/java/nckd/jxccl/opmc/pm/plugin/form/ExaminProjectResultListPlugin.java

@@ -0,0 +1,81 @@
+package nckd.jxccl.opmc.pm.plugin.form;
+
+import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.dataentity.entity.DynamicObjectCollection;
+import kd.bos.entity.datamodel.events.PackageDataEvent;
+import kd.bos.form.CloseCallBack;
+import kd.bos.form.FormShowParameter;
+import kd.bos.form.ShowType;
+import kd.bos.form.events.BeforeCreateListColumnsArgs;
+import kd.bos.form.events.BeforeDoOperationEventArgs;
+import kd.bos.form.events.ClosedCallBackEvent;
+import kd.bos.form.operate.FormOperate;
+import kd.bos.list.ListColumn;
+import kd.bos.list.plugin.AbstractListPlugin;
+import kd.bos.orm.query.QCP;
+import kd.bos.orm.query.QFilter;
+import kd.bos.servicehelper.BusinessDataServiceHelper;
+import org.apache.commons.lang3.ObjectUtils;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * @ClassName: ExaminProjectResultListPlugin
+ * @Description: 绩效结果列表插件
+ * @Author: PJJ
+ * @Date: 2026/1/7 上午9:41
+ * @Version: 1.0
+ */
+public class ExaminProjectResultListPlugin extends AbstractListPlugin {
+    @Override
+    public void beforeDoOperation(BeforeDoOperationEventArgs args) {
+            super.beforeDoOperation(args);
+        FormOperate source = (FormOperate) args.getSource();
+        String operateKey = source.getOperateKey();
+        if (StringUtils.equals(operateKey, "import")) {
+            //打开自定义导入模板选择界面
+            FormShowParameter fsp = new FormShowParameter();
+            fsp.setFormId("nckd_kpi_import_select");
+            fsp.setShowTitle(false);
+            fsp.getOpenStyle().setShowType(ShowType.Modal);
+            fsp.setCustomParam("importplan", this.getView().getFormShowParameter().getCustomParam("importplan"));
+            fsp.setCustomParam("template", this.getView().getFormShowParameter().getCustomParam("template"));
+            fsp.setCloseCallBack(new CloseCallBack(this, "importData"));
+            this.getView().showForm(fsp);
+        }
+    }
+
+    @Override
+    public void closedCallBack(ClosedCallBackEvent e) {
+        super.closedCallBack(e);
+        String actionId = e.getActionId();
+        if( StringUtils.equals(actionId, "importData") ){
+            Object returnData = e.getReturnData();
+            if( ObjectUtils.isNotEmpty(returnData) ){
+                this.getView().invokeOperation("refresh");
+            }
+        }
+    }
+
+    @Override
+    public void beforeCreateListColumns(BeforeCreateListColumnsArgs args) {
+        super.beforeCreateListColumns(args);
+        //添加动态列
+        FormShowParameter formShowParameter = this.getView().getFormShowParameter();
+        Object customParam = formShowParameter.getCustomParam("");
+        DynamicObject dynamicObject = BusinessDataServiceHelper.loadSingle("", "", new QFilter[]{new QFilter("", QCP.equals, customParam)});
+        DynamicObjectCollection dynamicObjectCollection = dynamicObject.getDynamicObjectCollection("");
+        for (DynamicObject object : dynamicObjectCollection) {
+//            DynamicObject dynamicObject1 = object.getDynamicObject("");
+//            dynamicObject1.getString("");
+//            ListColumn listColumn = new ListColumn();
+//            listColumn.setListFieldKey("nckd_kpi_select");
+//            listColumn.set
+        }
+    }
+
+    @Override
+    public void packageData(PackageDataEvent e) {
+        super.packageData(e);
+        //组装动态列数据
+    }
+}

+ 494 - 0
code/opmc/nckd-jxccl-opmc/src/main/java/nckd/jxccl/opmc/pm/plugin/form/ImportKPISelectFormPlugin.java

@@ -0,0 +1,494 @@
+package nckd.jxccl.opmc.pm.plugin.form;
+
+import com.google.common.collect.Lists;
+import kd.bos.context.RequestContext;
+import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.dataentity.entity.DynamicObjectCollection;
+import kd.bos.dataentity.resource.ResManager;
+import kd.bos.entity.datamodel.IDataModel;
+import kd.bos.exception.KDBizException;
+import kd.bos.fileservice.FileItem;
+import kd.bos.fileservice.FileService;
+import kd.bos.fileservice.FileServiceFactory;
+import kd.bos.form.FormShowParameter;
+import kd.bos.form.IFormView;
+import kd.bos.form.MessageTypes;
+import kd.bos.form.control.Control;
+import kd.bos.form.control.Image;
+import kd.bos.form.control.Label;
+import kd.bos.form.control.events.UploadEvent;
+import kd.bos.form.control.events.UploadListener;
+import kd.bos.form.plugin.AbstractFormPlugin;
+import kd.bos.impt.ExcelReader;
+import kd.bos.impt.SheetHandler;
+import kd.bos.logging.Log;
+import kd.bos.logging.LogFactory;
+import kd.bos.orm.query.QCP;
+import kd.bos.orm.query.QFilter;
+import kd.bos.servicehelper.BusinessDataServiceHelper;
+import kd.bos.servicehelper.QueryServiceHelper;
+import kd.bos.servicehelper.operation.SaveServiceHelper;
+import kd.bos.servicehelper.org.OrgUnitServiceHelper;
+import kd.bos.url.UrlService;
+import kd.bos.util.FileNameUtils;
+import org.apache.commons.lang3.ObjectUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.FillPatternType;
+import org.apache.poi.ss.usermodel.Font;
+import org.apache.poi.ss.usermodel.IndexedColors;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.EventObject;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+/**
+ * @ClassName: ImportKPISelectFormPlugin
+ * @Description: 绩效结果导入模板选择界面表单插件
+ * @Author: PJJ
+ * @Date: 2026/1/7 上午10:24
+ * @Version: 1.0
+ */
+public class ImportKPISelectFormPlugin extends AbstractFormPlugin implements UploadListener {
+    private static final Log logger = LogFactory.getLog(ImportKPISelectFormPlugin.class);
+
+    @Override
+    public void afterBindData(EventObject e) {
+        super.afterBindData(e);
+        this.getView().setVisible(false, "nckd_filepanel");
+        this.getView().setVisible(true, "nckd_uploadpanel");
+    }
+
+    @Override
+    public void registerListener(EventObject e) {
+        super.registerListener(e);
+        this.addClickListeners("nckd_btndownload", "nckd_btnresetfile", "btnok");
+        Image img = this.getControl("nckd_btnupload");
+        img.addUploadListener(this);
+        Label label = this.getControl("nckd_labelap3");
+        label.addUploadListener(this);
+    }
+
+    @Override
+    public void click(EventObject evt) {
+        super.click(evt);
+        String key = ((Control) evt.getSource()).getKey();
+        switch (key) {
+            case "nckd_btndownload":
+                //模板下载
+                downloadExcel();
+                break;
+            case "nckd_btnresetfile":
+                //删除文件
+                this.deleteTemplateFile();
+                break;
+            case "btnok":
+                //回传数据
+                this.importData();
+                break;
+            default:
+                break;
+
+        }
+    }
+
+    @Override
+    public void upload(UploadEvent evt) {
+        UploadListener.super.upload(evt);
+        Object[] urls = evt.getUrls();
+        if (urls.length > 0) {
+            IFormView view = this.getView();
+            String url = (String) urls[0];
+            view.setVisible(true, "nckd_filepanel");
+            view.setVisible(false, "nckd_uploadpanel");
+            IDataModel model = this.getModel();
+            model.setValue("nckd_filename", url.substring(url.lastIndexOf(47) + 1));
+            String fullUrl = UrlService.getAttachmentFullUrl(url);
+            model.setValue("nckd_filepath", url);
+            model.setValue("nckd_fullpath", fullUrl);
+        }
+    }
+
+    private void deleteTemplateFile() {
+        this.getModel().setValue("nckd_filename", "");
+        this.getModel().setValue("nckd_filepath", "");
+        this.getView().setVisible(false, "nckd_filepanel");
+        this.getView().setVisible(true, "nckd_uploadpanel");
+    }
+
+    private void importData() {
+        String url = this.getModel().getDataEntity().getString("nckd_filepath");
+        FormShowParameter params = this.getView().getFormShowParameter();
+        //导入任务id
+//        Long importPlanId = params.getCustomParam("importplan");
+        //导入模板id
+        Long templateId = params.getCustomParam("template");
+        //绩效导入模板
+        DynamicObject template = BusinessDataServiceHelper.loadSingle(templateId, "nckd_import_kpi_template");
+        DynamicObjectCollection entry = template.getDynamicObjectCollection("nckd_outimptplentry");
+//        //绩效导入任务
+//        DynamicObject importPlan = BusinessDataServiceHelper.loadSingle(importPlanId, "nckd_importplan");
+        if (StringUtils.isBlank(url)) {
+            this.getView().showErrorNotification(ResManager.loadKDString("请先上传数据文件后操作。", "ImportKPISelectFormPlugin_1", "opmc-formplugin", new Object[0]));
+        } else {
+            try {
+//                HashMap<String, List<Map<Integer, String>>> returnMap = new HashMap<>();
+                //编码集合
+                List<Map<Integer, String>> dataHeadNumberList = new ArrayList<>();
+                //名称集合
+                List<Map<Integer, String>> dataHeadList = new ArrayList<>();
+                //数据集合
+                List<Map<Integer, String>> dataRowList = new ArrayList<>();
+                readExcel(url, dataHeadList, dataRowList, dataHeadNumberList);
+                //校验导入模板
+                String templateMsg = checkExcelTemplate(dataHeadList, entry, dataHeadNumberList);
+                //校验数据必录
+                String DataMsg = checkExcelData(dataHeadList, dataRowList);
+                String errMsg = templateMsg + "\n" + DataMsg;
+                if (!StringUtils.isNotBlank(errMsg)) {
+//                    returnMap.put("dataHeadNumberList", dataHeadNumberList);
+//                    returnMap.put("dataHeadList", dataHeadList);
+//                    returnMap.put("dataRowList", dataRowList);
+                    //写入数据
+                    Boolean b = saveData(dataHeadNumberList, dataRowList);
+                    if( b ){
+                        this.getView().returnDataToParent(true);
+                        this.getView().close();
+                    }else{
+                        this.getView().showTipNotification("数据保存错误请联系管理员!");
+                    }
+                } else {
+                    this.getView().showTipNotification(errMsg);
+                }
+            } catch (Exception e) {
+                String msg = ResManager.loadKDString("excel解析错误!", "ImportKPISelectFormPlugin_2", "opmc-formplugin", new Object[0]);
+                this.getView().showMessage(msg, e.getMessage(), MessageTypes.Default);
+            }
+        }
+    }
+
+    private Boolean saveData(List<Map<Integer, String>> dataHeadNumberList,List<Map<Integer, String>> dataRowList){
+        QFilter commonQFilter = new QFilter("enable", QCP.equals, "1");
+        commonQFilter.and("status",QCP.equals,"C");
+        //表头编码
+        Map<Integer, String> zeroExcelRow = dataHeadNumberList.get(0);
+        QFilter dimensionQFilter = new QFilter("number", QCP.in, zeroExcelRow.values());
+        //查询绩效导入任务
+        DynamicObject importPlan = BusinessDataServiceHelper.loadSingle(this.getView().getFormShowParameter().getCustomParam("importplan"), "nckd_importplan");
+        //考核维度项目
+        DynamicObject[] examineDimension = BusinessDataServiceHelper.load("nckd_examine_dimension", "id,number,name", new QFilter[]{dimensionQFilter, commonQFilter});
+        Map<String, DynamicObject> examineDimensionMap = Arrays.stream(examineDimension).collect(Collectors.toMap(i -> i.getString("number"), i -> i));
+
+        //汇总员工工号
+        List<String> userNumbers = dataRowList.stream().map(i -> i.get(1)).collect(Collectors.toList());
+        QFilter userQFilter = new QFilter("number", QCP.in, userNumbers);
+        DynamicObject[] users = BusinessDataServiceHelper.load("bos_user", "id,name,number", new QFilter[]{userQFilter, commonQFilter});
+        Map<String, DynamicObject> userMap = Arrays.stream(users).collect(Collectors.toMap(i -> i.getString("number"), i -> i,(existing, replacement) -> existing));
+
+        //汇总组织编码
+        List<String> deptNumbers = dataRowList.stream().map(i -> i.get(3)).collect(Collectors.toList());
+        QFilter deptQFilter = new QFilter("number", QCP.in, deptNumbers);
+        DynamicObject[] depts = BusinessDataServiceHelper.load("bos_org", "id,name,number", new QFilter[]{deptQFilter, commonQFilter});
+        Map<String, DynamicObject> deptMap = Arrays.stream(depts).collect(Collectors.toMap(i -> i.getString("number"), i -> i,(existing, replacement) -> existing));
+
+        //汇总岗位编码
+        List<String> postNumbers = dataRowList.stream().map(i -> i.get(5)).collect(Collectors.toList());
+        QFilter postQFilter = new QFilter("number", QCP.in, postNumbers);
+        DynamicObject[] posts = BusinessDataServiceHelper.load("bos_position", "id,name,number", new QFilter[]{postQFilter, commonQFilter});
+        Map<String, DynamicObject> postMap = Arrays.stream(posts).collect(Collectors.toMap(i -> i.getString("number"), i -> i,(existing, replacement) -> existing));
+
+        //查询绩效绩效结果-后续计算部门累计平均排名
+        HashMap<String, List<String>> userHistoryRank = new HashMap<>();
+        DynamicObject[] examinProjectResult = BusinessDataServiceHelper.load("nckd_examinproject_result","nckd_entryentity.nckd_examine_dimension,nckd_entryentity.nckd_result,nckd_org,nckd_user",new QFilter[]{new QFilter("nckd_user.number",QCP.in,userNumbers)});
+        for (DynamicObject object : examinProjectResult) {
+            //用户
+            DynamicObject user = object.getDynamicObject("nckd_user");
+            String userNumber = user.getString("number");
+            for (DynamicObject entry : object.getDynamicObjectCollection("nckd_entryentity")) {
+                //分录项目类型
+                DynamicObject dimension = entry.getDynamicObject("nckd_examine_dimension");
+                String dimensionNumber = dimension.getString("number");
+                ArrayList<String> rank = new ArrayList<>();
+                //判断是否排名
+                if( StringUtils.equals(dimensionNumber,"JT-00012") ){
+                    //添加历史成绩
+                    rank.add(entry.getString("nckd_result"));
+                }
+                userHistoryRank.put(userNumber,rank);
+            }
+
+        }
+        //1为姓名 3 为组织 5为岗位 6为排名单位 17为备注 12 为部门累计平均排名
+        ArrayList<DynamicObject> saveList = new ArrayList<>();
+        for (Map<Integer, String> integerStringMap : dataRowList) {
+            DynamicObject newData = BusinessDataServiceHelper.newDynamicObject("nckd_examinproject_result");
+            //设置默认数据
+            newData.set("enable","1");
+            newData.set("status","A");
+            newData.set("nckd_importplan",importPlan);
+            //姓名
+            newData.set("nckd_user",userMap.get(integerStringMap.get(1)));
+            //行政组织
+            newData.set("nckd_org",deptMap.get(integerStringMap.get(3)));
+            newData.set("group",deptMap.get(integerStringMap.get(3)));
+            //岗位
+            newData.set("nckd_postbase",postMap.get(integerStringMap.get(5)));
+            //排名单位
+            newData.set("nckd_rank_org",integerStringMap.get(6));
+            //备注
+            newData.set("nckd_remark",integerStringMap.get(17));
+
+            //增加分录数据
+            DynamicObjectCollection entry = newData.getDynamicObjectCollection("nckd_entryentity");
+            for (Integer i : integerStringMap.keySet()) {
+                //除1为姓名 3 为组织 5为岗位 6为排名单位 17为备注 12 为部门累计平均排名外全部存入分录
+                if( i != 1 && i != 3 && i != 5 && i != 6 && i != 17 ){
+                    DynamicObject entryRow = entry.addNew();
+                    entryRow.set("nckd_examine_dimension",examineDimensionMap.get(zeroExcelRow.get(i)));
+                    entryRow.set("nckd_result",integerStringMap.get(i));
+                }
+                //计算部门累计平均排名
+                if( i == 12 ){
+                    //本次导入排名
+                    String rank = integerStringMap.get(11);
+                    //用户历史数据排名
+                    List<String> userHistory = userHistoryRank.get(integerStringMap.get(1));
+                    if( ObjectUtils.isNotEmpty(userHistory) ){
+                        //计算
+                        int sum = userHistory.stream().mapToInt(Integer::parseInt).sum();
+                        sum += Integer.parseInt(rank);
+                        int finalRank = sum / (userHistory.size() + 1);
+                        newData.set("nckd_cumulativeranking",finalRank);
+                    }else{
+                        newData.set("nckd_cumulativeranking",Integer.parseInt(rank));
+                    }
+                }
+            }
+            saveList.add(newData);
+        }
+        Object[] save = SaveServiceHelper.save(saveList.toArray(new DynamicObject[0]));
+        if(ObjectUtils.isNotEmpty(save)){
+            return true;
+        }else{
+            return false;
+        }
+    }
+
+    /**
+     * 校验导入模板
+     * @param dataHeadList 模板表头数据
+     * @param entry 导入模板基础资料分录数据
+     * @return 错误提示
+     */
+    @NotNull
+    private String checkExcelTemplate(List<Map<Integer, String>> dataHeadList, DynamicObjectCollection entry, List<Map<Integer, String>> dataHeadNumberList) {
+        //根据导入模板基础资料 判断excel表格表头数据是否正确
+        List<String> unMustInputRowData = entry.stream().filter(i -> !i.getBoolean("nckd_mustinput")).map(i -> i.getString("nckd_examinename")).collect(Collectors.toList());
+        List<String> mustInputRowData = entry.stream().filter(i -> i.getBoolean("nckd_mustinput")).map(i -> "*" + i.getString("nckd_examinename")).collect(Collectors.toList());
+        //编码
+        List<String> numberData = entry.stream().map(i -> i.getString("nckd_examinenumber")).collect(Collectors.toList());
+        unMustInputRowData.addAll(mustInputRowData);
+        List<String> excelHeadList = dataHeadList.stream().flatMap(map -> map.values().stream()).filter(Objects::nonNull).filter(str -> !str.trim().isEmpty()).collect(Collectors.toList());
+        if (unMustInputRowData.size() != excelHeadList.size() || !excelHeadList.containsAll(unMustInputRowData) || !dataHeadNumberList.get(0).values().containsAll(numberData)) {
+            return "导入模板格式错误,请上传正确格式的数据模板!";
+        }
+        return "";
+    }
+
+    private String checkExcelData(List<Map<Integer, String>> dataHeadList, List<Map<Integer, String>> dataRowList) {
+        boolean check = false;
+        //表头数据
+        Map<Integer, String> integerStringMap = dataHeadList.get(0);
+        //行数据
+        for (Map<Integer, String> stringMap : dataRowList) {
+            for (Integer i : integerStringMap.keySet()) {
+                //表头
+                String head = integerStringMap.get(i);
+                //行数据
+                String value = stringMap.get(i);
+                //表头必录且行数据为空
+                if (StringUtils.isBlank(value) && head.contains("*")) {
+                    check = true;
+                }
+            }
+        }
+        if (check) {
+            return "请填写必录项!";
+        } else {
+            return "";
+        }
+    }
+
+    /**
+     * 解析导入模板excel数据
+     * @param url excel文件的url
+     * @param dataHeadList 待读取表头数据
+     * @param dataRowList 待读取表格数据
+     * @return excel数据
+     * @throws IOException
+     */
+    private Map<String, Object> readExcel(String url, List<Map<Integer, String>> dataHeadList, List<Map<Integer, String>> dataRowList, List<Map<Integer, String>> dataHeadNumberList) throws IOException {
+        InputStream inputStream = FileServiceFactory.getAttachmentFileService().getInputStream(url);
+        try {
+            new ExcelReader().read(inputStream, new SheetHandler() {
+                @Override
+                public void handleRow(ParsedRow row) {
+                    if (row.getRowNum() == 0) {
+                        dataHeadNumberList.add(row.getData());
+                    } else if (row.getRowNum() == 1) {
+                        dataHeadList.add(row.getData());
+                    } else {
+                        dataRowList.add(row.getData());
+
+                    }
+                }
+            });
+        } catch (Exception e) {
+            throw new KDBizException("读取EXCEL文件失败,请联系管理员!");
+        } finally {
+            inputStream.close();
+        }
+        return null;
+    }
+
+    private void downloadExcel() {
+        // 创建工作簿(xlsx格式)
+        Workbook workbook = new XSSFWorkbook();
+
+        // 创建Sheet
+        Sheet sheet = workbook.createSheet();
+
+        // 创建样式
+        CellStyle headerStyle = workbook.createCellStyle();
+        headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+        headerStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
+
+        Font headerFont = workbook.createFont();
+        headerFont.setBold(true);
+        headerFont.setFontHeightInPoints((short) 12);
+        headerFont.setColor(IndexedColors.RED.getIndex());
+        headerStyle.setFont(headerFont);
+
+        //导入任务id
+        Long importPlanId = this.getView().getFormShowParameter().getCustomParam("importplan");
+        //导入模板id
+        Long templateId = this.getView().getFormShowParameter().getCustomParam("template");
+
+        //绩效导入模板
+        DynamicObject template = BusinessDataServiceHelper.loadSingle(templateId, "nckd_import_kpi_template");
+        String excelName = template.getString("name");
+        DynamicObjectCollection entry = template.getDynamicObjectCollection("nckd_outimptplentry");
+        //绩效导入任务
+        DynamicObject importPlan = BusinessDataServiceHelper.loadSingle(importPlanId, "nckd_importplan");
+
+
+        // 创建表头
+        Row zeroRow = sheet.createRow(0);
+        Row headerRow = sheet.createRow(1);
+        for (int i = 0; i < entry.size(); i++) {
+            //设置表头编码
+            Cell zeroRowCell = zeroRow.createCell(i);
+            String examineNumber = entry.get(i).getString("nckd_examinenumber");
+            zeroRowCell.setCellValue(examineNumber);
+            zeroRowCell.setCellStyle(headerStyle);
+
+            Cell headerRowCell = headerRow.createCell(i);
+            //是否必录
+            boolean mustInput = entry.get(i).getBoolean("nckd_mustinput");
+            //excel表头列名
+            String headName = entry.get(i).getString("nckd_examinename");
+            String cellValue = mustInput ? "*" + headName : headName;
+            headerRowCell.setCellValue(cellValue);
+            headerRowCell.setCellStyle(headerStyle);
+            //设置列宽
+            sheet.setColumnWidth(i, (examineNumber.length() + 5) * 256 * 2);
+        }
+
+
+        //获取模板使用组织
+        DynamicObject orgObj = template.getDynamicObject("nckd_orgfield");
+        //获取下级组织id
+        List<Long> subOrgIds = OrgUnitServiceHelper.getAllSubordinateOrgs(1L, Collections.singletonList(orgObj.getLong("id")), true);
+
+        //构建查询条件
+        QFilter qFilter = new QFilter("entryentity.dpt.id", QCP.in, subOrgIds);
+        qFilter.and("entryentity.ispartjob", QCP.equals, false);
+        qFilter.and("status", QCP.equals, "C");
+        qFilter.and("enable", QCP.equals, "1");
+        //查询组织对应人员数据
+        DynamicObjectCollection query = QueryServiceHelper.query("bos_user",
+                "id,name,number,entryentity.dpt.name as dptname,entryentity.dpt.number as dptnumber," +
+                        "entryentity.post.name as positionname,entryentity.post.number as positionnumber", qFilter.toArray());
+        //添加行数据
+        for (int i = 0; i < query.size(); i++) {
+            DynamicObject user = query.get(i);
+            //创建行数据
+            Row row = sheet.createRow(i + 2);
+            //设置姓名
+            Cell nameCell = row.createCell(0);
+            nameCell.setCellValue(user.getString("name"));
+            //设置工号
+            Cell numberCell = row.createCell(1);
+            numberCell.setCellValue(user.getString("number"));
+            //设置行政组织
+            Cell dptNameCell = row.createCell(2);
+            dptNameCell.setCellValue(user.getString("dptname"));
+            //设置行政组织编码
+            Cell dptNumberCell = row.createCell(3);
+            dptNumberCell.setCellValue(user.getString("dptnumber"));
+            //设置岗位
+            Cell positionNameCell = row.createCell(4);
+            positionNameCell.setCellValue(user.getString("positionname"));
+            //设置岗位
+            Cell positionNumberCell = row.createCell(5);
+            positionNumberCell.setCellValue(user.getString("positionnumber"));
+            //设置年份
+            Cell yearCell = row.createCell(7);
+            Calendar calendar = Calendar.getInstance();
+            calendar.setTime(importPlan.getDate("nckd_year"));
+            int currentYear = calendar.get(Calendar.YEAR);
+            yearCell.setCellValue(currentYear);
+            //设置周期
+            Cell monthCell = row.createCell(8);
+            monthCell.setCellValue(importPlan.getInt("nckd_month"));
+        }
+
+        // 保存文件
+        String fileName = excelName + ".xlsx";
+        try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
+            workbook.write(outputStream);
+            ByteArrayInputStream inStream = new ByteArrayInputStream(outputStream.toByteArray());
+            FileService fileService = FileServiceFactory.getAttachmentFileService();
+            RequestContext requestContext = RequestContext.get();
+            String pathParam = FileNameUtils.getAttachmentFileName(requestContext.getTenantId(), requestContext.getAccountId(), "salaryFile", fileName);
+            String path = fileService.upload(new FileItem(fileName, pathParam, inStream));
+            String url = UrlService.getAttachmentFullUrl(path);
+            this.getView().download(url);
+        } catch (IOException e) {
+            e.printStackTrace();
+        } finally {
+            try {
+                workbook.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+}

+ 46 - 0
code/opmc/nckd-jxccl-opmc/src/main/java/nckd/jxccl/opmc/pm/plugin/form/ImportKpiImportTemplateFormPlugin.java

@@ -0,0 +1,46 @@
+package nckd.jxccl.opmc.pm.plugin.form;
+
+import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.dataentity.entity.DynamicObjectCollection;
+import kd.bos.form.plugin.AbstractFormPlugin;
+import kd.bos.orm.query.QCP;
+import kd.bos.orm.query.QFilter;
+import kd.bos.servicehelper.BusinessDataServiceHelper;
+
+import java.util.EventObject;
+
+/**
+ * @ClassName: ImportKpiImportTemplateFormPlugin
+ * @Description: 绩效结果导入模板表单插件
+ * @Author: PJJ
+ * @Date: 2026/1/6 下午5:13
+ * @Version: 1.0
+ */
+public class ImportKpiImportTemplateFormPlugin extends AbstractFormPlugin{
+    @Override
+    public void afterCreateNewData(EventObject e) {
+        super.afterCreateNewData(e);
+        //设置默认数据
+        createDefaultRow();
+    }
+
+    private void createDefaultRow() {
+        //查询考核维度项目 中 非考核项目数据
+        QFilter qFilter = new QFilter("nckd_check", QCP.equals, false);
+        qFilter.and("status",QCP.equals,"C");
+        qFilter.and("enable",QCP.equals,"1");
+        DynamicObject[] examineDimension = BusinessDataServiceHelper.load("nckd_examine_dimension", "number,name,nckd_check,nckd_datatype", qFilter.toArray(),"number");
+        //赋值非考核项目分录行
+        DynamicObjectCollection entryEntity = this.getModel().getEntryEntity("nckd_outimptplentry");
+        for (DynamicObject obj : examineDimension) {
+            DynamicObject row = entryEntity.addNew();
+            row.set("nckd_textfield",">>");
+            row.set("nckd_examine_dimension",obj);
+            row.set("nckd_examinename",obj.getString("name"));
+            row.set("nckd_examineid",obj.getLong("id"));
+            row.set("nckd_examinenumber",obj.getString("number"));
+            row.set("nckd_datatype",obj.getDynamicObject("nckd_datatype"));
+            row.set("nckd_check",false);
+        }
+    }
+}

+ 67 - 0
code/opmc/nckd-jxccl-opmc/src/main/java/nckd/jxccl/opmc/pm/plugin/form/ImportPlanListPlugin.java

@@ -0,0 +1,67 @@
+package nckd.jxccl.opmc.pm.plugin.form;
+
+import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.dataentity.resource.ResManager;
+import kd.bos.entity.datamodel.ListSelectedRow;
+import kd.bos.form.ShowType;
+import kd.bos.form.events.ClosedCallBackEvent;
+import kd.bos.form.events.HyperLinkClickArgs;
+import kd.bos.form.events.HyperLinkClickEvent;
+import kd.bos.list.IListView;
+import kd.bos.list.ListShowParameter;
+import kd.bos.list.plugin.AbstractListPlugin;
+import kd.bos.orm.query.QCP;
+import kd.bos.orm.query.QFilter;
+import kd.bos.servicehelper.BusinessDataServiceHelper;
+import org.apache.commons.lang3.ObjectUtils;
+import org.apache.commons.lang3.StringUtils;
+
+import java.text.MessageFormat;
+
+/**
+ * @ClassName: ImportPlanListPlugin
+ * @Description: 绩效导入任务列表插件
+ * @Author: PJJ
+ * @Date: 2026/1/6 下午6:11
+ * @Version: 1.0
+ */
+public class ImportPlanListPlugin extends AbstractListPlugin {
+
+    @Override
+    public void billListHyperLinkClick(HyperLinkClickArgs args) {
+        super.billListHyperLinkClick(args);
+        HyperLinkClickEvent hyperLinkClickEvent = args.getHyperLinkClickEvent();
+        String fieldName = hyperLinkClickEvent.getFieldName();
+        if (StringUtils.equals(fieldName, "name")) {
+            //拦截导入任务超链接事件
+            args.setCancel(true);
+            IListView listView = (IListView) this.getView();
+            ListSelectedRow selectRow = listView.getCurrentSelectedRowInfo();
+            Long importTaskId = (Long) selectRow.getPrimaryKeyValue();
+            //打开绩效结果列表
+            this.openTempDataPage(importTaskId);
+        }
+    }
+
+    private void openTempDataPage(Long ImportPlanId) {
+        DynamicObject data = BusinessDataServiceHelper.loadSingle(ImportPlanId,"nckd_importplan");
+        if (ObjectUtils.isNotEmpty(data)) {
+            ListShowParameter parameter = new ListShowParameter();
+            parameter.getOpenStyle().setShowType(ShowType.MainNewTabPage);
+            parameter.setBillFormId("nckd_examinproject_result");
+            parameter.setFormId("bos_templatetreelist");
+            String caption = MessageFormat.format("绩效导入任务 - {0}", data.getString("name"));
+            parameter.setCaption(caption);
+            parameter.setCustomParam("importplan", ImportPlanId);
+            parameter.setCustomParam("template", data.getDynamicObject("nckd_import_kpi_template").getPkValue() );
+            parameter.getListFilterParameter().getQFilters().add(new QFilter("nckd_importplan", QCP.equals, ImportPlanId));
+            String pageId = this.getView().getMainView() == null ? this.getView().getPageId() : this.getView().getMainView().getPageId();
+            pageId = pageId + '_' + ImportPlanId;
+            parameter.setPageId(pageId);
+            this.getView().showForm(parameter);
+        } else {
+            String msg = ResManager.loadKDString("数据已不存在。", "ImportPlan_0", "opmc-formplugin");
+            this.getView().showErrorNotification(msg);
+        }
+    }
+}

+ 58 - 0
code/opmc/nckd-jxccl-opmc/src/main/java/nckd/jxccl/opmc/pm/plugin/operate/ExaminProjectResultOpPlugin.java

@@ -0,0 +1,58 @@
+package nckd.jxccl.opmc.pm.plugin.operate;
+
+import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.dataentity.entity.DynamicObjectCollection;
+import kd.bos.entity.plugin.AbstractOperationServicePlugIn;
+import kd.bos.entity.plugin.PreparePropertysEventArgs;
+import kd.bos.entity.plugin.args.BeforeOperationArgs;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * @ClassName: ExaminProjectResultOpPlugin
+ * @Description: 绩效结果操作插件
+ * @Author: PJJ
+ * @Date: 2026/1/9 上午11:16
+ * @Version: 1.0
+ */
+public class ExaminProjectResultOpPlugin extends AbstractOperationServicePlugIn {
+    @Override
+    public void onPreparePropertys(PreparePropertysEventArgs e) {
+        super.onPreparePropertys(e);
+        e.getFieldKeys().addAll(this.billEntityType.getAllFields().keySet());
+    }
+
+    @Override
+    public void beforeExecuteOperationTransaction(BeforeOperationArgs e) {
+        super.beforeExecuteOperationTransaction(e);
+        String operationKey = e.getOperationKey();
+        if (StringUtils.equals(operationKey, "submit")) {
+            DynamicObject[] dataEntities = e.getDataEntities();
+            //提示语句
+            StringBuffer sb = new StringBuffer();
+            sb.append("以下员工排名为空,请填写备注!\n");
+            Boolean submit = false;
+            for (DynamicObject baseData : dataEntities) {
+                String userName = baseData.getLocaleString("nckd_user.name").getLocaleValue_zh_CN();
+                //备注
+                String remark = baseData.getString("nckd_remark");
+                DynamicObjectCollection entry = baseData.getDynamicObjectCollection("nckd_entryentity");
+                //排名
+                List<String> collect = entry.stream().filter(i -> i.getString("nckd_examine_dimension.number").equals("JT-00012")).map(i -> i.getString("nckd_result")).collect(Collectors.toList());
+                //排名为空且备注未填写时校验
+                if(StringUtils.isBlank(collect.get(0)) && StringUtils.isBlank(remark)){
+                    submit = true;
+                    sb.append(userName).append(";");
+                }
+            }
+            if( submit ){
+                e.setCancel(true);
+                e.setCancelMessage(sb.toString());
+            }
+        }
+    }
+}