Pārlūkot izejas kodu

Merge remote-tracking branch 'origin/master'

彭佳杰 2 dienas atpakaļ
vecāks
revīzija
9969e64511
13 mainītis faili ar 1188 papildinājumiem un 11 dzēšanām
  1. 4 6
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hdm/plugin/operate/transfer/CancelContractAfterEffectOpPlugin.java
  2. 37 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hspm/common/TitleSkillAppointConstant.java
  3. 101 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hspm/plugin/form/tsapp/impt/TitleSkillAppointEntryImportPlugin.java
  4. 204 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hspm/plugin/form/tsapp/validator/TitleSkillAppointEntryImportValidator.java
  5. 57 1
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hspm/plugin/operate/tsapp/TitleSkillAppointEffectOpPlugin.java
  6. 53 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hspm/plugin/operate/tsapp/validator/TitleSkillAppointEmployeeValidator.java
  7. 51 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hspm/plugin/operate/tsapp/validator/TitleSkillAppointStartDateValidator.java
  8. 5 4
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/tsc/plugin/form/AnnounceDowndateFormPlugin.java
  9. 1 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/tsc/plugin/form/AnnouncementsListPlugin.java
  10. 165 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/tsc/plugin/form/AnnouncementsMobListPlugin.java
  11. 319 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/tsc/plugin/mob/common/FormModel.java
  12. 77 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/tsc/plugin/mob/common/MainPageModel.java
  13. 114 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/tsc/plugin/mob/common/TscNaviBarPlugin.java

+ 4 - 6
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hdm/plugin/operate/transfer/CancelContractAfterEffectOpPlugin.java

@@ -23,8 +23,6 @@ import kd.hr.hbp.business.servicehelper.HRMServiceHelper;
 import kd.hr.hbp.common.api.HrApiResponse;
 import kd.hr.hbp.common.util.HRObjectUtils;
 import kd.hr.hbp.common.util.HRStringUtils;
-import kd.hr.hlcm.common.enums.ContractCategoryEnum;
-import kd.hr.hlcm.common.enums.PostypeEnum;
 import kd.sdk.hr.hdm.common.enums.reg.RegBillStatusEnum;
 import kd.sdk.hr.hlcm.common.enums.BusinessTypeEnum;
 import nckd.jxccl.base.common.utils.QueryFieldBuilder;
