外协人员批量审批

This commit is contained in:
2025-12-11 14:49:20 +08:00
parent 0b48e4d785
commit 470e14e7a2
28 changed files with 2304 additions and 35 deletions

View File

@@ -14,6 +14,8 @@ import com.jeelowcode.framework.tenant.annotation.JeeLowCodeTenantIgnore;
import com.jeelowcode.framework.utils.model.ResultDataModel;
import com.jeelowcode.framework.utils.tool.CollectionUtil;
import com.jeelowcode.service.infra.service.IFileService;
import com.jeelowcode.service.system.api.IApiAdminUserApi;
import com.jeelowcode.service.system.dto.AdminUserRespDTO;
import com.jeelowcode.tool.framework.common.pojo.CommonResult;
import com.jeelowcode.tool.framework.common.util.io.FileUtil;
import com.jeelowcode.tool.framework.common.util.string.StrUtils;
@@ -27,8 +29,10 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.regex.Pattern;
@@ -51,6 +55,9 @@ public class OutSidePersonController extends BaseController {
@Autowired
private IFrameSqlService sqlService;
@Autowired
private IApiAdminUserApi apiAdminUserApi;
@GetMapping({"/importOutside"})
@ApiOperationSupport(order = 5)
@Operation(summary = "引入外协人员")
@@ -90,6 +97,93 @@ public class OutSidePersonController extends BaseController {
}
/**
* 批量发起审批
* 1) 校验外协人员审批状态未发起approveStatus != 1否则抛出姓名
* 2) 生成批量审批主表数据lc_outside_batch_approval
* 3) 按外协人员生成批量审批明细数据lc_outside_batch_approval_detail
*/
@PostMapping({"/batchApproval"})
@ApiOperationSupport(order = 6)
@Operation(summary = "批量发起审批")
public CommonResult<Map<String, Object>> batchApproval(@RequestParam("ids") String ids) {
String[] idArr = ids.split(Pattern.quote(","));
if (Objects.isNull(idArr) || idArr.length == 0) {
throw new JeeLowCodeException("缺少必要参数");
}
Long personFormId = dbFormService.getDbFormIdByTableName("lc_outside_person");
Long batchFormId = dbFormService.getDbFormIdByTableName("lc_outside_batch_approval");
Long detailFormId = dbFormService.getDbFormIdByTableName("lc_outside_batch_approval_detail");
List<String> invalidNames = new ArrayList<>();
List<JSONObject> detailDataList = new ArrayList<>();
for (String idStr : idArr) {
Long dataId = Long.valueOf(idStr);
ResultDataModel dataDetail = super.getDataDetail(personFormId, dataId, new HashMap<>());
if (CollectionUtil.isEmpty(dataDetail.getRecords())) {
continue;
}
Map<String, Object> person = (Map<String, Object>) dataDetail.getRecords().get(0);
Object approveStatus = person.get("approveStatus");
if (approveStatus != null && !"0".equals(String.valueOf(approveStatus))) {
invalidNames.add(String.valueOf(person.get("personName")));
continue;
}
JSONObject detail = new JSONObject();
detail.put("batchApprovalId", 0); // 先占位,主表保存后再回填
detail.put("outsideId", person.get("id"));
detail.put("demandId", person.get("demandId"));
detail.put("demandName", person.get("demandName"));
detail.put("workPlaceId", person.get("workPlaceId"));
detail.put("workPlaceName", person.get("workPlaceName"));
detail.put("supplierId", person.get("supplierId"));
detail.put("supplierName", person.get("supplierName"));
detail.put("personName", person.get("personName"));
detail.put("mobile", person.get("mobile"));
detail.put("cardNo", person.get("cardNo"));
detailDataList.add(detail);
}
if (CollectionUtil.isNotEmpty(invalidNames)) {
throw new JeeLowCodeException("以下人员已发起审批或状态异常:" + String.join(",", invalidNames));
}
if (CollectionUtil.isEmpty(detailDataList)) {
throw new JeeLowCodeException("未找到可发起审批的外协人员");
}
LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
Long initiatorId = loginUser != null ? loginUser.getId() : -1L;
JSONObject batchData = new JSONObject();
batchData.put("billNo", "PZ" + System.currentTimeMillis());
batchData.put("initiatorId", initiatorId);
//TODO:获取到当前登录用户的用户名
AdminUserRespDTO initiator = apiAdminUserApi.getUser(initiatorId);
batchData.put("initiator", initiator.getNickname());
batchData.put("start_time", LocalDateTime.now());
batchData.put("lc_outside_batch_approval_detail", detailDataList);
// 获取插入后的主键
String batchId = super.addJsonData(batchFormId, batchData);
// 构建返回结果
Map<String, Object> result = new HashMap<>();
result.put("batchFormId", batchFormId);
result.put("batchId", batchId);
result.put("message", "批量审批发起成功");
return success(result);
}
public Map<String, Object> getOutSideByCardNo(String cardNo) {
SqlInfoQueryWrapper.Wrapper wrapper = SqlHelper.getQueryWrapper();
wrapper.setTableName("lc_outside_person");

View File

@@ -0,0 +1,46 @@
package com.jeelowcode.module.biz.enhance;
import com.jeelowcode.core.framework.config.aspect.enhance.model.EnhanceContext;
import com.jeelowcode.core.framework.config.aspect.enhance.plugin.AfterAdvicePlugin;
import com.jeelowcode.core.framework.controller.BaseController;
import com.jeelowcode.framework.utils.tool.NumberUtil;
import com.jeelowcode.module.biz.service.IDrillPlanService;
import com.jeelowcode.module.biz.service.IWorkItemService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.Map;
/**
* 删除前校验
*/
@Slf4j
@Component("afterItemResultCreateEnhance")
public class AfterDrillTaskCreateEnhance extends BaseController implements AfterAdvicePlugin {
@Autowired
private IDrillPlanService drillPlanService;
private static AfterDrillTaskCreateEnhance ADTE;
@PostConstruct
public void init(){
ADTE = this;
}
@Override
public void execute(EnhanceContext enhanceContext) {
Map<String, Object> params = enhanceContext.getParam().getParams();
if(!params.containsKey("id")){
return;
}
Long id = NumberUtil.toLong(params.get("id").toString());
// 发送代办消息
ADTE.drillPlanService.pushDrillTaskWorkflow(id,"DRILL_TASK_TODO");
}
}

View File

@@ -84,6 +84,14 @@ public class AfterDrillTaskEditEnhance extends BaseController implements AfterAd
currentPlan.put("drill_plan_status_type", planStatus);
super.editJsonData(planFormId, JSONUtil.parseObj(currentPlan));
}
// 发送已办消息
if(currentTask.get("task_status").equals("3"))
{
// 发送已办消息
ADTE.iDrillPlanService.pushDrillTaskWorkflow(id,"DRILL_TASK_DONE");
}
}
}

