package com.kingdee.eas.custom.szpgm.osf.service; import com.kingdee.bos.BOSException; import com.kingdee.bos.Context; import com.kingdee.bos.bsf.service.app.IHRMsfService; import com.kingdee.eas.common.EASBizException; import com.kingdee.eas.util.app.DbUtil; import com.kingdee.jdbc.rowset.IRowSet; import org.apache.commons.lang3.StringUtils; import java.text.SimpleDateFormat; import java.util.*; /** * 员工兼职信息查询OSF服务 *

* 实现 {@link IHRMsfService} 接口,提供员工兼职信息的分页查询功能。 * 支持按员工编号(精确)、最后修改时间进行过滤筛选。 * 同一员工存在多个上级时,会将上级编码合并到一个列表中返回。 *

* *

关联数据表

* * *

入参说明

* * *

返回结果

*
{@code
 * {
 *     "msg": "成功",
 *     "code": "200",
 *     "page": 1,
 *     "size": 100,
 *     "data": [{
 *         "id": "分录主键",
 *         "personid": "员工ID",
 *         "personCode": "员工编号",
 *         "startDate": "兼职开始日期(yyyy-MM-dd)",
 *         "endDate": "兼职结束日期(yyyy-MM-dd),未结束则为2199-12-31",
 *         "orgCode": "兼职组织编码",
 *         "posCode": "兼职岗位编码",
 *         "leader": ["上级员工编码列表"],
 *         "description": "兼职备注"
 *     }]
 * }
 * }
* *

业务规则

* * * @author szpgm * @since 2026/07/02 */ public class GetPluralityInfoOsfService implements IHRMsfService { /** * 处理员工兼职信息查询请求 * * @param context EAS上下文对象,用于执行数据库查询 * @param map 入参Map,包含过滤条件和分页参数 * @return Map 包含查询结果、状态码和分页信息 * @throws EASBizException 业务异常 * @throws BOSException 平台异常 */ @Override public Object process(Context context, Map map) throws EASBizException, BOSException { // 返回结果容器 Map result = new HashMap(); List> list = new ArrayList<>(); // ==================== 入参解析 ==================== // 最后修改日期(格式:yyyy-MM-dd),同时检查加入兼职表和移除兼职表(增量同步场景) String modifyDate = (String) map.get("modifyDate"); // 生效开始日期(格式:yyyy-MM-dd),筛选兼职未结束或结束日期>=此日期的记录 String startDateStr = (String) map.get("startDate"); // 生效结束日期(格式:yyyy-MM-dd),筛选兼职开始日期<=此日期的记录 String endDateStr = (String) map.get("endDate"); // 员工编号(精确匹配) String code = (String) map.get("personCode"); // 每页条数(默认100,上限1000) int maxSize = 1000; int size = 100; if (map.get("size") != null) { if (map.get("size") instanceof Integer) { size = (int) map.get("size"); } else if (map.get("size") instanceof String) { size = Integer.parseInt((String) map.get("size")); } size = Math.min(maxSize, size); } // 页码(默认1) int page = 1; if (map.get("page") != null) { if (map.get("page") instanceof Integer) { page = (int) map.get("page"); } else if (map.get("page") instanceof String) { page = Integer.parseInt((String) map.get("page")); } } // ==================== 查询数据 ==================== try { // 初始化成功响应 result.put("msg", "成功"); result.put("code", "200"); result.put("page", page); result.put("size", size); result.put("data", list); // 构建基础SQL,动态追加过滤条件 StringBuilder sql = getSql(); // SQL参数列表(与?占位符一一对应) List paramArr = new ArrayList<>(); // 修改日期过滤(增量同步):加入兼职单或移除兼职单的最后修改时间 >= 指定日期 if (StringUtils.isNotBlank(modifyDate)) { sql.append(" and (pa.flastupdatetime >= ? or pd.flastupdatetime >= ?) "); paramArr.add(modifyDate); paramArr.add(modifyDate); } // 生效开始日期过滤:筛选在该日期之后仍有兼职效力的记录 // 即:移除兼职单未审批通过(兼职未结束,视为2199-12-31),或结束日期 >= startDate if (StringUtils.isNotBlank(startDateStr)) { sql.append(" and (pd.fbillstate is null or pd.fbillstate != 3 or pde.fbizdate >= ?) "); paramArr.add(startDateStr); } // 生效结束日期过滤:筛选兼职开始日期 <= endDate 的记录 if (StringUtils.isNotBlank(endDateStr)) { sql.append(" and pae.fbizdate <= ? "); paramArr.add(endDateStr); } // 员工编号精确匹配 if (StringUtils.isNotBlank(code)) { sql.append(" and pe.fnumber = ? "); paramArr.add(code); } // 分页:LIMIT 返回条数 OFFSET 跳过条数 sql.append(" order by pae.fpersonid desc LIMIT ? OFFSET ? "); paramArr.add(size); paramArr.add(((page - 1) * size)); // 执行SQL查询 IRowSet rs = DbUtil.executeQuery(context, sql.toString(), paramArr.toArray()); // 以员工ID为key的Map,用于合并同一员工的多条记录(一个员工可能有多个上级) Map> maps = new HashMap<>(); // 日期格式化器(yyyy-MM-dd) SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); // 遍历结果集,将同一员工的多行数据合并为一条记录 while (rs.next()) { String id = rs.getString("personid"); Map param = new HashMap<>(); // Map param = maps.get(id); // // 首次遇到该员工时,初始化记录并创建上级编码列表 // if (null == param) { // param = new HashMap<>(); // List leaderIds = new ArrayList<>(); // param.put("leader", leaderIds); // maps.put(id, param); // } // // 收集该员工的所有上级编码(多行数据的共同字段会覆盖,但值相同) // List leader = (List) param.get("leader"); // leader.add(rs.getString("leader")); // ---- 员工基本信息 ---- param.put("id", rs.getString("id")); // 员工ID param.put("personid", id); String leaderStr = rs.getString("leader"); List leaders = new ArrayList<>(); if(StringUtils.isNotBlank(leaderStr)){ leaders.addAll(Arrays.asList(leaderStr.split(","))); } param.put("leader", leaders); param.put("personCode", rs.getString("personCode")); // ---- 兼职日期(Date -> String 格式化) ---- // 兼职开始日期 Date startDate = rs.getDate("startDate"); param.put("startDate", (null != startDate ? sdf.format(startDate) : null)); // 移除兼职单审批状态(3表示审批通过) int pdbillstate = rs.getInt("pdbillstate"); // 兼职结束日期:只有移除兼职单审批通过时才取实际结束日期,否则返回"2199-12-31"表示兼职未结束 Date endDate = rs.getDate("endDate"); param.put("endDate", (null != endDate && 3 == pdbillstate ? sdf.format(endDate) : "2199-12-31")); // ---- 组织与岗位 ---- // 兼职所属组织编码 param.put("orgCode", rs.getString("orgCode")); // 兼职岗位编码 param.put("posCode", rs.getString("posCode")); // ---- 备注 ---- // 兼职备注(来自加入兼职单分录) param.put("description", rs.getString("description")); list.add(param); } // 将合并后的员工列表写入返回结果 result.put("data", list); } catch (Exception e) { // 异常时返回错误信息 e.printStackTrace(); result.put("msg", e.getMessage()); result.put("code", "500"); } return result; } /** * 构建员工兼职信息查询的基础SQL *

* 从员工加入兼职单分录表出发,LEFT JOIN 加入兼职单表获取审批状态, * LEFT JOIN 移除兼职单分录表和移除兼职单表获取结束日期和移除审批状态, * LEFT JOIN 员工基础信息表、岗位表、行政组织表获取基本字段, * LEFT JOIN 岗位任职历史表和员工基础信息表(二次关联)获取当前上级信息。 * 只查询加入兼职单审批通过(pa.fbillstate=3)的记录。 *

* *

核心关联逻辑

*
    *
  1. pae → pa:关联加入兼职单,获取审批状态,WHERE条件限定 fbillstate=3(审批通过)
  2. *
  3. pae → pe:通过 fpersonid 关联员工基础信息表,获取员工编号
  4. *
  5. pae → pde:通过 fpersonid 关联移除兼职单分录,获取兼职结束日期
  6. *
  7. pde → pd:关联移除兼职单,获取移除审批状态,用于判断结束日期是否有效
  8. *
  9. pae → pos:通过 fpositionid 关联岗位表,获取兼职岗位编码
  10. *
  11. pae → org:通过 fadminorgid 关联行政组织表,获取兼职组织编码
  12. *
  13. pos → phis:通过 pos.fparentid(上级岗位ID)关联任职历史,取当前有效上级(fpositionenddate >= 2199-12-31)
  14. *
  15. phis → ppe:关联员工基础信息表(二次),获取上级员工编码
  16. *
* * @return 包含完整SELECT语句的StringBuilder(以 WHERE pa.fbillstate=3 结尾,便于后续追加AND条件) */ private static StringBuilder getSql() { StringBuilder sql = new StringBuilder(); // /*dialect*/ 标记用于EAS平台识别SQL方言 sql.append(" /*dialect*/ select "); // ===== SELECT 字段列表 ===== sql.append(" pae.fid id, "); sql.append(" pae.fpersonid personid, "); // 员工FID sql.append(" pe.fnumber personCode, "); // 员工编号 sql.append(" pae.fbizdate startDate, "); // 兼职开始日期 sql.append(" pos.fnumber posCode, "); // 兼职岗位编码 sql.append(" org.fnumber orgCode, "); // 兼职所属组织编码 // 使用STRING_AGG将同一上级岗位下的多位领导编码合并为逗号分隔字段(Kingbase/PostgreSQL语法) sql.append(" (SELECT STRING_AGG(ppe_inner.fnumber, ',' ORDER BY ppe_inner.fnumber) "); sql.append(" FROM T_HR_EMPPOSTEXPERIENCEHIS phis_inner "); sql.append(" LEFT JOIN t_bd_person ppe_inner ON ppe_inner.fid = phis_inner.fpersonid "); sql.append(" WHERE phis_inner.fpositionid = pos.fparentid "); sql.append(" AND phis_inner.fpositionenddate >= '2199-12-31 00:00:00') leader, "); // sql.append(" ppe.fnumber leader, "); // 上级员工编码(通过岗位任职历史关联) sql.append(" pae.fdescription description, "); // 加入兼职单备注 sql.append(" pde.fdescription description2, "); // 移除兼职单备注(查询用,未返回给调用方) sql.append(" pde.fbizdate endDate, "); // 兼职结束日期(来自移除兼职单) sql.append(" pd.fbillstate pdbillstate "); // 移除兼职单审批状态(3:审批通过) // ===== FROM 子句及关联表 ===== sql.append(" from "); sql.append(" T_HR_PluralityAddBizBillEntry pae "); // 员工加入兼职单分录表(主表) sql.append(" left join T_HR_PluralityAddBizBill pa on pae.fbillid = pa.fid "); // 加入兼职单表(获取审批状态) sql.append(" left join T_HR_PluralityDelBizBillentry pde on pde.FPERSONID = pae.fpersonid "); // 移除兼职单分录表(获取结束日期) sql.append(" left join T_HR_PluralityDelBizBill pd on pd.fid = pde.fbillid "); // 移除兼职单表(获取移除审批状态) sql.append(" left join t_bd_person pe on pe.fid = pae.fpersonid "); // 员工基础信息表(取员工编号) sql.append(" left join t_org_position pos on pos.fid = pae.fpositionid "); // 岗位表(取兼职岗位信息) sql.append(" left join t_org_admin org on org.fid = pae.fadminorgid "); // 行政组织表 // sql.append(" left join T_HR_EMPPOSTEXPERIENCEHIS phis on phis.fpositionid = pos.fparentid "); // 岗位任职历史表(通过上级岗位ID关联) // sql.append(" and phis.fpositionenddate >= '2199-12-31 00:00:00'"); // 只取当前有效的任职记录 // sql.append(" left join t_bd_person ppe on ppe.fid = phis.fpersonid "); // 上级员工(任职历史中的人员) // WHERE 条件:只查加入兼职单审批通过的记录,后续可动态追加 AND 条件 sql.append(" where pa.fbillstate=3 "); return sql; } }