commit
This commit is contained in:
+11
-4
@@ -80,8 +80,9 @@ public class ProposalUnderTakeReplyController {
|
||||
public Result pageData(@Valid ProposalSearchParam pageForm, boolean approval, boolean transfer) {
|
||||
/*
|
||||
* 承办单位答复列表需要按“承办单位”维度展示。
|
||||
* 同一个任务可能挂了多个承办单位负责人,若只按 taskId 分组会把多条待审核合并成一条,
|
||||
* 因此这里优先使用任务参与人的承办单位信息拆行,历史数据缺失时再回退到流程变量。
|
||||
* 新流程生成的会签任务可能未写入 underTakeName、underTakeId、underTakeIsMaster,
|
||||
* 因此优先读取任务变量,变量缺失时再按“提案ID + 任务参与人单位ID”关联承办单位记录兜底,
|
||||
* 兼容已经生成的历史待办,同时保持原有任务变量的数据优先级。
|
||||
*/
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
@@ -107,8 +108,13 @@ public class ProposalUnderTakeReplyController {
|
||||
IFNULL(GROUP_CONCAT(DISTINCT nt.displayName),'结束') curTaskName,
|
||||
IFNULL(GROUP_CONCAT(DISTINCT nt.taskName),'结束') curTaskKey,
|
||||
CASE WHEN t.taskState = 20 AND ( rt.id IS NULL OR rt.taskState = 10 ) THEN 1 ELSE 0 END AS canRevoke,
|
||||
t.variable->>'$.underTakeName' AS underTakeName,
|
||||
IF(JSON_EXTRACT(t.variable, '$.underTakeIsMaster') = true, 1, 0) AS underTakeIsMaster,
|
||||
COALESCE(NULLIF(t.variable->>'$.underTakeName', ''), replyUnit.unitName) AS underTakeName,
|
||||
COALESCE(NULLIF(t.variable->>'$.underTakeId', ''), replyUnit.unitId) AS underTakeId,
|
||||
CASE
|
||||
WHEN JSON_EXTRACT(t.variable, '$.underTakeIsMaster') IS NOT NULL
|
||||
THEN IF(JSON_EXTRACT(t.variable, '$.underTakeIsMaster') = true, 1, 0)
|
||||
ELSE IFNULL(replyUnit.isMaster, 0)
|
||||
END AS underTakeIsMaster,
|
||||
t.variable->>'$.tf_transferUserId' AS tf_transferUserId,
|
||||
transferUser.username AS transferUserName,
|
||||
GROUP_CONCAT(DISTINCT ta.actorName, '(', ta.actorAccount, ')' ) AS auditUser
|
||||
@@ -119,6 +125,7 @@ public class ProposalUnderTakeReplyController {
|
||||
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_reply_unit replyUnit ON replyUnit.proposalId = info.id AND replyUnit.unitId = ta.actorUnitId
|
||||
LEFT JOIN proposal_type type on type.id = info.typeId
|
||||
LEFT JOIN proposal_merge mer ON mer.proposalId = info.id
|
||||
LEFT JOIN teacher_congress_session tcs on tcs.id = info.sessionId
|
||||
|
||||
+21
-6
@@ -6,6 +6,7 @@ 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.constant.FlowConst;
|
||||
import com.budwk.app.flow.engine.AssignmentHandler;
|
||||
import com.budwk.app.flow.engine.core.Execution;
|
||||
import com.budwk.app.flow.engine.core.ServiceContext;
|
||||
@@ -36,12 +37,7 @@ public class ProposalUnitAssignmentHandler implements AssignmentHandler {
|
||||
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));
|
||||
List<String> unitIds = resolveUnitIds(model, execution, dao, proposalId);
|
||||
|
||||
if (unitIds.isEmpty()) {
|
||||
throw new BaseException("提案没有配置承办单位");
|
||||
@@ -76,6 +72,25 @@ public class ProposalUnitAssignmentHandler implements AssignmentHandler {
|
||||
return assignee;
|
||||
}
|
||||
|
||||
/**
|
||||
* 确定当前答复节点需要分派的单位范围。
|
||||
* 二次答复页面已明确提交 tf_secondReplyUnitIds 时,该字段就是唯一分派范围;
|
||||
* 未选择的主办或协办单位不能再从历史承办单位记录中补回。
|
||||
* 旧流程没有该字段时,继续按主办、协办配置回退,保证历史流程可以正常运行。
|
||||
*/
|
||||
private List<String> resolveUnitIds(TaskModel model, Execution execution, Dao dao, String proposalId) {
|
||||
String secondReplyUnitIdsKey = FlowConst.TASK_FORM_DATA_PREFIX + "secondReplyUnitIds";
|
||||
if ("two_unit_reply".equals(model.getName()) && execution.getArgs().containsKey(secondReplyUnitIdsKey)) {
|
||||
return getStringList(execution.getArgs(), secondReplyUnitIdsKey);
|
||||
}
|
||||
|
||||
// 初次答复需要同时处理主办和协办负责人,旧二次答复流程也沿用该兼容逻辑。
|
||||
List<String> unitIds = new ArrayList<>();
|
||||
unitIds.addAll(resolveMasterUnitIds(execution, dao, proposalId));
|
||||
unitIds.addAll(resolveSlaveUnitIds(execution, dao, proposalId));
|
||||
return unitIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* 优先从当前流程变量读取主办单位,读不到时回落到承办单位记录表,兼容重新流转场景。
|
||||
*/
|
||||
|
||||
@@ -33,6 +33,11 @@ public class ProposalInfo extends BaseModel {
|
||||
@ColDefine(type = ColType.VARCHAR, width = 20)
|
||||
private String code;
|
||||
|
||||
@Column
|
||||
@Comment("立案编号")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 20)
|
||||
private String caseFilingCode;
|
||||
|
||||
@Column
|
||||
@Comment("提案名称")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||
|
||||
+32
-2
@@ -76,6 +76,8 @@ public class ProposalCommitteeFilingUnitServiceImpl extends BaseServiceImpl<Prop
|
||||
throw new BaseException("没有进行中的流程任务");
|
||||
}
|
||||
|
||||
validateAndNormalizeCaseFilingCode(args);
|
||||
|
||||
String proposalId = args.getStr("proposalId");
|
||||
List<String> proposalIds = proposalCommonService.mergeProposal(proposalId);
|
||||
if (ObjectUtil.isEmpty(proposalIds)) {
|
||||
@@ -98,16 +100,44 @@ public class ProposalCommitteeFilingUnitServiceImpl extends BaseServiceImpl<Prop
|
||||
|
||||
syncCommitteeFilingUnitData(proposalIds, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* old-flow 页面提交后,需要把立案结果以及主协办单位同步落业务表。
|
||||
* 校验并规范化立案编号。确定立案时必须传入不超过 20 个字符的编号;
|
||||
* 其他立案结果不保存编号,避免切换选项后把历史输入带入业务表和流程变量。
|
||||
*
|
||||
* @param args 流程提交参数,其中 tf_caseFilingResult 为立案结果,tf_caseFilingCode 为手工填写的立案编号
|
||||
*/
|
||||
private void validateAndNormalizeCaseFilingCode(Dict args) {
|
||||
String caseFilingResultKey = FlowConst.TASK_FORM_DATA_PREFIX + "caseFilingResult";
|
||||
String caseFilingCodeKey = FlowConst.TASK_FORM_DATA_PREFIX + "caseFilingCode";
|
||||
if (!"CONFIRM_FILING".equals(args.getStr(caseFilingResultKey))) {
|
||||
args.put(caseFilingCodeKey, "");
|
||||
return;
|
||||
}
|
||||
|
||||
String caseFilingCode = StrUtil.trim(args.getStr(caseFilingCodeKey));
|
||||
if (StrUtil.isBlank(caseFilingCode)) {
|
||||
throw new BaseException("立案编号不能为空");
|
||||
}
|
||||
if (caseFilingCode.length() > 20) {
|
||||
throw new BaseException("立案编号不能超过20个字符");
|
||||
}
|
||||
args.put(caseFilingCodeKey, caseFilingCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* old-flow 页面提交后,需要把立案编号、立案结果以及主协办单位同步落业务表。
|
||||
* 若这次改成“不予立案”等无需承办单位的结果,也要先清掉旧的承办单位记录,避免脏数据残留。
|
||||
*/
|
||||
private void syncCommitteeFilingUnitData(List<String> proposalIds, Dict args) {
|
||||
String caseFilingCode = args.getStr(FlowConst.TASK_FORM_DATA_PREFIX + "caseFilingCode");
|
||||
String caseFilingResult = args.getStr(FlowConst.TASK_FORM_DATA_PREFIX + "caseFilingResult");
|
||||
String caseFilingType = args.getStr(FlowConst.TASK_FORM_DATA_PREFIX + "caseFilingType");
|
||||
|
||||
dao().update(ProposalInfo.class,
|
||||
Chain.make("caseFilingResult", caseFilingResult).add("caseFilingType", caseFilingType),
|
||||
Chain.make("caseFilingCode", caseFilingCode)
|
||||
.add("caseFilingResult", caseFilingResult)
|
||||
.add("caseFilingType", caseFilingType),
|
||||
Cnd.where(ProposalInfo::getId, "in", proposalIds));
|
||||
|
||||
dao().clear(ProposalReplyUnit.class, Cnd.where(ProposalReplyUnit::getProposalId, "in", proposalIds));
|
||||
|
||||
+19
-9
@@ -83,15 +83,18 @@ public class TeacherCongressInstitutionController {
|
||||
}
|
||||
|
||||
/**
|
||||
* 表单中的树结构
|
||||
* 获取新增机构表单使用的固定机构字典树。
|
||||
*
|
||||
* @param sessionId
|
||||
* @return
|
||||
* @param sessionId 当前教代会届次ID,用于保持接口参数与机构管理页面上下文一致
|
||||
* @return Result,data.treeList 为级联组件树结构,data.treeFlat 为名称和代码回填使用的扁平字典列表
|
||||
*/
|
||||
@At
|
||||
@SaCheckPermission("tc.institution")
|
||||
public Result formTree(@Valid String sessionId) {
|
||||
Sys_dict institutionFixedDict = sysDictService.fetch(Cnd.where(Sys_dict::getCode, "=", "TEACHER_CONGRESS_INSTITUTION_FIXED"));
|
||||
if (ObjectUtil.isEmpty(institutionFixedDict)) {
|
||||
return Result.error("未配置双代会固定机构字典");
|
||||
}
|
||||
List<Sys_dict> children = sysDictService.query(Cnd.where(Sys_dict::getPath, "like", institutionFixedDict.getPath() + "%"));
|
||||
List<TreeNode<String>> treeNodes = children.stream().map(sysDict -> {
|
||||
TreeNode<String> treeNode = new TreeNode<>(sysDict.getId(), sysDict.getParentId(), sysDict.getName(), sysDict.getLocation());
|
||||
@@ -134,19 +137,24 @@ public class TeacherCongressInstitutionController {
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加机构
|
||||
* 添加当前届次的机构。
|
||||
*
|
||||
* @param institution
|
||||
* @return
|
||||
* @param institution 机构数据,包含 sessionId、name、code、parentId、location 和 introduce;parentId 可能是固定字典ID
|
||||
* @return Result,机构重复或父级不存在时返回错误,否则返回成功
|
||||
*/
|
||||
@At
|
||||
@SaCheckPermission("tc.institution")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public Result insert(Teacher_congress_institution institution) {
|
||||
if (dao.count(Teacher_congress_institution.class, Cnd.where(Teacher_congress_institution::getCode, "=", institution.getCode()).and(Teacher_congress_institution::getSessionId, "=", institution.getSessionId())) > 0) {
|
||||
return Result.error("机构已存在");
|
||||
}
|
||||
if (StrUtil.isNotBlank(institution.getParentId()) && !institution.getParentId().equals("0") && dao.count(Teacher_congress_institution.class, Cnd.where(Teacher_congress_institution::getId, "=", institution.getParentId()).and(Teacher_congress_institution::getSessionId, "=", institution.getSessionId())) == 0) {
|
||||
// 级联框提交的是固定字典父级ID,需要按机构代码匹配当前届次的实际父机构。
|
||||
Sys_dict sysDict = sysDictService.fetch(Cnd.where(Sys_dict::getId, "=", institution.getParentId()));
|
||||
if (ObjectUtil.isEmpty(sysDict)) {
|
||||
return Result.error("父级机构不存在");
|
||||
}
|
||||
Teacher_congress_institution parentInstitution = dao.fetch(Teacher_congress_institution.class,
|
||||
Cnd.where(Teacher_congress_institution::getCode, "=", sysDict.getCode())
|
||||
.and(Teacher_congress_institution::getSessionId, "=", institution.getSessionId())
|
||||
@@ -162,13 +170,14 @@ public class TeacherCongressInstitutionController {
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除机构
|
||||
* 更新机构名称、描述和排序。
|
||||
*
|
||||
* @param id
|
||||
* @return
|
||||
* @param institution 机构数据,id 标识待更新机构,name、introduce、location 为可更新内容
|
||||
* @return Result,机构不存在时返回错误,否则返回成功
|
||||
*/
|
||||
@At
|
||||
@SaCheckPermission("tc.institution")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public Result update(Teacher_congress_institution institution) {
|
||||
Teacher_congress_institution dbInstitution = dao.fetch(Teacher_congress_institution.class, institution.getId());
|
||||
if (ObjectUtil.isEmpty(dbInstitution)) {
|
||||
@@ -267,6 +276,7 @@ public class TeacherCongressInstitutionController {
|
||||
*/
|
||||
@At
|
||||
@SaCheckPermission("tc.institution")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
public Result userDelete(@Valid String id) {
|
||||
teacherCongressInstitutionUserService.userDelete(id);
|
||||
return Result.success();
|
||||
|
||||
+13
-1
@@ -61,6 +61,18 @@ public class TeacherCongressSessionController {
|
||||
return Result.success(pagination);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询历史届次已保存的提案类型,不需要请求参数。
|
||||
*
|
||||
* @return VO 列表,每项的 proposalType 字段表示一个下拉选项
|
||||
*/
|
||||
@At
|
||||
@SaCheckPermission("tc.prepare.session")
|
||||
@ApiOperation(value = "查询届次提案类型选项")
|
||||
public Result listProposalTypes() {
|
||||
return Result.success(teacherCongressSessionService.listProposalTypes());
|
||||
}
|
||||
|
||||
@At
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("tc.prepare.session")
|
||||
@@ -74,7 +86,7 @@ public class TeacherCongressSessionController {
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("tc.prepare.session")
|
||||
@ApiOperation(value = "修改届次信息")
|
||||
public Result update(Teacher_congress_session session) {
|
||||
public Result update(@Valid Teacher_congress_session session) {
|
||||
int count = dao.count(Teacher_congress_session.class,
|
||||
Cnd.where(Teacher_congress_session::getJ, "=", session.getJ())
|
||||
.and(Teacher_congress_session::getC, "=", session.getC())
|
||||
|
||||
+7
@@ -43,6 +43,13 @@ public class Teacher_congress_session extends BaseModel {
|
||||
@ColDefine(type = ColType.VARCHAR, width = 20)
|
||||
private String fullName;
|
||||
|
||||
@Column
|
||||
@Comment("提案类型")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 50)
|
||||
@NotBlank(message = "提案类型不能为空")
|
||||
@Size(max = 50, message = "提案类型最多50个字")
|
||||
private String proposalType;
|
||||
|
||||
@Column
|
||||
@Comment("教代会开启时间")
|
||||
@ColDefine(type = ColType.DATE)
|
||||
|
||||
+10
@@ -1,13 +1,23 @@
|
||||
package com.budwk.app.zhgh.democratic.teachercongress.prepare.service;
|
||||
|
||||
import com.budwk.app.base.service.BaseService;
|
||||
import com.budwk.app.zhgh.democratic.teachercongress.prepare.controller.vo.TeacherCongressSessionProposalTypeVO;
|
||||
import com.budwk.app.zhgh.democratic.teachercongress.prepare.models.Teacher_congress_session;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 教代会届次
|
||||
*/
|
||||
public interface TeacherCongressSessionService extends BaseService<Teacher_congress_session> {
|
||||
|
||||
/**
|
||||
* 查询届次中已经保存过的提案类型,供可输入下拉框复用。
|
||||
*
|
||||
* @return 提案类型 VO 列表,每项的 proposalType 字段为一个可选类型
|
||||
*/
|
||||
List<TeacherCongressSessionProposalTypeVO> listProposalTypes();
|
||||
|
||||
void insertSession(Teacher_congress_session session, boolean isExtend);
|
||||
|
||||
void deleteSession(String id);
|
||||
|
||||
+18
@@ -24,12 +24,15 @@ import com.budwk.app.zhgh.democratic.teachercongress.institution.models.Teacher_
|
||||
import com.budwk.app.zhgh.democratic.teachercongress.institution.models.Teacher_congress_institution_user;
|
||||
import com.budwk.app.zhgh.democratic.teachercongress.meetings.models.Teacher_congress_meeting;
|
||||
import com.budwk.app.zhgh.democratic.teachercongress.meetings.models.Teacher_congress_meeting_file;
|
||||
import com.budwk.app.zhgh.democratic.teachercongress.prepare.controller.vo.TeacherCongressSessionProposalTypeVO;
|
||||
import com.budwk.app.zhgh.democratic.teachercongress.prepare.models.Teacher_congress_prepare_file;
|
||||
import com.budwk.app.zhgh.democratic.teachercongress.prepare.models.Teacher_congress_session;
|
||||
import com.budwk.app.zhgh.democratic.teachercongress.prepare.service.TeacherCongressSessionService;
|
||||
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;
|
||||
@@ -52,6 +55,21 @@ public class TeacherCongressSessionServiceImpl extends BaseServiceImpl<Teacher_c
|
||||
super(dao);
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取历史届次中非空的提案类型并去重,用户既可复用已有类型,也可在前端输入新类型。
|
||||
*
|
||||
* @return 提案类型 VO 列表,每项只包含 proposalType 字段
|
||||
*/
|
||||
@Override
|
||||
public List<TeacherCongressSessionProposalTypeVO> listProposalTypes() {
|
||||
Sql sql = Sqls.create("SELECT DISTINCT proposalType FROM teacher_congress_session " +
|
||||
"WHERE proposalType IS NOT NULL AND TRIM(proposalType) <> '' ORDER BY proposalType");
|
||||
sql.setCallback(Sqls.callback.strList());
|
||||
dao().execute(sql);
|
||||
return sql.getList(String.class).stream()
|
||||
.map(TeacherCongressSessionProposalTypeVO::new)
|
||||
.toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
|
||||
Reference in New Issue
Block a user