@@ -262,10 +260,10 @@ public class CancelContractAfterEffectOpPlugin extends AbstractOperationServiceP
             DynamicObject posType = signBill.getDynamicObject(TransferApplyBillConstant.POSTYPE);
             if (!HRObjectUtils.isEmpty(posType)) {
                 Object posTypeId = posType.getPkValue();
-                if (Objects.equals(posTypeId, PostypeEnum.FULL.getCombKey())) {
-                    signBill.set(TransferApplyBillConstant.CONTRACTCATEGORY_KEY, ContractCategoryEnum.MAIN.getCombKey());
-                } else if (Objects.equals(posTypeId, PostypeEnum.EXPATRIATE.getCombKey())) {
-                    signBill.set(TransferApplyBillConstant.CONTRACTCATEGORY_KEY, ContractCategoryEnum.OUTER.getCombKey());
+                if (Objects.equals(posTypeId, 1010L)) {
+                    signBill.set(TransferApplyBillConstant.CONTRACTCATEGORY_KEY, "1");
+                } else if (Objects.equals(posTypeId, 1040L)) {
+                    signBill.set(TransferApplyBillConstant.CONTRACTCATEGORY_KEY, "2");
                 } else {
                     log.warn("posTypeId|{} is not 1010 or 1040", posTypeId);
                 }

+ 37 - 0
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hspm/common/TitleSkillAppointConstant.java

@@ -10,6 +10,43 @@ import nckd.jxccl.base.common.constant.FormConstant;
 public class TitleSkillAppointConstant extends FormConstant {
     /** 员工职称技能聘任-实体标识 */
     public static final String NCKD_HRPI_TITLSKLAPP_ENTITY = "nckd_hrpi_titlsklapp";
+    /** 职称技能聘任单-实体标识 */
+    public static final String NCKD_JOB_TITLE_SKILL_APPT_ENTITY = "nckd_job_title_skill_appt";
+    /** 职称技能聘任键值映射 */
+    public static final String NCKD_TS_APPOINT_KVM_ENTITY = "nckd_ts_appoint_kvm";
+    /** 员工职称信息-实体标识 */
+    public static final String NCKD_HRPI_NTITLE_ENTITY = "nckd_hrpi_ntitle";
+    /** 员工技能信息-实体标识 */
+    public static final String NCKD_HRPI_EMPSKILL_ENTITY = "nckd_hrpi_empskill";
+    /** 职称资格级别技能等级-实体标识 */
+    public static final String NCKD_HBSS_TITLESKLRK_ENTITY = "nckd_hbss_titlesklrk";
+
+    /** 聘任类型 */
+    public static final String NCKD_TYPE_KEY = "nckd_type";
+    /** 职称信息 */
+    public static final String NCKD_NTITLE_KEY = "nckd_ntitle";
+    /** 技能信息 */
+    public static final String NCKD_EMPSKILL_KEY = "nckd_empskill";
+    /** 聘任职称/技能等级 */
+    public static final String NCKD_A_TITLESKLRK_KEY = "nckd_a_titlesklrk";
+    /** 职务名称 */
+    public static final String NCKD_POSTNM_KEY = "nckd_postnm";
+    /** 是否虚拟 */
+    public static final String NCKD_ISVIRTUAL_KEY = "nckd_isvirtual";
+    /** 虚拟聘任职称/技能等级 */
+    public static final String NCKD_VIRTITLESKLRK_KEY = "nckd_virtitlesklrk";
+    /** 虚拟聘任职务名称 */
+    public static final String NCKD_VIRTPOSTNM_KEY = "nckd_virtpostnm";
+
+    /** 职称名称(资格名称) */
+    public static final String NCKD_TITLE_KEY = "nckd_title";
+    /** 资格级别 */
+    public static final String NCKD_QUALLEVEL_KEY = "nckd_quallevel";
+
+    /** 资格名称 */
+    public static final String NCKD_QUALINAME_KEY = "nckd_qualiname";
+    /** 职业技能等级 */
+    public static final String NCKD_SKILLLEVEL_KEY = "nckd_skilllevel";
 
 
 }

+ 101 - 0
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hspm/plugin/form/tsapp/impt/TitleSkillAppointEntryImportPlugin.java

@@ -0,0 +1,101 @@
+package nckd.jxccl.hr.hspm.plugin.form.tsapp.impt;
+
+import com.alibaba.fastjson.JSONObject;
+import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.dataentity.metadata.IDataEntityProperty;
+import kd.bos.entity.EntityMetadataCache;
+import kd.bos.entity.EntryType;
+import kd.bos.entity.ValueMapItem;
+import kd.bos.entity.property.ComboProp;
+import kd.bos.entity.property.EntryProp;
+import kd.bos.logging.Log;
+import kd.bos.logging.LogFactory;
+import kd.hr.hbp.common.util.HRObjectUtils;
+import kd.hrmp.hies.multientry.common.dto.EntryImptBillData;
+import kd.hrmp.hies.multientry.common.enu.EntryValidatorEnum;
+import kd.hrmp.hies.multientry.common.plugin.impt.BeforeBackFillDataEventArgs;
+import kd.hrmp.hies.multientry.common.plugin.impt.BeforeInitValidatorEventArgs;
+import kd.hrmp.hies.multientry.common.plugin.impt.BeforeValidateEventArgs;
+import kd.hrmp.hies.multientry.common.plugin.impt.HREntryImportPlugin;
+import nckd.jxccl.base.hrpi.helper.EmpPosOrgRelHelper;
+import nckd.jxccl.hr.hspm.common.TitleSkillAppointConstant;
+import nckd.jxccl.hr.hspm.plugin.form.tsapp.validator.TitleSkillAppointEntryImportValidator;
+
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ *
+ * @entity:
+ * @author: jtd
+ * @date: 2026/1/14 18:36
+ */
+public class TitleSkillAppointEntryImportPlugin implements HREntryImportPlugin {
+    private static final Log log = LogFactory.getLog(TitleSkillAppointEntryImportPlugin.class);
+
+    @Override
+    public void beforeInitValidator(BeforeInitValidatorEventArgs args) {
+        HREntryImportPlugin.super.beforeInitValidator(args);
+
+        args.setValidator(EntryValidatorEnum.CUSTOM_VALIDATOR, new TitleSkillAppointEntryImportValidator());
+    }
+
+    @Override
+    public void beforeValidate(BeforeValidateEventArgs args) {
+        HREntryImportPlugin.super.beforeValidate(args);
+
+        // 获取分录属性名称
+        Map<String, IDataEntityProperty> entryFields = ((EntryType) ((EntryProp) args.getDataModel().getDataEntityType().getProperty(TitleSkillAppointConstant.NCKD_ENTRYENTITY)).getItemType()).getFields();
+        Map<String, String> entryFieldNameMap = entryFields.values().stream().collect(Collectors.toMap(IDataEntityProperty::getName, entryProp -> entryProp.getDisplayName().getLocaleValue()));
+        args.getCustomParams().put("entryFieldNameMap", entryFieldNameMap);
+
+        // 获取聘任类型下拉值
+        ComboProp typeComboProp = (ComboProp) entryFields.get(TitleSkillAppointConstant.NCKD_TYPE_KEY);
+        Map<String, String> typeItemMap = typeComboProp.getComboItems().stream().collect(Collectors.toMap(ValueMapItem::getValue, comboItem -> comboItem.getName().getLocaleValue()));
+        args.getCustomParams().put(TitleSkillAppointConstant.NCKD_TYPE_KEY, typeItemMap);
+
+        // 获取员工职称信息属性名称
+        Map<String, IDataEntityProperty> empNtileFields = EntityMetadataCache.getDataEntityType(TitleSkillAppointConstant.NCKD_HRPI_NTITLE_ENTITY).getAllFields();
+        Map<String, String> empNtitleFieldNameMap = empNtileFields.values().stream().collect(Collectors.toMap(IDataEntityProperty::getName, entryProp -> entryProp.getDisplayName().getLocaleValue()));
+        args.getCustomParams().put("empNtitleFieldNameMap", empNtitleFieldNameMap);
+
+        // 获取员工技能信息属性名称
+        Map<String, IDataEntityProperty> empSkillFields = EntityMetadataCache.getDataEntityType(TitleSkillAppointConstant.NCKD_HRPI_EMPSKILL_ENTITY).getAllFields();
+        Map<String, String> empSkillFieldNameMap = empSkillFields.values().stream().collect(Collectors.toMap(IDataEntityProperty::getName, entryProp -> entryProp.getDisplayName().getLocaleValue()));
+        args.getCustomParams().put("empSkillFieldNameMap", empSkillFieldNameMap);
+    }
+
+    @Override
+    public void beforeBackFillData(BeforeBackFillDataEventArgs args) {
+        HREntryImportPlugin.super.beforeBackFillData(args);
+
+        Set<Long> employeeIds = args.getRowData().stream().map(billData -> billData.getData().getJSONObject(billData.getEntryKey()).getJSONObject(TitleSkillAppointConstant.NCKD_EMPLOYEE).getLongValue(TitleSkillAppointConstant.ID_KEY)).collect(Collectors.toSet());
+        Map<Long, DynamicObject> empPosOrgRel = EmpPosOrgRelHelper.queryEmpPosOrgRelByEmployeesMap(employeeIds);
+
+        for (EntryImptBillData billData : args.getRowData()) {
+            JSONObject entryData = billData.getData().getJSONObject(billData.getEntryKey());
+            Long employeeId = entryData.getJSONObject(TitleSkillAppointConstant.NCKD_EMPLOYEE).getLongValue(TitleSkillAppointConstant.ID_KEY);
+
+            DynamicObject empPosOrgRelDy = empPosOrgRel.get(employeeId);
+            if (!HRObjectUtils.isEmpty(empPosOrgRelDy)) {
+                JSONObject adminOrg = new JSONObject();
+                adminOrg.put(TitleSkillAppointConstant.ID_KEY, empPosOrgRelDy.getLong(String.join(".", TitleSkillAppointConstant.ADMINORG, TitleSkillAppointConstant.ID_KEY)));
+                entryData.put(TitleSkillAppointConstant.NCKD_ADMINORG, adminOrg);
+
+                JSONObject position = new JSONObject();
+                position.put(TitleSkillAppointConstant.ID_KEY, empPosOrgRelDy.getLong(String.join(".", TitleSkillAppointConstant.POSITION_KEY, TitleSkillAppointConstant.ID_KEY)));
+                entryData.put(TitleSkillAppointConstant.NCKD_POSITION_KEY, position);
+            }
+
+            if (!Objects.isNull(entryData.get(TitleSkillAppointConstant.NCKD_VIRTITLESKLRK_KEY)) || !Objects.isNull(entryData.get(TitleSkillAppointConstant.NCKD_VIRTPOSTNM_KEY))) {
+                entryData.put(TitleSkillAppointConstant.NCKD_ISVIRTUAL_KEY, true);
+            } else {
+                entryData.put(TitleSkillAppointConstant.NCKD_ISVIRTUAL_KEY, false);
+                entryData.put(TitleSkillAppointConstant.NCKD_VIRTITLESKLRK_KEY, null);
+                entryData.put(TitleSkillAppointConstant.NCKD_VIRTPOSTNM_KEY, null);
+            }
+        }
+    }
+}

+ 204 - 0
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hspm/plugin/form/tsapp/validator/TitleSkillAppointEntryImportValidator.java

@@ -0,0 +1,204 @@
+package nckd.jxccl.hr.hspm.plugin.form.tsapp.validator;
+
+import com.alibaba.fastjson.JSONObject;
+import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.entity.EntityMetadataCache;
+import kd.bos.orm.query.QCP;
+import kd.bos.orm.query.QFilter;
+import kd.bos.util.CollectionUtils;
+import kd.hr.hbp.business.servicehelper.HRBaseServiceHelper;
+import kd.hr.hbp.common.util.HRStringUtils;
+import kd.hr.impt.common.dto.ImportLog;
+import kd.hr.impt.common.dto.ImportRowErrorLog;
+import kd.hr.impt.common.enu.ValidatorOrderEnum;
+import kd.hrmp.hies.multientry.common.dto.EntryImptBillData;
+import kd.hrmp.hies.multientry.core.validate.AbstractEntryValidateHandler;
+import nckd.jxccl.base.common.utils.QueryFieldBuilder;
+import nckd.jxccl.hr.hspm.common.TitleSkillAppointConstant;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
+
+/**
+ *
+ * @entity:
+ * @author: jtd
+ * @date: 2026/1/14 22:20
+ */
+public class TitleSkillAppointEntryImportValidator extends AbstractEntryValidateHandler {
+    /** 员工职称信息基础服务 */
+    private static final HRBaseServiceHelper empNtitleHelper = new HRBaseServiceHelper(TitleSkillAppointConstant.NCKD_HRPI_NTITLE_ENTITY);
+    /** 员工技能信息-基础服务 */
+    private static final HRBaseServiceHelper empSkillHelper = new HRBaseServiceHelper(TitleSkillAppointConstant.NCKD_HRPI_EMPSKILL_ENTITY);
+    /** 职称资格级别技能等级-基础服务 */
+    private static final HRBaseServiceHelper titleSkillLevelHelper = new HRBaseServiceHelper(TitleSkillAppointConstant.NCKD_HBSS_TITLESKLRK_ENTITY);
+
+    @Override
+    public ValidatorOrderEnum setValidatorRole() {
+        return ValidatorOrderEnum.AFTER;
+    }
+
+    @Override
+    public void validate(List<EntryImptBillData> list, ImportLog importLog) {
+        if (CollectionUtils.isEmpty(list)) {
+            return;
+        }
+
+        // 获取错误信息
+        ConcurrentHashMap<String, ConcurrentHashMap<Integer, ImportRowErrorLog>> rowErrors = importLog.getRowErrors();
+        List<EntryImptBillData> billDataList = list.stream().filter(billData -> {
+            ConcurrentHashMap<Integer, ImportRowErrorLog> rowError = rowErrors.getOrDefault(billData.getSheetName(), null);
+            if (Objects.isNull(rowError) || rowError.isEmpty()) {
+                return true;
+            }
+
+            return !rowError.containsKey(billData.getStartIndex());
+        }).collect(Collectors.toList());
+
+        if (billDataList.isEmpty()) {
+            return;
+        }
+
+        Map<String, String> typeItemMap = (Map<String, String>) getCustomParams().get(TitleSkillAppointConstant.NCKD_TYPE_KEY);
+        Set<Long> employeeIds = billDataList.stream().map(billData -> billData.getData().getJSONObject(billData.getEntryKey()).getJSONObject(TitleSkillAppointConstant.NCKD_EMPLOYEE).getLongValue(TitleSkillAppointConstant.ID_KEY)).collect(Collectors.toSet());
+
+        // 获取职称技能等级
+        Map<String, Long> titleSkillLevelMap = titleSkillLevelHelper.queryOriginalCollection(String.join(",", TitleSkillAppointConstant.ID_KEY, TitleSkillAppointConstant.NAME_KEY), null, TitleSkillAppointConstant.MODIFY_TIME_KEY)
+                .stream().collect(Collectors.toMap(
+                        dyo -> dyo.getString(TitleSkillAppointConstant.NAME_KEY),
+                        dyo -> dyo.getLong(TitleSkillAppointConstant.ID_KEY),
+                        (oldValue, newValue) -> newValue)
+                );
+
+        String selectFields = QueryFieldBuilder.create()
+                .add(TitleSkillAppointConstant.ID_KEY)
+                .add(TitleSkillAppointConstant.EMPLOYEE_KEY, TitleSkillAppointConstant.ID_KEY)
+                .add(TitleSkillAppointConstant.NCKD_TITLE_KEY)
+                .add(TitleSkillAppointConstant.NCKD_QUALLEVEL_KEY, TitleSkillAppointConstant.NAME_KEY)
+                .buildSelect();
+        QFilter[] filters = new QFilter[]{new QFilter(TitleSkillAppointConstant.EMPLOYEE_KEY, QCP.in, employeeIds)};
+        // 查询员工职称信息
+        DynamicObject[] empNtitleDyos = empNtitleHelper.queryOriginalArray(selectFields, filters, TitleSkillAppointConstant.MODIFY_TIME_KEY);
+        Map<String, Long> empNtitleMap = Arrays.stream(empNtitleDyos).collect(Collectors.toMap(
+                ntitleDyo -> String.join("##",
+                        ntitleDyo.getString(String.join(".", TitleSkillAppointConstant.EMPLOYEE_KEY, TitleSkillAppointConstant.ID_KEY)),
+                        ntitleDyo.getString(TitleSkillAppointConstant.NCKD_TITLE_KEY),
+                        ntitleDyo.getString(String.join(".", TitleSkillAppointConstant.NCKD_QUALLEVEL_KEY, TitleSkillAppointConstant.NAME_KEY))
+                ),
+                ntitleDyo -> ntitleDyo.getLong(TitleSkillAppointConstant.ID_KEY),
+                (oldValue, newValue) -> newValue
+            )
+        );
+
+        // 查询员工技能信息
+        selectFields = QueryFieldBuilder.create()
+                .add(TitleSkillAppointConstant.ID_KEY)
+                .add(TitleSkillAppointConstant.EMPLOYEE_KEY, TitleSkillAppointConstant.ID_KEY)
+                .add(TitleSkillAppointConstant.NCKD_QUALINAME_KEY)
+                .add(TitleSkillAppointConstant.NCKD_SKILLLEVEL_KEY, TitleSkillAppointConstant.NAME_KEY)
+                .buildSelect();
+        DynamicObject[] empSkillDyos = empSkillHelper.queryOriginalArray(selectFields, filters, TitleSkillAppointConstant.MODIFY_TIME_KEY);
+        Map<String, Long> empSkillMap = Arrays.stream(empSkillDyos).collect(Collectors.toMap(
+                skillDyo -> String.join("##",
+                    skillDyo.getString(String.join(".", TitleSkillAppointConstant.EMPLOYEE_KEY, TitleSkillAppointConstant.ID_KEY)),
+                    skillDyo.getString(TitleSkillAppointConstant.NCKD_QUALINAME_KEY),
+                    skillDyo.getString(String.join(".", TitleSkillAppointConstant.NCKD_SKILLLEVEL_KEY, TitleSkillAppointConstant.NAME_KEY))
+                ),
+                skillDyo -> skillDyo.getLong(TitleSkillAppointConstant.ID_KEY),
+                (oldValue, newValue) -> newValue
+            )
+        );
+
+        // 获取字段名称
+        Map<String, String> entryFieldNameMap = (Map<String, String>) getCustomParams().get("entryFieldNameMap");
+        // 员工职称信息属性名称
+        Map<String, String> empNtitleFieldNameMap = (Map<String, String>) getCustomParams().get("empNtitleFieldNameMap");
+        // 员工技能信息属性名称
+        Map<String, String> empSkillFieldNameMap = (Map<String, String>) getCustomParams().get("empSkillFieldNameMap");
+        for (EntryImptBillData billData : billDataList) {
+            JSONObject entryData = billData.getData().getJSONObject(billData.getEntryKey());
+            String employeeId = entryData.getJSONObject(TitleSkillAppointConstant.NCKD_EMPLOYEE).getString(TitleSkillAppointConstant.ID_KEY);
+
+            // 判断聘任类型是否正确
+            String typeItemName = entryData.getString(TitleSkillAppointConstant.NCKD_TYPE_KEY);
+            String typeItemValue = null;
+            for (Map.Entry<String, String> item : typeItemMap.entrySet()) {
+                if (item.getValue().equals(typeItemName)) {
+                    typeItemValue = item.getKey();
+                }
+            }
+            if (HRStringUtils.isBlank(typeItemValue)) {
+                importLog.writeRowLog(billData.getSheetName(), billData.getStartIndex(), billData.getEndIndex(), HRStringUtils.format("“{}”录入有误,请重新录入。", entryFieldNameMap.getOrDefault(TitleSkillAppointConstant.NCKD_TYPE_KEY, "")));
+                continue;
+            }
+
+            String[] temp = new String[0];
+            // 根据聘任类型判断对应列是否有值
+            if ("1".equals(typeItemValue)) {
+                String ntitleTemp = entryData.getString(String.join("_", TitleSkillAppointConstant.NCKD_NTITLE_KEY, "temp"));
+                if (HRStringUtils.isBlank(ntitleTemp)) {
+                    importLog.writeRowLog(billData.getSheetName(), billData.getStartIndex(), billData.getEndIndex(), HRStringUtils.format("“{}”为[{}]时,必须录入“{}”。", new Object[]{entryFieldNameMap.getOrDefault(TitleSkillAppointConstant.NCKD_TYPE_KEY, ""), typeItemName, entryFieldNameMap.getOrDefault(TitleSkillAppointConstant.NCKD_NTITLE_KEY, "")}));
+                    continue;
+                }
+
+                temp = ntitleTemp.split("##");
+                if (temp.length != 2) {
+                    importLog.writeRowLog(billData.getSheetName(), billData.getStartIndex(), billData.getEndIndex(), HRStringUtils.format("“{}”录入有误,请重新录入。", entryFieldNameMap.getOrDefault(TitleSkillAppointConstant.NCKD_NTITLE_KEY, "")));
+                    continue;
+                }
+
+                Long empNtitleId = empNtitleMap.get(String.join("##", employeeId, ntitleTemp));
+                if (empNtitleId == null || !(empNtitleId > 0)) {
+                    importLog.writeRowLog(billData.getSheetName(), billData.getStartIndex(), billData.getEndIndex(), HRStringUtils.format("该员工的“{}”中不存在“{}”为[{}],“{}”为[{}]的记录,请重新录入。", new Object[]{EntityMetadataCache.getDataEntityType(empNtitleHelper.getEntityName()).getDisplayName().getLocaleValue(), empNtitleFieldNameMap.getOrDefault(TitleSkillAppointConstant.NCKD_TITLE_KEY, ""), temp[0], empNtitleFieldNameMap.getOrDefault(TitleSkillAppointConstant.NCKD_QUALLEVEL_KEY, ""), temp[1]}));
+                    continue;
+                }
+
+                JSONObject title = new JSONObject(){{put(TitleSkillAppointConstant.ID_KEY, empNtitleId);}};
+                entryData.put(TitleSkillAppointConstant.NCKD_NTITLE_KEY, title);
+
+                JSONObject level = new JSONObject();
+                level.put(TitleSkillAppointConstant.ID_KEY, titleSkillLevelMap.getOrDefault(temp[1], 0L));
+                entryData.put(TitleSkillAppointConstant.NCKD_A_TITLESKLRK_KEY, level);
+
+                entryData.put(TitleSkillAppointConstant.NCKD_POSTNM_KEY, temp[0]);
+                entryData.put(TitleSkillAppointConstant.NCKD_EMPSKILL_KEY, null);
+            } else if ("2".equals(typeItemValue)) {
+                String skillTemp = entryData.getString(String.join("_", TitleSkillAppointConstant.NCKD_EMPSKILL_KEY, "temp"));
+                if (HRStringUtils.isBlank(skillTemp)) {
+                    importLog.writeRowLog(billData.getSheetName(), billData.getStartIndex(), billData.getEndIndex(), HRStringUtils.format("“{}”为[{}]时,必须录入“{}”。", new Object[]{entryFieldNameMap.getOrDefault(TitleSkillAppointConstant.NCKD_TYPE_KEY, ""), typeItemName, entryFieldNameMap.getOrDefault(TitleSkillAppointConstant.NCKD_EMPSKILL_KEY, "")}));
+                    continue;
+                }
+
+                temp = skillTemp.split("##");
+                if (temp.length != 2) {
+                    importLog.writeRowLog(billData.getSheetName(), billData.getStartIndex(), billData.getEndIndex(), HRStringUtils.format("“{}”录入有误,请重新录入。", entryFieldNameMap.getOrDefault(TitleSkillAppointConstant.NCKD_EMPSKILL_KEY, "")));
+                    continue;
+                }
+
+                Long empSkillId = empSkillMap.get(String.join("##", employeeId, skillTemp));
+                if (empSkillId == null || !(empSkillId > 0)) {
+                    importLog.writeRowLog(billData.getSheetName(), billData.getStartIndex(), billData.getEndIndex(), HRStringUtils.format("该员工的“{}”中不存在“{}”为[{}],“{}”为[{}]的记录,请重新录入。", new Object[]{EntityMetadataCache.getDataEntityType(empSkillHelper.getEntityName()).getDisplayName().getLocaleValue(), empSkillFieldNameMap.getOrDefault(TitleSkillAppointConstant.NCKD_QUALINAME_KEY, ""), temp[0], empSkillFieldNameMap.getOrDefault(TitleSkillAppointConstant.NCKD_SKILLLEVEL_KEY, ""), temp[1]}));
+                    continue;
+                }
+
+                JSONObject skill = new JSONObject(){{put(TitleSkillAppointConstant.ID_KEY, empSkillId);}};
+                entryData.put(TitleSkillAppointConstant.NCKD_EMPSKILL_KEY, skill);
+
+                JSONObject level = new JSONObject();
+                level.put(TitleSkillAppointConstant.ID_KEY, titleSkillLevelMap.getOrDefault(temp[1], 0L));
+                entryData.put(TitleSkillAppointConstant.NCKD_A_TITLESKLRK_KEY, level);
+
+                entryData.put(TitleSkillAppointConstant.NCKD_POSTNM_KEY, temp[0]);
+                entryData.put(TitleSkillAppointConstant.NCKD_NTITLE_KEY, null);
+            } else {
+                importLog.writeRowLog(billData.getSheetName(), billData.getStartIndex(), billData.getEndIndex(), HRStringUtils.format("“{}”录入有误,请联系管理员处理。", new Object[]{entryFieldNameMap.getOrDefault(TitleSkillAppointConstant.NCKD_TYPE_KEY, "")}));
+            }
+        }
+    }
+
+}

+ 57 - 1
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hspm/plugin/operate/tsapp/TitleSkillAppointEffectOpPlugin.java

@@ -2,10 +2,24 @@ package nckd.jxccl.hr.hspm.plugin.operate.tsapp;
 
 import kd.bos.dataentity.entity.DynamicObject;
 import kd.bos.dataentity.entity.DynamicObjectCollection;
+import kd.bos.entity.operate.result.IOperateInfo;
+import kd.bos.entity.operate.result.OperationResult;
 import kd.bos.entity.plugin.AbstractOperationServicePlugIn;
+import kd.bos.entity.plugin.AddValidatorsEventArgs;
 import kd.bos.entity.plugin.PreparePropertysEventArgs;
 import kd.bos.entity.plugin.args.BeginOperationTransactionArgs;
+import kd.bos.exception.KDBizException;
+import kd.bos.servicehelper.operation.SaveServiceHelper;
+import kd.hr.hbp.business.servicehelper.HRBaseServiceHelper;
+import kd.hr.hbp.common.util.HRDateTimeUtils;
+import kd.hr.hbp.common.util.HRObjectUtils;
 import nckd.jxccl.hr.hspm.common.TitleSkillAppointConstant;
+import nckd.jxccl.hr.hspm.plugin.operate.tsapp.validator.TitleSkillAppointEmployeeValidator;
+import nckd.jxccl.hr.hspm.plugin.operate.tsapp.validator.TitleSkillAppointStartDateValidator;
+
+import java.util.Arrays;
+import java.util.Map;
+import java.util.stream.Collectors;
 
 /**
  * 职称技能聘任单生效操作插件
@@ -14,6 +28,12 @@ import nckd.jxccl.hr.hspm.common.TitleSkillAppointConstant;
  * @date: 2026/1/13 21:11
  */
 public class TitleSkillAppointEffectOpPlugin extends AbstractOperationServicePlugIn {
+    /** 员工职称技能聘任基础服务 */
+    private static final HRBaseServiceHelper tsappHelper = HRBaseServiceHelper.create(TitleSkillAppointConstant.NCKD_HRPI_TITLSKLAPP_ENTITY);
+    /** 职称技能聘任键值映射基础服务 */
+    private static final HRBaseServiceHelper appointKvmHelper = HRBaseServiceHelper.create(TitleSkillAppointConstant.NCKD_TS_APPOINT_KVM_ENTITY);
+    private Map<String, String> keyMapping;
+
 
     @Override
     public void onPreparePropertys(PreparePropertysEventArgs e) {
@@ -22,20 +42,56 @@ public class TitleSkillAppointEffectOpPlugin extends AbstractOperationServicePlu
         e.getFieldKeys().addAll(billEntityType.getAllFields().keySet());
     }
 
+    @Override
+    public void onAddValidators(AddValidatorsEventArgs e) {
+        super.onAddValidators(e);
+
+        e.addValidator(new TitleSkillAppointStartDateValidator());
+        e.addValidator(new TitleSkillAppointEmployeeValidator());
+    }
+
     @Override
     public void beginOperationTransaction(BeginOperationTransactionArgs e) {
         super.beginOperationTransaction(e);
 
+        if (HRObjectUtils.isEmpty(keyMapping)) {
+            keyMapping = Arrays.stream(appointKvmHelper.loadDynamicObjectArray(null)).collect(Collectors.toMap(dyo -> dyo.getString(TitleSkillAppointConstant.NUMBER_KEY), dyo -> dyo.getString(TitleSkillAppointConstant.NAME_KEY), (oldValue, newValue) -> newValue));
+        }
+
+        DynamicObjectCollection tkappCol = new DynamicObjectCollection();
         for (DynamicObject dataEntite : e.getDataEntities()) {
             DynamicObjectCollection entryEntity = dataEntite.getDynamicObjectCollection(TitleSkillAppointConstant.NCKD_ENTRYENTITY);
             for (DynamicObject entry : entryEntity) {
+                tkappCol.add(buildAppointRecordDy(entry));
+            }
+        }
+
+        if (!tkappCol.isEmpty()) {
+            OperationResult operationResult = SaveServiceHelper.saveOperate(TitleSkillAppointConstant.NCKD_HRPI_TITLSKLAPP_ENTITY, tkappCol.toArray(new DynamicObject[0]));
+            if (!operationResult.isSuccess()) {
+                StringBuilder errorMsg = new StringBuilder();
+
+                for(IOperateInfo operateInfo : operationResult.getAllErrorOrValidateInfo()) {
+                    errorMsg.append(operateInfo.getMessage());
+                }
 
+                throw new KDBizException(errorMsg.toString());
             }
         }
     }
 
-    private void doEffect(DynamicObject data) {
+    private DynamicObject buildAppointRecordDy(DynamicObject data) {
+        DynamicObject dyo = tsappHelper.generateEmptyDynamicObject();
 
+        for (Map.Entry<String, String> entry : keyMapping.entrySet()) {
+            dyo.set(entry.getKey(), data.get(entry.getValue()));
+        }
+
+        if (HRObjectUtils.isEmpty(dyo.get(TitleSkillAppointConstant.ENDDATE))) {
+            // 结束日期
+            dyo.set(TitleSkillAppointConstant.ENDDATE, HRDateTimeUtils.getSysMaxDate());
+        }
 
+        return dyo;
     }
 }

+ 53 - 0
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hspm/plugin/operate/tsapp/validator/TitleSkillAppointEmployeeValidator.java

@@ -0,0 +1,53 @@
+package nckd.jxccl.hr.hspm.plugin.operate.tsapp.validator;
+
+import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.dataentity.entity.DynamicObjectCollection;
+import kd.bos.entity.ExtendedDataEntity;
+import kd.bos.entity.validate.AbstractValidator;
+import kd.bos.orm.query.QCP;
+import kd.bos.orm.query.QFilter;
+import kd.hr.hbp.business.servicehelper.HRBaseServiceHelper;
+import kd.hr.hbp.common.util.HRStringUtils;
+import kd.sdk.hr.hdm.common.enums.reg.RegBillStatusEnum;
+import nckd.jxccl.base.common.utils.QueryFieldBuilder;
+import nckd.jxccl.hr.hspm.common.TitleSkillAppointConstant;
+
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ *
+ * 职称技能聘任单员工校验器
+ * @author: jtd
+ * @date: 2026/1/14 10:47
+ */
+public class TitleSkillAppointEmployeeValidator extends AbstractValidator {
+    /** 职称技能聘任单基础服务 */
+    private static final HRBaseServiceHelper tsapptHelper = HRBaseServiceHelper.create(TitleSkillAppointConstant.NCKD_JOB_TITLE_SKILL_APPT_ENTITY);
+
+    @Override
+    public void validate() {
+        String selectFields = QueryFieldBuilder.create().add(TitleSkillAppointConstant.BILL_NO_KEY).add(TitleSkillAppointConstant.NCKD_ENTRYENTITY, TitleSkillAppointConstant.NCKD_EMPLOYEE, TitleSkillAppointConstant.ID_KEY).buildSelect();
+        // 查询所有在途聘任单中的员工ID
+        Map<Long, String> employeeIds = tsapptHelper.queryOriginalCollection(selectFields, new QFilter[]{new QFilter(TitleSkillAppointConstant.BILL_STATUS_KEY, QCP.in, new Object[]{RegBillStatusEnum.ALREADYSUBMIT.getCode(), RegBillStatusEnum.APPROVING.getCode()})})
+                .stream().collect(Collectors.toMap(
+                        dyo -> dyo.getLong(String.join(".", TitleSkillAppointConstant.NCKD_EMPLOYEE, TitleSkillAppointConstant.ID_KEY)),
+                        dyo -> dyo.getString(String.join(".",TitleSkillAppointConstant.NCKD_ENTRYENTITY, TitleSkillAppointConstant.NCKD_EMPLOYEE, TitleSkillAppointConstant.ID_KEY)),
+                        (oldValue, newValue) -> newValue
+                ));
+        for (ExtendedDataEntity dataEntity : getDataEntities()) {
+            DynamicObjectCollection entryEntity = dataEntity.getDataEntity().getDynamicObjectCollection(TitleSkillAppointConstant.NCKD_ENTRYENTITY);
+            for (int i = 0; i < entryEntity.size(); i++) {
+                DynamicObject entry = entryEntity.get(i);
+                long employeeId = entry.getLong(String.join(".", TitleSkillAppointConstant.NCKD_EMPLOYEE, TitleSkillAppointConstant.ID_KEY));
+                if (employeeIds.containsKey(employeeId)) {
+                    String employeeDisplayname = entry.getDynamicObjectType().getProperty(TitleSkillAppointConstant.NCKD_EMPLOYEE).getDisplayName().getLocaleValue();
+                    String empNumber = entry.getString(String.join(".", TitleSkillAppointConstant.NCKD_EMPLOYEE, TitleSkillAppointConstant.EMP_NUMBER_KEY));
+                    String name = entry.getString(String.join(".", TitleSkillAppointConstant.NCKD_EMPLOYEE, TitleSkillAppointConstant.NAME_KEY));
+                    String billDisplayName = entryEntity.getDynamicObjectType().getDisplayName().getLocaleValue();
+                    addErrorMessage(dataEntity, HRStringUtils.format("第{}行{}[{}/{}]在{}[{}]中已存在,不允许重复聘任!", new Object[]{i+1, employeeDisplayname, empNumber, name, billDisplayName}));
+                }
+            }
+        }
+    }
+}

+ 51 - 0
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hspm/plugin/operate/tsapp/validator/TitleSkillAppointStartDateValidator.java

@@ -0,0 +1,51 @@
+package nckd.jxccl.hr.hspm.plugin.operate.tsapp.validator;
+
+import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.dataentity.entity.DynamicObjectCollection;
+import kd.bos.entity.ExtendedDataEntity;
+import kd.bos.entity.validate.AbstractValidator;
+import kd.bos.orm.query.QCP;
+import kd.bos.orm.query.QFilter;
+import kd.hr.hbp.business.servicehelper.HRBaseServiceHelper;
+import kd.hr.hbp.common.util.HRStringUtils;
+import nckd.jxccl.hr.hspm.common.TitleSkillAppointConstant;
+
+import java.util.Date;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * 职称技能聘任单开始日期校验器
+ * @author: jtd
+ * @date: 2026/1/14 09:30
+ */
+public class TitleSkillAppointStartDateValidator extends AbstractValidator {
+    /** 员工职称技能聘任基础服务 */
+    private static final HRBaseServiceHelper tkappHelper = HRBaseServiceHelper.create(TitleSkillAppointConstant.NCKD_HRPI_TITLSKLAPP_ENTITY);
+
+    @Override
+    public void validate() {
+        for (ExtendedDataEntity dataEntity : getDataEntities()) {
+            DynamicObjectCollection entryEntity = dataEntity.getDataEntity().getDynamicObjectCollection(TitleSkillAppointConstant.NCKD_ENTRYENTITY);
+            Set<Long> employeeIds = entryEntity.stream().map(entry -> entry.getLong(String.join(".", TitleSkillAppointConstant.NCKD_EMPLOYEE, TitleSkillAppointConstant.ID_KEY))).collect(Collectors.toSet());
+            // 获取每个员工最近一笔聘任记录
+            Map<Long, Date> appointRecord = tkappHelper.queryOriginalCollection(TitleSkillAppointConstant.STARTDATE, new QFilter[]{new QFilter(TitleSkillAppointConstant.EMPLOYEE_KEY, QCP.in, employeeIds)}, String.format("%s desc", TitleSkillAppointConstant.STARTDATE))
+                    .stream().collect(Collectors.groupingBy(dyo -> dyo.getLong(String.join(".", TitleSkillAppointConstant.NCKD_EMPLOYEE, TitleSkillAppointConstant.ID_KEY)),
+                    Collectors.collectingAndThen(Collectors.toList(), list -> list.get(0).getDate(TitleSkillAppointConstant.STARTDATE))
+            ));
+
+            // 校验最近一次聘任记录的开始时间
+            for (int i = 0; i < entryEntity.size(); i++) {
+                DynamicObject entry = entryEntity.get(i);
+                Long employeeId = entry.getLong(String.join(".", TitleSkillAppointConstant.NCKD_EMPLOYEE, TitleSkillAppointConstant.ID_KEY));
+                Date appointStartDate = entry.getDate(TitleSkillAppointConstant.NCKD_STARTDATE);
+                Date recordStartDate = appointRecord.get(employeeId);
+                if (recordStartDate != null && recordStartDate.after(appointStartDate)) {
+                    String displayName = entry.getDynamicObjectType().getProperty(TitleSkillAppointConstant.NCKD_STARTDATE).getDisplayName().getLocaleValue();
+                    addErrorMessage(dataEntity, HRStringUtils.format("第{}行${}不能早于最近一次聘任记录的开始日期[{}]!", new Object[]{i+1, displayName, recordStartDate}));
+                }
+            }
+        }
+    }
+}

+ 5 - 4
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/tsc/plugin/form/AnnounceDowndateFormPlugin.java

@@ -3,14 +3,15 @@ package nckd.jxccl.hr.tsc.plugin.form;
 import kd.bos.form.events.AfterDoOperationEventArgs;
 import kd.bos.form.plugin.AbstractFormPlugin;
 import kd.sdk.plugin.Plugin;
-import nckd.jxccl.base.common.constant.FormConstant;
-
 import java.util.HashMap;
 import java.util.Map;
 
 /**
- * 动态表单插件
+ * 政策公告延长下架时间弹窗插件 动态表单插件
+ * @author turborao
+ * 时间 2026/1/15 16:05
  */
+@SuppressWarnings("unused")
 public class AnnounceDowndateFormPlugin extends AbstractFormPlugin implements Plugin {
 
     @Override
@@ -19,7 +20,7 @@ public class AnnounceDowndateFormPlugin extends AbstractFormPlugin implements Pl
         boolean success = afterDoOperationEventArgs.getOperationResult() != null && afterDoOperationEventArgs.getOperationResult().isSuccess();
         if (success && "commit".equalsIgnoreCase(operateKey)) {
             Object value = this.getModel().getValue("nckd_date");
-            Map<String,Object> map = new HashMap(1);
+            Map<String,Object> map = new HashMap<>();
             map.put("downdate",value);
             this.getView().returnDataToParent(map);
             this.getView().close();

+ 1 - 0
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/tsc/plugin/form/AnnouncementsListPlugin.java

@@ -175,6 +175,7 @@ public class AnnouncementsListPlugin extends AbstractListPlugin implements Plugi
                 Map<String, Object> map = ConvertUtil.toMap(returnData);
                 Date date = ConvertUtil.toDate(map.get("downdate"));
                 setDowndate(date);
+                this.getView().updateView();
             }
         }
     }

+ 165 - 0
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/tsc/plugin/form/AnnouncementsMobListPlugin.java

@@ -0,0 +1,165 @@
+package nckd.jxccl.hr.tsc.plugin.form;
+
+import kd.bos.algo.DataSet;
+import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.dataentity.entity.DynamicObjectCollection;
+import kd.bos.db.DB;
+import kd.bos.db.DBRoute;
+import kd.bos.form.events.SetFilterEvent;
+import kd.bos.list.plugin.AbstractMobListPlugin;
+import kd.bos.logging.Log;
+import kd.bos.logging.LogFactory;
+import kd.bos.orm.ORM;
+import kd.bos.orm.query.QCP;
+import kd.bos.orm.query.QFilter;
+import kd.bos.servicehelper.user.UserServiceHelper;
+import kd.hr.hbp.common.util.HRStringUtils;
+import kd.sdk.plugin.Plugin;
+import nckd.jxccl.base.common.constant.FormConstant;
+import nckd.jxccl.base.swc.helper.SWCHelper;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * 政策公告布局移动页面布局列表插件
+ * @author turborao
+ * 时间 2026/1/16 16:05
+ */
+@SuppressWarnings("unused")
+public class AnnouncementsMobListPlugin extends AbstractMobListPlugin implements Plugin {
+
+    private static final Log logger = LogFactory.getLog(AnnouncementsMobListPlugin.class);
+
+    @Override
+    public void setFilter(SetFilterEvent e) {
+        super.setFilter(e);
+        List<QFilter> qFilters = e.getQFilters();
+        List<QFilter> qFilterList = null;
+        if(qFilters.size()>0 && qFilters.get(0) != null) {
+            qFilterList = (List) qFilters.stream().filter((qFilter) -> {
+                return HRStringUtils.equals(qFilter.getProperty(), "nckd_hradminorg.id");
+            }).collect(Collectors.toList());
+        }
+
+        QFilter qFilter = null;
+        Long userId = UserServiceHelper.getCurrentUserId();
+        DynamicObject personUserDyn = SWCHelper.queryOne(FormConstant.HRPI_PERSONUSERREL, "employee.id","user",userId);
+
+        Long empId = 0L;
+        if(personUserDyn == null){
+            /**
+             * 没有员工信息时,返回常量,用于测试
+             */
+            //empId = 2313784485549715456L;
+            this.getView().showMessage("未找到员工!");
+            return;
+        }else {
+            empId = personUserDyn.getLong("employee.id");
+        }
+        List<Long> employeeIds = new java.util.ArrayList<>();
+        employeeIds.add(empId);
+        DynamicObject[] empDyns = SWCHelper.queryEmpPosOrgRelDyns(employeeIds);
+        if(empDyns != null && empDyns.length > 0){
+            ///获取当前员工的行政组织长编码
+            String adminOrgStructnumber = empDyns[0].getString("adminorg.structlongnumber");
+            logger.info("AnnouncementsMobListPlugin currEmpId:" + empId + " AdminOrgStructnumber:"+ adminOrgStructnumber);
+            ///查询符合条件的公告
+            Map<Long, String> announcementsMap = queryAnnouncementsByBillStatus();
+            ///组织结构编码匹配,返回符合条件的公告
+            List<Long> ids = getMatchingAnnouncementIds(announcementsMap, adminOrgStructnumber);
+            if(ids.size() > 0){
+                qFilter = new QFilter("id", QCP.in, ids);
+            }
+
+        }
+
+        if (qFilterList == null  && qFilter != null) {
+            //qFilter = new QFilter("number", QCP.equals, "在地愿为连理枝");
+            qFilters.add(qFilter);
+        }else{
+            if(qFilterList != null && qFilterList.size() > 0){
+                QFilter adminOrgFilter = (QFilter)qFilterList.get(0);
+                qFilters.remove(adminOrgFilter);
+                qFilters.add(qFilter);
+
+            }else {
+                qFilter = new QFilter("id", QCP.equals, 10000000000000000L);
+                qFilters.add(qFilter);
+            }
+        }
+        e.setOrderBy("nckd_istop Desc,nckd_publishdate Desc");
+
+        logger.info("AnnouncementsMobListPlugin setFilters:" +  e.getQFilters().toString() );
+    }
+
+
+    @Override
+    public void afterBindData(EventObject e) {
+        super.afterBindData(e);
+    }
+
+    /**
+     * 根据组织结构编码匹配,返回符合条件的公告ID列表
+     * @param announcementsMap Map<id, structnumber> 公告ID与组织结构编码的映射
+     * @param adminOrgStructnumber 当前用户的行政组织结构编码
+     * @return 匹配成功的公告ID列表
+     */
+    public List<Long> getMatchingAnnouncementIds(Map<Long, String> announcementsMap, String adminOrgStructnumber) {
+        List<Long> matchingIds = new ArrayList<>();
+
+        // 循环遍历 announcementsMap
+        for (Map.Entry<Long, String> entry : announcementsMap.entrySet()) {
+            Long id = entry.getKey();
+            String structnumber = entry.getValue();
+
+            // 检查 adminOrgStructnumber 是否包含 structnumber 中的字符
+            if (adminOrgStructnumber != null && structnumber != null &&
+                    adminOrgStructnumber.contains(structnumber)) {
+                matchingIds.add(id);
+            }
+        }
+
+        return matchingIds;
+    }
+
+
+
+    /**
+     * 根据 billstatus 查询公告信息并返回 Map 结构
+     * @return Map<id, structnumber>
+     */
+    public  Map<Long, String> queryAnnouncementsByBillStatus() {
+        // 设置查询条件
+        QFilter filter = new QFilter("nckd_billstatus", QCP.equals, "C");
+
+        // 执行查询
+        StringBuilder sb = getBillDetailSql();
+        DataSet dataSet = DB.queryDataSet(this.getClass().getName(), DBRoute.of("hr"), sb.toString());
+        DynamicObjectCollection result = ORM.create().toPlainDynamicObjectCollection(dataSet);
+
+        // 将结果转换为 Map<Long, String>
+        Map<Long, String> resultMap = new HashMap<>();
+        for (DynamicObject item : result) {
+            Long id = item.getLong("fid");
+            String structnumber = (String) item.get("fstructlongnumber");
+            if (structnumber != null) {
+                resultMap.put(id, structnumber);
+            }
+        }
+        return resultMap;
+    }
+
+    public  StringBuilder getBillDetailSql() {
+
+        StringBuilder sb = new StringBuilder();
+        sb.append("/*dialect*/ SELECT  a.fid, \n")
+                .append("e.fstructlongnumber \n")
+                .append("from tk_nckd_announcements a \n")
+                .append("left join tk_nckd_announcesentry b on a.fid = b.fid \n")
+                .append("left join t_haos_adminstruct e on e.fadminorgid = b.fk_nckd_adminorg and e.fiscurrentdata = '1' \n")
+                .append("where 1 = 1 and e.fstructprojectid = 1010 \n")
+                .append("and a.fk_nckd_billstatus in ('C') \n");
+        return sb;
+    }
+}

+ 319 - 0
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/tsc/plugin/mob/common/FormModel.java

@@ -0,0 +1,319 @@
+package nckd.jxccl.hr.tsc.plugin.mob.common;
+import java.io.Serializable;
+import java.util.Map;
+import kd.bos.base.BaseShowParameter;
+import kd.bos.base.MobileBaseShowParameter;
+import kd.bos.bill.BillShowParameter;
+import kd.bos.bill.MobileBillShowParameter;
+import kd.bos.form.FormShowParameter;
+import kd.bos.form.MobileFormShowParameter;
+import kd.bos.form.ShowType;
+import kd.bos.form.StyleCss;
+import kd.bos.list.ListFilterParameter;
+import kd.bos.list.ListShowParameter;
+import kd.bos.list.MobileListShowParameter;
+import kd.bos.report.ReportShowParameter;
+import kd.bos.script.annotations.KSMethod;
+import kd.bos.script.annotations.KSObject;
+import kd.sdk.annotation.SdkDeprecated;
+
+@KSObject
+public class FormModel implements Serializable {
+    private static final long serialVersionUID = 1L;
+    private String formId;
+    private String formName;
+    private String formType;
+    private Boolean callBack;
+    private Map<String, Object> customParam;
+    private ShowType showType;
+    private String templateId;
+    private Boolean lookup;
+    private FormShowParameter formShowParameter;
+    private String targetKey;
+    private ListFilterParameter listFilterParameter;
+    private Boolean closeCurrentPage;
+    private int width;
+    private int height;
+    private boolean showTitle;
+
+    public FormModel(String formId) {
+        this.width = Integer.MIN_VALUE;
+        this.height = Integer.MIN_VALUE;
+        this.showTitle = true;
+        this.formId = formId;
+        this.callBack = false;
+        this.formType = "14";
+    }
+
+    @SdkDeprecated
+    public FormModel(String formId, String formName, String formType) {
+        this(formId, formName, formType, false);
+    }
+
+    @SdkDeprecated
+    public FormModel(String formId, String formName, String formType, boolean callBack) {
+        this(formId, formName, formType, callBack, (Map)null);
+    }
+
+    @SdkDeprecated
+    public FormModel(String formId, String formName, String formType, boolean callBack, Map<String, Object> customParam) {
+        this.width = Integer.MIN_VALUE;
+        this.height = Integer.MIN_VALUE;
+        this.showTitle = true;
+        this.formId = formId;
+        this.formName = formName;
+        this.formType = formType;
+        this.callBack = callBack;
+        this.customParam = customParam;
+    }
+
+    @KSMethod
+    @SdkDeprecated
+    public String getFormId() {
+        return this.formId;
+    }
+
+    public void setFormId(String formId) {
+        this.formId = formId;
+    }
+
+    public String getFormName() {
+        return this.formName;
+    }
+
+    public void setFormName(String formName) {
+        this.formName = formName;
+    }
+
+    public String getFormType() {
+        return this.formType;
+    }
+
+    public void setFormType(String formType) {
+        this.formType = formType;
+    }
+
+    @KSMethod
+    @SdkDeprecated
+    public Boolean getCallBack() {
+        return this.callBack == null ? Boolean.FALSE : this.callBack;
+    }
+
+    @SdkDeprecated
+    public void setCallBack(Boolean callBack) {
+        this.callBack = callBack;
+    }
+
+    @SdkDeprecated
+    public Map<String, Object> getCustomParam() {
+        return this.customParam;
+    }
+
+    @SdkDeprecated
+    public void setCustomParam(Map<String, Object> customParam) {
+        this.customParam = customParam;
+    }
+
+    public ShowType getShowType() {
+        if (this.showType == null) {
+            switch (this.formType) {
+                case "7":
+                case "2":
+                case "1":
+                case "0":
+                case "3":
+                case "9":
+                    this.showType = ShowType.MainNewTabPage;
+                    break;
+                case "14":
+                case "15":
+                    this.showType = ShowType.Modal;
+                    break;
+                case "8":
+                case "10":
+                case "6":
+                case "4":
+                case "5":
+                    this.showType = ShowType.Floating;
+                    break;
+                case "11":
+                case "12":
+                    this.showType = ShowType.NewWindow;
+            }
+        }
+
+        return this.showType;
+    }
+
+    @SdkDeprecated
+    public void setShowType(ShowType showType) {
+        this.showType = showType;
+    }
+
+    public String getTemplateId() {
+        if (this.templateId == null) {
+            switch (this.formType) {
+                case "0":
+                    this.templateId = "bos_list";
+                    break;
+                case "9":
+                    this.templateId = "bos_treelist";
+                    break;
+                case "10":
+                    this.templateId = "er_basetemplate";
+                    break;
+                case "4":
+                case "12":
+                    this.templateId = "er_billtemplate";
+            }
+        }
+
+        return this.templateId;
+    }
+
+    public void setTemplateId(String templateId) {
+        this.templateId = templateId;
+    }
+
+    public Boolean getLookup() {
+        return this.lookup == null ? Boolean.FALSE : this.lookup;
+    }
+
+    public void setLookup(Boolean lookup) {
+        this.lookup = lookup;
+    }
+
+    @KSMethod
+    @SdkDeprecated
+    public FormShowParameter getFormShowParameter() {
+        switch (this.formType) {
+            case "0":
+            case "9":
+                this.formShowParameter = new ListShowParameter();
+                break;
+            case "1":
+            case "14":
+                this.formShowParameter = new FormShowParameter();
+                break;
+            case "2":
+                this.formShowParameter = new BillShowParameter();
+                break;
+            case "3":
+                this.formShowParameter = new ReportShowParameter();
+                break;
+            case "7":
+                this.formShowParameter = new BaseShowParameter();
+                break;
+            case "5":
+            case "11":
+                this.formShowParameter = new MobileFormShowParameter();
+                break;
+            case "6":
+                this.formShowParameter = new MobileBillShowParameter();
+                break;
+            case "4":
+            case "10":
+            case "12":
+                this.formShowParameter = new MobileListShowParameter();
+                break;
+            case "8":
+                this.formShowParameter = new MobileBaseShowParameter();
+                break;
+            case "13":
+            case "15":
+                this.formShowParameter = new MobileFormShowParameter();
+        }
+
+        if (this.formShowParameter instanceof ListShowParameter) {
+            ListShowParameter listShowParameter = (ListShowParameter)this.formShowParameter;
+            listShowParameter.setBillFormId(this.getFormId());
+            listShowParameter.setFormId(this.getTemplateId());
+            listShowParameter.setLookUp(this.getLookup());
+            listShowParameter.setListFilterParameter(this.getListFilterParameter());
+        } else {
+            this.formShowParameter.setFormId(this.getFormId());
+        }
+
+        this.formShowParameter.getOpenStyle().setShowType(this.getShowType());
+        this.formShowParameter.getOpenStyle().setTargetKey(this.getTargetKey());
+        this.formShowParameter.setCaption(this.getFormName());
+        if (this.getCustomParam() != null) {
+            this.formShowParameter.getCustomParams().putAll(this.getCustomParam());
+        }
+
+        this.formShowParameter.getOpenStyle().setShowType(this.getShowType());
+        if (this.width > Integer.MIN_VALUE && this.height > Integer.MIN_VALUE) {
+            StyleCss inlineStyleCss = new StyleCss();
+            inlineStyleCss.setWidth(String.valueOf(this.width));
+            inlineStyleCss.setHeight(String.valueOf(this.height));
+            this.formShowParameter.getOpenStyle().setInlineStyleCss(inlineStyleCss);
+        }
+
+        this.formShowParameter.setShowTitle(this.showTitle);
+        return this.formShowParameter;
+    }
+
+    public String getTargetKey() {
+        if (this.targetKey == null) {
+            switch (this.formType) {
+                case "7":
+                case "2":
+                case "1":
+                case "0":
+                case "3":
+                case "9":
+                    this.targetKey = "_submaintab_";
+            }
+        }
+
+        return this.targetKey;
+    }
+
+    @SdkDeprecated
+    public void setTargetKey(String targetKey) {
+        this.targetKey = targetKey;
+    }
+
+    public ListFilterParameter getListFilterParameter() {
+        return this.listFilterParameter;
+    }
+
+    public void setListFilterParameter(ListFilterParameter listFilterParameter) {
+        this.listFilterParameter = listFilterParameter;
+    }
+
+    public Boolean getCloseCurrentPage() {
+        return this.closeCurrentPage == null ? Boolean.FALSE : this.closeCurrentPage;
+    }
+
+    public void setCloseCurrentPage(Boolean closeCurrentPage) {
+        this.closeCurrentPage = closeCurrentPage;
+    }
+
+    public int getWidth() {
+        return this.width;
+    }
+
+    @SdkDeprecated
+    public void setWidth(int width) {
+        this.width = width;
+    }
+
+    public int getHeight() {
+        return this.height;
+    }
+
+    @SdkDeprecated
+    public void setHeight(int height) {
+        this.height = height;
+    }
+
+    public boolean isShowTitle() {
+        return this.showTitle;
+    }
+
+    @SdkDeprecated
+    public void setShowTitle(boolean showTitle) {
+        this.showTitle = showTitle;
+    }
+}

+ 77 - 0
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/tsc/plugin/mob/common/MainPageModel.java

@@ -0,0 +1,77 @@
+package nckd.jxccl.hr.tsc.plugin.mob.common;
+
+import java.util.HashMap;
+import java.util.Map;
+import kd.sdk.annotation.SdkDeprecated;
+
+public class MainPageModel {
+    private String formId;
+    private String formName;
+    private String formType;
+    private Boolean callBack;
+    private Map<String, Object> customParam;
+
+    @SdkDeprecated
+    public String getFormId() {
+        return this.formId;
+    }
+
+    public void setFormId(String formId) {
+        this.formId = formId;
+    }
+
+    @SdkDeprecated
+    public String getFormName() {
+        return this.formName;
+    }
+
+    public void setFormName(String formName) {
+        this.formName = formName;
+    }
+
+    @SdkDeprecated
+    public String getFormType() {
+        return this.formType;
+    }
+
+    public void setFormType(String formType) {
+        this.formType = formType;
+    }
+
+    @SdkDeprecated
+    public Boolean getCallBack() {
+        return this.callBack;
+    }
+
+    public void setCallBack(Boolean callBack) {
+        this.callBack = callBack;
+    }
+
+    @SdkDeprecated
+    public Map<String, Object> getCustomParam() {
+        return this.customParam;
+    }
+
+    public void setCustomParam(Map<String, Object> customParam) {
+        this.customParam = customParam;
+    }
+
+    @SdkDeprecated
+    public MainPageModel(String formId, String formName, String formType, boolean callBack, Map<String, Object> customParam) {
+        this.formId = formId;
+        this.formName = formName;
+        this.formType = formType;
+        this.callBack = callBack;
+        this.customParam = customParam;
+    }
+
+    @SdkDeprecated
+    public MainPageModel(String formId, String formName, String formType) {
+        this(formId, formName, formType, false);
+    }
+
+    @SdkDeprecated
+    public MainPageModel(String formId, String formName, String formType, boolean callBack) {
+        this(formId, formName, formType, callBack, new HashMap());
+    }
+}

+ 114 - 0
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/tsc/plugin/mob/common/TscNaviBarPlugin.java

@@ -0,0 +1,114 @@
+package nckd.jxccl.hr.tsc.plugin.mob.common;
+
+import kd.bos.bill.AbstractMobBillPlugIn;
+import kd.bos.dataentity.resource.ResManager;
+import kd.bos.form.CloseCallBack;
+import kd.bos.form.FormShowParameter;
+import kd.bos.form.ShowType;
+import kd.bos.form.control.Control;
+import kd.bos.form.control.events.ClickListener;
+import kd.bos.form.control.events.ItemClickEvent;
+import kd.bos.form.control.events.RowClickEventListener;
+import kd.bos.form.plugin.AbstractFormPlugin;
+import kd.bos.list.ListShowParameter;
+import kd.bos.list.MobileListShowParameter;
+import org.apache.commons.lang.StringUtils;
+
+import java.util.EventObject;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * 应聘自助移动端底部工具栏通用插件
+ * @author Tyx
+ * 时间 2026/1/16 14:12
+ */
+public class TscNaviBarPlugin extends AbstractMobBillPlugIn implements ClickListener, RowClickEventListener {
+
+    protected static final Map<String, MainPageModel> controlMap = new HashMap();
+
+    public TscNaviBarPlugin() {
+
+    }
+
+    @Override
+    public void registerListener(EventObject e) {
+        super.registerListener(e);
+        this.addItemClickListeners("mtoolbarap");
+        Set<String> controlIdSet = controlMap.keySet();
+        String[] controlIds = (String[])controlIdSet.toArray(new String[controlIdSet.size()]);
+        this.addClickListeners(controlIds);
+    }
+
+    @Override
+    public void itemClick(ItemClickEvent evt) {
+        super.itemClick(evt);
+        String key = evt.getItemKey();
+        MainPageModel mainPageModel = this.getMultilingualModel(controlMap, key);
+        FormModel formModel = null;
+        if (mainPageModel != null) {
+            formModel = new FormModel(mainPageModel.getFormId(), mainPageModel.getFormName(), mainPageModel.getFormType(), mainPageModel.getCallBack());
+        }
+        if (formModel != null) {
+            String formId = formModel.getFormId();
+            if (StringUtils.isEmpty(formId)) {
+                this.getView().showMessage(ResManager.loadKDString("敬请期待", "TripNaviBarPlugin_5", "fi-er-formplugin", new Object[0]));
+            } else {
+                showPage(formModel, this);
+            }
+        }
+    }
+
+    /**
+     * 点击事件
+     * @param evt
+     */
+    @Override
+    public void click(EventObject evt) {
+        super.click(evt);
+        Control control = (Control)evt.getSource();
+        String key = control.getKey();
+
+    }
+
+    /**
+     * 打开页面
+     * @param formModel
+     * @param formPlugin
+     * @return
+     */
+    public static String showPage(FormModel formModel, AbstractFormPlugin formPlugin) {
+        MobileListShowParameter listShowParameter = new MobileListShowParameter();
+        listShowParameter.setFormId("bos_moblist");
+        listShowParameter.setBillFormId(formModel.getFormId());
+        listShowParameter.getOpenStyle().setShowType(ShowType.Floating);
+        if (formModel.getCallBack()) {
+            listShowParameter.setCloseCallBack(new CloseCallBack(formPlugin, formModel.getFormId()));
+        }
+
+        formPlugin.getView().showForm(listShowParameter);
+        return listShowParameter.getPageId();
+    }
+
+
+
+    private MainPageModel getMultilingualModel(Map<String, MainPageModel> controlMap, String key) {
+        MainPageModel model = controlMap.get(key);
+        if (model == null) {
+            return null;
+        } else {
+            return model;
+        }
+    }
+
+    static {
+        controlMap.put("nckd_mbaritemap1", new MainPageModel("nckd_announcementsmob", "政策公告", "5"));
+        controlMap.put("nckd_mbaritemap2", new MainPageModel("nckd_advertmob", "招聘职位", "5"));
+        controlMap.put("nckd_mbaritemap3", new MainPageModel("er_trip", "我的应聘", "5"));  // TODO
+        controlMap.put("nckd_mbaritemap4", new MainPageModel("er_myviewpage_m", "我的简历", "5")); // TODO
+        controlMap.put("nckd_mbaritemap5", new MainPageModel("er_myviewpage_m", "我的收藏", "5")); // TODO
+    }
+
+
+}