Merge remote-tracking branch 'origin/main'
This commit is contained in:
@@ -134,6 +134,15 @@ public interface ProcessTaskService extends BaseService<ProcessTask> {
|
|||||||
*/
|
*/
|
||||||
void removeTaskActor(Long processTaskId, List<String> actors);
|
void removeTaskActor(Long processTaskId, List<String> actors);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按最新办理人配置覆盖同步指定流程任务的参与者。
|
||||||
|
*
|
||||||
|
* @param processTaskId 流程任务id
|
||||||
|
* @param actors 最新办理人用户id集合;为空时不处理,避免误清空任务办理人
|
||||||
|
* @return 新增和移除的参与者数量合计
|
||||||
|
*/
|
||||||
|
int syncTaskActors(Long processTaskId, List<String> actors);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据taskId、operator,判断操作人operator是否允许执行任务
|
* 根据taskId、operator,判断操作人operator是否允许执行任务
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -279,6 +279,31 @@ public class ProcessTaskServiceImpl extends BaseServiceImpl<ProcessTask> impleme
|
|||||||
dao().clear(ProcessTaskActor.class, Cnd.where(ProcessTaskActor::getProcessTaskId, "=", processTaskId).and(ProcessTaskActor::getActorId, "in", actors));
|
dao().clear(ProcessTaskActor.class, Cnd.where(ProcessTaskActor::getProcessTaskId, "=", processTaskId).and(ProcessTaskActor::getActorId, "in", actors));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Aop(TransAop.READ_COMMITTED)
|
||||||
|
public int syncTaskActors(Long processTaskId, List<String> actors) {
|
||||||
|
if (CollectionUtil.isEmpty(actors)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
List<String> latestActors = actors.stream().filter(StrUtil::isNotBlank).distinct().toList();
|
||||||
|
if (CollectionUtil.isEmpty(latestActors)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 以最新负责人配置为准:缺失的办理人补上,不再是负责人的办理人移除。
|
||||||
|
List<String> dbActors = getTaskActors(processTaskId);
|
||||||
|
List<String> addActors = latestActors.stream().filter(actor -> !dbActors.contains(actor)).toList();
|
||||||
|
List<String> removeActors = dbActors.stream().filter(actor -> !latestActors.contains(actor)).toList();
|
||||||
|
|
||||||
|
if (CollectionUtil.isNotEmpty(removeActors)) {
|
||||||
|
removeTaskActor(processTaskId, removeActors);
|
||||||
|
}
|
||||||
|
if (CollectionUtil.isNotEmpty(addActors)) {
|
||||||
|
addTaskActor(processTaskId, addActors);
|
||||||
|
}
|
||||||
|
return addActors.size() + removeActors.size();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isAllowed(ProcessTask task, String operator) {
|
public boolean isAllowed(ProcessTask task, String operator) {
|
||||||
// 执行者为超级管理员或自动执行用户
|
// 执行者为超级管理员或自动执行用户
|
||||||
|
|||||||
+166
-2
@@ -13,6 +13,8 @@ import com.budwk.app.base.page.Pagination;
|
|||||||
import com.budwk.app.base.param.PageForm;
|
import com.budwk.app.base.param.PageForm;
|
||||||
import com.budwk.app.base.result.Result;
|
import com.budwk.app.base.result.Result;
|
||||||
import com.budwk.app.base.service.BaseService;
|
import com.budwk.app.base.service.BaseService;
|
||||||
|
import com.budwk.app.flow.enums.ProcessTaskStateEnum;
|
||||||
|
import com.budwk.app.flow.service.ProcessTaskService;
|
||||||
import com.budwk.app.sys.models.Sys_role;
|
import com.budwk.app.sys.models.Sys_role;
|
||||||
import com.budwk.app.sys.models.Sys_unit;
|
import com.budwk.app.sys.models.Sys_unit;
|
||||||
import com.budwk.app.sys.models.Sys_user_role;
|
import com.budwk.app.sys.models.Sys_user_role;
|
||||||
@@ -57,6 +59,8 @@ public class ProposalConfigUnitController {
|
|||||||
private BaseService baseService;
|
private BaseService baseService;
|
||||||
@Inject
|
@Inject
|
||||||
private SysRoleService sysRoleService;
|
private SysRoleService sysRoleService;
|
||||||
|
@Inject
|
||||||
|
private ProcessTaskService processTaskService;
|
||||||
|
|
||||||
@At("")
|
@At("")
|
||||||
@Ok("beetl:/platform/zhgh/democratic/proposal/config/unit/index.html")
|
@Ok("beetl:/platform/zhgh/democratic/proposal/config/unit/index.html")
|
||||||
@@ -80,8 +84,8 @@ public class ProposalConfigUnitController {
|
|||||||
Sql sql = Sqls.create("""
|
Sql sql = Sqls.create("""
|
||||||
SELECT
|
SELECT
|
||||||
t1.*,
|
t1.*,
|
||||||
u1.username AS branchSchoolLeader,
|
GROUP_CONCAT(DISTINCT u1.username ORDER BY u1.username SEPARATOR '、') AS branchSchoolLeader,
|
||||||
u2.username AS unitLeader
|
GROUP_CONCAT(DISTINCT u2.username ORDER BY u2.username SEPARATOR '、') AS unitLeader
|
||||||
FROM
|
FROM
|
||||||
proposal_undertake t1
|
proposal_undertake t1
|
||||||
LEFT JOIN sys_user_role sur1 ON sur1.underTakeId = t1.id
|
LEFT JOIN sys_user_role sur1 ON sur1.underTakeId = t1.id
|
||||||
@@ -103,6 +107,7 @@ public class ProposalConfigUnitController {
|
|||||||
cnd.where().orLike("t1.name", pageForm.getSearchKeyword());
|
cnd.where().orLike("t1.name", pageForm.getSearchKeyword());
|
||||||
}
|
}
|
||||||
cnd.and("t1.enable","=", true);
|
cnd.and("t1.enable","=", true);
|
||||||
|
cnd.groupBy("t1.id");
|
||||||
cnd.asc("t1.code");
|
cnd.asc("t1.code");
|
||||||
sql.setCondition(cnd);
|
sql.setCondition(cnd);
|
||||||
Pagination pagination = baseService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
Pagination pagination = baseService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
||||||
@@ -146,6 +151,165 @@ public class ProposalConfigUnitController {
|
|||||||
return Result.success();
|
return Result.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 同步当前进行中的承办单位答复任务办理人。
|
||||||
|
*
|
||||||
|
* 按承办单位当前配置的单位负责人覆盖同步 wf_process_task_actor:
|
||||||
|
* 1. 参数:无参数,系统自动扫描所有启用承办单位。
|
||||||
|
* 2. 单位负责人来源:PROPOSAL_UNIT_LEADER 角色且 underTakeId 等于承办单位id。
|
||||||
|
* 3. 同步范围:当前进行中的主办答复、协办答复、意见主办答复任务。
|
||||||
|
* 4. 返回值:Result,msg 中说明同步任务数、办理人变更数、未配置负责人单位数。
|
||||||
|
*/
|
||||||
|
@At
|
||||||
|
@SaCheckPermission("proposal.config.unit")
|
||||||
|
@SLog(tag = "提案", msg = "同步承办单位答复人")
|
||||||
|
@Aop(TransAop.READ_COMMITTED)
|
||||||
|
public Result syncUnitReplyActors() {
|
||||||
|
Sys_role sysRole = sysRoleService.getByCode(RoleConstant.PROPOSAL_UNIT_LEADER);
|
||||||
|
List<ProposalUndertake> undertakes = dao.query(ProposalUndertake.class, Cnd.where(ProposalUndertake::getEnable, "=", true));
|
||||||
|
int scanTaskCount = 0;
|
||||||
|
int syncTaskCount = 0;
|
||||||
|
int syncActorCount = 0;
|
||||||
|
int skipUnitCount = 0;
|
||||||
|
|
||||||
|
Map<String, List<String>> unitLeaderMap = undertakes.stream().collect(Collectors.toMap(ProposalUndertake::getId, undertake -> {
|
||||||
|
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()));
|
||||||
|
return sysUserRoles.stream().map(Sys_user_role::getUserId).filter(StrUtil::isNotBlank).distinct().toList();
|
||||||
|
}));
|
||||||
|
for (ProposalUndertake undertake : undertakes) {
|
||||||
|
if (CollectionUtil.isEmpty(unitLeaderMap.get(undertake.getId()))) {
|
||||||
|
skipUnitCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<NutMap> taskTargets = queryDoingUnitReplyTaskTargets();
|
||||||
|
scanTaskCount = taskTargets.size();
|
||||||
|
for (NutMap taskTarget : taskTargets) {
|
||||||
|
List<String> userIds = unitLeaderMap.get(taskTarget.getString("unitId"));
|
||||||
|
if (CollectionUtil.isNotEmpty(userIds)) {
|
||||||
|
int syncCount = processTaskService.syncTaskActors(taskTarget.getLong("taskId"), userIds);
|
||||||
|
if (syncCount > 0) {
|
||||||
|
syncTaskCount++;
|
||||||
|
syncActorCount += syncCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.success("同步完成,扫描任务" + scanTaskCount + "个,更新任务" + syncTaskCount + "个,办理人变更" + syncActorCount + "人次,跳过未配置负责人单位" + skipUnitCount + "个。");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据提案承办单位记录计算正在办理中的答复任务与承办单位对应关系。
|
||||||
|
*
|
||||||
|
* 说明:
|
||||||
|
* 1. 无入参,自动扫描当前进行中的主办答复、协办答复、意见主办答复任务。
|
||||||
|
* 2. 返回值为 List<NutMap>,每行包含 taskId 和 unitId,表示该任务应按哪个承办单位负责人同步办理人。
|
||||||
|
* 3. 优先使用 task.variable.underTakeId,其次使用现有 actorUnitId 与 proposal_reply_unit.unitId 的匹配关系。
|
||||||
|
* 4. 对历史缺少 underTakeId 且 actorUnitId 不匹配承办单位的数据,只在“剩余任务数”和“剩余承办单位数”能一一对应时按顺序补位,避免多个协办单位互相覆盖。
|
||||||
|
*/
|
||||||
|
private List<NutMap> queryDoingUnitReplyTaskTargets() {
|
||||||
|
Sql sql = Sqls.create("""
|
||||||
|
WITH direct_targets AS (
|
||||||
|
SELECT DISTINCT
|
||||||
|
ins.businessNo AS proposalId,
|
||||||
|
t.id AS taskId,
|
||||||
|
IF(t.taskName IN ('master_reply', 'opinion_master_reply'), 1, 0) AS isMaster,
|
||||||
|
pru.unitId AS unitId
|
||||||
|
FROM
|
||||||
|
wf_process_task t
|
||||||
|
INNER JOIN wf_process_instance ins ON ins.id = t.processInstanceId
|
||||||
|
INNER JOIN proposal_reply_unit pru ON pru.proposalId = ins.businessNo
|
||||||
|
AND (
|
||||||
|
(t.taskName IN ('master_reply', 'opinion_master_reply') AND pru.isMaster = 1)
|
||||||
|
OR (t.taskName = 'slave_reply' AND pru.isMaster = 0)
|
||||||
|
)
|
||||||
|
LEFT JOIN wf_process_task_actor ta ON ta.processTaskId = t.id
|
||||||
|
WHERE
|
||||||
|
t.taskState = @taskState
|
||||||
|
AND t.taskName IN ('master_reply', 'slave_reply', 'opinion_master_reply')
|
||||||
|
AND (
|
||||||
|
JSON_UNQUOTE(JSON_EXTRACT(t.variable, '$.underTakeId')) = pru.unitId
|
||||||
|
OR (
|
||||||
|
IFNULL(JSON_UNQUOTE(JSON_EXTRACT(t.variable, '$.underTakeId')), '') = ''
|
||||||
|
AND ta.actorUnitId = pru.unitId
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
remain_units AS (
|
||||||
|
SELECT
|
||||||
|
pru.proposalId,
|
||||||
|
pru.unitId,
|
||||||
|
pru.unitName,
|
||||||
|
pru.isMaster,
|
||||||
|
ROW_NUMBER() OVER(PARTITION BY pru.proposalId, pru.isMaster ORDER BY pru.unitName, pru.unitId) AS rn,
|
||||||
|
COUNT(*) OVER(PARTITION BY pru.proposalId, pru.isMaster) AS unitCount
|
||||||
|
FROM
|
||||||
|
proposal_reply_unit pru
|
||||||
|
WHERE
|
||||||
|
EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM wf_process_instance ins
|
||||||
|
INNER JOIN wf_process_task t ON t.processInstanceId = ins.id
|
||||||
|
WHERE ins.businessNo = pru.proposalId
|
||||||
|
AND t.taskState = @taskState
|
||||||
|
AND (
|
||||||
|
(t.taskName IN ('master_reply', 'opinion_master_reply') AND pru.isMaster = 1)
|
||||||
|
OR (t.taskName = 'slave_reply' AND pru.isMaster = 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
AND NOT EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM direct_targets dt
|
||||||
|
WHERE dt.proposalId = pru.proposalId
|
||||||
|
AND dt.unitId = pru.unitId
|
||||||
|
)
|
||||||
|
),
|
||||||
|
remain_tasks AS (
|
||||||
|
SELECT
|
||||||
|
ins.businessNo AS proposalId,
|
||||||
|
t.id AS taskId,
|
||||||
|
IF(t.taskName IN ('master_reply', 'opinion_master_reply'), 1, 0) AS isMaster,
|
||||||
|
ROW_NUMBER() OVER(
|
||||||
|
PARTITION BY ins.businessNo, IF(t.taskName IN ('master_reply', 'opinion_master_reply'), 1, 0)
|
||||||
|
ORDER BY t.id
|
||||||
|
) AS rn,
|
||||||
|
COUNT(*) OVER(
|
||||||
|
PARTITION BY ins.businessNo, IF(t.taskName IN ('master_reply', 'opinion_master_reply'), 1, 0)
|
||||||
|
) AS taskCount
|
||||||
|
FROM
|
||||||
|
wf_process_task t
|
||||||
|
INNER JOIN wf_process_instance ins ON ins.id = t.processInstanceId
|
||||||
|
WHERE
|
||||||
|
t.taskState = @taskState
|
||||||
|
AND t.taskName IN ('master_reply', 'slave_reply', 'opinion_master_reply')
|
||||||
|
AND IFNULL(JSON_UNQUOTE(JSON_EXTRACT(t.variable, '$.underTakeId')), '') = ''
|
||||||
|
AND NOT EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM direct_targets dt
|
||||||
|
WHERE dt.taskId = t.id
|
||||||
|
)
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
taskId,
|
||||||
|
unitId
|
||||||
|
FROM
|
||||||
|
direct_targets
|
||||||
|
UNION
|
||||||
|
SELECT
|
||||||
|
rt.taskId,
|
||||||
|
ru.unitId
|
||||||
|
FROM
|
||||||
|
remain_tasks rt
|
||||||
|
INNER JOIN remain_units ru ON ru.proposalId = rt.proposalId
|
||||||
|
AND ru.isMaster = rt.isMaster
|
||||||
|
AND ru.rn = rt.rn
|
||||||
|
AND ru.unitCount = rt.taskCount
|
||||||
|
""");
|
||||||
|
sql.setParam("taskState", ProcessTaskStateEnum.DOING.getCode());
|
||||||
|
return baseService.listMap(sql);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置分管校领导
|
* 设置分管校领导
|
||||||
*
|
*
|
||||||
|
|||||||
+45
@@ -1,13 +1,18 @@
|
|||||||
package com.budwk.app.zhgh.democratic.proposal.controller.query;
|
package com.budwk.app.zhgh.democratic.proposal.controller.query;
|
||||||
|
|
||||||
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||||
|
import com.budwk.app.base.page.Pagination;
|
||||||
import com.budwk.app.base.result.Result;
|
import com.budwk.app.base.result.Result;
|
||||||
import com.budwk.app.flow.engine.util.FlowUtil;
|
import com.budwk.app.flow.engine.util.FlowUtil;
|
||||||
import com.budwk.app.flow.entity.ProcessTask;
|
import com.budwk.app.flow.entity.ProcessTask;
|
||||||
import com.budwk.app.flow.enums.ProcessTaskStateEnum;
|
import com.budwk.app.flow.enums.ProcessTaskStateEnum;
|
||||||
|
import com.budwk.app.zhgh.democratic.proposal.controller.vo.ProposalUnitReplyProposalVO;
|
||||||
import com.budwk.app.zhgh.democratic.proposal.models.ProposalConfig;
|
import com.budwk.app.zhgh.democratic.proposal.models.ProposalConfig;
|
||||||
import com.budwk.app.zhgh.democratic.proposal.models.ProposalReplyUnit;
|
import com.budwk.app.zhgh.democratic.proposal.models.ProposalReplyUnit;
|
||||||
|
import com.budwk.app.zhgh.democratic.proposal.param.ProposalSearchParam;
|
||||||
import com.budwk.app.zhgh.democratic.proposal.service.common.ProposalCommonService;
|
import com.budwk.app.zhgh.democratic.proposal.service.common.ProposalCommonService;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.nutz.dao.Cnd;
|
import org.nutz.dao.Cnd;
|
||||||
import org.nutz.dao.Dao;
|
import org.nutz.dao.Dao;
|
||||||
@@ -19,6 +24,7 @@ import org.nutz.lang.util.NutMap;
|
|||||||
import org.nutz.mvc.annotation.At;
|
import org.nutz.mvc.annotation.At;
|
||||||
import org.nutz.mvc.annotation.Ok;
|
import org.nutz.mvc.annotation.Ok;
|
||||||
|
|
||||||
|
import javax.validation.Valid;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@@ -131,4 +137,43 @@ public class ProposalQueryUnitReplyController {
|
|||||||
|
|
||||||
return Result.success().addData(Map.of("tableData", tableData, "slaveNeedReply", slaveNeedReply));
|
return Result.success().addData(Map.of("tableData", tableData, "slaveNeedReply", slaveNeedReply));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@At
|
||||||
|
@SaCheckPermission("proposal.query.unitReply")
|
||||||
|
@ApiOperation("承办单位提案明细")
|
||||||
|
public Result getProposalsByUnit(@Valid ProposalSearchParam pageForm, String unitCode) {
|
||||||
|
Sql sql = Sqls.create("""
|
||||||
|
SELECT
|
||||||
|
info.id,
|
||||||
|
info.code,
|
||||||
|
info.name,
|
||||||
|
info.createUserName,
|
||||||
|
type.name AS typeName,
|
||||||
|
tcs.fullName AS sessionName,
|
||||||
|
tcd.`name` AS delegationName,
|
||||||
|
pru.unitName AS underTakeUnitName,
|
||||||
|
IF(pru.isMaster = 1, '主办', '协办') AS underTakeType,
|
||||||
|
IFNULL(GROUP_CONCAT(DISTINCT t.displayName), '结束') AS curTaskName
|
||||||
|
FROM
|
||||||
|
proposal_reply_unit pru
|
||||||
|
INNER JOIN proposal_info info ON info.id = pru.proposalId
|
||||||
|
LEFT JOIN proposal_type type on type.id = info.typeId
|
||||||
|
LEFT JOIN teacher_congress_session tcs on tcs.id = info.sessionId
|
||||||
|
LEFT JOIN teacher_congress_delegation tcd on tcd.id = info.delegationId
|
||||||
|
LEFT JOIN wf_process_instance ins ON ins.businessNo = info.id
|
||||||
|
LEFT JOIN wf_process_task t ON t.processInstanceId = ins.id AND t.taskState = 10
|
||||||
|
$condition
|
||||||
|
""");
|
||||||
|
Cnd cnd = Cnd.NEW();
|
||||||
|
// 明细弹窗按当前届次和点击的承办单位编码查询,返回该单位主办、协办的提案列表。
|
||||||
|
cnd.andEX("pru.unitCode", "=", unitCode);
|
||||||
|
ProposalSearchParam.buildSearch(cnd, pageForm);
|
||||||
|
cnd.groupBy("info.id", "pru.unitName", "pru.isMaster");
|
||||||
|
sql.setCondition(cnd);
|
||||||
|
|
||||||
|
Pagination pagination = proposalCommonService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
||||||
|
List<ProposalUnitReplyProposalVO> list = BeanUtil.copyToList(pagination.getList(), ProposalUnitReplyProposalVO.class);
|
||||||
|
pagination.setList(list);
|
||||||
|
return Result.success(pagination);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+55
-10
@@ -98,27 +98,60 @@ public class ProposalUnderTakeReplyController {
|
|||||||
t.finishTime,
|
t.finishTime,
|
||||||
t.taskParentId,
|
t.taskParentId,
|
||||||
t.variable taskVariable,
|
t.variable taskVariable,
|
||||||
IFNULL(GROUP_CONCAT(DISTINCT nt.displayName),'结束') curTaskName,
|
IFNULL((
|
||||||
IFNULL(GROUP_CONCAT(DISTINCT nt.taskName),'结束') curTaskKey,
|
SELECT GROUP_CONCAT(DISTINCT nt.displayName)
|
||||||
CASE WHEN t.taskState = 20 AND ( rt.id IS NULL OR rt.taskState = 10 ) THEN 1 ELSE 0 END AS canRevoke,
|
FROM wf_process_task nt
|
||||||
t.variable->>'$.underTakeName' AS underTakeName,
|
WHERE nt.processInstanceId = ins.id AND nt.taskState = 10
|
||||||
IF(JSON_EXTRACT(t.variable, '$.underTakeIsMaster') = true, 1, 0) AS underTakeIsMaster,
|
), '结束') curTaskName,
|
||||||
|
IFNULL((
|
||||||
|
SELECT GROUP_CONCAT(DISTINCT nt.taskName)
|
||||||
|
FROM wf_process_task nt
|
||||||
|
WHERE nt.processInstanceId = ins.id AND nt.taskState = 10
|
||||||
|
), '结束') curTaskKey,
|
||||||
|
CASE WHEN t.taskState = 20 AND (
|
||||||
|
NOT EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM wf_process_task rt
|
||||||
|
WHERE rt.processInstanceId = ins.id AND rt.taskParentId = t.id
|
||||||
|
)
|
||||||
|
OR EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM wf_process_task rt
|
||||||
|
WHERE rt.processInstanceId = ins.id AND rt.taskParentId = t.id AND rt.taskState = 10
|
||||||
|
)
|
||||||
|
) THEN 1 ELSE 0 END AS canRevoke,
|
||||||
|
IFNULL(pru.unitName, t.variable->>'$.underTakeName') AS underTakeName,
|
||||||
|
IFNULL(pru.isMaster, IF(JSON_EXTRACT(t.variable, '$.underTakeIsMaster') = true, 1, 0)) AS underTakeIsMaster,
|
||||||
t.variable->>'$.tf_transferUserId' AS tf_transferUserId,
|
t.variable->>'$.tf_transferUserId' AS tf_transferUserId,
|
||||||
transferUser.username AS transferUserName
|
transferUser.username AS transferUserName
|
||||||
FROM
|
FROM
|
||||||
wf_process_task t
|
wf_process_task t
|
||||||
LEFT JOIN wf_process_instance ins ON ins.id = t.processInstanceId
|
LEFT JOIN wf_process_instance ins ON ins.id = t.processInstanceId
|
||||||
LEFT JOIN wf_process_task_actor ta ON ta.processTaskId = t.id
|
LEFT JOIN wf_process_task_actor ta ON ta.processTaskId = t.id
|
||||||
LEFT JOIN wf_process_task nt ON nt.processInstanceId = ins.id AND nt.taskState = 10
|
|
||||||
LEFT JOIN wf_process_task rt ON rt.processInstanceId = ins.id AND rt.taskParentId = t.id
|
|
||||||
LEFT JOIN proposal_info info ON info.id = ins.businessNo
|
LEFT JOIN proposal_info info ON info.id = ins.businessNo
|
||||||
LEFT JOIN proposal_type type on type.id = info.typeId
|
LEFT JOIN proposal_type type on type.id = info.typeId
|
||||||
LEFT JOIN proposal_merge mer ON mer.proposalId = info.id
|
LEFT JOIN proposal_merge mer ON mer.proposalId = info.id
|
||||||
|
LEFT JOIN proposal_reply_unit pru ON pru.proposalId = ins.businessNo
|
||||||
|
AND pru.unitId = IFNULL(t.variable->>'$.underTakeId', ta.actorUnitId)
|
||||||
|
AND (
|
||||||
|
(t.taskName IN ('master_reply', 'opinion_master_reply') AND pru.isMaster = 1)
|
||||||
|
OR (t.taskName = 'slave_reply' AND pru.isMaster = 0)
|
||||||
|
)
|
||||||
LEFT JOIN teacher_congress_session tcs on tcs.id = info.sessionId
|
LEFT JOIN teacher_congress_session tcs on tcs.id = info.sessionId
|
||||||
LEFT JOIN teacher_congress_delegation tcd on tcd.id = info.delegationId
|
LEFT JOIN teacher_congress_delegation tcd on tcd.id = info.delegationId
|
||||||
LEFT JOIN sys_user transferUser on transferUser.id = t.variable->>'$.tf_transferUserId'
|
LEFT JOIN sys_user transferUser on transferUser.id = t.variable->>'$.tf_transferUserId'
|
||||||
$condition
|
$condition
|
||||||
""");
|
""");
|
||||||
|
// 分页统计只保留任务、办理人和提案查询所需关联,避免完整列表 SQL 的聚合字段参与 count。
|
||||||
|
Sql countSql = Sqls.create("""
|
||||||
|
SELECT COUNT(DISTINCT t.id)
|
||||||
|
FROM
|
||||||
|
wf_process_task t
|
||||||
|
LEFT JOIN wf_process_instance ins ON ins.id = t.processInstanceId
|
||||||
|
LEFT JOIN wf_process_task_actor ta ON ta.processTaskId = t.id
|
||||||
|
LEFT JOIN proposal_info info ON info.id = ins.businessNo
|
||||||
|
$condition
|
||||||
|
""");
|
||||||
Cnd cnd = Cnd.NEW();
|
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"));
|
||||||
|
|
||||||
@@ -132,14 +165,26 @@ public class ProposalUnderTakeReplyController {
|
|||||||
cnd.and("t.taskState", "=", ProcessTaskStateEnum.DOING.getCode());
|
cnd.and("t.taskState", "=", ProcessTaskStateEnum.DOING.getCode());
|
||||||
}
|
}
|
||||||
ProposalSearchParam.buildSearch(cnd, pageForm);
|
ProposalSearchParam.buildSearch(cnd, pageForm);
|
||||||
cnd.groupBy("t.id");
|
cnd.groupBy("t.id", "pru.unitId", "pru.unitName", "pru.isMaster");
|
||||||
cnd.desc("t.createdAt");
|
cnd.desc("t.createdAt");
|
||||||
sql.setCondition(cnd);
|
sql.setCondition(cnd);
|
||||||
Pagination pagination = proposalCommonService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
Cnd countCnd = Cnd.NEW();
|
||||||
|
countCnd.and("t.taskName", "in", List.of("master_reply", "slave_reply", "opinion_master_reply"));
|
||||||
|
if (!AuthUtil.hasRole(RoleConstant.SYSADMIN.name())) {
|
||||||
|
countCnd.and("ta.actorId", "in", List.of(SecurityUtil.getUserId()));
|
||||||
|
}
|
||||||
|
if (approval) {
|
||||||
|
countCnd.and("t.taskState", "in", List.of(ProcessTaskStateEnum.FINISHED.getCode(), ProcessTaskStateEnum.TRANSFER.getCode()));
|
||||||
|
} else {
|
||||||
|
countCnd.and("t.taskState", "=", ProcessTaskStateEnum.DOING.getCode());
|
||||||
|
}
|
||||||
|
ProposalSearchParam.buildSearch(countCnd, pageForm);
|
||||||
|
countSql.setCondition(countCnd);
|
||||||
|
Pagination pagination = proposalCommonService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql, countSql);
|
||||||
|
|
||||||
List<NutMap> list = pagination.getList();
|
List<NutMap> list = pagination.getList();
|
||||||
for (NutMap row : list) {
|
for (NutMap row : list) {
|
||||||
if (row.getInt("taskIsMaster") == 1) {
|
if (row.getInt("underTakeIsMaster") == 1) {
|
||||||
boolean b = Stream.of("master_reply", "slave_reply", "school_leader")
|
boolean b = Stream.of("master_reply", "slave_reply", "school_leader")
|
||||||
.anyMatch(a -> row.getString("curTaskKey").contains(a));
|
.anyMatch(a -> row.getString("curTaskKey").contains(a));
|
||||||
row.setv("canRevoke", b && row.getInt("taskState") == ProcessTaskStateEnum.FINISHED.getCode());
|
row.setv("canRevoke", b && row.getInt("taskState") == ProcessTaskStateEnum.FINISHED.getCode());
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ layout("/layouts/platform.html"){
|
|||||||
<el-card shadow="never" style="border: 1px solid var(--border-color-lighter);flex: 1;" :body-style="{ height: '100%', display: 'flex' , 'flex-direction': 'column' }">
|
<el-card shadow="never" style="border: 1px solid var(--border-color-lighter);flex: 1;" :body-style="{ height: '100%', display: 'flex' , 'flex-direction': 'column' }">
|
||||||
<table-tool>
|
<table-tool>
|
||||||
<el-button type="primary" size="small" icon="el-icon-refresh" @click="syncSysUnit">同步系统单位</el-button>
|
<el-button type="primary" size="small" icon="el-icon-refresh" @click="syncSysUnit">同步系统单位</el-button>
|
||||||
|
<el-button type="primary" size="small" icon="el-icon-refresh" :loading="syncUnitReplyActorsLoading" @click="syncUnitReplyActors">同步承办单位答复人</el-button>
|
||||||
</table-tool>
|
</table-tool>
|
||||||
<el-table :data="tableData" border ref="tableRef" height="100%">
|
<el-table :data="tableData" border ref="tableRef" height="100%">
|
||||||
<el-table-column label="序号" type="index" :index="indexMethod" width="60"></el-table-column>
|
<el-table-column label="序号" type="index" :index="indexMethod" width="60"></el-table-column>
|
||||||
@@ -69,7 +70,8 @@ layout("/layouts/platform.html"){
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
currentTreeNode: null,
|
currentTreeNode: null,
|
||||||
currentTreeData: null
|
currentTreeData: null,
|
||||||
|
syncUnitReplyActorsLoading: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@@ -85,6 +87,23 @@ layout("/layouts/platform.html"){
|
|||||||
this.$refs.treeRef.listTree()
|
this.$refs.treeRef.listTree()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
syncUnitReplyActors() {
|
||||||
|
this.$confirm("确定要按当前单位领导配置同步进行中的承办单位答复待办吗?", "提示", {
|
||||||
|
type: "warning"
|
||||||
|
}).then(() => {
|
||||||
|
this.syncUnitReplyActorsLoading = true
|
||||||
|
this.$axios.post(loc() + "/syncUnitReplyActors")
|
||||||
|
.then((res) => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
this.$message.success(res.msg)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.syncUnitReplyActorsLoading = false
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
|
|||||||
+86
-2
@@ -21,7 +21,11 @@ layout("/layouts/platform.html"){
|
|||||||
<el-card shadow="never">
|
<el-card shadow="never">
|
||||||
<el-table :data="tableData">
|
<el-table :data="tableData">
|
||||||
<el-table-column label="序号" type="index" width="50"></el-table-column>
|
<el-table-column label="序号" type="index" width="50"></el-table-column>
|
||||||
<el-table-column label="单位名称" prop="unitName" width="400" sortable show-overflow-tooltip></el-table-column>
|
<el-table-column label="单位名称" prop="unitName" width="400" sortable show-overflow-tooltip>
|
||||||
|
<template slot-scope="{row}">
|
||||||
|
<el-link type="primary" @click="openUnitProposals(row)">{{row.unitName}}</el-link>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column label="提案总数" prop="sum" sortable></el-table-column>
|
<el-table-column label="提案总数" prop="sum" sortable></el-table-column>
|
||||||
<el-table-column label="主办提案">
|
<el-table-column label="主办提案">
|
||||||
<el-table-column label="提案数量" prop="masterSum" sortable></el-table-column>
|
<el-table-column label="提案数量" prop="masterSum" sortable></el-table-column>
|
||||||
@@ -35,6 +39,40 @@ layout("/layouts/platform.html"){
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
|
<el-dialog :title="detailDialogTitle" :visible.sync="detailDialogVisible" width="80%" :close-on-click-modal="false">
|
||||||
|
<el-table :data="detailTableData" v-loading="detailLoading" row-key="id">
|
||||||
|
<el-table-column label="序号" type="index" width="60"></el-table-column>
|
||||||
|
<el-table-column label="提案编号" prop="code" width="160" show-overflow-tooltip></el-table-column>
|
||||||
|
<el-table-column label="提案名称" prop="name" min-width="260" show-overflow-tooltip></el-table-column>
|
||||||
|
<el-table-column label="提案人" prop="createUserName" width="120" show-overflow-tooltip></el-table-column>
|
||||||
|
<el-table-column label="提案类别" prop="typeName" width="140" show-overflow-tooltip></el-table-column>
|
||||||
|
<el-table-column label="承办类型" prop="underTakeType" width="100"></el-table-column>
|
||||||
|
<el-table-column label="当前节点" prop="curTaskName" width="160" show-overflow-tooltip></el-table-column>
|
||||||
|
<el-table-column label="操作" width="100" fixed="right">
|
||||||
|
<template slot-scope="{row}">
|
||||||
|
<el-button size="mini" type="primary" @click="viewSingleProposal(row)">查看</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<el-row class="el-pagination-container" style="margin-top: 20px">
|
||||||
|
<el-pagination
|
||||||
|
@size-change="detailPageSizeChange"
|
||||||
|
@current-change="detailPageNumberChange"
|
||||||
|
:current-page="detailPageForm.pageNumber"
|
||||||
|
:page-sizes="[5,10, 20, 30, 50]"
|
||||||
|
:page-size="detailPageForm.pageSize"
|
||||||
|
layout="total, sizes, prev, pager, next"
|
||||||
|
:total="detailPageForm.totalCount"
|
||||||
|
></el-pagination>
|
||||||
|
</el-row>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
<el-dialog title="提案详情" :visible.sync="proposalInfoVisible" width="1200px" append-to-body top="5vh">
|
||||||
|
<div style="max-height: 80vh;overflow-y: auto">
|
||||||
|
<proposal-info ref="infoRef"></proposal-info>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@@ -50,7 +88,19 @@ layout("/layouts/platform.html"){
|
|||||||
return {
|
return {
|
||||||
sessionOptions: [],
|
sessionOptions: [],
|
||||||
underTakeOptions: [],
|
underTakeOptions: [],
|
||||||
slaveNeedReply: false
|
slaveNeedReply: false,
|
||||||
|
detailDialogVisible: false,
|
||||||
|
detailDialogTitle: "",
|
||||||
|
detailLoading: false,
|
||||||
|
detailTableData: [],
|
||||||
|
detailPageForm: {
|
||||||
|
pageNumber: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
totalCount: 0,
|
||||||
|
sessionId: "",
|
||||||
|
unitCode: ""
|
||||||
|
},
|
||||||
|
proposalInfoVisible: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@@ -82,6 +132,40 @@ layout("/layouts/platform.html"){
|
|||||||
this.slaveNeedReply = res.data.slaveNeedReply
|
this.slaveNeedReply = res.data.slaveNeedReply
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
openUnitProposals(row) {
|
||||||
|
this.detailDialogTitle = row.unitName + "承办提案"
|
||||||
|
this.detailDialogVisible = true
|
||||||
|
this.$set(this.detailPageForm, "unitCode", row.unitCode)
|
||||||
|
this.$set(this.detailPageForm, "sessionId", this.pageForm.sessionId)
|
||||||
|
this.$set(this.detailPageForm, "pageNumber", 1)
|
||||||
|
this.loadUnitProposals()
|
||||||
|
},
|
||||||
|
loadUnitProposals() {
|
||||||
|
this.detailLoading = true
|
||||||
|
this.$axios.post(loc() + "/getProposalsByUnit", this.detailPageForm).then((res) => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
this.$set(this, "detailTableData", res.data.list)
|
||||||
|
this.$set(this.detailPageForm, "totalCount", res.data.totalCount)
|
||||||
|
}
|
||||||
|
}).finally(() => {
|
||||||
|
this.detailLoading = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
detailPageSizeChange(val) {
|
||||||
|
this.$set(this.detailPageForm, "pageSize", val)
|
||||||
|
this.$set(this.detailPageForm, "pageNumber", 1)
|
||||||
|
this.loadUnitProposals()
|
||||||
|
},
|
||||||
|
detailPageNumberChange(val) {
|
||||||
|
this.$set(this.detailPageForm, "pageNumber", val)
|
||||||
|
this.loadUnitProposals()
|
||||||
|
},
|
||||||
|
viewSingleProposal(row) {
|
||||||
|
this.proposalInfoVisible = true
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.$refs.infoRef.onOpen(row)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
|
|||||||
+13
-3
@@ -305,11 +305,13 @@ layout("/layouts/platform.html"){
|
|||||||
|
|
||||||
getDefaultReplyOpinion(row) {
|
getDefaultReplyOpinion(row) {
|
||||||
const contentPlaceholder = "<p> 【请在此处填写答复内容】</p><br/>"
|
const contentPlaceholder = "<p> 【请在此处填写答复内容】</p><br/>"
|
||||||
|
const proposalUserName = this.escapeHtml(row.createUserName || "×××")
|
||||||
|
const proposalName = this.escapeHtml(row.name || "……")
|
||||||
|
|
||||||
if (row.underTakeIsMaster) {
|
if (row.underTakeIsMaster) {
|
||||||
return [
|
return [
|
||||||
"<p>×××代表(仅写第一提案人姓名):</p>",
|
"<p>" + proposalUserName + "代表:</p>",
|
||||||
"<p> 您提出的关于“……”的提案收悉,现答复如下:</p>",
|
"<p> 您提出的关于“" + proposalName + "”的提案收悉,现答复如下:</p>",
|
||||||
contentPlaceholder,
|
contentPlaceholder,
|
||||||
"<p> 感谢您对学校工作的关心和支持。</p>"
|
"<p> 感谢您对学校工作的关心和支持。</p>"
|
||||||
].join("")
|
].join("")
|
||||||
@@ -324,6 +326,15 @@ layout("/layouts/platform.html"){
|
|||||||
].join("")
|
].join("")
|
||||||
},
|
},
|
||||||
|
|
||||||
|
escapeHtml(value) {
|
||||||
|
return String(value)
|
||||||
|
.replace(/&/g, "&")
|
||||||
|
.replace(/</g, "<")
|
||||||
|
.replace(/>/g, ">")
|
||||||
|
.replace(/"/g, """)
|
||||||
|
.replace(/'/g, "'")
|
||||||
|
},
|
||||||
|
|
||||||
handleTaskAction(val) {
|
handleTaskAction(val) {
|
||||||
this.$refs.formRef.validate(valid => {
|
this.$refs.formRef.validate(valid => {
|
||||||
if (!valid) return
|
if (!valid) return
|
||||||
@@ -445,7 +456,6 @@ layout("/layouts/platform.html"){
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.pageData()
|
|
||||||
this.listOpenSession()
|
this.listOpenSession()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user