ReportOrgUtil.java 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  1. package com.kingdee.eas.custom.perfweb.util;
  2. import com.kingdee.bos.BOSException;
  3. import com.kingdee.bos.Context;
  4. import com.kingdee.bos.ctrl.swing.StringUtils;
  5. import com.kingdee.jdbc.rowset.IRowSet;
  6. import com.kingdee.eas.util.app.DbUtil;
  7. import org.apache.log4j.Logger;
  8. import java.sql.SQLException;
  9. import java.util.ArrayList;
  10. import java.util.LinkedHashMap;
  11. import java.util.List;
  12. import java.util.Map;
  13. /**
  14. * 类名称: ReportOrgUtil
  15. *
  16. * 功能描述: 报表组织范围过滤工具(排除130及下级、中心/部门层级查询与SQL拼接)
  17. * 创建日期: 2026-06-23
  18. * 作 者: 青梧
  19. * 版 本: 1.3
  20. */
  21. public final class ReportOrgUtil {
  22. public static final String EXCLUDED_ORG_NUMBER = "130";
  23. public static final String LAYER_CENTER = "中心";
  24. public static final String LAYER_DEPT = "部门";
  25. private ReportOrgUtil() {
  26. }
  27. /** 按组织FID查询显示名称(FNAME_L2)。 */
  28. public static String getOrgDisplayName(Context ctx, String orgId) throws BOSException, SQLException {
  29. if (StringUtils.isEmpty(orgId)) {
  30. return null;
  31. }
  32. StringBuilder sql = new StringBuilder();
  33. sql.append("SELECT FNAME_L2 FROM T_ORG_Admin WHERE FID = ?");
  34. IRowSet rs = DbUtil.executeQuery(ctx, sql.toString(), new Object[]{orgId});
  35. if (rs.next()) {
  36. return rs.getString("FNAME_L2");
  37. }
  38. return null;
  39. }
  40. /**
  41. * 按行政组织FID查询其下所有部门(跨公司同名合并,排除130)。
  42. */
  43. public static List<OrgNameCode> getDistinctDeptNameCodesUnderAdminOrg(Context ctx, String adminOrgId, String companyId)
  44. throws BOSException, SQLException {
  45. Map<String, String> nameToCode = new LinkedHashMap<String, String>();
  46. if (StringUtils.isEmpty(adminOrgId)) {
  47. return new ArrayList<OrgNameCode>();
  48. }
  49. String longNumber = getOrgLongNumber(ctx, adminOrgId);
  50. if (StringUtils.isEmpty(longNumber)) {
  51. return new ArrayList<OrgNameCode>();
  52. }
  53. String excludedLongNumber = getExcludedOrgLongNumber(ctx);
  54. StringBuilder sql = new StringBuilder();
  55. sql.append("SELECT dept.FNAME_L2 AS orgName, dept.FNUMBER AS orgCode ");
  56. sql.append("FROM T_ORG_Admin root ");
  57. sql.append("INNER JOIN T_ORG_Admin dept ");
  58. sql.append(" ON LEFT(dept.FLongNumber, LEN(root.FLongNumber)) = root.FLongNumber ");
  59. sql.append("INNER JOIN T_Org_LayerType ltDept ON ltDept.FID = dept.FLAYERTYPEID ");
  60. sql.append("WHERE root.FID = '").append(escapeSql(adminOrgId)).append("' ");
  61. sql.append("AND ltDept.FNUMBER = '").append(escapeSql(LAYER_DEPT)).append("' ");
  62. sql.append("AND root.FIsSealUp = 0 AND dept.FIsSealUp = 0 ");
  63. if (!StringUtils.isEmpty(excludedLongNumber)) {
  64. sql.append("AND root.FLongNumber NOT LIKE '").append(excludedLongNumber).append("%' ");
  65. }
  66. sql.append("ORDER BY dept.FNAME_L2, dept.FNUMBER");
  67. IRowSet rs = DbUtil.executeQuery(ctx, sql.toString());
  68. while (rs.next()) {
  69. String name = rs.getString("orgName");
  70. String code = rs.getString("orgCode");
  71. if (StringUtils.isEmpty(name) || StringUtils.isEmpty(code)) {
  72. continue;
  73. }
  74. if (!nameToCode.containsKey(name)) {
  75. nameToCode.put(name, code);
  76. }
  77. }
  78. List<OrgNameCode> result = new ArrayList<OrgNameCode>();
  79. for (Map.Entry<String, String> entry : nameToCode.entrySet()) {
  80. result.add(new OrgNameCode(entry.getKey(), entry.getValue()));
  81. }
  82. return result;
  83. }
  84. /** 按组织FID查询长编码(FLongNumber)。 */
  85. public static String getOrgLongNumber(Context ctx, String orgId) throws BOSException, SQLException {
  86. if (StringUtils.isEmpty(orgId)) {
  87. return null;
  88. }
  89. StringBuilder sql = new StringBuilder();
  90. sql.append("SELECT FLONGNUMBER FROM T_ORG_Admin WHERE FID = ?");
  91. IRowSet rs = DbUtil.executeQuery(ctx, sql.toString(), new Object[]{orgId});
  92. if (rs.next()) {
  93. return rs.getString("FLONGNUMBER");
  94. }
  95. return null;
  96. }
  97. /** 查询排除组织130的长编码前缀。 */
  98. public static String getExcludedOrgLongNumber(Context ctx) throws BOSException, SQLException {
  99. StringBuilder sql = new StringBuilder();
  100. sql.append("SELECT FLONGNUMBER FROM T_ORG_Admin WHERE FNUMBER = ? AND FIsSealUp = 0");
  101. IRowSet rs = DbUtil.executeQuery(ctx, sql.toString(), new Object[]{EXCLUDED_ORG_NUMBER});
  102. if (rs.next()) {
  103. return rs.getString("FLONGNUMBER");
  104. }
  105. return null;
  106. }
  107. /** 按组织别名追加排除130子树条件(FLongNumber NOT LIKE)。 */
  108. public static void appendExcludeOrg130(StringBuilder sql, String orgAlias, Context ctx)
  109. throws BOSException, SQLException {
  110. String excludedLongNumber = getExcludedOrgLongNumber(ctx);
  111. if (!StringUtils.isEmpty(excludedLongNumber)) {
  112. sql.append("AND ").append(orgAlias).append(".FLongNumber NOT LIKE '").append(excludedLongNumber).append("%' ");
  113. }
  114. }
  115. /** 按组织FID字段追加排除130子树条件(NOT IN 子查询)。 */
  116. public static void appendExcludeOrg130ById(StringBuilder sql, String orgIdField, Context ctx)
  117. throws BOSException, SQLException {
  118. String excludedLongNumber = getExcludedOrgLongNumber(ctx);
  119. if (!StringUtils.isEmpty(excludedLongNumber)) {
  120. sql.append("AND ").append(orgIdField).append(" NOT IN (");
  121. sql.append("SELECT sub.FID FROM T_ORG_Admin sub WHERE sub.FLongNumber LIKE '");
  122. sql.append(excludedLongNumber).append("%') ");
  123. }
  124. }
  125. /**
  126. * 组织过滤范围:按名称(跨公司)或按行政组织FID筛选。
  127. */
  128. public static final class OrgScope {
  129. /** 中心/部门名称 FNAME_L2 */
  130. public final String orgName;
  131. /** 组织层级类型,如 中心 / 部门 */
  132. public final String orgLayer;
  133. /** 行政组织FID(快筛选组织时生效) */
  134. public final String adminOrg;
  135. public OrgScope(String orgName, String orgLayer, String adminOrg) {
  136. this.orgName = orgName;
  137. this.orgLayer = orgLayer;
  138. this.adminOrg = adminOrg;
  139. }
  140. }
  141. /**
  142. * 按行政组织FID及其下级追加 IN 条件(长编码 LIKE 前缀匹配)。
  143. */
  144. public static void appendOrgFilter(StringBuilder sql, Context ctx, String adminOrg, String orgField)
  145. throws BOSException, SQLException {
  146. if (StringUtils.isEmpty(adminOrg)) {
  147. return;
  148. }
  149. String longNumber = getOrgLongNumber(ctx, adminOrg);
  150. if (StringUtils.isEmpty(longNumber)) {
  151. return;
  152. }
  153. sql.append("AND ").append(orgField).append(" IN (");
  154. sql.append("SELECT admin.FID FROM T_ORG_Admin admin ");
  155. sql.append("WHERE admin.FLongNumber LIKE '").append(escapeSql(longNumber)).append("%' ");
  156. sql.append("AND admin.FIsSealUp = 0 ");
  157. sql.append(") ");
  158. }
  159. /**
  160. * 按组织名称+层级追加 IN 条件(跨公司同名合并,排除130)。
  161. */
  162. public static void appendOrgFilterByName(StringBuilder sql, Context ctx, String orgName,
  163. String layerType, String orgField) throws BOSException, SQLException {
  164. if (StringUtils.isEmpty(orgName)) {
  165. return;
  166. }
  167. String layer = StringUtils.isEmpty(layerType) ? LAYER_CENTER : layerType;
  168. String excludedLongNumber = getExcludedOrgLongNumber(ctx);
  169. sql.append("AND ").append(orgField).append(" IN (");
  170. sql.append("SELECT subOrg.FID FROM T_ORG_Admin orgNode ");
  171. sql.append("INNER JOIN T_Org_LayerType lt ON lt.FID = orgNode.FLAYERTYPEID ");
  172. sql.append("INNER JOIN T_ORG_Admin subOrg ");
  173. sql.append(" ON LEFT(subOrg.FLongNumber, LEN(orgNode.FLongNumber)) = orgNode.FLongNumber ");
  174. sql.append("WHERE orgNode.FNAME_L2 = '").append(escapeSql(orgName)).append("' ");
  175. sql.append("AND lt.FNUMBER = '").append(escapeSql(layer)).append("' ");
  176. sql.append("AND orgNode.FIsSealUp = 0 AND subOrg.FIsSealUp = 0 ");
  177. if (!StringUtils.isEmpty(excludedLongNumber)) {
  178. sql.append("AND orgNode.FLongNumber NOT LIKE '").append(excludedLongNumber).append("%' ");
  179. }
  180. sql.append(") ");
  181. }
  182. /**
  183. * 统一组织范围过滤:优先名称,其次行政组织FID,最后排除130。
  184. */
  185. public static void appendOrgScopeFilter(StringBuilder sql, Context ctx, String orgField, OrgScope scope)
  186. throws BOSException, SQLException {
  187. if (scope != null && !StringUtils.isEmpty(scope.orgName)) {
  188. appendOrgFilterByName(sql, ctx, scope.orgName, scope.orgLayer, orgField);
  189. return;
  190. }
  191. if (scope != null && !StringUtils.isEmpty(scope.adminOrg)) {
  192. appendOrgFilter(sql, ctx, scope.adminOrg, orgField);
  193. }
  194. appendExcludeOrg130ById(sql, orgField, ctx);
  195. }
  196. /** 人员任职部门范围过滤。 */
  197. public static void appendPersonDepScopeFilter(StringBuilder sql, Context ctx, OrgScope scope)
  198. throws BOSException, SQLException {
  199. appendOrgScopeFilter(sql, ctx, "personPos.FPersonDep", scope);
  200. }
  201. /** 行政组织字段范围过滤。 */
  202. public static void appendAdminOrgScopeFilter(StringBuilder sql, Context ctx, OrgScope scope, String orgField)
  203. throws BOSException, SQLException {
  204. appendOrgScopeFilter(sql, ctx, orgField, scope);
  205. }
  206. /**
  207. * 中心人员范围:可选公司 + 按中心名称过滤任职部门(跨公司同名,排除130)。
  208. */
  209. public static void appendCenterPersonScope(StringBuilder sql, Context ctx, String centerName, String companyId)
  210. throws BOSException, SQLException {
  211. if (!StringUtils.isEmpty(companyId)) {
  212. sql.append("AND personPos.FCompanyID = '").append(companyId).append("' ");
  213. }
  214. appendOrgFilterByName(sql, ctx, centerName, LAYER_CENTER, "personPos.FPersonDep");
  215. }
  216. /**
  217. * 部门人员范围:可选公司 + 按部门名称过滤任职部门(跨公司同名,排除130)。
  218. */
  219. public static void appendDeptPersonScope(StringBuilder sql, Context ctx, String deptName, String companyId)
  220. throws BOSException, SQLException {
  221. if (!StringUtils.isEmpty(companyId)) {
  222. sql.append("AND personPos.FCompanyID = '").append(companyId).append("' ");
  223. }
  224. appendOrgFilterByName(sql, ctx, deptName, LAYER_DEPT, "personPos.FPersonDep");
  225. }
  226. /**
  227. * 查询指定中心下的部门名称编码列表(跨公司同名合并,排除130)。
  228. */
  229. public static List<OrgNameCode> getDistinctDeptNameCodesUnderCenter(Context ctx, String centerName, String companyId)
  230. throws BOSException, SQLException {
  231. Map<String, String> nameToCode = new LinkedHashMap<String, String>();
  232. if (StringUtils.isEmpty(centerName)) {
  233. return new ArrayList<OrgNameCode>();
  234. }
  235. String excludedLongNumber = getExcludedOrgLongNumber(ctx);
  236. StringBuilder sql = new StringBuilder();
  237. sql.append("SELECT dept.FNAME_L2 AS orgName, dept.FNUMBER AS orgCode ");
  238. sql.append("FROM T_ORG_Admin center ");
  239. sql.append("INNER JOIN T_Org_LayerType ltCenter ON ltCenter.FID = center.FLAYERTYPEID ");
  240. sql.append("INNER JOIN T_ORG_Admin dept ");
  241. sql.append(" ON LEFT(dept.FLongNumber, LEN(center.FLongNumber)) = center.FLongNumber ");
  242. sql.append("INNER JOIN T_Org_LayerType ltDept ON ltDept.FID = dept.FLAYERTYPEID ");
  243. sql.append("WHERE center.FNAME_L2 = '").append(escapeSql(centerName)).append("' ");
  244. sql.append("AND ltCenter.FNUMBER = '").append(escapeSql(LAYER_CENTER)).append("' ");
  245. sql.append("AND ltDept.FNUMBER = '").append(escapeSql(LAYER_DEPT)).append("' ");
  246. sql.append("AND center.FIsSealUp = 0 AND dept.FIsSealUp = 0 ");
  247. if (!StringUtils.isEmpty(excludedLongNumber)) {
  248. sql.append("AND center.FLongNumber NOT LIKE '").append(excludedLongNumber).append("%' ");
  249. }
  250. sql.append("ORDER BY dept.FNAME_L2, dept.FNUMBER");
  251. IRowSet rs = DbUtil.executeQuery(ctx, sql.toString());
  252. while (rs.next()) {
  253. String name = rs.getString("orgName");
  254. String code = rs.getString("orgCode");
  255. if (StringUtils.isEmpty(name) || StringUtils.isEmpty(code)) {
  256. continue;
  257. }
  258. if (!nameToCode.containsKey(name)) {
  259. nameToCode.put(name, code);
  260. }
  261. }
  262. List<OrgNameCode> result = new ArrayList<OrgNameCode>();
  263. for (Map.Entry<String, String> entry : nameToCode.entrySet()) {
  264. result.add(new OrgNameCode(entry.getKey(), entry.getValue()));
  265. }
  266. return result;
  267. }
  268. /**
  269. * 行政组织FID+部门名称追加 IN 条件(部门须在该行政组织树下)。
  270. */
  271. public static void appendDeptUnderAdminOrgFilter(StringBuilder sql, Context ctx, String adminOrgId,
  272. String deptName, String orgField) throws BOSException, SQLException {
  273. if (StringUtils.isEmpty(adminOrgId) || StringUtils.isEmpty(deptName)) {
  274. return;
  275. }
  276. String excludedLongNumber = getExcludedOrgLongNumber(ctx);
  277. sql.append("AND ").append(orgField).append(" IN (");
  278. sql.append("SELECT sub.FID FROM T_ORG_Admin root ");
  279. sql.append("INNER JOIN T_ORG_Admin deptNode ON deptNode.FNAME_L2 = '").append(escapeSql(deptName)).append("' ");
  280. sql.append("INNER JOIN T_Org_LayerType ltDept ON ltDept.FID = deptNode.FLAYERTYPEID ");
  281. sql.append("INNER JOIN T_ORG_Admin sub ");
  282. sql.append(" ON LEFT(sub.FLongNumber, LEN(deptNode.FLongNumber)) = deptNode.FLongNumber ");
  283. sql.append("WHERE root.FID = '").append(escapeSql(adminOrgId)).append("' ");
  284. sql.append("AND ltDept.FNUMBER = '").append(escapeSql(LAYER_DEPT)).append("' ");
  285. sql.append("AND LEFT(deptNode.FLongNumber, LEN(root.FLongNumber)) = root.FLongNumber ");
  286. sql.append("AND root.FIsSealUp = 0 AND deptNode.FIsSealUp = 0 AND sub.FIsSealUp = 0 ");
  287. if (!StringUtils.isEmpty(excludedLongNumber)) {
  288. sql.append("AND root.FLongNumber NOT LIKE '").append(excludedLongNumber).append("%' ");
  289. }
  290. sql.append(") ");
  291. }
  292. /**
  293. * 行政组织FID+部门编码追加 IN 条件(部门须在该组织树下)。
  294. */
  295. public static void appendDeptUnderAdminOrgFilterByCode(StringBuilder sql, Context ctx, String adminOrgId,
  296. String deptCode, String orgField) throws BOSException, SQLException {
  297. if (StringUtils.isEmpty(adminOrgId) || StringUtils.isEmpty(deptCode)) {
  298. return;
  299. }
  300. String excludedLongNumber = getExcludedOrgLongNumber(ctx);
  301. sql.append("AND ").append(orgField).append(" IN (");
  302. sql.append("SELECT sub.FID FROM T_ORG_Admin root ");
  303. sql.append("INNER JOIN T_ORG_Admin deptNode ON deptNode.FNUMBER = '").append(escapeSql(deptCode)).append("' ");
  304. sql.append("INNER JOIN T_ORG_Admin sub ");
  305. sql.append(" ON LEFT(sub.FLongNumber, LEN(deptNode.FLongNumber)) = deptNode.FLongNumber ");
  306. sql.append("WHERE root.FID = '").append(escapeSql(adminOrgId)).append("' ");
  307. sql.append("AND LEFT(deptNode.FLongNumber, LEN(root.FLongNumber)) = root.FLongNumber ");
  308. sql.append("AND root.FIsSealUp = 0 AND deptNode.FIsSealUp = 0 AND sub.FIsSealUp = 0 ");
  309. if (!StringUtils.isEmpty(excludedLongNumber)) {
  310. sql.append("AND root.FLongNumber NOT LIKE '").append(excludedLongNumber).append("%' ");
  311. }
  312. sql.append(") ");
  313. }
  314. /**
  315. * 中心名称+部门编码追加 IN 条件(跨公司同名,排除130)。
  316. */
  317. public static void appendDeptUnderCenterFilterByCode(StringBuilder sql, Context ctx, String centerName,
  318. String deptCode, String orgField) throws BOSException, SQLException {
  319. if (StringUtils.isEmpty(centerName) || StringUtils.isEmpty(deptCode)) {
  320. return;
  321. }
  322. String excludedLongNumber = getExcludedOrgLongNumber(ctx);
  323. sql.append("AND ").append(orgField).append(" IN (");
  324. sql.append("SELECT sub.FID FROM T_ORG_Admin center ");
  325. sql.append("INNER JOIN T_Org_LayerType ltCenter ON ltCenter.FID = center.FLAYERTYPEID ");
  326. sql.append("INNER JOIN T_ORG_Admin deptNode ON deptNode.FNUMBER = '").append(escapeSql(deptCode)).append("' ");
  327. sql.append("INNER JOIN T_ORG_Admin sub ");
  328. sql.append(" ON LEFT(sub.FLongNumber, LEN(deptNode.FLongNumber)) = deptNode.FLongNumber ");
  329. sql.append("WHERE center.FNAME_L2 = '").append(escapeSql(centerName)).append("' ");
  330. sql.append("AND ltCenter.FNUMBER = '").append(escapeSql(LAYER_CENTER)).append("' ");
  331. sql.append("AND LEFT(deptNode.FLongNumber, LEN(center.FLongNumber)) = center.FLongNumber ");
  332. sql.append("AND center.FIsSealUp = 0 AND deptNode.FIsSealUp = 0 AND sub.FIsSealUp = 0 ");
  333. if (!StringUtils.isEmpty(excludedLongNumber)) {
  334. sql.append("AND center.FLongNumber NOT LIKE '").append(excludedLongNumber).append("%' ");
  335. }
  336. sql.append(") ");
  337. }
  338. /**
  339. * 中心名称+部门名称追加 IN 条件(跨公司同名,排除130)。
  340. */
  341. public static void appendDeptUnderCenterFilter(StringBuilder sql, Context ctx, String centerName,
  342. String deptName, String orgField) throws BOSException, SQLException {
  343. if (StringUtils.isEmpty(centerName) || StringUtils.isEmpty(deptName)) {
  344. return;
  345. }
  346. String excludedLongNumber = getExcludedOrgLongNumber(ctx);
  347. sql.append("AND ").append(orgField).append(" IN (");
  348. sql.append("SELECT sub.FID FROM T_ORG_Admin center ");
  349. sql.append("INNER JOIN T_Org_LayerType ltCenter ON ltCenter.FID = center.FLAYERTYPEID ");
  350. sql.append("INNER JOIN T_ORG_Admin deptNode ON deptNode.FNAME_L2 = '").append(escapeSql(deptName)).append("' ");
  351. sql.append("INNER JOIN T_Org_LayerType ltDept ON ltDept.FID = deptNode.FLAYERTYPEID ");
  352. sql.append("INNER JOIN T_ORG_Admin sub ");
  353. sql.append(" ON LEFT(sub.FLongNumber, LEN(deptNode.FLongNumber)) = deptNode.FLongNumber ");
  354. sql.append("WHERE center.FNAME_L2 = '").append(escapeSql(centerName)).append("' ");
  355. sql.append("AND ltCenter.FNUMBER = '").append(escapeSql(LAYER_CENTER)).append("' ");
  356. sql.append("AND ltDept.FNUMBER = '").append(escapeSql(LAYER_DEPT)).append("' ");
  357. sql.append("AND LEFT(deptNode.FLongNumber, LEN(center.FLongNumber)) = center.FLongNumber ");
  358. sql.append("AND center.FIsSealUp = 0 AND deptNode.FIsSealUp = 0 AND sub.FIsSealUp = 0 ");
  359. if (!StringUtils.isEmpty(excludedLongNumber)) {
  360. sql.append("AND center.FLongNumber NOT LIKE '").append(excludedLongNumber).append("%' ");
  361. }
  362. sql.append(") ");
  363. }
  364. /**
  365. * 组织名称与编码(跨公司同名时编码取第一个)。
  366. */
  367. public static final class OrgNameCode {
  368. /** 组织名称 FNAME_L2 */
  369. public final String orgName;
  370. /** 组织编码 FNUMBER,同名跨公司时取第一个 */
  371. public final String orgCode;
  372. public OrgNameCode(String orgName, String orgCode) {
  373. this.orgName = orgName;
  374. this.orgCode = orgCode;
  375. }
  376. }
  377. /**
  378. * 按快筛文本过滤组织列表(文本包含组织名称则保留,无匹配则返回原列表)。
  379. */
  380. public static List<OrgNameCode> filterOrgNameCodes(List<OrgNameCode> source, String filterText) {
  381. if (source == null || source.isEmpty() || StringUtils.isEmpty(filterText)) {
  382. return source;
  383. }
  384. List<OrgNameCode> filtered = new ArrayList<OrgNameCode>();
  385. for (OrgNameCode item : source) {
  386. if (filterText.contains(item.orgName)) {
  387. filtered.add(item);
  388. }
  389. }
  390. return filtered.isEmpty() ? source : filtered;
  391. }
  392. /**
  393. * 查询指定层级的去重组织名称编码列表(跨公司同名合并,排除130)。
  394. *
  395. * @param layerType 组织层级,如"中心"/"部门"
  396. * @param companyId 公司FID,可选限定范围
  397. * @return 去重后的组织名称编码列表
  398. */
  399. public static List<OrgNameCode> getDistinctOrgNameCodes(Context ctx, String layerType, String companyId)
  400. throws BOSException, SQLException {
  401. Map<String, String> nameToCode = new LinkedHashMap<String, String>();
  402. StringBuilder sql = new StringBuilder();
  403. List<Object> params = new ArrayList<Object>();
  404. sql.append("SELECT admin.FNAME_L2 AS orgName, admin.FNUMBER AS orgCode ");
  405. sql.append("FROM T_ORG_Admin admin ");
  406. sql.append("INNER JOIN T_Org_LayerType lt ON lt.FID = admin.FLAYERTYPEID ");
  407. sql.append("WHERE lt.FNUMBER = ? AND admin.FIsSealUp = 0 ");
  408. params.add(layerType);
  409. if (!StringUtils.isEmpty(companyId)) {
  410. sql.append("AND admin.FParentID = ? ");
  411. params.add(companyId);
  412. }
  413. appendExcludeOrg130(sql, "admin", ctx);
  414. sql.append("ORDER BY admin.FNAME_L2, admin.FNUMBER");
  415. IRowSet rs = DbUtil.executeQuery(ctx, sql.toString(), params.toArray());
  416. while (rs.next()) {
  417. String name = rs.getString("orgName");
  418. String code = rs.getString("orgCode");
  419. if (StringUtils.isEmpty(name) || StringUtils.isEmpty(code)) {
  420. continue;
  421. }
  422. if (!nameToCode.containsKey(name)) {
  423. nameToCode.put(name, code);
  424. }
  425. }
  426. List<OrgNameCode> result = new ArrayList<OrgNameCode>();
  427. for (Map.Entry<String, String> entry : nameToCode.entrySet()) {
  428. result.add(new OrgNameCode(entry.getKey(), entry.getValue()));
  429. }
  430. return result;
  431. }
  432. /** 执行 COUNT 查询并返回结果,可选打日志。 */
  433. public static int executeCountQuery(Context ctx, StringBuilder sql, String logPrefix, Logger logger)
  434. throws BOSException, SQLException {
  435. if (logger != null) {
  436. logger.error(logPrefix + "SQL: " + sql.toString());
  437. }
  438. IRowSet rs = DbUtil.executeQuery(ctx, sql.toString());
  439. if (rs.next()) {
  440. return rs.getInt("count");
  441. }
  442. return 0;
  443. }
  444. /** SQL 单引号转义。 */
  445. private static String escapeSql(String value) {
  446. if (value == null) {
  447. return "";
  448. }
  449. return value.replace("'", "''");
  450. }
  451. }