| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425 |
- package com.kingdee.eas.custom.perfweb.handler;
- import com.alibaba.fastjson.JSONArray;
- import com.alibaba.fastjson.JSONObject;
- import com.kingdee.bos.Context;
- import com.kingdee.bos.dao.ormapping.ObjectUuidPK;
- import com.kingdee.eas.base.permission.UserInfo;
- import com.kingdee.eas.custom.perfweb.AssessmentResultDescriptionFactory;
- import com.kingdee.eas.custom.perfweb.AssessmentResultDescriptionInfo;
- import com.kingdee.eas.custom.perfweb.IAssessmentResultDescription;
- import com.kingdee.eas.custom.perfweb.bizEnum.AutoStatusEnum;
- import com.kingdee.eas.custom.perfweb.service.CenterPerfStatService;
- import com.kingdee.eas.custom.perfweb.utils.FeishuMessageUtil;
- import com.kingdee.eas.custom.perfweb.utils.UrlParamUtil;
- import com.kingdee.eas.util.app.ContextUtil;
- import com.kingdee.eas.util.app.DbUtil;
- import com.kingdee.jdbc.rowset.IRowSet;
- import com.kingdee.shr.base.syssetting.context.SHRContext;
- import com.kingdee.shr.base.syssetting.exception.SHRWebException;
- import com.kingdee.shr.base.syssetting.exception.ShrWebBizException;
- import com.kingdee.shr.base.syssetting.json.GridDataEntity;
- import com.kingdee.shr.base.syssetting.web.handler.ListHandler;
- import com.kingdee.shr.base.syssetting.web.json.JSONUtils;
- import com.kingdee.shr.perfweb.app.base.evalplan.PerfPeriodFactory;
- import com.kingdee.shr.perfweb.app.base.evalplan.PerfPeriodInfo;
- import org.apache.commons.lang3.StringUtils;
- import org.apache.log4j.Logger;
- import org.springframework.ui.ModelMap;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import java.util.ArrayList;
- import java.util.HashMap;
- import java.util.LinkedHashMap;
- import java.util.List;
- import java.util.Map;
- import java.util.Set;
- /**
- * 绩效考核结果报表 ListHandler:getGridRequestData 加载表格数据,approve 审批发飞书待办。
- */
- public class CenterPerfStatReportHandlerEx extends ListHandler {
- private final Logger logger = Logger.getLogger(CenterPerfStatReportHandlerEx.class);
- private final Context ctx = SHRContext.getInstance().getContext();
- /**
- * 报表列表数据:调 getCenterPerfStatService(CenterPerfStatService.queryReport)后封装 GridDataEntity。
- * periodId 未选时由 Service 取考核中最新周期;组织未选时按系统行政组织范围过滤。
- */
- @Override
- protected GridDataEntity getGridRequestData(HttpServletRequest request, HttpServletResponse response, ModelMap modelMap) throws SHRWebException {
- try {
- ListFilterParams filterParams = parseListFilterParams(request);
- Map<String, Object> queryResult = CenterPerfStatService.queryReport(ctx, filterParams.periodId, filterParams.orgId, filterParams.adminOrgRangeIds);
- if (!"200".equals(String.valueOf(queryResult.get("code")))) {
- throw new ShrWebBizException(String.valueOf(queryResult.get("msg")));
- }
- Map<String, Object> data = (Map<String, Object>) queryResult.get("data");
- List<Map<String, Object>> allRows = data != null && data.get("rows") != null ? (List<Map<String, Object>>) data.get("rows") : new ArrayList<>();
- int rows = Integer.parseInt(request.getParameter("rows"));
- int page = Integer.parseInt(request.getParameter("page"));
- int records = allRows.size();
- int from = Math.max((page - 1) * rows, 0);
- int to = Math.min(from + rows, records);
- List<Map<String, Object>> pageRows = from < to ? allRows.subList(from, to) : new ArrayList<>();
- GridDataEntity grid = new GridDataEntity();
- grid.setRecords(records);
- grid.setPage(page);
- grid.setTotal(records == 0 ? 0 : (records % rows == 0 ? records / rows : records / rows + 1));
- grid.setRows(pageRows);
- Map<String, Object> userdata = new HashMap<>();
- if (data != null) {
- userdata.put("periodId", data.get("periodId"));
- userdata.put("periodName", data.get("periodName"));
- userdata.put("gradePercents", data.get("gradePercents"));
- }
- grid.setUserdata(userdata);
- return grid;
- } catch (ShrWebBizException e) {
- throw e;
- } catch (Exception e) {
- logger.error("绩效考核结果报表加载失败", e);
- throw new ShrWebBizException(e.getMessage());
- }
- }
- /**
- * 从高级过滤 JSON 取 F7 选中项 id(dataItem)
- */
- private String getFilterId(JSONObject filterJson, String key) {
- if (filterJson == null || !filterJson.containsKey(key)) {
- return null;
- }
- JSONObject item = filterJson.getJSONObject(key);
- if (item == null) {
- return null;
- }
- JSONArray dataItem = item.getJSONArray("dataItem");
- if (dataItem == null || dataItem.isEmpty()) {
- return null;
- }
- return dataItem.getJSONObject(0).getString("id");
- }
- /**
- * 从高级过滤 JSON 取 values 字段(与前端 getFastFilterItems().period.values 一致)
- */
- private String getFilterValues(JSONObject filterJson, String key) {
- if (filterJson == null || !filterJson.containsKey(key)) {
- return null;
- }
- JSONObject item = filterJson.getJSONObject(key);
- if (item == null) {
- return null;
- }
- return StringUtils.trimToNull(item.getString("values"));
- }
- private String resolvePeriodId(JSONObject filterJson, HttpServletRequest request) {
- String periodId = getFilterId(filterJson, "period");
- if (StringUtils.isBlank(periodId)) {
- periodId = getFilterId(filterJson, "periodId");
- }
- if (StringUtils.isBlank(periodId)) {
- periodId = getFilterValues(filterJson, "period");
- }
- if (StringUtils.isBlank(periodId)) {
- periodId = getFilterValues(filterJson, "periodId");
- }
- if (StringUtils.isBlank(periodId)) {
- periodId = StringUtils.trimToNull(request.getParameter("periodId"));
- }
- return periodId;
- }
- private String resolveOrgId(JSONObject filterJson) {
- String orgId = getFilterId(filterJson, "orgId");
- if (StringUtils.isBlank(orgId)) {
- orgId = getFilterId(filterJson, "adminOrg");
- }
- if (StringUtils.isBlank(orgId)) {
- orgId = getFilterValues(filterJson, "orgId");
- }
- if (StringUtils.isBlank(orgId)) {
- orgId = getFilterValues(filterJson, "adminOrg");
- }
- return orgId;
- }
- /**
- * 审批:action=hrStart|directorApprove|gmApprove(与前端 remoteCall method=approve 对应)。
- * billIds 由 fastFilterItems 查询条件及单据状态自动解析,无需勾选行。
- */
- public void approveAction(HttpServletRequest request, HttpServletResponse response, ModelMap modelMap) throws SHRWebException {
- Map<String, Object> res = new LinkedHashMap<>();
- String action = request.getParameter("action");
- ListFilterParams filterParams = parseListFilterParams(request);
- String periodId = filterParams.periodId;
- UserInfo user = ContextUtil.getCurrentUserInfo(ctx);
- String creatorId = user != null && user.getPerson() != null ? user.getPerson().getNumber() : null;
- if (StringUtils.isBlank(creatorId)) {
- res.put("code", "500");
- res.put("msg", "无法获取当前登录人工号");
- JSONUtils.writeJson(response, res);
- return;
- }
- AutoStatusEnum expect;
- AutoStatusEnum target;
- String nextCode;
- String doneCode;
- String emptyMsg;
- String successMsgPrefix;
- if ("hrStart".equals(action)) {
- expect = AutoStatusEnum.WFQ;
- target = AutoStatusEnum.ZJSPZ;
- nextCode = "JXJG02";
- doneCode = null;
- emptyMsg = "当前查询条件下没有可发起的单据";
- successMsgPrefix = "发起审批成功";
- } else if ("directorApprove".equals(action)) {
- expect = AutoStatusEnum.ZJSPZ;
- target = AutoStatusEnum.ZJLSPZ;
- nextCode = "JXJG03";
- doneCode = "JXJG02";
- emptyMsg = "当前查询条件下没有总监审批中的单据";
- successMsgPrefix = "总监审批通过";
- } else if ("gmApprove".equals(action)) {
- expect = AutoStatusEnum.ZJLSPZ;
- target = AutoStatusEnum.SPTG;
- nextCode = null;
- doneCode = "JXJG03";
- emptyMsg = "当前查询条件下没有总经理审批中的单据";
- successMsgPrefix = "总经理审批通过";
- } else {
- res.put("code", "500");
- res.put("msg", "不支持的 action:" + action);
- JSONUtils.writeJson(response, res);
- return;
- }
- String billIds;
- try {
- billIds = resolveApproveBillIds(periodId, filterParams.orgId, filterParams.adminOrgRangeIds, expect.getValue());
- } catch (ShrWebBizException e) {
- res.put("code", "500");
- res.put("msg", e.getMessage());
- JSONUtils.writeJson(response, res);
- return;
- }
- if (StringUtils.isBlank(billIds)) {
- res.put("code", "500");
- res.put("msg", emptyMsg);
- JSONUtils.writeJson(response, res);
- return;
- }
- if ("hrStart".equals(action)) {
- String gradeCheckMsg = CenterPerfStatService.validateGradeActualEqualsTotalForHrStart(
- ctx, periodId, filterParams.orgId, filterParams.adminOrgRangeIds, expect.getValue());
- if (gradeCheckMsg != null) {
- res.put("code", "500");
- res.put("msg", gradeCheckMsg);
- JSONUtils.writeJson(response, res);
- return;
- }
- }
- try {
- String periodName = "";
- if (StringUtils.isBlank(periodId)) {
- periodId = CenterPerfStatService.resolveDefaultPeriodId(ctx);
- }
- if (StringUtils.isNotBlank(periodId)) {
- PerfPeriodInfo period = PerfPeriodFactory.getLocalInstance(ctx).getPerfPeriodInfo("where id = '" + periodId + "'");
- if (period != null) {
- periodName = period.getName();
- }
- }
- String title = "绩效考核结果待审批【" + periodName + "】,请及时处理";
- String pcurl = UrlParamUtil.buildCenterPerfStatReportListOaUrl(periodId);
- String appurl = pcurl;
- String nextReceiver = nextCode != null ? getHrBaseNumber(ctx, nextCode) : null;
- if (nextCode != null && StringUtils.isBlank(nextReceiver)) {
- res.put("code", "500");
- res.put("msg", "未配置审批人工号:" + nextCode);
- JSONUtils.writeJson(response, res);
- return;
- }
- IAssessmentResultDescription iBill = AssessmentResultDescriptionFactory.getLocalInstance(ctx);
- List<String> validBillIds = new ArrayList<>();
- for (String billId : billIds.split(",")) {
- billId = billId.trim();
- if (StringUtils.isBlank(billId)) {
- continue;
- }
- AssessmentResultDescriptionInfo bill = iBill.getAssessmentResultDescriptionInfo(new ObjectUuidPK(billId));
- if (bill == null) {
- res.put("code", "500");
- res.put("msg", "未找到单据:" + billId);
- JSONUtils.writeJson(response, res);
- return;
- }
- if (bill.getAutoStatus() != expect) {
- res.put("code", "500");
- res.put("msg", "单据[" + bill.getNumber() + "]状态不正确,无法执行该操作");
- JSONUtils.writeJson(response, res);
- return;
- }
- validBillIds.add(billId);
- }
- // 办结上一节点待办:flowId 与推送时一致(周期 + 接收人 + 待办时状态)
- if (doneCode != null) {
- String doneReceiver = getHrBaseNumber(ctx, doneCode);
- if (StringUtils.isBlank(doneReceiver)) {
- res.put("code", "500");
- res.put("msg", "未配置审批人工号:" + doneCode);
- JSONUtils.writeJson(response, res);
- return;
- }
- String doneFlowId = buildCenterPerfFlowId(periodId, doneReceiver, expect.getValue());
- if (target == AutoStatusEnum.SPTG) {
- FeishuMessageUtil.sendFeishuCall(doneReceiver, title, pcurl, "绩效考核结果审批", appurl, doneFlowId,
- FeishuMessageUtil.VIEWTYPE_READ, FeishuMessageUtil.ISREMARK_COMPLETE, creatorId);
- } else {
- FeishuMessageUtil.sendFeishuCall(doneReceiver, title, pcurl, "绩效考核结果审批", appurl, doneFlowId,
- FeishuMessageUtil.VIEWTYPE_READ, FeishuMessageUtil.ISREMARK_DONE, creatorId);
- }
- }
- for (String billId : validBillIds) {
- AssessmentResultDescriptionInfo bill = iBill.getAssessmentResultDescriptionInfo(new ObjectUuidPK(billId));
- bill.setAutoStatus(target);
- iBill.update(new ObjectUuidPK(billId), bill);
- }
- // 推送下一节点待办(每个周期每个接收人一条,总监审批后 HR 推给总监的那条 flowId 已被置为已办)
- if (nextReceiver != null && !validBillIds.isEmpty()) {
- String nextFlowId = buildCenterPerfFlowId(periodId, nextReceiver, target.getValue());
- FeishuMessageUtil.sendFeishuTodo(nextReceiver, title, pcurl, "绩效考核结果审批", appurl, nextFlowId, creatorId);
- }
- int processedCount = validBillIds.size();
- res.put("code", "200");
- res.put("msg", buildSuccessMsg(successMsgPrefix, periodName, processedCount, action));
- } catch (Exception e) {
- logger.error("绩效考核结果审批失败", e);
- res.put("code", "500");
- res.put("msg", "审批失败:" + e.getMessage());
- }
- JSONUtils.writeJson(response, res);
- }
- /**
- * 解析列表快速过滤:考核周期、组织及行政组织范围(与前端 getFastFilterItems 同源)。
- */
- private ListFilterParams parseListFilterParams(HttpServletRequest request) throws SHRWebException {
- ListFilterParams params = new ListFilterParams();
- String fastFilterItems = request.getParameter("fastFilterItems");
- JSONObject filterJson = StringUtils.isNotBlank(fastFilterItems) ? JSONObject.parseObject(fastFilterItems) : null;
- params.periodId = resolvePeriodId(filterJson, request);
- params.orgId = resolveOrgId(filterJson);
- if (StringUtils.isBlank(params.orgId)) {
- params.adminOrgRangeIds = getCurrentRequestAdminOrgRangeIdSet(request);
- }
- return params;
- }
- /**
- * 按查询条件及目标状态解析待处理单据 id。
- */
- private String resolveApproveBillIds(String periodId, String orgId, Set<String> adminOrgRangeIds,
- String expectStatusValue) throws ShrWebBizException {
- Map<String, Object> queryResult = CenterPerfStatService.queryReport(ctx, periodId, orgId, adminOrgRangeIds);
- if (!"200".equals(String.valueOf(queryResult.get("code")))) {
- throw new ShrWebBizException(String.valueOf(queryResult.get("msg")));
- }
- Map<String, Object> data = (Map<String, Object>) queryResult.get("data");
- List<Map<String, Object>> rows = data != null && data.get("rows") != null ? (List<Map<String, Object>>) data.get("rows") : new ArrayList<>();
- List<String> billIds = new ArrayList<>();
- for (Map<String, Object> row : rows) {
- if (!expectStatusValue.equals(String.valueOf(row.get("autoStatus")))) {
- continue;
- }
- Object id = row.get("id");
- if (id != null && StringUtils.isNotBlank(String.valueOf(id))) {
- billIds.add(String.valueOf(id));
- }
- }
- return StringUtils.join(billIds, ",");
- }
- private static class ListFilterParams {
- private String periodId;
- private String orgId;
- private Set<String> adminOrgRangeIds;
- }
- private String buildSuccessMsg(String prefix, String periodName, int count, String action) {
- String periodPart = StringUtils.isNotBlank(periodName) ? "【" + periodName + "】" : "";
- String countPart = ",共处理 " + count + " 条绩效考核结果";
- if ("hrStart".equals(action)) {
- return prefix + periodPart + countPart + ",已推送总监审批待办";
- }
- if ("directorApprove".equals(action)) {
- return prefix + periodPart + countPart + ",总监待办已办结,已推送总经理审批待办";
- }
- if ("gmApprove".equals(action)) {
- return prefix + periodPart + countPart + ",审批流程已全部完成";
- }
- return prefix + periodPart + countPart;
- }
- private String getHrBaseNumber(Context ctx, String code) throws Exception {
- if (StringUtils.isBlank(code)) {
- return null;
- }
- String sql = "select FSimpleName from T_HR_ZDY0HRBase where FNumber=? and FState=1";
- IRowSet rowSet = DbUtil.executeQuery(ctx, sql, new Object[]{code});
- if (rowSet != null && rowSet.next()) {
- return StringUtils.trimToNull(rowSet.getString("FSimpleName"));
- }
- return null;
- }
- /**
- * 飞书待办 flowId:{考核周期短码}_{接收人工号}_{状态}
- * <p>
- * 周期 ID 形如 LJiKDANrQyeBpHqSZW/o/UUaiOU=,仅取 / 前一段,避免 flowId 过长。
- * 推送待办与办结须使用相同 flowId。例如 HR 发起推总监时状态为 ZJSPZ,总监审批办结时也用 ZJSPZ。
- */
- private String buildCenterPerfFlowId(String periodId, String receiverNumber, String statusValue) {
- return toShortPeriodId(periodId) + "_" + toFlowIdPart(receiverNumber)
- + "_" + toFlowIdPart(statusValue);
- }
- /** BOS 主键含 /、=,flowId 只保留第一段(/ 之前)。 */
- private String toShortPeriodId(String periodId) {
- if (StringUtils.isBlank(periodId)) {
- return "";
- }
- String trimmed = periodId.trim();
- int slash = trimmed.indexOf('/');
- if (slash > 0) {
- return trimmed.substring(0, slash);
- }
- return trimmed.replace("=", "_");
- }
- private String toFlowIdPart(String value) {
- if (StringUtils.isBlank(value)) {
- return "";
- }
- return value.trim().replace("/", "_").replace("=", "_");
- }
- }
|