View File

@@ -17,7 +17,7 @@ import java.util.Map;
* 删除前校验
*/
@Slf4j
@Component("afterItemResultCreateEnhance")
@Component("AfterItemResultCreateEnhance")
public class AfterItemResultCreateEnhance extends BaseController implements AfterAdvicePlugin {
@Autowired

View File

@@ -0,0 +1,147 @@
package com.jeelowcode.module.biz.enhance;
import cn.hutool.json.JSONObject;
import com.jeelowcode.core.framework.config.aspect.enhance.model.EnhanceContext;
import com.jeelowcode.core.framework.config.aspect.enhance.plugin.AfterAdvicePlugin;
import com.jeelowcode.core.framework.controller.BaseController;
import com.jeelowcode.core.framework.enums.ApproveStatusEnum;
import com.jeelowcode.core.framework.service.IFormService;
import com.jeelowcode.core.framework.service.IFrameSqlService;
import com.jeelowcode.framework.plus.SqlHelper;
import com.jeelowcode.framework.plus.build.buildmodel.wrapper.SqlInfoQueryWrapper;
import com.jeelowcode.framework.utils.model.ResultDataModel;
import com.jeelowcode.framework.utils.tool.CollectionUtil;
import com.jeelowcode.framework.utils.tool.NumberUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 批量审批编辑后增强处理
* 根据lc_outside_batch_approval的审批状态同步更新lc_outside_person表的审批状态和流程实例ID
*/
@Slf4j
@Component("AfterOutsideBatchApprovalEditEnhance")
public class AfterOutsideBatchApprovalEditEnhance extends BaseController implements AfterAdvicePlugin {
@Autowired
IFormService dbFormService;
@Autowired
IFrameSqlService sqlService;
private static AfterOutsideBatchApprovalEditEnhance ADTE;
@PostConstruct
public void init(){
ADTE = this;
}
@Override
public void execute(EnhanceContext enhanceContext) {
Map<String, Object> params = enhanceContext.getParam().getParams();
if(!params.containsKey("id")){
return;
}
Long dataId = NumberUtil.toLong(params.get("id").toString());
Long personFormId = ADTE.dbFormService.getDbFormIdByTableName("lc_outside_person");
Long batchFormId = ADTE.dbFormService.getDbFormIdByTableName("lc_outside_batch_approval");
ResultDataModel resultDataModel = super.getDataDetail(batchFormId, dataId, new HashMap<>());
if (CollectionUtil.isNotEmpty(resultDataModel.getRecords())) {
if (resultDataModel.getRecords().get(0).containsKey("jeelowcode_subtable_data")) {
HashMap<String, Object> details = (HashMap<String, Object>) resultDataModel.getRecords().get(0).get("jeelowcode_subtable_data");
if (details.containsKey("lc_outside_batch_approval_detail")) {
List<HashMap<String, Object>> detailList = (List<HashMap<String, Object>>) details.get("lc_outside_batch_approval_detail");
// 从params中获取审批状态和流程实例ID
// 尝试多种可能的字段名(框架可能返回不同的大小写格式)
Object approveStatusObj = params.get(ApproveStatusEnum.codeField);
if (approveStatusObj == null) {
approveStatusObj = params.get("approveStatus");
}
Object processInstanceIdObj = params.get("processInstanceId");
if (processInstanceIdObj == null) {
processInstanceIdObj = params.get("ProcessInstanceId");
}
if (approveStatusObj == null) {
log.warn("批量审批记录 {} 的审批状态为空,跳过同步", dataId);
return;
}
Integer approveStatus = NumberUtil.toInt(approveStatusObj.toString());
String processInstanceId = processInstanceIdObj != null ? processInstanceIdObj.toString() : null;
// 根据审批状态获取对应的描述
String approveStatusName = getApproveStatusName(approveStatus);
if (CollectionUtil.isEmpty(detailList)) {
log.warn("批量审批记录 {} 没有关联的明细数据,跳过同步", dataId);
return;
}
// 收集需要更新的外协人员ID
List<Long> outsideIdList = new ArrayList<>();
for (Map<String, Object> detail : detailList) {
Object outsideIdObj = detail.get("outsideId");
if (outsideIdObj != null) {
Long outsideId = NumberUtil.toLong(outsideIdObj.toString());
if (outsideId != null) {
outsideIdList.add(outsideId);
}
}
}
if (CollectionUtil.isEmpty(outsideIdList)) {
log.warn("批量审批记录 {} 没有有效的外协人员ID跳过同步", dataId);
return;
}
// 批量更新外协人员表的审批状态和流程实例ID
List<JSONObject> updateList = new ArrayList<>();
for (Long outsideId : outsideIdList) {
JSONObject updateData = new JSONObject();
updateData.put("id", outsideId);
updateData.put(ApproveStatusEnum.codeField, approveStatus);
updateData.put(ApproveStatusEnum.nameField, approveStatusName);
if (processInstanceId != null) {
updateData.put("processInstanceId", processInstanceId);
}
updateList.add(updateData);
}
// 执行批量更新
if (CollectionUtil.isNotEmpty(updateList)) {
super.editJsonData(personFormId, updateList);
log.info("批量审批记录 {} 同步更新了 {} 条外协人员记录的审批状态", dataId, updateList.size());
}
}
}
}
}
/**
* 根据审批状态码获取对应的描述
*/
private String getApproveStatusName(Integer approveStatus) {
if (approveStatus == null) {
return ApproveStatusEnum.UNAPPROVED.getDesc();
}
for (ApproveStatusEnum statusEnum : ApproveStatusEnum.values()) {
if (statusEnum.getCode() == approveStatus) {
return statusEnum.getDesc();
}
}
return ApproveStatusEnum.UNAPPROVED.getDesc();
}
}

View File

@@ -16,4 +16,6 @@ public interface IDrillPlanService {
Map<String, Object> getDrillTaskById(long id);
List<Map<String, Object>> getDrillTaskByPlanId(Long drillPlanId);
boolean pushDrillTaskWorkflow(Long drillTaskId, String todoType);
}

View File

@@ -1,18 +1,30 @@
package com.jeelowcode.module.biz.service.impl;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.jeelowcode.core.framework.service.IFrameSqlService;
import com.jeelowcode.framework.plus.SqlHelper;
import com.jeelowcode.framework.plus.build.buildmodel.wrapper.SqlInfoQueryWrapper;
import com.jeelowcode.framework.plus.core.toolkit.StringUtils;
import com.jeelowcode.framework.utils.tool.spring.SpringUtils;
import com.jeelowcode.module.biz.mapper.DrillPlanMapper;
import com.jeelowcode.module.biz.service.IDrillPlanService;
import com.jeelowcode.module.biz.service.ITodoRequestService;
import com.jeelowcode.service.bpm.config.framework.portal.core.PortalRequest;
import com.jeelowcode.service.bpm.config.framework.portal.core.dto.ReceiveRequestInfoDTO;
import com.jeelowcode.service.system.api.IApiAdminUserApi;
import com.jeelowcode.service.system.dto.AdminUserRespDTO;
import com.jeelowcode.tool.framework.common.util.object.BeanUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import javax.annotation.Resource;
import java.util.*;
/**
@@ -23,9 +35,29 @@ import java.util.Map;
public class DrillPlanServiceImpl implements IDrillPlanService {
private static final String SPACE = " ";
private static final String WORK_NODE_NAME = "下发演练计划";
private static final String WORK_FLOW_NAME = "演练计划信息";
// TODO 待办跳转链接,这个以后需要优化,通过配置去取这个链接,不能写死在这里
private static final String RISK_PC_URL = "/yljg/table/view/1966394259751907330";
private static final String WORK_STATUS_TODO = "0";
private static final String WORK_STATUS_DONE = "2";
private static final String WORK_STATUS_COMPLETE = "4";
private static final String VIEW_TYPE_UNREAD = "0";
private static final String VIEW_TYPE_READ = "1";
private static final String Bill_Table_Name = "lc_drill_task";
@Autowired
private IFrameSqlService sqlService;
@Resource
private ITodoRequestService todoRequestService;
@Resource
private IApiAdminUserApi apiAdminUserApi;
@Override
public Map<String, Object> getDrillPlanById(long id) {
SqlInfoQueryWrapper.Wrapper wrapper = SqlHelper.getQueryWrapper();
@@ -71,5 +103,112 @@ public class DrillPlanServiceImpl implements IDrillPlanService {
return dataMapList;
}
@Override
public boolean pushDrillTaskWorkflow(Long drillTaskId, String todoType) {
// 0.1.查找工作事项数据,如果查不到则放弃推送
Map<String, Object> drillTask = getDrillTaskById(drillTaskId);
if (MapUtil.isEmpty(drillTask)) return false;
// 0.2.从容器中获取 PortalRequest 对象,如果没有配置则放弃通知
PortalRequest portalRequest = SpringUtils.getBean(PortalRequest.class);
if (ObjectUtil.isNull(portalRequest)) return false;
// 0.3.判断是否存在 场景下发送的消息,已经发送过消息的不重复发送
boolean isExist = todoRequestService.isExistTodoRequest(drillTaskId, todoType);
if(isExist)
{
return true;
}
// 1.构建请求参数,准备推送待办信息
String creator="";
String receiver="";
String isRemark="";
String viewType="";
// 1.1.拼接标题
String requestName = "计划于【"+
DateUtil.formatDate( (Date) drillTask.getOrDefault("sDate", new Date()))
+ "】-【" +
DateUtil.formatDate( (Date) drillTask.getOrDefault("sDate", new Date()))
+"】进行"+
drillTask.getOrDefault("drill_plan_name", "");
// 1.2.根据代办类型取消息发送者 TODO 需要升级存储检查人的username
if(todoType.equals("DRILL_TASK_TODO"))
{
isRemark=WORK_STATUS_TODO;
viewType=VIEW_TYPE_UNREAD;
}else
{
isRemark=WORK_STATUS_DONE;
viewType=VIEW_TYPE_READ;
}
// 消息发送者为 工作事项 发起人
Long createUserId = Objects.isNull(drillTask.get("create_user")) ? null : Long.valueOf(drillTask.get("create_user").toString());
AdminUserRespDTO createUser = Optional.ofNullable(createUserId)
.map(userId -> apiAdminUserApi.getUser(userId))
.orElse(new AdminUserRespDTO());
if(StringUtils.isEmpty(createUser.getUsername()))
{
return false;
}else
{
creator=createUser.getUsername();
}
// 消息接受者为 事项结果 责任人
Long receiveId = Objects.isNull(drillTask.get("charge_id")) ? null : Long.valueOf( drillTask.get("charge_id").toString());
AdminUserRespDTO receiveUser = Optional.ofNullable(receiveId)
.map(userId -> apiAdminUserApi.getUser(userId))
.orElse(new AdminUserRespDTO());
if(StringUtils.isEmpty(receiveUser.getUsername()))
{
return false;
}else
{
receiver=receiveUser.getUsername();
}
// 1.2.组织请求数据
ReceiveRequestInfoDTO todoRequestDTO = new ReceiveRequestInfoDTO()
.setFlowId(Base64.encode(String.valueOf(drillTaskId)))
.setRequestName(requestName)
.setWorkflowName(WORK_FLOW_NAME)
.setNodeName(WORK_NODE_NAME)
.setPcUrl(RISK_PC_URL)
.setIsRemark(isRemark)
.setViewType(viewType)
.setCreator(creator)
.setCreateDateTime(new Date())
.setReceiver(receiver)
.setReceiveDateTime(new Date())
.setReceiveTs(String.valueOf(System.currentTimeMillis()));
ReceiveRequestInfoDTO completeRequestDTO = BeanUtils.toBean(todoRequestDTO, ReceiveRequestInfoDTO.class);
completeRequestDTO.setIsRemark(WORK_STATUS_COMPLETE);
// 1.3.构建发送消息详情
HashMap<String, Object> newRecord = new HashMap<>();
newRecord.put("bill_id", drillTaskId);
newRecord.put("bill_table_name", Bill_Table_Name);
newRecord.put("bill_action", todoType);
newRecord.put("todo_request", JSONUtil.toJsonStr(todoRequestDTO));
// 2.推送待办信息使用try-catch避免影响上层调用方法的事务回滚
try {
portalRequest.receiveRequestInfo(todoRequestDTO);
newRecord.put("is_success", 1);
todoRequestService.addTodoRequest(newRecord);
if(todoType.equals("DRILL_TASK_DONE"))
{
portalRequest.receiveRequestInfo(completeRequestDTO);
}
} catch (Exception e) {
log.error("推送待办信息失败", e);
newRecord.put("is_success", 0);
todoRequestService.addTodoRequest(newRecord);
return false;
}
return true;
}
}