From 09798a57555b24c7bc89aae64dab4e8ce7170836 Mon Sep 17 00:00:00 2001 From: ye1023 <12588209+ye1023@user.noreply.gitee.com> Date: Wed, 15 Jul 2026 09:49:16 +0800 Subject: [PATCH] =?UTF-8?q?yxk-20260715=20=E5=9C=A8=E6=B5=81=E7=A8=8B?= =?UTF-8?q?=E8=AF=A6=E6=83=85=E5=BC=B9=E7=AA=97=E4=B8=AD=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=20=E5=A2=9E=E8=A1=A5=E5=AE=A1=E6=89=B9=E6=84=8F=E8=A7=81=20tab?= =?UTF-8?q?=EF=BC=8C=E4=BB=85=E4=BB=8E=20=E6=88=91=E7=9A=84=E5=BE=85?= =?UTF-8?q?=E9=98=85=E3=80=81=E6=88=91=E7=9A=84=E5=B7=B2=E9=98=85=E3=80=81?= =?UTF-8?q?=E6=88=91=E7=9A=84=E5=B7=B2=E5=8A=9E=20=E4=B8=89=E7=B1=BB?= =?UTF-8?q?=E5=85=A5=E5=8F=A3=E6=89=93=E5=BC=80=E6=97=B6=E6=98=BE=E7=A4=BA?= =?UTF-8?q?=E3=80=82=20=E7=94=A8=E6=88=B7=E6=8F=90=E4=BA=A4=E5=90=8E?= =?UTF-8?q?=E5=8F=AA=E5=86=99=E5=85=A5=20task=5Fapproval=5Fopinion?= =?UTF-8?q?=EF=BC=8C=E4=B8=8D=E5=86=99=20Flowable=20=E5=8E=9F=E7=94=9F?= =?UTF-8?q?=E5=8E=86=E5=8F=B2/=E8=AF=84=E8=AE=BA=E8=A1=A8=EF=BC=8C?= =?UTF-8?q?=E4=B9=9F=E4=B8=8D=E5=86=99=E6=97=A7=E6=B5=81=E7=A8=8B=E6=97=A5?= =?UTF-8?q?=E5=BF=97=E8=A1=A8=E3=80=82=20=E6=8F=90=E4=BA=A4=E6=88=90?= =?UTF-8?q?=E5=8A=9F=E5=90=8E=E5=88=B7=E6=96=B0=20=E5=AE=A1=E6=89=B9?= =?UTF-8?q?=E5=8E=86=E5=8F=B2=EF=BC=8C=E6=96=B0=E5=A2=9E=E6=84=8F=E8=A7=81?= =?UTF-8?q?=E5=8F=AF=E5=9C=A8=E5=AE=A1=E6=89=B9=E5=8E=86=E5=8F=B2=E4=B8=AD?= =?UTF-8?q?=E7=9C=8B=E5=88=B0=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TaskApprovalOpinionController.java | 15 ++ .../dto/SupplementApprovalOpinionDTO.java | 36 ++++ .../service/ITaskApprovalOpinionService.java | 5 + .../impl/TaskApprovalOpinionServiceImpl.java | 203 ++++++++++++++++++ 4 files changed, 259 insertions(+) create mode 100644 jeecg-boot-platform/jeecg-boot-module-bpm-flowable/src/main/java/org/jeecg/modules/taskapprovalopinion/dto/SupplementApprovalOpinionDTO.java diff --git a/jeecg-boot-platform/jeecg-boot-module-bpm-flowable/src/main/java/org/jeecg/modules/taskapprovalopinion/controller/TaskApprovalOpinionController.java b/jeecg-boot-platform/jeecg-boot-module-bpm-flowable/src/main/java/org/jeecg/modules/taskapprovalopinion/controller/TaskApprovalOpinionController.java index 83f5ec3..96fc998 100644 --- a/jeecg-boot-platform/jeecg-boot-module-bpm-flowable/src/main/java/org/jeecg/modules/taskapprovalopinion/controller/TaskApprovalOpinionController.java +++ b/jeecg-boot-platform/jeecg-boot-module-bpm-flowable/src/main/java/org/jeecg/modules/taskapprovalopinion/controller/TaskApprovalOpinionController.java @@ -14,6 +14,7 @@ import org.jeecg.common.api.vo.Result; import org.jeecg.common.system.query.QueryGenerator; import org.jeecg.common.system.query.QueryRuleEnum; import org.jeecg.common.util.oConvertUtils; +import org.jeecg.modules.taskapprovalopinion.dto.SupplementApprovalOpinionDTO; import org.jeecg.modules.taskapprovalopinion.entity.TaskApprovalOpinion; import org.jeecg.modules.taskapprovalopinion.service.ITaskApprovalOpinionService; @@ -95,6 +96,20 @@ public class TaskApprovalOpinionController extends JeecgController supplement(@RequestBody SupplementApprovalOpinionDTO supplementDTO) { + taskApprovalOpinionService.saveSupplementOpinion(supplementDTO); + return Result.OK("提交成功!"); + } + /** * 编辑 * diff --git a/jeecg-boot-platform/jeecg-boot-module-bpm-flowable/src/main/java/org/jeecg/modules/taskapprovalopinion/dto/SupplementApprovalOpinionDTO.java b/jeecg-boot-platform/jeecg-boot-module-bpm-flowable/src/main/java/org/jeecg/modules/taskapprovalopinion/dto/SupplementApprovalOpinionDTO.java new file mode 100644 index 0000000..44bb6d3 --- /dev/null +++ b/jeecg-boot-platform/jeecg-boot-module-bpm-flowable/src/main/java/org/jeecg/modules/taskapprovalopinion/dto/SupplementApprovalOpinionDTO.java @@ -0,0 +1,36 @@ +package org.jeecg.modules.taskapprovalopinion.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; + +/** + * 增补审批意见提交参数。 + */ +@Data +@Schema(description = "增补审批意见提交参数") +public class SupplementApprovalOpinionDTO implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "流程实例ID") + private String processInstId; + + @Schema(description = "Flowable任务ID") + private String flowTaskId; + + @Schema(description = "流程节点Key") + private String taskDefKey; + + @Schema(description = "事项任务ID,对应task_task.id") + private String taskTaskId; + + @Schema(description = "关联业务ID") + private String businessId; + + @Schema(description = "流程编码") + private String flowCode; + + @Schema(description = "增补审批意见") + private String opinion; +} diff --git a/jeecg-boot-platform/jeecg-boot-module-bpm-flowable/src/main/java/org/jeecg/modules/taskapprovalopinion/service/ITaskApprovalOpinionService.java b/jeecg-boot-platform/jeecg-boot-module-bpm-flowable/src/main/java/org/jeecg/modules/taskapprovalopinion/service/ITaskApprovalOpinionService.java index a5eb000..c337926 100644 --- a/jeecg-boot-platform/jeecg-boot-module-bpm-flowable/src/main/java/org/jeecg/modules/taskapprovalopinion/service/ITaskApprovalOpinionService.java +++ b/jeecg-boot-platform/jeecg-boot-module-bpm-flowable/src/main/java/org/jeecg/modules/taskapprovalopinion/service/ITaskApprovalOpinionService.java @@ -1,10 +1,15 @@ package org.jeecg.modules.taskapprovalopinion.service; import org.jeecg.modules.taskapprovalopinion.entity.TaskApprovalOpinion; +import org.jeecg.modules.taskapprovalopinion.dto.SupplementApprovalOpinionDTO; import com.baomidou.mybatisplus.extension.service.IService; /** * 审批意见快照 Service。 */ public interface ITaskApprovalOpinionService extends IService { + /** + * 保存增补审批意见,仅写入 task_approval_opinion。 + */ + void saveSupplementOpinion(SupplementApprovalOpinionDTO supplementDTO); } diff --git a/jeecg-boot-platform/jeecg-boot-module-bpm-flowable/src/main/java/org/jeecg/modules/taskapprovalopinion/service/impl/TaskApprovalOpinionServiceImpl.java b/jeecg-boot-platform/jeecg-boot-module-bpm-flowable/src/main/java/org/jeecg/modules/taskapprovalopinion/service/impl/TaskApprovalOpinionServiceImpl.java index b1499eb..f286a51 100644 --- a/jeecg-boot-platform/jeecg-boot-module-bpm-flowable/src/main/java/org/jeecg/modules/taskapprovalopinion/service/impl/TaskApprovalOpinionServiceImpl.java +++ b/jeecg-boot-platform/jeecg-boot-module-bpm-flowable/src/main/java/org/jeecg/modules/taskapprovalopinion/service/impl/TaskApprovalOpinionServiceImpl.java @@ -1,14 +1,217 @@ package org.jeecg.modules.taskapprovalopinion.service.impl; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import lombok.extern.slf4j.Slf4j; +import org.apache.shiro.SecurityUtils; +import org.jeecg.common.exception.JeecgBootException; +import org.jeecg.common.system.api.ISysBaseAPI; +import org.jeecg.common.system.vo.LoginUser; +import org.jeecg.common.util.oConvertUtils; +import org.jeecg.modules.extbpm.process.entity.ExtActFlowData; +import org.jeecg.modules.extbpm.process.mapper.ExtActFlowDataMapper; +import org.jeecg.modules.taskapprovalopinion.dto.SupplementApprovalOpinionDTO; import org.jeecg.modules.taskapprovalopinion.entity.TaskApprovalOpinion; import org.jeecg.modules.taskapprovalopinion.mapper.TaskApprovalOpinionMapper; import org.jeecg.modules.taskapprovalopinion.service.ITaskApprovalOpinionService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Lazy; +import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Date; +import java.util.List; +import java.util.Map; /** * 审批意见快照 Service 实现。 */ +@Slf4j @Service public class TaskApprovalOpinionServiceImpl extends ServiceImpl implements ITaskApprovalOpinionService { + private static final String RECORD_TYPE_SUPPLEMENT = "SUPPLEMENT"; + private static final String SUPPLEMENT_TASK_NAME = "增补审批意见"; + private static final String SUPPLEMENT_ACTION_TYPE = "增补"; + private static final String SUPPLEMENT_ACTION_RESULT = "增补审批意见"; + + @Lazy + @Autowired + private ISysBaseAPI sysBaseAPI; + @Autowired + private ExtActFlowDataMapper extActFlowDataMapper; + @Autowired(required = false) + private JdbcTemplate jdbcTemplate; + + /** + * 保存增补审批意见。该入口只写 task_approval_opinion,不触碰 Flowable 原生表或旧流程日志表。 + */ + @Override + @Transactional(rollbackFor = Exception.class) + public void saveSupplementOpinion(SupplementApprovalOpinionDTO supplementDTO) { + if (supplementDTO == null || oConvertUtils.isEmpty(supplementDTO.getProcessInstId())) { + throw new JeecgBootException("流程实例ID不能为空"); + } + String opinionText = supplementDTO.getOpinion() == null ? null : supplementDTO.getOpinion().trim(); + if (oConvertUtils.isEmpty(opinionText)) { + throw new JeecgBootException("增补审批意见不能为空"); + } + + LoginUser loginUser = getCurrentLoginUser(); + Date now = new Date(); + ApprovalDeptInfo deptInfo = resolveCurrentApprovalDept(loginUser, loginUser.getUsername()); + + TaskApprovalOpinion opinion = new TaskApprovalOpinion(); + opinion.setRecordType(RECORD_TYPE_SUPPLEMENT); + opinion.setTaskTaskId(supplementDTO.getTaskTaskId()); + opinion.setBusinessId(supplementDTO.getBusinessId()); + opinion.setFlowCode(supplementDTO.getFlowCode()); + opinion.setProcessInstId(supplementDTO.getProcessInstId()); + opinion.setFlowTaskId(supplementDTO.getFlowTaskId()); + opinion.setTaskDefKey(supplementDTO.getTaskDefKey()); + opinion.setTaskName(SUPPLEMENT_TASK_NAME); + opinion.setActionType(SUPPLEMENT_ACTION_TYPE); + opinion.setActionResult(SUPPLEMENT_ACTION_RESULT); + opinion.setOpinion(opinionText); + opinion.setOpUserId(loginUser.getUsername()); + opinion.setOpUserName(oConvertUtils.isNotEmpty(loginUser.getRealname()) ? loginUser.getRealname() : loginUser.getUsername()); + opinion.setOpDeptId(deptInfo.id); + opinion.setOpDeptName(deptInfo.name); + opinion.setOpDeptCode(deptInfo.code); + opinion.setStartTime(now); + opinion.setOpTime(now); + opinion.setDelFlag("0"); + opinion.setCreateBy(loginUser.getUsername()); + opinion.setCreateTime(now); + opinion.setSysOrgCode(deptInfo.code); + + fillBusinessSnapshot(opinion); + save(opinion); + } + + private LoginUser getCurrentLoginUser() { + Object principal = SecurityUtils.getSubject().getPrincipal(); + if (principal instanceof LoginUser) { + return (LoginUser) principal; + } + throw new JeecgBootException("未获取到当前登录用户"); + } + + /** + * 优先记录当前登录部门,避免多部门用户写入第一个所属部门导致审批历史筛选不准。 + */ + private ApprovalDeptInfo resolveCurrentApprovalDept(LoginUser user, String username) { + String deptId = user != null ? user.getOrgId() : null; + String deptCode = user != null ? user.getOrgCode() : null; + String deptName = null; + + if (oConvertUtils.isNotEmpty(deptCode)) { + try { + List departs = sysBaseAPI.queryDepartsByOrgcodes(deptCode); + if (departs != null && !departs.isEmpty()) { + JSONObject depart = departs.get(0); + if (oConvertUtils.isEmpty(deptId)) { + deptId = depart.getString("id"); + } + deptName = depart.getString("departName"); + if (oConvertUtils.isEmpty(deptName)) { + deptName = depart.getString("depart_name"); + } + } + } catch (Exception e) { + log.debug("获取当前登录部门失败, username={}, orgCode={}", username, deptCode, e); + } + } + + if (oConvertUtils.isEmpty(deptName) && oConvertUtils.isNotEmpty(username)) { + deptName = resolveDeptName(username); + } + return new ApprovalDeptInfo(deptId, deptName, deptCode); + } + + private String resolveDeptName(String username) { + try { + List names = sysBaseAPI.getDepartNamesByUsername(username); + if (names != null && !names.isEmpty()) { + return names.get(0); + } + } catch (Exception e) { + log.debug("获取部门名称失败, username={}", username, e); + } + return null; + } + + private void fillBusinessSnapshot(TaskApprovalOpinion opinion) { + ExtActFlowData flowData = queryFlowData(opinion.getProcessInstId()); + if (flowData != null) { + if (oConvertUtils.isEmpty(opinion.getTaskTaskId())) { + opinion.setTaskTaskId(flowData.getFormDataId()); + } + if (oConvertUtils.isEmpty(opinion.getFlowCode())) { + opinion.setFlowCode(flowData.getRelationCode()); + } + } + fillTaskTaskFields(opinion); + } + + private ExtActFlowData queryFlowData(String processInstanceId) { + if (oConvertUtils.isEmpty(processInstanceId)) { + return null; + } + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(ExtActFlowData::getProcessInstId, processInstanceId); + List flowDataList = extActFlowDataMapper.selectList(queryWrapper); + return flowDataList.isEmpty() ? null : flowDataList.get(0); + } + + /** + * task_task 属于业务侧表,这里只做可选字段补齐,补齐失败不影响增补意见保存。 + */ + private void fillTaskTaskFields(TaskApprovalOpinion opinion) { + if (jdbcTemplate == null || oConvertUtils.isEmpty(opinion.getTaskTaskId())) { + return; + } + try { + List> rows = jdbcTemplate.queryForList( + "select business_id, flow_code, sys_org_code from task_task where id = ?", + opinion.getTaskTaskId()); + if (rows.isEmpty()) { + return; + } + Map row = rows.get(0); + if (oConvertUtils.isEmpty(opinion.getBusinessId())) { + opinion.setBusinessId(getStringValue(row, "business_id")); + } + if (oConvertUtils.isEmpty(opinion.getFlowCode())) { + opinion.setFlowCode(getStringValue(row, "flow_code")); + } + if (oConvertUtils.isEmpty(opinion.getSysOrgCode())) { + opinion.setSysOrgCode(getStringValue(row, "sys_org_code")); + } + } catch (Exception e) { + log.debug("补全 task_task 业务字段失败,跳过。taskTaskId={}", opinion.getTaskTaskId(), e); + } + } + + private String getStringValue(Map row, String key) { + for (Map.Entry entry : row.entrySet()) { + if (entry.getKey() != null && entry.getKey().equalsIgnoreCase(key) && entry.getValue() != null) { + return String.valueOf(entry.getValue()); + } + } + return null; + } + + private static class ApprovalDeptInfo { + private final String id; + private final String name; + private final String code; + + private ApprovalDeptInfo(String id, String name, String code) { + this.id = id; + this.name = name; + this.code = code; + } + } }