提案整改
This commit is contained in:
@@ -27,10 +27,10 @@ import java.util.Map;
|
||||
@IocBean
|
||||
public class SmsJshvcServiceImpl implements SmsService {
|
||||
|
||||
private static final String APPID = "1430576717768122368";
|
||||
private static final String APP_SECRET = "19A0ACB03FBQHL4R4XQD";
|
||||
private static final String TOKEN_URL = "https://gateway.jshvc.edu.cn/token/gateway/accessToken";
|
||||
private static final String MSG_URL = "https://gateway.jshvc.edu.cn/mp/restful/v2/message/send";
|
||||
private static final String APPID = "";
|
||||
private static final String APP_SECRET = "";
|
||||
private static final String TOKEN_URL = "";
|
||||
private static final String MSG_URL = "";
|
||||
private static final String REDIS_KEY_MSG_ACCESS_TOKEN = "msg:token:";
|
||||
|
||||
@Inject
|
||||
|
||||
+10
@@ -9,6 +9,7 @@ import com.budwk.app.flow.enums.ProcessTaskStateEnum;
|
||||
import com.budwk.app.web.commons.auth.utils.AuthUtil;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.democratic.proposal.param.ProposalSearchParam;
|
||||
import com.budwk.app.zhgh.democratic.proposal.service.ProposalCaseCheckService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -39,6 +40,8 @@ public class ProposalCaseCheckController {
|
||||
|
||||
@Inject
|
||||
private BaseService baseService;
|
||||
@Inject
|
||||
private ProposalCaseCheckService proposalCaseCheckService;
|
||||
|
||||
@At("")
|
||||
@Ok("beetl:/platform/zhgh/democratic/proposal/transact/caseCheck/index.html")
|
||||
@@ -103,4 +106,11 @@ public class ProposalCaseCheckController {
|
||||
Pagination pagination = baseService.listPageMap(pageForm.getPageNumber(),pageForm.getPageSize(), sql);
|
||||
return Result.success(pagination);
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("proposal.caseCheck")
|
||||
@ApiOperation("查询当前提案承办单位")
|
||||
public Result listReplyUnits(String proposalId) {
|
||||
return Result.success(proposalCaseCheckService.listReplyUnits(proposalId));
|
||||
}
|
||||
}
|
||||
|
||||
+9
-27
@@ -5,12 +5,9 @@ import cn.hutool.core.lang.Dict;
|
||||
import com.budwk.app.base.constant.RoleConstant;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.flow.constant.FlowConst;
|
||||
import com.budwk.app.flow.enums.ProcessTaskStateEnum;
|
||||
import com.budwk.app.flow.service.FlowCommonService;
|
||||
import com.budwk.app.web.commons.auth.utils.AuthUtil;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.democratic.proposal.models.ProposalMerge;
|
||||
import com.budwk.app.zhgh.democratic.proposal.param.ProposalSearchParam;
|
||||
import com.budwk.app.zhgh.democratic.proposal.service.ProposalCommitteeFilingService;
|
||||
import io.swagger.annotations.Api;
|
||||
@@ -25,7 +22,6 @@ import org.nutz.ioc.aop.Aop;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.json.Json;
|
||||
import org.nutz.lang.random.R;
|
||||
import org.nutz.mvc.annotation.At;
|
||||
import org.nutz.mvc.annotation.Ok;
|
||||
import org.nutz.mvc.annotation.Param;
|
||||
@@ -44,9 +40,6 @@ public class ProposalCommitteeFilingController {
|
||||
private Dao dao;
|
||||
@Inject
|
||||
private ProposalCommitteeFilingService proposalCommitteeFilingService;
|
||||
@Inject
|
||||
private FlowCommonService flowCommonService;
|
||||
|
||||
|
||||
@At("")
|
||||
@Ok("beetl:/platform/zhgh/democratic/proposal/transact/committeeFiling/index.html")
|
||||
@@ -118,27 +111,16 @@ public class ProposalCommitteeFilingController {
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public Result merge(@Param("data") String data) {
|
||||
Dict args = Json.fromJson(Dict.class, data);
|
||||
proposalCommitteeFilingService.merge(args);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
List<Integer> taskIds = (List<Integer>) args.get("processTaskIds");
|
||||
List<String> proposalIds = (List<String>) args.get("proposalIds");
|
||||
|
||||
// 记录提案并案
|
||||
dao.clear(ProposalMerge.class, Cnd.where(ProposalMerge::getProposalId, "in", proposalIds));
|
||||
String groupId = R.UU32();
|
||||
List<ProposalMerge> merges = proposalIds.stream().map(proposalId -> {
|
||||
ProposalMerge merge = new ProposalMerge();
|
||||
merge.setProposalId(proposalId);
|
||||
merge.setGroupId(groupId);
|
||||
return merge;
|
||||
}).toList();
|
||||
dao.insert(merges);
|
||||
|
||||
for (Integer taskId : taskIds) {
|
||||
Dict taskArgs = args.clone();
|
||||
taskArgs.put(FlowConst.PROCESS_TASK_ID_KEY, taskId);
|
||||
flowCommonService.executeTask(taskArgs);
|
||||
}
|
||||
|
||||
@At
|
||||
@SaCheckPermission("proposal.committeeFiling")
|
||||
@ApiOperation("撤回任务")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public Result revokeTask(@Param("taskId") Long taskId, @Param("proposalId") String proposalId) {
|
||||
proposalCommitteeFilingService.revokeTask(taskId, proposalId);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
|
||||
+1
-23
@@ -8,7 +8,6 @@ import com.budwk.app.base.constant.RoleConstant;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.base.service.BaseService;
|
||||
import com.budwk.app.flow.constant.FlowConst;
|
||||
import com.budwk.app.flow.entity.ProcessInstance;
|
||||
import com.budwk.app.flow.entity.ProcessTask;
|
||||
import com.budwk.app.flow.entity.ProcessTaskActor;
|
||||
@@ -128,28 +127,7 @@ public class ProposalCommitteeFilingUnitController {
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public Result executeTask(@Param("data") String data) {
|
||||
Dict args = Json.fromJson(Dict.class, data);
|
||||
String proposalId = args.getStr("proposalId");
|
||||
|
||||
// 查询是否提案
|
||||
|
||||
// 单条审核
|
||||
List<String> mergeProposalIds = proposalCommonService.mergeProposal(proposalId);
|
||||
if (ObjectUtil.isEmpty(mergeProposalIds)) {
|
||||
flowCommonService.executeTask(args);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
// 并案审核
|
||||
ProcessTask thisTask = baseService.dao().fetch(ProcessTask.class, args.getLong(FlowConst.PROCESS_TASK_ID_KEY));
|
||||
List<ProcessTask> mergeTasks = processTaskService.getDoingTaskByBizIdTaskName(mergeProposalIds, thisTask.getTaskName());
|
||||
for (ProcessTask mergeTask : mergeTasks) {
|
||||
Dict cloneArgs = args.clone();
|
||||
cloneArgs.put(FlowConst.PROCESS_TASK_ID_KEY, mergeTask.getId());
|
||||
flowCommonService.executeTask(cloneArgs);
|
||||
}
|
||||
|
||||
ProposalInfo info = proposalCommonService.fetch(proposalId);
|
||||
info.setCaseFilingResult(args.getStr("caseFilingResult"));
|
||||
proposalCommitteeFilingUnitService.executeFlowTask(args);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
|
||||
+85
-10
@@ -3,6 +3,7 @@ package com.budwk.app.zhgh.democratic.proposal.controller.transact;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.hutool.core.lang.Dict;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.budwk.app.base.constant.RoleConstant;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
@@ -23,10 +24,12 @@ import com.budwk.app.zhgh.democratic.proposal.service.common.ProposalCommonServi
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.dao.Sqls;
|
||||
import org.nutz.dao.sql.Sql;
|
||||
import org.nutz.ioc.aop.Aop;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.json.Json;
|
||||
@@ -35,6 +38,7 @@ import org.nutz.mvc.annotation.Ok;
|
||||
import org.nutz.mvc.annotation.Param;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@IocBean
|
||||
@@ -95,6 +99,8 @@ public class ProposalSchoolLeaderApprovalController {
|
||||
t.finishTime,
|
||||
t.taskParentId,
|
||||
t.variable taskVariable,
|
||||
GROUP_CONCAT(DISTINCT CASE WHEN pru.isMaster = 1 THEN pru.unitName END) AS masterUnitName,
|
||||
GROUP_CONCAT(DISTINCT CASE WHEN pru.isMaster = 0 THEN pru.unitName END) AS slaveUnitNames,
|
||||
IFNULL(GROUP_CONCAT(DISTINCT nt.displayName),'结束') curTaskName,
|
||||
IF(rt.id IS NOT NULL, 1, 0) AS canRevoke,
|
||||
GROUP_CONCAT(DISTINCT ta.actorName, '(', ta.actorAccount, ')' ) AS auditUser
|
||||
@@ -107,6 +113,7 @@ public class ProposalSchoolLeaderApprovalController {
|
||||
LEFT JOIN proposal_info info ON info.id = ins.businessNo
|
||||
LEFT JOIN proposal_type type on type.id = info.typeId
|
||||
LEFT JOIN proposal_merge mer ON mer.proposalId = info.id
|
||||
LEFT JOIN proposal_reply_unit pru ON pru.proposalId = info.id
|
||||
LEFT JOIN teacher_congress_session tcs on tcs.id = info.sessionId
|
||||
LEFT JOIN teacher_congress_delegation tcd on tcd.id = info.delegationId
|
||||
$condition
|
||||
@@ -142,6 +149,7 @@ public class ProposalSchoolLeaderApprovalController {
|
||||
@At
|
||||
@SaCheckPermission("proposal.schoolLeaderApproval")
|
||||
@ApiOperation("执行任务")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public Result executeTask(@Param("data") String data) {
|
||||
Dict args = Json.fromJson(Dict.class, data);
|
||||
|
||||
@@ -156,18 +164,34 @@ public class ProposalSchoolLeaderApprovalController {
|
||||
|
||||
ProcessTask thisTask = dao.fetch(ProcessTask.class, args.getLong(FlowConst.PROCESS_TASK_ID_KEY));
|
||||
ProcessTask parentTask = dao.fetch(ProcessTask.class, Cnd.where("id", "=", thisTask.getTaskParentId()));
|
||||
Dict dict = Json.fromJson(Dict.class, parentTask.getVariable());
|
||||
|
||||
args.put("tf_caseFilingResult", dict.getStr("tf_caseFilingResult"));
|
||||
args.put("tf_helpunitreply", dict.getStr("tf_helpunitreply"));
|
||||
args.put("tf_masterUnitId", dict.getStr("tf_masterUnitId"));
|
||||
args.put("tf_slaveUnitIds", dict.getObj("tf_slaveUnitIds"));
|
||||
Dict dict = ObjectUtil.defaultIfNull(Json.fromJson(Dict.class, parentTask.getVariable()), Dict.create());
|
||||
|
||||
ProcessInstance instance = dao.fetch(ProcessInstance.class, Cnd.where(ProcessInstance::getId, "=", thisTask.getProcessInstanceId()));
|
||||
Dict instanceDict = Json.fromJson(Dict.class, instance.getVariable());
|
||||
instanceDict.put("tf_helpunitreply", dict.getStr("tf_helpunitreply"));
|
||||
instanceDict.put("tf_masterUnitId", dict.getStr("tf_masterUnitId"));
|
||||
instanceDict.put("tf_slaveUnitIds", dict.getObj("tf_slaveUnitIds"));
|
||||
Dict instanceDict = ObjectUtil.defaultIfNull(Json.fromJson(Dict.class, instance.getVariable()), Dict.create());
|
||||
|
||||
// 分管领导审批需要把提委会立案环节的承办单位信息继续透传,兼容主办单位由单个改为多个的场景。
|
||||
Object masterUnitIds = getProcessVariable(dict, instanceDict, "tf_masterUnitIds");
|
||||
String masterUnitId = getProcessVariableStr(dict, instanceDict, "tf_masterUnitId");
|
||||
if (ObjectUtil.isEmpty(masterUnitIds) && StrUtil.isNotBlank(masterUnitId)) {
|
||||
masterUnitIds = List.of(masterUnitId);
|
||||
}
|
||||
if (StrUtil.isBlank(masterUnitId)) {
|
||||
List<String> masterUnitIdList = toStringList(masterUnitIds);
|
||||
if (ObjectUtil.isNotEmpty(masterUnitIdList)) {
|
||||
masterUnitId = masterUnitIdList.get(0);
|
||||
}
|
||||
}
|
||||
|
||||
args.put("tf_caseFilingResult", getProcessVariableStr(dict, instanceDict, "tf_caseFilingResult"));
|
||||
args.put("tf_helpunitreply", getProcessVariableStr(dict, instanceDict, "tf_helpunitreply"));
|
||||
args.put("tf_masterUnitId", masterUnitId);
|
||||
args.put("tf_masterUnitIds", masterUnitIds);
|
||||
args.put("tf_slaveUnitIds", getProcessVariable(dict, instanceDict, "tf_slaveUnitIds"));
|
||||
|
||||
instanceDict.put("tf_helpunitreply", getProcessVariableStr(dict, instanceDict, "tf_helpunitreply"));
|
||||
instanceDict.put("tf_masterUnitId", masterUnitId);
|
||||
instanceDict.put("tf_masterUnitIds", masterUnitIds);
|
||||
instanceDict.put("tf_slaveUnitIds", getProcessVariable(dict, instanceDict, "tf_slaveUnitIds"));
|
||||
instance.setVariable(JSONUtil.toJsonStr(instanceDict));
|
||||
|
||||
dao.update(instance);
|
||||
@@ -190,4 +214,55 @@ public class ProposalSchoolLeaderApprovalController {
|
||||
}
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 优先取当前父任务变量,没有时回退到流程实例变量,避免审批流转时丢失承办单位信息。
|
||||
*/
|
||||
private Object getProcessVariable(Dict taskDict, Dict instanceDict, String key) {
|
||||
Object taskValue = taskDict.getObj(key);
|
||||
if (ObjectUtil.isNotEmpty(taskValue)) {
|
||||
return taskValue;
|
||||
}
|
||||
return instanceDict.getObj(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 字符串类型流程变量统一做空值兼容,便于兼容老流程里单主办字段的读取。
|
||||
*/
|
||||
private String getProcessVariableStr(Dict taskDict, Dict instanceDict, String key) {
|
||||
Object value = getProcessVariable(taskDict, instanceDict, key);
|
||||
return ObjectUtil.isEmpty(value) ? "" : String.valueOf(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 主办单位可能以集合、数组、JSON 字符串或逗号分隔字符串保存,这里统一转换为字符串列表。
|
||||
*/
|
||||
private List<String> toStringList(Object value) {
|
||||
if (ObjectUtil.isEmpty(value)) {
|
||||
return List.of();
|
||||
}
|
||||
if (value instanceof List<?> list) {
|
||||
return list.stream().filter(ObjectUtil::isNotEmpty).map(String::valueOf).toList();
|
||||
}
|
||||
if (value instanceof Object[] array) {
|
||||
List<String> result = new ArrayList<>();
|
||||
for (Object item : array) {
|
||||
if (ObjectUtil.isNotEmpty(item)) {
|
||||
result.add(String.valueOf(item));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
if (value instanceof String strValue) {
|
||||
if (StrUtil.isBlank(strValue)) {
|
||||
return List.of();
|
||||
}
|
||||
if (JSONUtil.isTypeJSONArray(strValue)) {
|
||||
return JSONUtil.parseArray(strValue).toList(String.class);
|
||||
}
|
||||
return StrUtil.splitTrim(strValue, ",");
|
||||
}
|
||||
return List.of(String.valueOf(value));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+76
-29
@@ -6,10 +6,8 @@ import cn.hutool.core.util.ObjectUtil;
|
||||
import com.budwk.app.base.constant.RoleConstant;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.flow.constant.FlowConst;
|
||||
import com.budwk.app.flow.entity.ProcessTask;
|
||||
import com.budwk.app.flow.enums.ProcessTaskStateEnum;
|
||||
import com.budwk.app.flow.service.FlowCommonService;
|
||||
import com.budwk.app.flow.service.ProcessTaskService;
|
||||
import com.budwk.app.sys.models.Sys_role;
|
||||
import com.budwk.app.sys.models.Sys_user_role;
|
||||
@@ -18,6 +16,7 @@ import com.budwk.app.sys.services.SysUserService;
|
||||
import com.budwk.app.web.commons.auth.utils.AuthUtil;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.democratic.proposal.param.ProposalSearchParam;
|
||||
import com.budwk.app.zhgh.democratic.proposal.service.ProposalUnderTakeReplyService;
|
||||
import com.budwk.app.zhgh.democratic.proposal.service.common.ProposalCommonService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
@@ -38,6 +37,8 @@ import org.nutz.mvc.annotation.Ok;
|
||||
import org.nutz.mvc.annotation.Param;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@@ -53,7 +54,7 @@ public class ProposalUnderTakeReplyController {
|
||||
@Inject
|
||||
private ProposalCommonService proposalCommonService;
|
||||
@Inject
|
||||
private FlowCommonService flowCommonService;
|
||||
private ProposalUnderTakeReplyService proposalUnderTakeReplyService;
|
||||
@Inject
|
||||
private ProcessTaskService processTaskService;
|
||||
@Inject
|
||||
@@ -77,6 +78,11 @@ public class ProposalUnderTakeReplyController {
|
||||
@SaCheckPermission("proposal.unitReply")
|
||||
@ApiOperation("分页列表")
|
||||
public Result pageData(@Valid ProposalSearchParam pageForm, boolean approval, boolean transfer) {
|
||||
/*
|
||||
* 承办单位答复列表需要按“承办单位”维度展示。
|
||||
* 同一个任务可能挂了多个承办单位负责人,若只按 taskId 分组会把多条待审核合并成一条,
|
||||
* 因此这里优先使用任务参与人的承办单位信息拆行,历史数据缺失时再回退到流程变量。
|
||||
*/
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
info.*,
|
||||
@@ -121,10 +127,11 @@ public class ProposalUnderTakeReplyController {
|
||||
$condition
|
||||
""");
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and("t.taskName", "in", List.of("master_reply", "slave_reply", "opinion_master_reply"));
|
||||
// cnd.and("t.taskName", "in", List.of("master_reply", "slave_reply", "opinion_master_reply"));
|
||||
cnd.and("t.taskName", "in", List.of("unit_reply", "two_unit_reply", "opinion_unit_reply"));
|
||||
|
||||
if (!AuthUtil.hasRole(RoleConstant.SYSADMIN.name())) {
|
||||
cnd.and("ta.actorId", "in", List.of(SecurityUtil.getUserId()));
|
||||
if (!SecurityUtil.getUserLoginname().equals("superadmin")) {
|
||||
cnd.and("ta.actorId", "=", SecurityUtil.getUserId());
|
||||
}
|
||||
|
||||
if (approval) {
|
||||
@@ -140,45 +147,85 @@ public class ProposalUnderTakeReplyController {
|
||||
|
||||
List<NutMap> list = pagination.getList();
|
||||
for (NutMap row : list) {
|
||||
if (row.getInt("taskIsMaster") == 1) {
|
||||
boolean b = Stream.of("master_reply", "slave_reply", "school_leader")
|
||||
.anyMatch(a -> row.getString("curTaskKey").contains(a));
|
||||
row.setv("canRevoke", b && row.getInt("taskState") == ProcessTaskStateEnum.FINISHED.getCode());
|
||||
} else {
|
||||
boolean b = Stream.of("master_reply", "slave_reply").anyMatch(a -> row.getString("curTaskKey").contains(a));
|
||||
row.setv("canRevoke", b && row.getInt("taskState") == ProcessTaskStateEnum.FINISHED.getCode());
|
||||
}
|
||||
/*
|
||||
* 承办单位答复撤回必须按“当前整组待办节点”统一判断。
|
||||
* 这里不能再用 contains,只要出现过 unit_reply/two_unit_reply 就会误判可撤回;
|
||||
* 正确规则是:curTaskKey 必须精确等于某一个允许撤回的节点编码,
|
||||
* 像 unit_reply,two_unit_reply 这种混合状态一律不允许撤回。
|
||||
*/
|
||||
row.setv("canRevoke", isReplyTaskGroupRevocable(row));
|
||||
}
|
||||
pagination.setList(list);
|
||||
|
||||
return Result.success(pagination);
|
||||
}
|
||||
|
||||
/**
|
||||
* 承办单位答复节点撤回需要基于整组当前节点判断。
|
||||
* 只有“当前流程正在办理的节点”和“这条列表记录所属节点”完全一致时,才允许撤回;
|
||||
* 这样流程已经从 unit_reply 走到 two_unit_reply 后,历史 unit_reply 记录会自动失去撤回资格。
|
||||
* 主办只能撤回 unit_reply、two_unit_reply、school_leader;
|
||||
* 协办只能撤回 unit_reply、two_unit_reply。
|
||||
*/
|
||||
private boolean isReplyTaskGroupRevocable(NutMap row) {
|
||||
if (!ObjectUtil.equal(row.getInt("taskState"), ProcessTaskStateEnum.FINISHED.getCode())) {
|
||||
return false;
|
||||
}
|
||||
String taskKey = row.getString("taskKey");
|
||||
String curTaskKey = row.getString("curTaskKey");
|
||||
if (!ObjectUtil.equal(taskKey, curTaskKey)) {
|
||||
return false;
|
||||
}
|
||||
if (row.getInt("underTakeIsMaster") == 1) {
|
||||
return Stream.of("unit_reply", "two_unit_reply", "school_leader")
|
||||
.anyMatch(a -> ObjectUtil.equal(a, taskKey));
|
||||
}
|
||||
return Stream.of("unit_reply", "two_unit_reply")
|
||||
.anyMatch(a -> ObjectUtil.equal(a, taskKey));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@At
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("proposal.unitReply")
|
||||
@ApiOperation("执行任务")
|
||||
public Result executeTask(@Param("data") String data) {
|
||||
Dict args = Json.fromJson(Dict.class, data);
|
||||
String proposalId = args.getStr("proposalId");
|
||||
proposalUnderTakeReplyService.executeFlowTask(args);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
// 查询是否提案
|
||||
|
||||
// 单条审核
|
||||
List<String> mergeProposalIds = proposalCommonService.mergeProposal(proposalId);
|
||||
if (ObjectUtil.isEmpty(mergeProposalIds)) {
|
||||
flowCommonService.executeTask(args);
|
||||
return Result.success();
|
||||
@At
|
||||
@SaCheckPermission("proposal.unitReply")
|
||||
@ApiOperation("查询历史答复内容")
|
||||
public Result getReplyOpinion(@Param("taskId") @NotNull(message = "任务ID不能为空") Long taskId) {
|
||||
/*
|
||||
* 页面上的“编辑答复内容”入口只对超级管理员开放。
|
||||
* 这里继续在服务端做一次角色兜底,避免前端绕过按钮显隐后越权修改历史答复。
|
||||
*/
|
||||
if (!AuthUtil.hasRole(RoleConstant.SYSADMIN.name())) {
|
||||
return Result.error("只有超级管理员可以编辑答复内容");
|
||||
}
|
||||
return Result.success(proposalUnderTakeReplyService.getReplyOpinion(taskId));
|
||||
}
|
||||
|
||||
// 并案审核
|
||||
ProcessTask thisTask = dao.fetch(ProcessTask.class, args.getLong(FlowConst.PROCESS_TASK_ID_KEY));
|
||||
List<ProcessTask> mergeTasks = processTaskService.getDoingTaskByBizIdTaskName(mergeProposalIds, thisTask.getTaskName());
|
||||
for (ProcessTask mergeTask : mergeTasks) {
|
||||
Dict cloneArgs = args.clone();
|
||||
cloneArgs.put(FlowConst.PROCESS_TASK_ID_KEY, mergeTask.getId());
|
||||
flowCommonService.executeTask(cloneArgs);
|
||||
@At
|
||||
@SaCheckPermission("proposal.unitReply")
|
||||
@ApiOperation("更新历史答复内容")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public Result updateReplyOpinion(@Param("taskId") @NotNull(message = "任务ID不能为空") Long taskId,
|
||||
@Param("opinion") @NotBlank(message = "答复内容不能为空") String opinion) {
|
||||
/*
|
||||
* 这里只允许超级管理员改历史答复内容,且只改 tf_opinion 字段。
|
||||
* 具体的任务范围和状态校验放在 service 层统一处理,避免控制器承载业务逻辑。
|
||||
*/
|
||||
if (!AuthUtil.hasRole(RoleConstant.SYSADMIN.name())) {
|
||||
return Result.error("只有超级管理员可以编辑答复内容");
|
||||
}
|
||||
proposalUnderTakeReplyService.updateReplyOpinion(taskId, opinion);
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
|
||||
+172
@@ -0,0 +1,172 @@
|
||||
package com.budwk.app.zhgh.democratic.proposal.handler;
|
||||
|
||||
import cn.hutool.core.lang.Dict;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.budwk.app.base.constant.RoleConstant;
|
||||
import com.budwk.app.base.exception.BaseException;
|
||||
import com.budwk.app.flow.engine.AssignmentHandler;
|
||||
import com.budwk.app.flow.engine.core.Execution;
|
||||
import com.budwk.app.flow.engine.core.ServiceContext;
|
||||
import com.budwk.app.flow.engine.model.TaskModel;
|
||||
import com.budwk.app.sys.models.Sys_role;
|
||||
import com.budwk.app.sys.models.Sys_user_role;
|
||||
import com.budwk.app.sys.services.SysRoleService;
|
||||
import com.budwk.app.zhgh.democratic.proposal.models.ProposalReplyUnit;
|
||||
import com.budwk.app.zhgh.democratic.proposal.models.ProposalUndertake;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.ioc.aop.Aop;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 提案承办单位处理人
|
||||
*/
|
||||
public class ProposalUnitAssignmentHandler implements AssignmentHandler {
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public List<String> assign(TaskModel model, Execution execution) {
|
||||
Dao dao = ServiceContext.find(Dao.class);
|
||||
SysRoleService sysRoleService = ServiceContext.find(SysRoleService.class);
|
||||
String proposalId = execution.getProcessInstance().getBusinessNo();
|
||||
|
||||
// 当前节点需要同时处理主办和协办负责人。
|
||||
// 这里不能按单位ID去重,必须保留每个承办单位对应的一条分派记录,
|
||||
// 否则同一用户负责多个单位时,会被错误合并成更少的待办。
|
||||
List<String> unitIds = new ArrayList<>();
|
||||
unitIds.addAll(resolveMasterUnitIds(execution, dao, proposalId));
|
||||
unitIds.addAll(resolveSlaveUnitIds(execution, dao, proposalId));
|
||||
|
||||
if (unitIds.isEmpty()) {
|
||||
throw new BaseException("提案没有配置承办单位");
|
||||
}
|
||||
|
||||
Sys_role sysRole = sysRoleService.getByCode(RoleConstant.PROPOSAL_UNIT_LEADER);
|
||||
if (sysRole == null) {
|
||||
throw new BaseException("提案承办单位领导角色不存在");
|
||||
}
|
||||
|
||||
List<String> assignee = new ArrayList<>();
|
||||
for (String unitId : unitIds) {
|
||||
ProposalUndertake undertake = dao.fetch(ProposalUndertake.class, unitId);
|
||||
if (undertake == null) {
|
||||
throw new BaseException("承办单位不存在");
|
||||
}
|
||||
|
||||
// 只要存在单位 ID,就必须找到该单位负责人,否则流程无法继续往下分派。
|
||||
List<Sys_user_role> sysUserRoles = dao.query(Sys_user_role.class,
|
||||
Cnd.where(Sys_user_role::getRoleId, "=", sysRole.getId())
|
||||
.and(Sys_user_role::getUnderTakeId, "=", undertake.getId()));
|
||||
if (ObjectUtil.isEmpty(sysUserRoles)) {
|
||||
throw new BaseException(undertake.getName() + "单位没有设置负责人!");
|
||||
}
|
||||
/*
|
||||
* 会签需要按“承办单位”创建实例。
|
||||
* 同一个用户若同时负责主办、协办多个承办单位,不能在这里跨单位去重;
|
||||
* 否则流程会把多个承办单位合并成一个会签实例,导致“全部承办单位答复完”判断失真。
|
||||
*/
|
||||
assignee.addAll(sysUserRoles.stream().map(Sys_user_role::getUserId).toList());
|
||||
}
|
||||
return assignee;
|
||||
}
|
||||
|
||||
/**
|
||||
* 优先从当前流程变量读取主办单位,读不到时回落到承办单位记录表,兼容重新流转场景。
|
||||
*/
|
||||
private List<String> resolveMasterUnitIds(Execution execution, Dao dao, String proposalId) {
|
||||
List<String> masterUnitIds = new ArrayList<>();
|
||||
|
||||
/*
|
||||
* 页面会同时提交 tf_masterUnitId 和 tf_masterUnitIds:
|
||||
* 前者是给旧流程兼容的“第一个主办单位”,后者才是当前页面真实的主办单位列表。
|
||||
* 这里必须优先使用列表字段;只有列表为空时,才回退到单值字段,
|
||||
* 否则单主办场景会把同一个单位重复加入两次,最终多生成一条会签任务。
|
||||
*/
|
||||
List<String> masterUnitIdList = getStringList(execution.getArgs(), "tf_masterUnitIds");
|
||||
if (ObjectUtil.isNotEmpty(masterUnitIdList)) {
|
||||
masterUnitIds.addAll(masterUnitIdList);
|
||||
} else {
|
||||
String masterUnitId = execution.getArgs().getStr("tf_masterUnitId");
|
||||
if (StrUtil.isNotBlank(masterUnitId)) {
|
||||
masterUnitIds.add(masterUnitId);
|
||||
}
|
||||
}
|
||||
|
||||
if (masterUnitIds.isEmpty()) {
|
||||
List<ProposalReplyUnit> masterUnits = dao.query(ProposalReplyUnit.class,
|
||||
Cnd.where(ProposalReplyUnit::getProposalId, "=", proposalId)
|
||||
.and(ProposalReplyUnit::getIsMaster, "=", true));
|
||||
if (ObjectUtil.isNotEmpty(masterUnits)) {
|
||||
masterUnitIds.addAll(masterUnits.stream().map(ProposalReplyUnit::getUnitId).toList());
|
||||
}
|
||||
}
|
||||
return masterUnitIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* 协办单位不区分是否需要答复,只要流程变量或记录表里存在协办单位 ID,就分派给对应负责人。
|
||||
*/
|
||||
private List<String> resolveSlaveUnitIds(Execution execution, Dao dao, String proposalId) {
|
||||
List<String> slaveUnitIds = new ArrayList<>();
|
||||
|
||||
List<String> slaveUnitIdList = getStringList(execution.getArgs(), "tf_slaveUnitIds");
|
||||
if (ObjectUtil.isNotEmpty(slaveUnitIdList)) {
|
||||
slaveUnitIds.addAll(slaveUnitIdList);
|
||||
}
|
||||
|
||||
if (slaveUnitIds.isEmpty()) {
|
||||
List<ProposalReplyUnit> slaveUnits = dao.query(ProposalReplyUnit.class,
|
||||
Cnd.where(ProposalReplyUnit::getProposalId, "=", proposalId)
|
||||
.and(ProposalReplyUnit::getIsMaster, "=", false));
|
||||
if (ObjectUtil.isNotEmpty(slaveUnits)) {
|
||||
slaveUnitIds.addAll(slaveUnits.stream().map(ProposalReplyUnit::getUnitId).toList());
|
||||
}
|
||||
}
|
||||
return slaveUnitIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* 流程变量里的单位ID可能是 List、数组、JSON 字符串或逗号分隔字符串,这里统一转成字符串列表。
|
||||
*/
|
||||
private List<String> getStringList(Dict args, String key) {
|
||||
Object value = args.getObj(key);
|
||||
if (ObjectUtil.isEmpty(value)) {
|
||||
return List.of();
|
||||
}
|
||||
if (value instanceof Collection<?> collection) {
|
||||
return collection.stream().filter(ObjectUtil::isNotEmpty).map(String::valueOf).toList();
|
||||
}
|
||||
if (value instanceof Object[] array) {
|
||||
return Arrays.stream(array).filter(ObjectUtil::isNotEmpty).map(String::valueOf).toList();
|
||||
}
|
||||
if (value instanceof String strValue) {
|
||||
if (StrUtil.isBlank(strValue)) {
|
||||
return List.of();
|
||||
}
|
||||
if (JSONUtil.isTypeJSONArray(strValue)) {
|
||||
return JSONUtil.parseArray(strValue).toList(String.class);
|
||||
}
|
||||
return Arrays.stream(strValue.split(","))
|
||||
.map(String::trim)
|
||||
.filter(StrUtil::isNotBlank)
|
||||
.toList();
|
||||
}
|
||||
return List.of(String.valueOf(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return "提案单位处理人";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return 210;
|
||||
}
|
||||
}
|
||||
+12
-45
@@ -26,6 +26,9 @@ import org.nutz.ioc.aop.Aop;
|
||||
import org.nutz.json.Json;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -36,62 +39,26 @@ public class ProposalCaseFilingInterceptor implements FlowInterceptor {
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public void intercept(Execution execution) {
|
||||
if ("0".equals(execution.getArgs().getStr("tf_caseCheckNeedSecondReply"))){
|
||||
return;
|
||||
}
|
||||
Dao dao = ServiceContext.find(Dao.class);
|
||||
// 提案ID
|
||||
String proposalId = execution.getProcessInstance().getBusinessNo();
|
||||
|
||||
// 立案结果
|
||||
String caseFilingResult = execution.getArgs().getStr(FlowConst.TASK_FORM_DATA_PREFIX + "caseFilingResult");
|
||||
|
||||
// 储存承办单位
|
||||
if (StrUtil.isNotBlank(caseFilingResult) && List.of("CONFIRM_FILING", "SUGGESTION").contains(caseFilingResult)) {
|
||||
// 删除原来的记录
|
||||
dao.clear(ProposalReplyUnit.class,Cnd.where(ProposalReplyUnit::getProposalId, "=", proposalId));
|
||||
|
||||
// 主办单位
|
||||
String masterUnitId = execution.getArgs().getStr(FlowConst.TASK_FORM_DATA_PREFIX + "masterUnitId");
|
||||
ProposalUndertake masterUnit = dao.fetch(ProposalUndertake.class, masterUnitId);
|
||||
ProposalReplyUnit masterReplyUnit = new ProposalReplyUnit();
|
||||
masterReplyUnit.setProposalId(proposalId);
|
||||
masterReplyUnit.setUnitId(masterUnit.getId());
|
||||
masterReplyUnit.setUnitCode(masterUnit.getCode());
|
||||
masterReplyUnit.setUnitName(masterUnit.getName());
|
||||
masterReplyUnit.setIsMaster(true);
|
||||
dao.insert(masterReplyUnit);
|
||||
|
||||
// 协办单位
|
||||
List<String> helpUnitIds = (List<String>) execution.getArgs().getObj(FlowConst.TASK_FORM_DATA_PREFIX + "slaveUnitIds");
|
||||
if(ObjectUtil.isNotEmpty(helpUnitIds)){
|
||||
for (String helpUnitId : helpUnitIds) {
|
||||
ProposalUndertake helpUnit = dao.fetch(ProposalUndertake.class, helpUnitId);
|
||||
ProposalReplyUnit helpReplyUnit = new ProposalReplyUnit();
|
||||
helpReplyUnit.setProposalId(proposalId);
|
||||
helpReplyUnit.setUnitId(helpUnit.getId());
|
||||
helpReplyUnit.setUnitCode(helpUnit.getCode());
|
||||
helpReplyUnit.setUnitName(helpUnit.getName());
|
||||
helpReplyUnit.setIsMaster(false);
|
||||
dao.insert(helpReplyUnit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 更新立案结果、立案类型
|
||||
ProcessInstance processInstance = execution.getProcessInstance();
|
||||
String businessNo = processInstance.getBusinessNo();
|
||||
|
||||
Chain chain = Chain.make("caseFilingResult", execution.getArgs().getStr(FlowConst.TASK_FORM_DATA_PREFIX + "caseFilingResult"));
|
||||
chain.add("caseFilingType", execution.getArgs().getStr(FlowConst.TASK_FORM_DATA_PREFIX + "caseFilingType"));
|
||||
dao.update(ProposalInfo.class, chain, Cnd.where(ProposalInfo::getId, "=", businessNo));
|
||||
|
||||
|
||||
// 当前任务
|
||||
List<ProcessTask> processTaskList = execution.getProcessTaskList();
|
||||
|
||||
for (ProcessTask task : processTaskList) {
|
||||
// 办理人
|
||||
ProcessTaskActor taskActor = dao.fetch(ProcessTaskActor.class, Cnd.where(ProcessTaskActor::getProcessTaskId, "=", task.getId()));
|
||||
if (taskActor == null) {
|
||||
continue;
|
||||
}
|
||||
String actorUnitId = taskActor.getActorUnitId();
|
||||
ProposalReplyUnit replyUnit = dao.fetch(ProposalReplyUnit.class, Cnd.where(ProposalReplyUnit::getProposalId, "=", proposalId).and(ProposalReplyUnit::getUnitId, "=", actorUnitId));
|
||||
if (replyUnit == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Dict variable = FlowUtil.variableToDict(task.getVariable());
|
||||
variable.set("underTakeName", replyUnit.getUnitName());
|
||||
|
||||
+7
-2
@@ -1,5 +1,6 @@
|
||||
package com.budwk.app.zhgh.democratic.proposal.interceptor;
|
||||
|
||||
import cn.hutool.core.lang.Dict;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.flow.constant.FlowConst;
|
||||
import com.budwk.app.flow.engine.FlowInterceptor;
|
||||
@@ -13,7 +14,7 @@ import org.nutz.dao.Dao;
|
||||
|
||||
/**
|
||||
* 提案分管领导审批前缀拦截器
|
||||
* 用于设置主办单位变量 tf_masterUnitId
|
||||
* 用于设置主办单位变量,兼容主办单位由单个改为多个的场景
|
||||
*/
|
||||
public class ProposalFgxldPrefixInterceptor implements FlowInterceptor {
|
||||
@Override
|
||||
@@ -27,8 +28,12 @@ public class ProposalFgxldPrefixInterceptor implements FlowInterceptor {
|
||||
.and(ProcessTask::getTaskState, "=", ProcessTaskStateEnum.FINISHED.getCode())
|
||||
.desc(ProcessTask::getCreatedAt)
|
||||
);
|
||||
String masterUnitId = FlowUtil.variableToDict(task.getVariable()).getStr(FlowConst.TASK_FORM_DATA_PREFIX + "masterUnitId");
|
||||
Dict variable = FlowUtil.variableToDict(task.getVariable());
|
||||
String masterUnitId = variable.getStr(FlowConst.TASK_FORM_DATA_PREFIX + "masterUnitId");
|
||||
execution.getArgs().set(FlowConst.TASK_FORM_DATA_PREFIX + "masterUnitId", masterUnitId);
|
||||
// 退回提委会时保留主办单位集合,避免多主办场景下页面无法完整回显。
|
||||
execution.getArgs().set(FlowConst.TASK_FORM_DATA_PREFIX + "masterUnitIds",
|
||||
variable.getObj(FlowConst.TASK_FORM_DATA_PREFIX + "masterUnitIds"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+15
-3
@@ -1,12 +1,24 @@
|
||||
package com.budwk.app.zhgh.democratic.proposal.service;
|
||||
|
||||
import com.budwk.app.base.service.BaseService;
|
||||
import cn.hutool.core.lang.Dict;
|
||||
import com.budwk.app.zhgh.democratic.proposal.models.ProposalInfo;
|
||||
import com.budwk.app.zhgh.democratic.proposal.param.ProposalCommitteeFilingApprovalParam;
|
||||
|
||||
public interface ProposalCommitteeFilingService extends BaseService<ProposalInfo> {
|
||||
|
||||
void approval(ProposalCommitteeFilingApprovalParam approvalParam);
|
||||
/**
|
||||
* 提案委员会并案审核。
|
||||
*
|
||||
* @param args 页面提交的流程参数
|
||||
*/
|
||||
void merge(Dict args);
|
||||
|
||||
void revoke(String taskId);
|
||||
/**
|
||||
* 提案委员会立案撤回。
|
||||
* 单条提案只撤回当前任务;并案提案需要整组一起撤回,确保流程状态一致。
|
||||
*
|
||||
* @param taskId 当前已办任务ID
|
||||
* @param proposalId 当前提案ID
|
||||
*/
|
||||
void revokeTask(Long taskId, String proposalId);
|
||||
}
|
||||
|
||||
+9
-2
@@ -1,12 +1,19 @@
|
||||
package com.budwk.app.zhgh.democratic.proposal.service;
|
||||
|
||||
import cn.hutool.core.lang.Dict;
|
||||
import com.budwk.app.base.service.BaseService;
|
||||
import com.budwk.app.zhgh.democratic.proposal.models.ProposalInfo;
|
||||
import com.budwk.app.zhgh.democratic.proposal.param.ProposalCommitteeFilingUnitApprovalParam;
|
||||
|
||||
public interface ProposalCommitteeFilingUnitService extends BaseService<ProposalInfo> {
|
||||
|
||||
void approval(ProposalCommitteeFilingUnitApprovalParam approvalParam);
|
||||
|
||||
void revoke(String taskId);
|
||||
/**
|
||||
* old-flow 提案委员会确认承办单位执行。
|
||||
* 执行流程任务后,同步落库立案结果以及主协办单位配置。
|
||||
*
|
||||
* @param args 页面提交的流程参数
|
||||
*/
|
||||
void executeFlowTask(Dict args);
|
||||
|
||||
}
|
||||
|
||||
+23
-20
@@ -1,10 +1,10 @@
|
||||
package com.budwk.app.zhgh.democratic.proposal.service;
|
||||
|
||||
import cn.hutool.core.lang.Dict;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.service.BaseService;
|
||||
import com.budwk.app.zhgh.democratic.proposal.models.ProposalInfo;
|
||||
import com.budwk.app.zhgh.democratic.proposal.param.ProposalSearchParam;
|
||||
import com.budwk.app.zhgh.democratic.proposal.param.ProposalUnderTakeReplyApprovalParam;
|
||||
import com.budwk.app.zhgh.democratic.proposal.param.ProposalUnderTakeReplyTransferParam;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
|
||||
@@ -15,7 +15,15 @@ public interface ProposalUnderTakeReplyService extends BaseService<ProposalInfo>
|
||||
|
||||
Pagination pageData(ProposalSearchParam param);
|
||||
|
||||
void approval(ProposalUnderTakeReplyApprovalParam param);
|
||||
|
||||
/**
|
||||
* old-flow 提案承办单位答复执行。
|
||||
* 同一批次存在多个 wf_process_task 时,前面的任务只完结当前待办,
|
||||
* 最后一条待办才真正驱动流程流转到下一节点。
|
||||
*
|
||||
* @param args 页面提交的流程参数
|
||||
*/
|
||||
void executeFlowTask(Dict args);
|
||||
|
||||
/**
|
||||
* 查询本单位可转办用户
|
||||
@@ -24,26 +32,21 @@ public interface ProposalUnderTakeReplyService extends BaseService<ProposalInfo>
|
||||
List<NutMap> queryTransferUser(String keyword);
|
||||
|
||||
/**
|
||||
* 转办
|
||||
* @param param
|
||||
* 查询历史承办单位答复任务中的答复内容。
|
||||
* 该能力仅用于超级管理员在页面上回显“编辑答复内容”弹窗,
|
||||
* 因此只返回当前编辑场景所需的最小字段,避免误改其他流程数据。
|
||||
*
|
||||
* @param taskId 历史承办单位答复任务ID
|
||||
* @return 包含任务ID和 tf_opinion 的回显数据
|
||||
*/
|
||||
void transfer(ProposalUnderTakeReplyTransferParam param);
|
||||
NutMap getReplyOpinion(Long taskId);
|
||||
|
||||
/**
|
||||
* 撤回
|
||||
* @param taskId
|
||||
* 更新历史承办单位答复任务中的答复内容。
|
||||
* 这里只允许修改流程任务变量里的 tf_opinion,其他字段如落实情况、附件、流程状态均保持不变。
|
||||
*
|
||||
* @param taskId 历史承办单位答复任务ID
|
||||
* @param opinion 最新答复内容
|
||||
*/
|
||||
void revokeTask(@Valid String taskId);
|
||||
|
||||
/**
|
||||
* 检查是否可以办理
|
||||
* @param taskId
|
||||
*/
|
||||
String checkCanReply(String taskId);
|
||||
|
||||
/**
|
||||
* 撤回转办
|
||||
* @param taskId
|
||||
*/
|
||||
void revokeTransfer(String taskId);
|
||||
void updateReplyOpinion(Long taskId, String opinion);
|
||||
}
|
||||
|
||||
+47
-155
@@ -1,40 +1,26 @@
|
||||
package com.budwk.app.zhgh.democratic.proposal.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.lang.Dict;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.budwk.app.base.constant.RoleConstant;
|
||||
import com.budwk.app.base.exception.BaseException;
|
||||
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||
import com.budwk.app.bpm.dto.BpmAssignmentDto;
|
||||
import com.budwk.app.bpm.enums.BpmTaskApprovalTypeEnum;
|
||||
import com.budwk.app.bpm.models.BpmProcessInstance;
|
||||
import com.budwk.app.bpm.models.BpmProcessTask;
|
||||
import com.budwk.app.bpm.service.BpmService;
|
||||
import com.budwk.app.sys.models.Sys_user_role;
|
||||
import com.budwk.app.sys.services.SysMsgService;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.web.controllers.open.commons.service.CommonService;
|
||||
import com.budwk.app.flow.constant.FlowConst;
|
||||
import com.budwk.app.flow.entity.ProcessTask;
|
||||
import com.budwk.app.flow.service.FlowCommonService;
|
||||
import com.budwk.app.flow.service.ProcessTaskService;
|
||||
import com.budwk.app.zhgh.democratic.proposal.models.ProposalConsolidation;
|
||||
import com.budwk.app.zhgh.democratic.proposal.models.ProposalInfo;
|
||||
import com.budwk.app.zhgh.democratic.proposal.models.ProposalUndertake;
|
||||
import com.budwk.app.zhgh.democratic.proposal.param.ProposalCommitteeFilingApprovalParam;
|
||||
import com.budwk.app.zhgh.democratic.proposal.models.ProposalMerge;
|
||||
import com.budwk.app.zhgh.democratic.proposal.service.ProposalCommitteeFilingService;
|
||||
import com.budwk.app.zhgh.democratic.proposal.service.common.ProposalCommonService;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.dao.Chain;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.dao.util.cri.Static;
|
||||
import org.nutz.ioc.aop.Aop;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.lang.random.R;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@IocBean(args = {"refer:dao"})
|
||||
public class ProposalCommitteeFilingServiceImpl extends BaseServiceImpl<ProposalInfo> implements ProposalCommitteeFilingService {
|
||||
@@ -42,155 +28,61 @@ public class ProposalCommitteeFilingServiceImpl extends BaseServiceImpl<Proposal
|
||||
@Inject
|
||||
private ProposalCommonService proposalCommonService;
|
||||
@Inject
|
||||
private BpmService bpmService;
|
||||
private FlowCommonService flowCommonService;
|
||||
@Inject
|
||||
private CommonService commonService;
|
||||
@Inject
|
||||
private SysMsgService sysMsgService;
|
||||
private ProcessTaskService processTaskService;
|
||||
|
||||
public ProposalCommitteeFilingServiceImpl(Dao dao) {
|
||||
super(dao);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void approval(ProposalCommitteeFilingApprovalParam approvalParam) {
|
||||
approvalParam.getBpmTaskApprovalTypeEnum();
|
||||
Map<String, Object> variables = BeanUtil.beanToMap(approvalParam);
|
||||
variables.put("proposalIds", approvalParam.getProposalIds());
|
||||
variables.put("hostUnitId", approvalParam.getHostUnitId());
|
||||
variables.put("helpUnitIds", approvalParam.getHelpUnitIds());
|
||||
variables.put("caseFilingResult", approvalParam.getCaseFilingResult());
|
||||
variables.put("consolidationIds", approvalParam.getProposalIds());
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public void merge(Dict args) {
|
||||
List<Integer> taskIds = (List<Integer>) args.get("processTaskIds");
|
||||
List<String> proposalIds = (List<String>) args.get("proposalIds");
|
||||
|
||||
ProposalUndertake hostUnit = null;
|
||||
List<ProposalUndertake> helpUnits = null;
|
||||
//承办单位答复人初步阅览
|
||||
List<BpmAssignmentDto> nextApprovals = new ArrayList<>();
|
||||
// 记录提案并案,后续撤回、查询等场景都依赖这组并案关系。
|
||||
dao().clear(ProposalMerge.class, Cnd.where(ProposalMerge::getProposalId, "in", proposalIds));
|
||||
ProposalConsolidation proposalConsolidation = new ProposalConsolidation();
|
||||
proposalConsolidation.setConsolidationIds(proposalIds);
|
||||
dao().insert(proposalConsolidation);
|
||||
|
||||
if (approvalParam.getBpmTaskApprovalTypeEnum().equals(BpmTaskApprovalTypeEnum.DYNAMIC)) {
|
||||
if (List.of("CONFIRM_FILING", "SUGGESTION").contains(approvalParam.getCaseFilingResult())) {
|
||||
hostUnit = dao().fetch(ProposalUndertake.class, approvalParam.getHostUnitId());
|
||||
helpUnits = dao().query(ProposalUndertake.class, Cnd.where(ProposalUndertake::getId, "in", approvalParam.getHelpUnitIds()));
|
||||
variables.put("hostUnit", hostUnit.getName());
|
||||
variables.put("helpUnits", helpUnits.stream().map(ProposalUndertake::getName).toArray(String[]::new));
|
||||
String groupId = R.UU32();
|
||||
List<ProposalMerge> merges = proposalIds.stream().map(proposalId -> {
|
||||
ProposalMerge merge = new ProposalMerge();
|
||||
merge.setProposalId(proposalId);
|
||||
merge.setGroupId(groupId);
|
||||
return merge;
|
||||
}).toList();
|
||||
dao().insert(merges);
|
||||
|
||||
List<JSONObject> units = new ArrayList<>();
|
||||
units.add(new JSONObject()
|
||||
.set("isMaster",true)
|
||||
.set("underTakeId", hostUnit.getId())
|
||||
.set("underTakeName", hostUnit.getName())
|
||||
.set("underTakeCode", hostUnit.getCode())
|
||||
);
|
||||
|
||||
if(ObjectUtil.isNotEmpty(helpUnits)){
|
||||
for (ProposalUndertake helpUnit : helpUnits) {
|
||||
units.add(new JSONObject()
|
||||
.set("isMaster",false)
|
||||
.set("underTakeId", helpUnit.getId())
|
||||
.set("underTakeName", helpUnit.getName())
|
||||
.set("underTakeCode", helpUnit.getCode())
|
||||
);
|
||||
}
|
||||
}
|
||||
variables.put("units",units);
|
||||
}
|
||||
|
||||
//并案审核
|
||||
if (approvalParam.getProposalIds().length > 1) {
|
||||
ProposalConsolidation proposalConsolidation = new ProposalConsolidation();
|
||||
proposalConsolidation.setConsolidationIds(Arrays.asList(approvalParam.getProposalIds()));
|
||||
dao().insert(proposalConsolidation);
|
||||
}
|
||||
|
||||
//立案和作为意见会有承办单位
|
||||
if (approvalParam.getCaseFilingResult().equals("CONFIRM_FILING") || approvalParam.getCaseFilingResult().equals("SUGGESTION")) {
|
||||
List<ProposalUndertake> units = new ArrayList<>();
|
||||
units.add(hostUnit);
|
||||
if (ObjectUtil.isNotNull(helpUnits)) {
|
||||
units.addAll(helpUnits);
|
||||
}
|
||||
for (ProposalUndertake unit : units) {
|
||||
String approvalLoginName = commonService.findUserLoginNameByRoleCode(RoleConstant.PROPOSAL_UNIT_LEADER, Cnd.where(Sys_user_role::getUnderTakeId, "=", unit.getId()));
|
||||
if (StrUtil.isBlank(approvalLoginName)) {
|
||||
throw new BaseException("{}答复人没有配置,请到承办单位管理页面设置!", unit.getName());
|
||||
}
|
||||
|
||||
assert hostUnit != null;
|
||||
nextApprovals.add(new BpmAssignmentDto()
|
||||
.setLoginName(approvalLoginName)
|
||||
.setJsonObject(new JSONObject()
|
||||
.set("isMaster", hostUnit.getId().equals(unit.getId()))
|
||||
.set("underTakeId", unit.getId())
|
||||
.set("underTakeName", unit.getName())
|
||||
.set("underTakeCode", unit.getCode())
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
//下一个审批人
|
||||
String nextApprovalLoginName = proposalCommonService.getCommitteeDirectorByProposalId(approvalParam.getProcessInstanceBusinessId());
|
||||
|
||||
//提交并案
|
||||
for (String consolidationProposalId : approvalParam.getProposalIds()) {
|
||||
BpmProcessInstance instance = dao().fetch(BpmProcessInstance.class, Cnd.where(BpmProcessInstance::getProcessInstanceBusinessId, "=", consolidationProposalId));
|
||||
// bpmService.completeTaskWithNextTaskVariable(instance.getProcessInstanceTaskIds().get(0), approvalParam.getBpmTaskApprovalTypeEnum(), variables, nextApprovals);
|
||||
bpmService.completeTask(instance.getProcessInstanceTaskIds().get(0), approvalParam.getBpmTaskApprovalTypeEnum(), variables, List.of(nextApprovalLoginName));
|
||||
}
|
||||
|
||||
//修改提案立案结果
|
||||
dao().update(ProposalInfo.class, Chain.make("caseFilingResult", approvalParam.getCaseFilingResult()), Cnd.where(ProposalInfo::getId, "in", approvalParam.getProposalIds()));
|
||||
|
||||
List<ProposalInfo> proposalInfos = dao().query(ProposalInfo.class, Cnd.where(ProposalInfo::getId, "in", approvalParam.getProposalIds()));
|
||||
for (ProposalInfo proposalInfo : proposalInfos) {
|
||||
//给代表发送消息
|
||||
if("CONFIRM_FILING".equals(approvalParam.getCaseFilingResult())){
|
||||
String template = "{}代表您好!您的提案《{}》提案委员会已立案审核,审核结果为准予立案,您可登陆智慧校园下的暖心工会查看详情。";
|
||||
String content = StrUtil.format(template, proposalInfo.getCreateUserName(), proposalInfo.getName());
|
||||
sysMsgService.sendMsg(proposalInfo.getCreateUserLoginName(), "提案委员会立案审核", content, SecurityUtil.getUserId());
|
||||
}else if("SUGGESTION".equals(approvalParam.getCaseFilingResult())){
|
||||
|
||||
}else if("NOT".equals(approvalParam.getCaseFilingResult())){
|
||||
String template = "{}代表您好!您的提案《{}》提案委员会已立案审核,审核结果为不予立案,您可登陆智慧校园下的暖心工会查看详情。";
|
||||
String content = StrUtil.format(template, proposalInfo.getCreateUserName(), proposalInfo.getName());
|
||||
sysMsgService.sendMsg(proposalInfo.getCreateUserLoginName(), "提案委员会立案审核", content, SecurityUtil.getUserId());
|
||||
}
|
||||
|
||||
//给承办单位发送消息
|
||||
if("CONFIRM_FILING".equals(approvalParam.getCaseFilingResult())){
|
||||
for (BpmAssignmentDto nextApproval : nextApprovals) {
|
||||
String template = "经提案委员会立案审核,提案《{}》由{}作为{}单位,您可登陆智慧校园下的暖心工会查看详情,感谢您对教代会提案工作的大力支持!。";
|
||||
String underTakeName = nextApproval.getJsonObject().getStr("underTakeName");
|
||||
Boolean isMaster = nextApproval.getJsonObject().getBool("isMaster", false);
|
||||
String content = StrUtil.format(template, proposalInfo.getName(), underTakeName,isMaster?"主办":"协办");
|
||||
sysMsgService.sendMsg(nextApproval.getLoginName(), "承办单位初步意见", content, SecurityUtil.getUserId());
|
||||
}
|
||||
}
|
||||
}
|
||||
// 并案审核需要把同一批提案的当前节点一起提交,保持整组流程同步往下走。
|
||||
for (Integer taskId : taskIds) {
|
||||
Dict taskArgs = args.clone();
|
||||
taskArgs.put(FlowConst.PROCESS_TASK_ID_KEY, taskId);
|
||||
flowCommonService.executeTask(taskArgs);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public void revoke(String taskId) {
|
||||
BpmProcessTask task = dao().fetch(BpmProcessTask.class, taskId);
|
||||
String instanceId = task.getProcessInstanceId();
|
||||
BpmProcessInstance instance = dao().fetch(BpmProcessInstance.class, instanceId);
|
||||
String instanceBusinessId = instance.getProcessInstanceBusinessId();
|
||||
List<String> consolidationIds = proposalCommonService.getConsolidation(instanceBusinessId);
|
||||
for (String consolidationId : consolidationIds) {
|
||||
BpmProcessInstance consolidationProposalInstance = dao().fetch(BpmProcessInstance.class, Cnd.where(BpmProcessInstance::getProcessInstanceBusinessId, "=", consolidationId));
|
||||
if (ObjectUtil.isNotEmpty(consolidationProposalInstance.getProcessInstanceTaskIds())) {
|
||||
//还有待处理的任务 那么走的就是确定立案
|
||||
String activeTaskId = consolidationProposalInstance.getProcessInstanceTaskIds().get(0);
|
||||
BpmProcessTask activeTask = dao().fetch(BpmProcessTask.class, Cnd.where(BpmProcessTask::getId, "=", activeTaskId));
|
||||
bpmService.revokeTask(activeTask.getPrevTaskId());
|
||||
}else{
|
||||
//不予立案后撤回
|
||||
bpmService.revokeTask(taskId);
|
||||
}
|
||||
public void revokeTask(Long taskId, String proposalId) {
|
||||
/*
|
||||
* 提委会立案撤回统一走 flowCommonService。
|
||||
* 非并案时直接撤回当前任务;并案时按当前节点找出整组已办任务,逐条撤回,避免只回退一部分提案。
|
||||
*/
|
||||
List<String> mergeProposalIds = proposalCommonService.mergeProposal(proposalId);
|
||||
if (ObjectUtil.isEmpty(mergeProposalIds)) {
|
||||
flowCommonService.revokeTask(taskId);
|
||||
return;
|
||||
}
|
||||
|
||||
ProcessTask thisTask = dao().fetch(ProcessTask.class, taskId);
|
||||
List<ProcessTask> mergeTasks = processTaskService.getDoneTaskByBizIdTaskName(mergeProposalIds, thisTask.getTaskName());
|
||||
for (ProcessTask mergeTask : mergeTasks) {
|
||||
flowCommonService.revokeTask(mergeTask.getId());
|
||||
}
|
||||
dao().update(ProposalInfo.class, Chain.make("caseFilingResult", null), Cnd.where(ProposalInfo::getId, "in", consolidationIds));
|
||||
dao().clear(ProposalConsolidation.class, Cnd.where(new Static("JSON_CONTAINS(consolidationIds,'\"" + instanceBusinessId + "\"')")));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+126
-107
@@ -1,8 +1,10 @@
|
||||
package com.budwk.app.zhgh.democratic.proposal.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.lang.Dict;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.budwk.app.base.constant.RoleConstant;
|
||||
import com.budwk.app.base.exception.BaseException;
|
||||
@@ -12,6 +14,10 @@ import com.budwk.app.bpm.enums.BpmProcessTaskStatusEnum;
|
||||
import com.budwk.app.bpm.models.BpmProcessInstance;
|
||||
import com.budwk.app.bpm.models.BpmProcessTask;
|
||||
import com.budwk.app.bpm.service.BpmService;
|
||||
import com.budwk.app.flow.constant.FlowConst;
|
||||
import com.budwk.app.flow.entity.ProcessTask;
|
||||
import com.budwk.app.flow.service.FlowCommonService;
|
||||
import com.budwk.app.flow.service.ProcessTaskService;
|
||||
import com.budwk.app.sys.models.Sys_user_role;
|
||||
import com.budwk.app.sys.services.SysMsgService;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
@@ -19,6 +25,7 @@ import com.budwk.app.web.controllers.open.commons.service.CommonService;
|
||||
import com.budwk.app.zhgh.democratic.proposal.models.ProposalConfig;
|
||||
import com.budwk.app.zhgh.democratic.proposal.models.ProposalConsolidation;
|
||||
import com.budwk.app.zhgh.democratic.proposal.models.ProposalInfo;
|
||||
import com.budwk.app.zhgh.democratic.proposal.models.ProposalReplyUnit;
|
||||
import com.budwk.app.zhgh.democratic.proposal.models.ProposalUndertake;
|
||||
import com.budwk.app.zhgh.democratic.proposal.param.ProposalCommitteeFilingUnitApprovalParam;
|
||||
import com.budwk.app.zhgh.democratic.proposal.service.ProposalCommitteeFilingUnitService;
|
||||
@@ -33,9 +40,12 @@ import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@IocBean(args = {"refer:dao"})
|
||||
public class ProposalCommitteeFilingUnitServiceImpl extends BaseServiceImpl<ProposalInfo> implements ProposalCommitteeFilingUnitService {
|
||||
@@ -48,6 +58,10 @@ public class ProposalCommitteeFilingUnitServiceImpl extends BaseServiceImpl<Prop
|
||||
private BpmService bpmService;
|
||||
@Inject
|
||||
private SysMsgService sysMsgService;
|
||||
@Inject
|
||||
private FlowCommonService flowCommonService;
|
||||
@Inject
|
||||
private ProcessTaskService processTaskService;
|
||||
|
||||
public ProposalCommitteeFilingUnitServiceImpl(Dao dao) {
|
||||
super(dao);
|
||||
@@ -55,129 +69,134 @@ public class ProposalCommitteeFilingUnitServiceImpl extends BaseServiceImpl<Prop
|
||||
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public void approval(ProposalCommitteeFilingUnitApprovalParam approvalParam) {
|
||||
approvalParam.getBpmTaskApprovalTypeEnum();
|
||||
Map<String, Object> variables = BeanUtil.beanToMap(approvalParam);
|
||||
|
||||
//审批变量
|
||||
variables.put("proposalIds", approvalParam.getProposalIds());
|
||||
variables.put("hostUnitId", approvalParam.getHostUnitId());
|
||||
variables.put("helpUnitIds", approvalParam.getHelpUnitIds());
|
||||
variables.put("caseFilingResult", approvalParam.getCaseFilingResult());
|
||||
|
||||
//承办单位
|
||||
ProposalUndertake hostUnit = dao().fetch(ProposalUndertake.class, approvalParam.getHostUnitId());
|
||||
List<ProposalUndertake> helpUnits = dao().query(ProposalUndertake.class, Cnd.where(ProposalUndertake::getId, "in", approvalParam.getHelpUnitIds()));
|
||||
variables.put("hostUnit", hostUnit.getName());
|
||||
variables.put("helpUnits", helpUnits.stream().map(ProposalUndertake::getName).toArray(String[]::new));
|
||||
|
||||
//查询提案配置协办单位是否需要答复
|
||||
ProposalConfig proposalConfig = dao().fetch(ProposalConfig.class, Cnd.NEW());
|
||||
Boolean slaveUnitNeedReply = proposalConfig.getSlaveUnitNeedReply();
|
||||
if (ObjectUtil.isNull(slaveUnitNeedReply)) {
|
||||
throw new BaseException("协办是否需要答复提案配置缺失,请联系校工会!");
|
||||
public void executeFlowTask(Dict args) {
|
||||
Long processTaskId = args.getLong(FlowConst.PROCESS_TASK_ID_KEY);
|
||||
ProcessTask currentTask = dao().fetch(ProcessTask.class, processTaskId);
|
||||
if (currentTask == null) {
|
||||
throw new BaseException("没有进行中的流程任务");
|
||||
}
|
||||
|
||||
//重新并案审核
|
||||
if (approvalParam.getProposalIds().length > 1) {
|
||||
for (String proposalId : approvalParam.getProposalIds()) {
|
||||
dao().clear(ProposalConsolidation.class, Cnd.where(new Static("JSON_CONTAINS(consolidationIds,'\"%s\"')".formatted(proposalId))));
|
||||
}
|
||||
ProposalConsolidation proposalConsolidation = new ProposalConsolidation();
|
||||
proposalConsolidation.setConsolidationIds(Arrays.asList(approvalParam.getProposalIds()));
|
||||
dao().insert(proposalConsolidation);
|
||||
String proposalId = args.getStr("proposalId");
|
||||
List<String> proposalIds = proposalCommonService.mergeProposal(proposalId);
|
||||
if (ObjectUtil.isEmpty(proposalIds)) {
|
||||
proposalIds = List.of(proposalId);
|
||||
}
|
||||
|
||||
List<ProposalUndertake> proposalUndertakes = new ArrayList<>();
|
||||
proposalUndertakes.add(hostUnit);
|
||||
if (ObjectUtil.isNotEmpty(helpUnits) && slaveUnitNeedReply) {
|
||||
proposalUndertakes.addAll(helpUnits);
|
||||
/*
|
||||
* 并案场景下,同一个节点会在每条提案实例上各有一条待办。
|
||||
* 这里统一按 taskName 找出整组正在办理中的任务,逐条执行,确保并案提案的流程状态保持一致。
|
||||
*/
|
||||
List<ProcessTask> executeTasks = processTaskService.getDoingTaskByBizIdTaskName(proposalIds, currentTask.getTaskName());
|
||||
if (ObjectUtil.isEmpty(executeTasks)) {
|
||||
executeTasks = List.of(currentTask);
|
||||
}
|
||||
for (ProcessTask executeTask : executeTasks) {
|
||||
Dict cloneArgs = args.clone();
|
||||
cloneArgs.put(FlowConst.PROCESS_TASK_ID_KEY, executeTask.getId());
|
||||
flowCommonService.executeTask(cloneArgs);
|
||||
}
|
||||
|
||||
//承办单位答复人
|
||||
List<BpmAssignmentDto> nextApprovals = new ArrayList<>();
|
||||
// if (approvalParam.getCaseFilingResult().equals("CONFIRM_FILING") || approvalParam.getCaseFilingResult().equals("SUGGESTION")) {
|
||||
//南邮 只有立案需要答复
|
||||
if (approvalParam.getCaseFilingResult().equals("CONFIRM_FILING")) {
|
||||
for (ProposalUndertake undertake : proposalUndertakes) {
|
||||
String approvalLoginName = commonService.findUserLoginNameByRoleCode(RoleConstant.PROPOSAL_UNIT_LEADER, Cnd.where(Sys_user_role::getUnderTakeId, "=", undertake.getId()));
|
||||
if (StrUtil.isBlank(approvalLoginName)) {
|
||||
throw new BaseException("{}答复人没有配置,请到承办单位管理页面进行配置。", undertake.getName());
|
||||
}
|
||||
syncCommitteeFilingUnitData(proposalIds, args);
|
||||
}
|
||||
/**
|
||||
* old-flow 页面提交后,需要把立案结果以及主协办单位同步落业务表。
|
||||
* 若这次改成“不予立案”等无需承办单位的结果,也要先清掉旧的承办单位记录,避免脏数据残留。
|
||||
*/
|
||||
private void syncCommitteeFilingUnitData(List<String> proposalIds, Dict args) {
|
||||
String caseFilingResult = args.getStr(FlowConst.TASK_FORM_DATA_PREFIX + "caseFilingResult");
|
||||
String caseFilingType = args.getStr(FlowConst.TASK_FORM_DATA_PREFIX + "caseFilingType");
|
||||
|
||||
nextApprovals.add(new BpmAssignmentDto()
|
||||
.setLoginName(approvalLoginName)
|
||||
.setJsonObject(new JSONObject()
|
||||
.set("isMaster", hostUnit.getId().equals(undertake.getId()))
|
||||
.set("underTakeId", undertake.getId())
|
||||
.set("underTakeName", undertake.getName())
|
||||
.set("underTakeCode", undertake.getCode())
|
||||
)
|
||||
);
|
||||
dao().update(ProposalInfo.class,
|
||||
Chain.make("caseFilingResult", caseFilingResult).add("caseFilingType", caseFilingType),
|
||||
Cnd.where(ProposalInfo::getId, "in", proposalIds));
|
||||
|
||||
dao().clear(ProposalReplyUnit.class, Cnd.where(ProposalReplyUnit::getProposalId, "in", proposalIds));
|
||||
if (!List.of("CONFIRM_FILING", "SUGGESTION").contains(caseFilingResult)) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<String> masterUnitIds = getUnitIdList(args, FlowConst.TASK_FORM_DATA_PREFIX + "masterUnitIds");
|
||||
if (ObjectUtil.isEmpty(masterUnitIds)) {
|
||||
String masterUnitId = args.getStr(FlowConst.TASK_FORM_DATA_PREFIX + "masterUnitId");
|
||||
if (StrUtil.isNotBlank(masterUnitId)) {
|
||||
masterUnitIds = List.of(masterUnitId);
|
||||
}
|
||||
}
|
||||
List<String> slaveUnitIds = getUnitIdList(args, FlowConst.TASK_FORM_DATA_PREFIX + "slaveUnitIds");
|
||||
|
||||
for (String consolidationProposalId : approvalParam.getProposalIds()) {
|
||||
BpmProcessInstance instance = dao().fetch(BpmProcessInstance.class, Cnd.where(BpmProcessInstance::getProcessInstanceBusinessId, "=", consolidationProposalId));
|
||||
BpmProcessTask caseUnitTask = dao().fetch(BpmProcessTask.class, Cnd.where(BpmProcessTask::getProcessInstanceId, "=", instance.getId())
|
||||
.and(BpmProcessTask::getProcessTaskNodeCode, "=", 70)
|
||||
.and(BpmProcessTask::getTaskStatus, "=", BpmProcessTaskStatusEnum.ACTIVE.name())
|
||||
.and(BpmProcessTask::getDelFlag, "=", 0)
|
||||
.desc(BpmProcessTask::getCreatedOn)
|
||||
);
|
||||
bpmService.completeTaskWithNextTaskVariable(caseUnitTask.getId(), approvalParam.getBpmTaskApprovalTypeEnum(), variables, nextApprovals);
|
||||
List<String> allUnitIds = new ArrayList<>();
|
||||
allUnitIds.addAll(masterUnitIds);
|
||||
allUnitIds.addAll(slaveUnitIds);
|
||||
if (allUnitIds.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
//修改提案立案结果
|
||||
dao().update(ProposalInfo.class, Chain.make("caseFilingResult", approvalParam.getCaseFilingResult())
|
||||
, Cnd.where(ProposalInfo::getId, "in", approvalParam.getProposalIds()));
|
||||
Map<String, ProposalUndertake> undertakeMap = dao().query(ProposalUndertake.class, Cnd.where(ProposalUndertake::getId, "in", allUnitIds))
|
||||
.stream()
|
||||
.collect(Collectors.toMap(ProposalUndertake::getId, v -> v));
|
||||
|
||||
List<ProposalInfo> proposalInfos = dao().query(ProposalInfo.class, Cnd.where(ProposalInfo::getId, "in", approvalParam.getProposalIds()));
|
||||
for (ProposalInfo proposalInfo : proposalInfos) {
|
||||
//给代表发送消息
|
||||
// if("CONFIRM_FILING".equals(approvalParam.getCaseFilingResult())){
|
||||
// String template = "{}代表您好!您的提案《{}》提案委员会已立案审核,审核结果为准予立案,您可登陆智慧校园下的暖心工会查看详情。";
|
||||
// String content = StrUtil.format(template, proposalInfo.getCreateUserName(), proposalInfo.getName());
|
||||
// sysMsgService.sendMsg(proposalInfo.getCreateUserLoginName(), "提案委员会立案审核", content, SecurityUtil.getUserId());
|
||||
// }else if("SUGGESTION".equals(approvalParam.getCaseFilingResult())){
|
||||
//
|
||||
// }else if("NOT".equals(approvalParam.getCaseFilingResult())){
|
||||
// String template = "{}代表您好!您的提案《{}》提案委员会已立案审核,审核结果为不予立案,您可登陆智慧校园下的暖心工会查看详情。";
|
||||
// String content = StrUtil.format(template, proposalInfo.getCreateUserName(), proposalInfo.getName());
|
||||
// sysMsgService.sendMsg(proposalInfo.getCreateUserLoginName(), "提案委员会立案审核", content, SecurityUtil.getUserId());
|
||||
// }
|
||||
|
||||
//给承办单位发送消息
|
||||
if("CONFIRM_FILING".equals(approvalParam.getCaseFilingResult())) {
|
||||
for (BpmAssignmentDto nextApproval : nextApprovals) {
|
||||
String template = "经提案委员会立案审核,提案《{}》最终由{}作为{}单位,您可登陆智慧校园下的暖心工会进行答复,感谢您对教代会提案工作的大力支持!。";
|
||||
String underTakeName = nextApproval.getJsonObject().getStr("underTakeName");
|
||||
Boolean isMaster = nextApproval.getJsonObject().getBool("isMaster", false);
|
||||
String content = StrUtil.format(template, proposalInfo.getName(), underTakeName, isMaster ? "主办" : "协办");
|
||||
sysMsgService.sendMsg(nextApproval.getLoginName(), "承办单位答复", content, SecurityUtil.getUserId());
|
||||
}
|
||||
}
|
||||
List<ProposalReplyUnit> replyUnits = new ArrayList<>();
|
||||
for (String proposalId : proposalIds) {
|
||||
replyUnits.addAll(buildReplyUnits(proposalId, masterUnitIds, undertakeMap, true));
|
||||
replyUnits.addAll(buildReplyUnits(proposalId, slaveUnitIds, undertakeMap, false));
|
||||
}
|
||||
if (!replyUnits.isEmpty()) {
|
||||
dao().insert(replyUnits);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public void revoke(String taskId) {
|
||||
BpmProcessTask task = dao().fetch(BpmProcessTask.class, taskId);
|
||||
String instanceId = task.getProcessInstanceId();
|
||||
BpmProcessInstance instance = dao().fetch(BpmProcessInstance.class, instanceId);
|
||||
String instanceBusinessId = instance.getProcessInstanceBusinessId();
|
||||
List<String> consolidationIds = proposalCommonService.getConsolidation(instanceBusinessId);
|
||||
for (String consolidationId : consolidationIds) {
|
||||
BpmProcessInstance consolidationProposalInstance = dao().fetch(BpmProcessInstance.class, Cnd.where(BpmProcessInstance::getProcessInstanceBusinessId, "=", consolidationId));
|
||||
String activeTaskId = consolidationProposalInstance.getProcessInstanceTaskIds().get(0);
|
||||
BpmProcessTask activeTask = dao().fetch(BpmProcessTask.class, Cnd.where(BpmProcessTask::getId, "=", activeTaskId));
|
||||
bpmService.revokeTask(activeTask.getPrevTaskId());
|
||||
/**
|
||||
* 一个提案可以配置多个主办单位和多个协办单位。
|
||||
* 这里按页面提交顺序逐条生成承办单位记录,兼容多主办的业务场景。
|
||||
*/
|
||||
private List<ProposalReplyUnit> buildReplyUnits(String proposalId, List<String> unitIds, Map<String, ProposalUndertake> undertakeMap, boolean isMaster) {
|
||||
List<ProposalReplyUnit> replyUnits = new ArrayList<>();
|
||||
for (String unitId : unitIds) {
|
||||
ProposalUndertake undertake = undertakeMap.get(unitId);
|
||||
if (undertake == null) {
|
||||
continue;
|
||||
}
|
||||
ProposalReplyUnit replyUnit = new ProposalReplyUnit();
|
||||
replyUnit.setProposalId(proposalId);
|
||||
replyUnit.setUnitId(undertake.getId());
|
||||
replyUnit.setUnitCode(undertake.getCode());
|
||||
replyUnit.setUnitName(undertake.getName());
|
||||
replyUnit.setIsMaster(isMaster);
|
||||
replyUnits.add(replyUnit);
|
||||
}
|
||||
dao().update(ProposalInfo.class, Chain.make("caseFilingResult", null), Cnd.where(ProposalInfo::getId, "in", consolidationIds));
|
||||
dao().clear(ProposalConsolidation.class, Cnd.where(new Static("JSON_CONTAINS(consolidationIds,'\"" + instanceBusinessId + "\"')")));
|
||||
return replyUnits;
|
||||
}
|
||||
|
||||
/**
|
||||
* 页面里的单位字段可能是数组、JSON 字符串或逗号分隔字符串,这里统一转成去空去重后的列表。
|
||||
*/
|
||||
private List<String> getUnitIdList(Dict args, String key) {
|
||||
Object value = args.get(key);
|
||||
if (ObjectUtil.isEmpty(value)) {
|
||||
return List.of();
|
||||
}
|
||||
List<String> unitIds = new ArrayList<>();
|
||||
if (value instanceof Collection<?> collection) {
|
||||
collection.forEach(item -> {
|
||||
if (ObjectUtil.isNotEmpty(item)) {
|
||||
unitIds.add(String.valueOf(item));
|
||||
}
|
||||
});
|
||||
} else if (value instanceof String strValue) {
|
||||
if (StrUtil.isBlank(strValue)) {
|
||||
return List.of();
|
||||
}
|
||||
if (JSONUtil.isTypeJSONArray(strValue)) {
|
||||
unitIds.addAll(JSONUtil.parseArray(strValue).toList(String.class));
|
||||
} else {
|
||||
Arrays.stream(strValue.split(","))
|
||||
.map(String::trim)
|
||||
.filter(StrUtil::isNotBlank)
|
||||
.forEach(unitIds::add);
|
||||
}
|
||||
} else {
|
||||
unitIds.add(String.valueOf(value));
|
||||
}
|
||||
return new ArrayList<>(new LinkedHashSet<>(unitIds));
|
||||
}
|
||||
}
|
||||
|
||||
+231
-239
@@ -1,6 +1,7 @@
|
||||
package com.budwk.app.zhgh.democratic.proposal.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.lang.Dict;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.budwk.app.base.constant.BpmProcessConstant;
|
||||
@@ -16,6 +17,16 @@ import com.budwk.app.bpm.models.BpmProcessInstance;
|
||||
import com.budwk.app.bpm.models.BpmProcessNodeDefine;
|
||||
import com.budwk.app.bpm.models.BpmProcessTask;
|
||||
import com.budwk.app.bpm.service.BpmService;
|
||||
import com.budwk.app.flow.constant.FlowConst;
|
||||
import com.budwk.app.flow.entity.ProcessInstance;
|
||||
import com.budwk.app.flow.entity.ProcessTask;
|
||||
import com.budwk.app.flow.engine.util.FlowUtil;
|
||||
import com.budwk.app.flow.enums.ProcessSubmitTypeEnum;
|
||||
import com.budwk.app.flow.enums.ProcessTaskPerformTypeEnum;
|
||||
import com.budwk.app.flow.enums.ProcessTaskStateEnum;
|
||||
import com.budwk.app.flow.service.FlowCommonService;
|
||||
import com.budwk.app.flow.service.ProcessInstanceService;
|
||||
import com.budwk.app.flow.service.ProcessTaskService;
|
||||
import com.budwk.app.sys.models.Sys_role;
|
||||
import com.budwk.app.sys.models.Sys_user;
|
||||
import com.budwk.app.sys.models.Sys_user_role;
|
||||
@@ -43,6 +54,7 @@ import org.nutz.ioc.aop.Aop;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
import org.nutz.json.Json;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -65,6 +77,12 @@ public class ProposalUnderTakeReplyServiceImpl extends BaseServiceImpl<ProposalI
|
||||
private SysUserService sysUserService;
|
||||
@Inject
|
||||
private SysMsgService sysMsgService;
|
||||
@Inject
|
||||
private FlowCommonService flowCommonService;
|
||||
@Inject
|
||||
private ProcessTaskService processTaskService;
|
||||
@Inject
|
||||
private ProcessInstanceService processInstanceService;
|
||||
|
||||
public ProposalUnderTakeReplyServiceImpl(Dao dao) {
|
||||
super(dao);
|
||||
@@ -77,115 +95,25 @@ public class ProposalUnderTakeReplyServiceImpl extends BaseServiceImpl<ProposalI
|
||||
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public void approval(ProposalUnderTakeReplyApprovalParam approvalParam) {
|
||||
approvalParam.getBpmTaskApprovalTypeEnum();
|
||||
Map<String, Object> variables = BeanUtil.beanToMap(approvalParam);
|
||||
|
||||
String processInstanceBusinessId = approvalParam.getProcessInstanceBusinessId();
|
||||
ProposalInfo proposalInfo = dao().fetch(ProposalInfo.class, processInstanceBusinessId);
|
||||
|
||||
//查询是否都答复完成
|
||||
boolean ALL_REPLY = false;
|
||||
BpmProcessTask task = dao().fetch(BpmProcessTask.class, approvalParam.getProcessInstanceTaskId());
|
||||
String prevTaskId = task.getPrevTaskId();
|
||||
//查询一同分配的承办单位的答复记录
|
||||
int otherUnderTakeTasks = dao().count(BpmProcessTask.class, Cnd.where("prevTaskId", "=", prevTaskId)
|
||||
.and(BpmProcessTask::getProcessInstanceId, "=", approvalParam.getProcessInstanceId())
|
||||
.and(BpmProcessTask::getId, "!=", task.getId())
|
||||
.and(BpmProcessTask::getTaskStatus, "=", BpmProcessTaskStatusEnum.ACTIVE.name())
|
||||
.and(BpmProcessTask::getDelFlag, "=", 0)
|
||||
);
|
||||
if (otherUnderTakeTasks == 0) {
|
||||
//说明其他单位都答复完成了
|
||||
ALL_REPLY = true;
|
||||
}
|
||||
variables.put("ALL_REPLY", ALL_REPLY);
|
||||
variables.put("caseFilingResult", proposalInfo.getCaseFilingResult());
|
||||
|
||||
//查询提案配置
|
||||
ProposalConfig proposalConfig = dao().fetch(ProposalConfig.class, Cnd.NEW());
|
||||
Boolean slaveUnitLeaderNeedApprove = proposalConfig.getSlaveUnitLeaderNeedApprove();
|
||||
|
||||
//查询出分配的承办单位
|
||||
BpmProcessDefine proposalProcessDefine = dao().fetch(BpmProcessDefine.class, Cnd.where(BpmProcessDefine::getCode, "=", BpmProcessConstant.PROPOSAL.name()));
|
||||
BpmProcessNodeDefine caseUnitNode = dao().fetch(BpmProcessNodeDefine.class, Cnd.where(BpmProcessNodeDefine::getProcessDefineId, "=", proposalProcessDefine.getId())
|
||||
.and(BpmProcessNodeDefine::getNodeCode, "=", 70));
|
||||
BpmProcessTask caseUnitTask = dao().fetch(BpmProcessTask.class, Cnd.where(BpmProcessTask::getProcessInstanceId, "=", approvalParam.getProcessInstanceId())
|
||||
.and(BpmProcessTask::getTaskStatus, "=", BpmProcessTaskStatusEnum.COMPLETE.name())
|
||||
.and(BpmProcessTask::getDelFlag, "=", 0)
|
||||
.and(BpmProcessTask::getProcessTaskNodeId, "=", caseUnitNode.getId())
|
||||
);
|
||||
JSONObject caseUnitExtVariable = caseUnitTask.getExtVariable();
|
||||
List<String> helpUnitIds = caseUnitExtVariable.getBeanList("helpUnitIds", String.class);
|
||||
String hostUnitId = caseUnitExtVariable.getStr("hostUnitId");
|
||||
|
||||
//任务接收人
|
||||
List<BpmAssignmentDto> assignmentDTOS = new ArrayList<>();
|
||||
|
||||
if (ALL_REPLY) {
|
||||
String masterApprovalLoginName = commonService.findUserLoginNameByRoleCode(RoleConstant.PROPOSAL_BRANCH_SCHOOL_LEADER, Cnd.where(Sys_user_role::getUnderTakeId, "=", hostUnitId));
|
||||
if (StrUtil.isBlank(masterApprovalLoginName)) {
|
||||
throw new BaseException("主办单位分管校领导没有配置!");
|
||||
}
|
||||
ProposalUndertake masterUndertake = dao().fetch(ProposalUndertake.class, hostUnitId);
|
||||
assignmentDTOS.add(new BpmAssignmentDto()
|
||||
.setLoginName(masterApprovalLoginName)
|
||||
.setJsonObject(new JSONObject()
|
||||
.set("isMaster", true)
|
||||
.set("underTakeId", masterUndertake.getId())
|
||||
.set("underTakeName", masterUndertake.getName())
|
||||
.set("underTakeCode", masterUndertake.getCode())
|
||||
)
|
||||
|
||||
);
|
||||
//如果需要协办领导审批
|
||||
if (slaveUnitLeaderNeedApprove) {
|
||||
for (String helpUnitId : helpUnitIds) {
|
||||
String slaveApprovalLoginName = commonService.findUserLoginNameByRoleCode(RoleConstant.PROPOSAL_BRANCH_SCHOOL_LEADER, Cnd.where(Sys_user_role::getUnderTakeId, "=", helpUnitId));
|
||||
if (StrUtil.isBlank(slaveApprovalLoginName)) {
|
||||
throw new BaseException("协办单位分管校领导没有配置!");
|
||||
}
|
||||
ProposalUndertake slaveUndertake = dao().fetch(ProposalUndertake.class, helpUnitId);
|
||||
assignmentDTOS.add(new BpmAssignmentDto()
|
||||
.setLoginName(slaveApprovalLoginName)
|
||||
.setJsonObject(new JSONObject()
|
||||
.set("isMaster", false)
|
||||
.set("underTakeId", slaveUndertake.getId())
|
||||
.set("underTakeName", slaveUndertake.getName())
|
||||
.set("underTakeCode", slaveUndertake.getCode())
|
||||
)
|
||||
|
||||
);
|
||||
}
|
||||
}
|
||||
public void executeFlowTask(Dict args) {
|
||||
String proposalId = args.getStr("proposalId");
|
||||
List<String> mergeProposalIds = proposalCommonService.mergeProposal(proposalId);
|
||||
if (mergeProposalIds == null || mergeProposalIds.isEmpty()) {
|
||||
executeSingleFlowTask(args);
|
||||
return;
|
||||
}
|
||||
|
||||
//查询并案的提案
|
||||
List<String> consolidationProposalIds = proposalCommonService.getConsolidation(proposalInfo.getId());
|
||||
//完成本单位的任务
|
||||
for (String consolidationProposalId : consolidationProposalIds) {
|
||||
BpmProcessInstance instance = dao().fetch(BpmProcessInstance.class, Cnd.where(BpmProcessInstance::getProcessInstanceBusinessId, "=", consolidationProposalId));
|
||||
BpmProcessTask otherTask = dao().fetch(BpmProcessTask.class, Cnd.where(BpmProcessTask::getProcessInstanceId, "=", instance.getId())
|
||||
.and(BpmProcessTask::getTaskStatus, "=", BpmProcessTaskStatusEnum.ACTIVE.name())
|
||||
.and(BpmProcessTask::getProcessTaskNodeCode, "=", task.getProcessTaskNodeCode())
|
||||
.and("JSON_EXTRACT(createVariable, '$.underTakeId')", "=", approvalParam.getUnderTakeId())
|
||||
.and(BpmProcessTask::getDelFlag, "=", 0)
|
||||
);
|
||||
bpmService.completeTaskWithNextTaskVariable(otherTask.getId(), BpmTaskApprovalTypeEnum.DYNAMIC, variables, assignmentDTOS);
|
||||
ProcessTask currentTask = dao().fetch(ProcessTask.class, args.getLong(FlowConst.PROCESS_TASK_ID_KEY));
|
||||
if (currentTask == null) {
|
||||
throw new BaseException("没有进行中的流程任务");
|
||||
}
|
||||
|
||||
//全部答复完成发送消息到校领导
|
||||
if(ALL_REPLY){
|
||||
List<ProposalInfo> proposalInfos = dao().query(ProposalInfo.class, Cnd.where(ProposalInfo::getId, "in", consolidationProposalIds));
|
||||
for (ProposalInfo info : proposalInfos) {
|
||||
for (BpmAssignmentDto assignmentDTO : assignmentDTOS) {
|
||||
String template = "尊敬的校领导您好!提案《{}》承办单位已经全部答复完毕,请您登陆智慧校园下的暖心工会进行审批,感谢您对教代会提案工作的大力支持!。";
|
||||
String content = StrUtil.format(template, info.getName());
|
||||
sysMsgService.sendMsg(assignmentDTO.getLoginName(), "分管校领导审批", content, SecurityUtil.getUserId());
|
||||
}
|
||||
}
|
||||
List<ProcessTask> mergeTasks = processTaskService.getDoingTaskByBizIdTaskName(mergeProposalIds, currentTask.getTaskName());
|
||||
for (ProcessTask mergeTask : mergeTasks) {
|
||||
Dict cloneArgs = args.clone();
|
||||
cloneArgs.put(FlowConst.PROCESS_TASK_ID_KEY, mergeTask.getId());
|
||||
executeSingleFlowTask(cloneArgs);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -203,154 +131,218 @@ public class ProposalUnderTakeReplyServiceImpl extends BaseServiceImpl<ProposalI
|
||||
return pagination.getList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public NutMap getReplyOpinion(Long taskId) {
|
||||
ProcessTask replyTask = getEditableReplyTask(taskId);
|
||||
Dict variable = FlowUtil.variableToDict(replyTask.getVariable());
|
||||
String opinion = variable.getStr("tf_opinion");
|
||||
return NutMap.NEW()
|
||||
.addv("taskId", replyTask.getId())
|
||||
.addv("tf_opinion", opinion == null ? "" : opinion);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public void transfer(com.budwk.app.zhgh.democratic.proposal.param.ProposalUnderTakeReplyTransferParam param) {
|
||||
BpmProcessTask task = dao().fetch(BpmProcessTask.class, param.getProcessInstanceTaskId());
|
||||
|
||||
Sys_role sysRole = sysRoleService.getByCode(RoleConstant.PROPOSAL_UNIT_PROXY);
|
||||
|
||||
List<String> consolidation = proposalCommonService.getConsolidation(param.getProposalId());
|
||||
for (String proposalId : consolidation) {
|
||||
BpmProcessInstance instance = dao().fetch(BpmProcessInstance.class, Cnd.where(BpmProcessInstance::getProcessInstanceBusinessId, "=", proposalId));
|
||||
//查询出其他并案提案的任务ID
|
||||
BpmProcessTask otherTask = dao().fetch(BpmProcessTask.class, Cnd.where(BpmProcessTask::getProcessInstanceId, "=", instance.getId())
|
||||
.and(BpmProcessTask::getTaskStatus, "=", BpmProcessTaskStatusEnum.ACTIVE.name())
|
||||
.and(BpmProcessTask::getProcessTaskNodeId, "=", task.getProcessTaskNodeId())
|
||||
.and("JSON_EXTRACT(createVariable, '$.underTakeId')", "=", param.getUnderTakeId())
|
||||
.and(BpmProcessTask::getDelFlag, "=", 0)
|
||||
);
|
||||
bpmService.transferTask(otherTask.getId(), param.getTransferUserLoginName(), BeanUtil.beanToMap(param));
|
||||
//分配权限
|
||||
FieldFilter fieldFilter = FieldFilter.create(Sys_user.class, "^id$");
|
||||
Sys_user proxyUser = Daos.ext(dao(), fieldFilter).fetch(Sys_user.class, Cnd.where(Sys_user::getLoginname, "=", param.getTransferUserLoginName()));
|
||||
|
||||
Sys_user_role sysUserRole = new Sys_user_role();
|
||||
sysUserRole.setUserId(proxyUser.getId());
|
||||
sysUserRole.setRoleId(sysRole.getId());
|
||||
dao().insert(sysUserRole);
|
||||
sysRoleService.clearCache();
|
||||
sysUserService.deleteCache(proxyUser.getId());
|
||||
}
|
||||
|
||||
//发送消息
|
||||
List<ProposalInfo> proposalInfos = dao().query(ProposalInfo.class, Cnd.where(ProposalInfo::getId, "in", consolidation));
|
||||
for (ProposalInfo info : proposalInfos) {
|
||||
BpmProcessInstance instance = dao().fetch(BpmProcessInstance.class, Cnd.where(BpmProcessInstance::getProcessInstanceBusinessId, "=", info.getId()));
|
||||
//查询出其他并案提案的任务ID
|
||||
BpmProcessTask otherTask = dao().fetch(BpmProcessTask.class, Cnd.where(BpmProcessTask::getProcessInstanceId, "=", instance.getId())
|
||||
.and(BpmProcessTask::getProcessTaskNodeId, "=", task.getProcessTaskNodeId())
|
||||
.and("JSON_EXTRACT(createVariable, '$.underTakeId')", "=", param.getUnderTakeId())
|
||||
.and(BpmProcessTask::getDelFlag, "=", 0)
|
||||
);
|
||||
String underTakeName = otherTask.getCreateVariable().getStr("underTakeName");
|
||||
|
||||
String template = "您好!提案《{}》{}单位的答复工作已由{}转交给您,请您登陆智慧校园下的暖心工会进行答复,感谢您对教代会提案工作的大力支持!。";
|
||||
String content = StrUtil.format(template, info.getName(),underTakeName,SecurityUtil.getUserUsername());
|
||||
sysMsgService.sendMsg(param.getTransferUserLoginName(), "承办单位答复", content, SecurityUtil.getUserId());
|
||||
}
|
||||
|
||||
|
||||
public void updateReplyOpinion(Long taskId, String opinion) {
|
||||
ProcessTask replyTask = getEditableReplyTask(taskId);
|
||||
Dict variable = FlowUtil.variableToDict(replyTask.getVariable());
|
||||
/*
|
||||
* 超级管理员编辑入口只允许修改答复内容。
|
||||
* 因此这里仅覆盖 tf_opinion,避免把落实情况、附件或办理人信息一并改掉。
|
||||
*/
|
||||
variable.put("tf_opinion", opinion);
|
||||
replyTask.setVariable(Json.toJson(variable));
|
||||
dao().update(replyTask, "variable");
|
||||
}
|
||||
|
||||
@Override
|
||||
@Aop({TransAop.READ_COMMITTED})
|
||||
public void revokeTask(String taskId) {
|
||||
BpmProcessTask task = dao().fetch(BpmProcessTask.class, taskId);
|
||||
String instanceId = task.getProcessInstanceId();
|
||||
BpmProcessInstance instance = dao().fetch(BpmProcessInstance.class, instanceId);
|
||||
String instanceBusinessId = instance.getProcessInstanceBusinessId();
|
||||
List<String> consolidationIds = proposalCommonService.getConsolidation(instanceBusinessId);
|
||||
for (String consolidationId : consolidationIds) {
|
||||
BpmProcessInstance consolidationProposalInstance = dao().fetch(BpmProcessInstance.class, Cnd.where(BpmProcessInstance::getProcessInstanceBusinessId, "=", consolidationId));
|
||||
|
||||
BpmProcessTask caseUnitTask = dao().fetch(BpmProcessTask.class,
|
||||
Cnd.where(BpmProcessTask::getProcessInstanceId, "=", consolidationProposalInstance.getId())
|
||||
.and(BpmProcessTask::getProcessTaskNodeCode, "=", 70)
|
||||
.and(BpmProcessTask::getDelFlag, "=", 0)
|
||||
.desc(BpmProcessTask::getCreatedOn)
|
||||
);
|
||||
|
||||
BpmProcessTask replyTask = dao().fetch(BpmProcessTask.class,
|
||||
Cnd.where(BpmProcessTask::getPrevTaskId, "=", caseUnitTask.getId())
|
||||
.and("JSON_EXTRACT(createVariable, '$.underTakeId')", "=", task.getCreateVariable().getStr("underTakeId"))
|
||||
.and(BpmProcessTask::getTaskStatus, "=", BpmProcessTaskStatusEnum.COMPLETE.name())
|
||||
.and(BpmProcessTask::getDelFlag, "=", 0)
|
||||
);
|
||||
|
||||
Boolean isMaster = replyTask.getCreateVariable().getBool("isMaster", false);
|
||||
if (isMaster) {
|
||||
bpmService.revokeTask(replyTask.getId());
|
||||
}else{
|
||||
//判断主办是否已答复完
|
||||
// int masterActiveTaskCount = dao().count(BpmProcessTask.class, Cnd.where(BpmProcessTask::getPrevTaskId, "=", caseUnitTask.getId())
|
||||
// .and("JSON_EXTRACT(createVariable, '$.isMaster')", "=", task.getCreateVariable().getBool("isMaster") ? "true" : "false")
|
||||
// .and(BpmProcessTask::getTaskStatus, "=", BpmProcessTaskStatusEnum.ACTIVE.name())
|
||||
// .and(BpmProcessTask::getDelFlag, "=", 0)
|
||||
// );
|
||||
|
||||
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
COUNT(*)\s
|
||||
FROM
|
||||
bpm_process_task\s
|
||||
WHERE
|
||||
prevTaskId = @prevTaskId
|
||||
AND JSON_EXTRACT( createVariable, '$.isMaster' )= TRUE\s
|
||||
AND taskStatus = 'ACTIVE'\s
|
||||
AND processTaskNodeCode = 80\s
|
||||
AND delFlag =0
|
||||
""");
|
||||
sql.setParam("prevTaskId",caseUnitTask.getId());
|
||||
sql.setCallback(Sqls.callback.integer());
|
||||
execute(sql);
|
||||
int anInt = sql.getInt();
|
||||
|
||||
if(anInt == 0){
|
||||
throw new BaseException("主办单位已经答复完成,无法撤回,如需修改答复内容请联系校工会");
|
||||
}else{
|
||||
bpmService.revokeTask(replyTask.getId());
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* 同一批次承办单位答复任务未全部完成时,只完结当前任务,不触发流程流转。
|
||||
* 等最后一条 reply 任务提交时,再交给流程引擎继续往下走。
|
||||
*/
|
||||
private void executeSingleFlowTask(Dict args) {
|
||||
Long processTaskId = args.getLong(FlowConst.PROCESS_TASK_ID_KEY);
|
||||
ProcessTask currentTask = dao().fetch(ProcessTask.class, processTaskId);
|
||||
if (currentTask == null || !ProcessTaskStateEnum.DOING.getCode().equals(currentTask.getTaskState())) {
|
||||
throw new BaseException("没有进行中的流程任务");
|
||||
}
|
||||
|
||||
String operator = resolveFlowExecuteOperator(args);
|
||||
if (!processTaskService.isAllowed(currentTask, operator)) {
|
||||
throw new BaseException("当前参与者不能执行该流程任务");
|
||||
}
|
||||
|
||||
Dict executeArgs = buildFlowExecuteArgs(args);
|
||||
if (shouldOnlyFinishCurrentReplyTask(currentTask, executeArgs)) {
|
||||
/*
|
||||
* 主办单位可能先于协办单位提交,此时校领导候选人要先写入流程实例变量,
|
||||
* 这样最后一条 reply 任务触发流转时,下一节点仍能拿到主办单位选择的办理人。
|
||||
*/
|
||||
persistSharedReplyArgs(currentTask.getProcessInstanceId(), executeArgs);
|
||||
/*
|
||||
* 会签节点如果配置了完成条件,最后一条任务真正走引擎时仍会读取流程实例里的计数器。
|
||||
* 因此前面这些“只完结不流转”的任务,也要同步补齐会签统计,避免最后一条被误判退回。
|
||||
*/
|
||||
persistCountersignProgress(currentTask, executeArgs);
|
||||
processTaskService.finishProcessTask(currentTask.getId(), operator, executeArgs);
|
||||
return;
|
||||
}
|
||||
flowCommonService.executeTask(args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String checkCanReply(String taskId) {
|
||||
// 获取提案配置
|
||||
ProposalConfig config = dao().fetch(ProposalConfig.class, Cnd.NEW());
|
||||
// 如果不需要协办单位先答复,直接返回null
|
||||
if (!Boolean.TRUE.equals(config.getSlaveUnitFirstReply())) {
|
||||
return null;
|
||||
/**
|
||||
* 仅在“正常提交”场景下拦截流程继续往后流转。
|
||||
* 只要同一批次还有别的承办单位 reply 待办,就让当前任务先单独完结。
|
||||
*/
|
||||
private boolean shouldOnlyFinishCurrentReplyTask(ProcessTask currentTask, Dict executeArgs) {
|
||||
Integer submitType = executeArgs.getInt(FlowConst.SUBMIT_TYPE);
|
||||
if (!ProcessSubmitTypeEnum.AGREE.getCode().equals(submitType)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
BpmProcessTask task = dao().fetch(BpmProcessTask.class, taskId);
|
||||
// 如果不是主办单位,直接返回null
|
||||
if (!task.getCreateVariable().getBool("isMaster", false)) {
|
||||
return null;
|
||||
Long batchParentTaskId = resolveReplyBatchParentTaskId(currentTask, currentTask.getTaskName());
|
||||
if (batchParentTaskId == null || batchParentTaskId <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// 查询同一批次的其他活动任务
|
||||
List<BpmProcessTask> activeTasks = dao().query(BpmProcessTask.class,
|
||||
Cnd.where("prevTaskId", "=", task.getPrevTaskId())
|
||||
.and("id", "!=", task.getId())
|
||||
.and("taskStatus", "=", BpmProcessTaskStatusEnum.ACTIVE.name())
|
||||
.and("delFlag", "=", 0)
|
||||
List<ProcessTask> doingReplyTasks = dao().query(
|
||||
ProcessTask.class,
|
||||
Cnd.where("processInstanceId", "=", currentTask.getProcessInstanceId())
|
||||
.and("taskState", "=", ProcessTaskStateEnum.DOING.getCode())
|
||||
.and("taskName", "=", currentTask.getTaskName())
|
||||
);
|
||||
|
||||
// 如果还有未完成的协办任务,返回提示信息
|
||||
return activeTasks.isEmpty() ? null :
|
||||
activeTasks.stream()
|
||||
.map(t -> t.getCreateVariable().getStr("underTakeName"))
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.joining(",")) + "协办单位还未答复完成,暂时无法操作,您可以点击查看按钮关注协办单位办理进度。<br/> 如果您已经线下和协办单位交流沟通完成,请点击答复按钮进行答复。";
|
||||
return doingReplyTasks.stream()
|
||||
.filter(task -> !task.getId().equals(currentTask.getId()))
|
||||
.anyMatch(task -> batchParentTaskId.equals(resolveReplyBatchParentTaskId(task, currentTask.getTaskName())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void revokeTransfer(String taskId) {
|
||||
bpmService.revokeTask(taskId);
|
||||
/**
|
||||
* 转办会把新任务的 parentId 指向原 reply 任务,因此这里要一直向上追溯,
|
||||
* 找到本批次承办单位答复任务共同归属的上游节点ID,作为“同一批次”的判定依据。
|
||||
*/
|
||||
private Long resolveReplyBatchParentTaskId(ProcessTask task, String taskName) {
|
||||
Long batchParentTaskId = task.getTaskParentId();
|
||||
Long parentTaskId = task.getTaskParentId();
|
||||
while (parentTaskId != null && parentTaskId > 0) {
|
||||
ProcessTask parentTask = dao().fetch(ProcessTask.class, parentTaskId);
|
||||
if (parentTask == null || !taskName.equals(parentTask.getTaskName())) {
|
||||
break;
|
||||
}
|
||||
batchParentTaskId = parentTask.getTaskParentId();
|
||||
parentTaskId = parentTask.getTaskParentId();
|
||||
}
|
||||
return batchParentTaskId;
|
||||
}
|
||||
|
||||
/**
|
||||
* old-flow 的 executeTask 会补齐办理人信息并移除 processTaskId。
|
||||
* 前置完结当前任务时,也要保持同样的数据结构,避免任务变量格式不一致。
|
||||
*/
|
||||
private Dict buildFlowExecuteArgs(Dict args) {
|
||||
Dict executeArgs = args.clone();
|
||||
executeArgs.remove(FlowConst.PROCESS_TASK_ID_KEY);
|
||||
Integer submitType = executeArgs.getInt(FlowConst.SUBMIT_TYPE);
|
||||
if (submitType == null) {
|
||||
submitType = ProcessSubmitTypeEnum.AGREE.getCode();
|
||||
}
|
||||
executeArgs.put(FlowConst.SUBMIT_TYPE, submitType);
|
||||
executeArgs.put(FlowConst.TASK_FORM_DATA_PREFIX + "userName", SecurityUtil.getUserUsername());
|
||||
executeArgs.put(FlowConst.TASK_FORM_DATA_PREFIX + "loginName", SecurityUtil.getUserLoginname());
|
||||
executeArgs.put(FlowConst.TASK_FORM_DATA_PREFIX + "unitId", SecurityUtil.getUnitId());
|
||||
executeArgs.put(FlowConst.TASK_FORM_DATA_PREFIX + "unitName", SecurityUtil.getUnitId());
|
||||
executeArgs.put(FlowConst.TASK_FORM_DATA_PREFIX + "unionId", SecurityUtil.getUnionId());
|
||||
return executeArgs;
|
||||
}
|
||||
|
||||
/**
|
||||
* 承办单位答复环节真正往下流转时,下一节点可能依赖主办单位预先选择的候选人。
|
||||
* 这里只把跨任务共享所需的字段写入流程实例,避免把每个单位自己的答复内容互相覆盖。
|
||||
*/
|
||||
private void persistSharedReplyArgs(Long processInstanceId, Dict executeArgs) {
|
||||
Dict sharedArgs = Dict.create();
|
||||
if (StrUtil.isNotBlank(executeArgs.getStr(FlowConst.NEXT_NODE_OPERATOR))) {
|
||||
sharedArgs.put(FlowConst.NEXT_NODE_OPERATOR, executeArgs.getStr(FlowConst.NEXT_NODE_OPERATOR));
|
||||
}
|
||||
if (StrUtil.isNotBlank(executeArgs.getStr(FlowConst.TASK_FORM_DATA_PREFIX + "nextNodeOperatorName"))) {
|
||||
sharedArgs.put(FlowConst.TASK_FORM_DATA_PREFIX + "nextNodeOperatorName", executeArgs.getStr(FlowConst.TASK_FORM_DATA_PREFIX + "nextNodeOperatorName"));
|
||||
}
|
||||
if (!sharedArgs.isEmpty()) {
|
||||
processInstanceService.addVariable(processInstanceId, sharedArgs);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 前面的 reply 任务虽然不触发节点流转,但依然属于会签实例的一部分。
|
||||
* 这里补齐流程实例上的会签计数,保证最后一条任务进入引擎时,计数与真实完结数一致。
|
||||
*/
|
||||
private void persistCountersignProgress(ProcessTask currentTask, Dict executeArgs) {
|
||||
if (!ProcessTaskPerformTypeEnum.COUNTERSIGN.getCode().equals(currentTask.getPerformType())) {
|
||||
return;
|
||||
}
|
||||
|
||||
String prefix = FlowConst.COUNTERSIGN_VARIABLE_PREFIX + currentTask.getTaskName() + "_";
|
||||
List<ProcessTask> doingSameNameTasks = dao().query(
|
||||
ProcessTask.class,
|
||||
Cnd.where("processInstanceId", "=", currentTask.getProcessInstanceId())
|
||||
.and("taskState", "=", ProcessTaskStateEnum.DOING.getCode())
|
||||
.and("taskName", "=", currentTask.getTaskName())
|
||||
);
|
||||
Dict addVariable = Dict.create();
|
||||
addVariable.put(prefix + FlowConst.NR_OF_COMPLETED_INSTANCES,
|
||||
getProcessInstanceIntValue(currentTask.getProcessInstanceId(), prefix + FlowConst.NR_OF_COMPLETED_INSTANCES) + 1);
|
||||
if (!executeArgs.containsKey(FlowConst.COUNTERSIGN_DISAGREE_FLAG)) {
|
||||
addVariable.put(prefix + FlowConst.NR_OF_COMPLETED_AGREE_INSTANCES,
|
||||
getProcessInstanceIntValue(currentTask.getProcessInstanceId(), prefix + FlowConst.NR_OF_COMPLETED_AGREE_INSTANCES) + 1);
|
||||
}
|
||||
addVariable.put(prefix + FlowConst.NR_OF_ACTIVATE_INSTANCES,
|
||||
Math.max(doingSameNameTasks.size() - 1, 0));
|
||||
processInstanceService.addVariable(currentTask.getProcessInstanceId(), addVariable);
|
||||
}
|
||||
|
||||
/**
|
||||
* old-flow 会签计数统一保存在流程实例变量里,这里读取当前值并转成整型,便于补写增量。
|
||||
*/
|
||||
private int getProcessInstanceIntValue(Long processInstanceId, String key) {
|
||||
ProcessInstance processInstance = processInstanceService.getById(processInstanceId);
|
||||
if (processInstance == null || StrUtil.isBlank(processInstance.getVariable())) {
|
||||
return 0;
|
||||
}
|
||||
Dict variable = cn.hutool.json.JSONUtil.toBean(processInstance.getVariable(), Dict.class);
|
||||
/*
|
||||
* 当前项目使用的 Hutool Dict 不支持 getInt(key, defaultValue) 这种重载。
|
||||
* 会签计数键在首次提交前可能还没写入流程实例变量,这里需要先显式判空,
|
||||
* 避免 Integer 为 null 时自动拆箱触发空指针。
|
||||
*/
|
||||
Integer value = variable.getInt(key);
|
||||
return value == null ? 0 : value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 与 old-flow 公共执行逻辑保持一致,支持开启扩展执行人时以管理员身份提交。
|
||||
*/
|
||||
private String resolveFlowExecuteOperator(Dict args) {
|
||||
String operator = SecurityUtil.getUserId();
|
||||
if (args.containsKey(FlowConst.EXT_ENABLE_OPERATOR) && args.getBool(FlowConst.EXT_ENABLE_OPERATOR)) {
|
||||
operator = FlowConst.ADMIN_ID;
|
||||
}
|
||||
return operator;
|
||||
}
|
||||
|
||||
/**
|
||||
* “编辑答复内容”只能针对已经完成的承办单位答复任务。
|
||||
* 这里统一校验任务存在性、节点范围和任务状态,避免页面把其他流程节点误传进来。
|
||||
*/
|
||||
private ProcessTask getEditableReplyTask(Long taskId) {
|
||||
ProcessTask replyTask = dao().fetch(ProcessTask.class, taskId);
|
||||
if (replyTask == null) {
|
||||
throw new BaseException("未找到答复任务");
|
||||
}
|
||||
if (!List.of("unit_reply", "two_unit_reply", "opinion_master_reply").contains(replyTask.getTaskName())) {
|
||||
throw new BaseException("当前任务不支持编辑答复内容");
|
||||
}
|
||||
if (!Objects.equals(ProcessTaskStateEnum.FINISHED.getCode(), replyTask.getTaskState())) {
|
||||
throw new BaseException("只有已完成的答复任务才能编辑内容");
|
||||
}
|
||||
return replyTask;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user