This commit is contained in:
2026-07-23 18:30:30 +08:00
parent 86ab0142da
commit 785b9a4b80
57 changed files with 1795 additions and 340 deletions
@@ -265,6 +265,7 @@ public class ProposalMineController {
Cnd cnd = Cnd.where("t1.sessionId", "=", sessionId);
cnd.andEX("t1.delegationId", "=", delegationId);
cnd.and("t1.roleId", "=", "72e24b5b4c4f4e90a6641e6af8487e42");
cnd.and("t1.delFlag", "!=", 1);
cnd.and("t1.loginName", "!=", SecurityUtil.getUserLoginname());
if (isInvite) {
@@ -286,11 +287,33 @@ public class ProposalMineController {
return Result.success(pagination);
}
/**
* 邀请当前提案所属教代会届次内的正式代表参与附议。
*
* @param seconders 附议人工号数组,数组中的每个工号必须属于当前提案届次的有效正式代表
* @param proposalId 提案ID,用于确定流程实例及可信的教代会届次
* @return Result;邀请成功返回 success,提案不存在、代表信息无效或人数不足时返回错误信息
*/
@At
@SaCheckPermission("proposal.mine")
@Aop(TransAop.READ_COMMITTED)
@SLog(tag = "提案", msg = "邀请附议人")
public Result inviteSeconder(@Param("seconders") String[] seconders, @Valid String proposalId) {
if (seconders == null || seconders.length == 0) {
return Result.error("请选择附议人");
}
ProposalInfo proposalInfo = dao.fetch(ProposalInfo.class, proposalId);
if (proposalInfo == null || StrUtil.isBlank(proposalInfo.getSessionId())) {
return Result.error("提案信息不存在");
}
List<String> requestedLoginNames = List.of(seconders).stream()
.filter(StrUtil::isNotBlank)
.distinct()
.toList();
if (requestedLoginNames.isEmpty()) {
return Result.error("请选择附议人");
}
// 查询已经邀请的附议人
ProcessInstance processInstance = dao.fetch(ProcessInstance.class, Cnd.where(ProcessInstance::getBusinessNo, "=", proposalId));
@@ -319,11 +342,7 @@ public class ProposalMineController {
ProposalConfig proposalConfig = dao.fetch(ProposalConfig.class, Cnd.NEW());
if (tasks.size() + seconders.length < proposalConfig.getSeconderNum()) {
return Result.error("至少邀请" + proposalConfig.getSeconderNum() + "个附议人");
}
// 必须使用提案自身的届次查询,不能只按工号匹配,否则同一代表的历史届次记录会污染代表团等快照信息。
Sql sql = Sqls.create("""
SELECT
t1.id,
@@ -340,8 +359,20 @@ public class ProposalMineController {
LEFT JOIN teacher_congress_delegation t2 ON t2.id = t1.delegationId
$condition
""");
sql.setCondition(Cnd.where("t1.loginName", "in", seconders).groupBy("t1.loginName"));
Cnd seconderCnd = Cnd.where("t1.sessionId", "=", proposalInfo.getSessionId())
.and("t1.loginName", "in", requestedLoginNames)
.and("t1.roleId", "=", "72e24b5b4c4f4e90a6641e6af8487e42")
.and("t1.delFlag", "!=", 1);
sql.setCondition(seconderCnd);
List<NutMap> list = proposalCommonService.listMap(sql);
// 每个工号在当前届次必须且只能匹配一条有效代表记录,防止无效工号或重复基础数据进入流程。
if (list.size() != requestedLoginNames.size()) {
return Result.error("部分附议人不属于当前提案届次或代表信息重复,请重新选择");
}
if (tasks.size() + list.size() < proposalConfig.getSeconderNum()) {
return Result.error("至少邀请" + proposalConfig.getSeconderNum() + "个附议人");
}
// 附议人ID
List<String> userIds = list.stream().map(item -> item.getString("userId")).toList();
// 获取正在执行的任务(邀请附议人||提案附议)
@@ -45,6 +45,7 @@ import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
@IocBean(args = {"refer:dao"})
@@ -76,14 +77,24 @@ public class ProposalCommitteeFilingUnitServiceImpl extends BaseServiceImpl<Prop
throw new BaseException("没有进行中的流程任务");
}
String proposalId = StrUtil.trim(args.getStr("proposalId"));
if (StrUtil.isBlank(proposalId) || dao().fetch(ProposalInfo.class, proposalId) == null) {
throw new BaseException("提案信息不存在");
}
args.put("proposalId", proposalId);
validateAndNormalizeCaseFilingCode(args);
String proposalId = args.getStr("proposalId");
List<String> proposalIds = proposalCommonService.mergeProposal(proposalId);
if (ObjectUtil.isEmpty(proposalIds)) {
proposalIds = List.of(proposalId);
}
/*
* 先同步 proposal_info 和承办单位,再执行 WF 流转,使查看页面及下一节点读取到的都是本次最新数据。
* 当前方法处于同一事务中,后续流程执行失败时这里的业务数据会一并回滚。
*/
syncCommitteeFilingUnitData(proposalIds, args);
/*
* 并案场景下,同一个节点会在每条提案实例上各有一条待办。
* 这里统一按 taskName 找出整组正在办理中的任务,逐条执行,确保并案提案的流程状态保持一致。
@@ -97,8 +108,6 @@ public class ProposalCommitteeFilingUnitServiceImpl extends BaseServiceImpl<Prop
cloneArgs.put(FlowConst.PROCESS_TASK_ID_KEY, executeTask.getId());
flowCommonService.executeTask(cloneArgs);
}
syncCommitteeFilingUnitData(proposalIds, args);
}
/**
@@ -110,8 +119,10 @@ public class ProposalCommitteeFilingUnitServiceImpl extends BaseServiceImpl<Prop
private void validateAndNormalizeCaseFilingCode(Dict args) {
String caseFilingResultKey = FlowConst.TASK_FORM_DATA_PREFIX + "caseFilingResult";
String caseFilingCodeKey = FlowConst.TASK_FORM_DATA_PREFIX + "caseFilingCode";
String caseFilingTypeKey = FlowConst.TASK_FORM_DATA_PREFIX + "caseFilingType";
if (!"CONFIRM_FILING".equals(args.getStr(caseFilingResultKey))) {
args.put(caseFilingCodeKey, "");
args.put(caseFilingTypeKey, "");
return;
}
@@ -139,6 +150,7 @@ public class ProposalCommitteeFilingUnitServiceImpl extends BaseServiceImpl<Prop
.add("caseFilingResult", caseFilingResult)
.add("caseFilingType", caseFilingType),
Cnd.where(ProposalInfo::getId, "in", proposalIds));
verifyCommitteeFilingUnitData(proposalIds, caseFilingCode, caseFilingResult, caseFilingType);
dao().clear(ProposalReplyUnit.class, Cnd.where(ProposalReplyUnit::getProposalId, "in", proposalIds));
if (!List.of("CONFIRM_FILING", "SUGGESTION").contains(caseFilingResult)) {
@@ -175,6 +187,28 @@ public class ProposalCommitteeFilingUnitServiceImpl extends BaseServiceImpl<Prop
}
}
/**
* 校验本次立案字段是否已同步到全部提案,避免流程变量更新成功但 info 基础信息仍保留旧值。
*/
private void verifyCommitteeFilingUnitData(List<String> proposalIds, String caseFilingCode,
String caseFilingResult, String caseFilingType) {
List<ProposalInfo> proposalInfos = dao().query(ProposalInfo.class,
Cnd.where(ProposalInfo::getId, "in", proposalIds));
if (proposalInfos.size() != new LinkedHashSet<>(proposalIds).size()) {
throw new BaseException("部分提案信息不存在,无法同步立案结果");
}
boolean syncFailed = proposalInfos.stream().anyMatch(proposalInfo ->
!Objects.equals(StrUtil.nullToDefault(proposalInfo.getCaseFilingCode(), ""),
StrUtil.nullToDefault(caseFilingCode, ""))
|| !Objects.equals(StrUtil.nullToDefault(proposalInfo.getCaseFilingResult(), ""),
StrUtil.nullToDefault(caseFilingResult, ""))
|| !Objects.equals(StrUtil.nullToDefault(proposalInfo.getCaseFilingType(), ""),
StrUtil.nullToDefault(caseFilingType, "")));
if (syncFailed) {
throw new BaseException("立案结果同步失败,请稍后重试");
}
}
/**
* 一个提案可以配置多个主办单位和多个协办单位。
* 这里按页面提交顺序逐条生成承办单位记录,兼容多主办的业务场景。
@@ -95,6 +95,7 @@ public class SuggestionBoxMineController {
}
cnd.andEX("YEAR(info.submitTime)", "=", year);
cnd.desc("info.submitTime");
cnd.groupBy("info.id");
sql.setCondition(cnd);
Pagination<NutMap> pagination = suggestionBoxService.listPageMap(pageNumber, pageSize, sql);
return Result.success(pagination);