yxk-20260715

在流程详情弹窗中新增 增补审批意见 tab,仅从 我的待阅、我的已阅、我的已办 三类入口打开时显示。
用户提交后只写入 task_approval_opinion,不写 Flowable 原生历史/评论表,也不写旧流程日志表。
提交成功后刷新 审批历史,新增意见可在审批历史中看到。
This commit is contained in:
ye1023
2026-07-15 09:49:16 +08:00
parent cbd84bc63e
commit 09798a5755
4 changed files with 259 additions and 0 deletions
@@ -14,6 +14,7 @@ import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.query.QueryGenerator; import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.system.query.QueryRuleEnum; import org.jeecg.common.system.query.QueryRuleEnum;
import org.jeecg.common.util.oConvertUtils; 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.entity.TaskApprovalOpinion;
import org.jeecg.modules.taskapprovalopinion.service.ITaskApprovalOpinionService; import org.jeecg.modules.taskapprovalopinion.service.ITaskApprovalOpinionService;
@@ -95,6 +96,20 @@ public class TaskApprovalOpinionController extends JeecgController<TaskApprovalO
return Result.OK("添加成功!"); return Result.OK("添加成功!");
} }
/**
* 增补审批意见,只写入 task_approval_opinion。
*
* @param supplementDTO
* @return
*/
@AutoLog(value = "task_approval_opinion-增补审批意见")
@Operation(summary="task_approval_opinion-增补审批意见")
@PostMapping(value = "/supplement")
public Result<String> supplement(@RequestBody SupplementApprovalOpinionDTO supplementDTO) {
taskApprovalOpinionService.saveSupplementOpinion(supplementDTO);
return Result.OK("提交成功!");
}
/** /**
* 编辑 * 编辑
* *
@@ -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;
}
@@ -1,10 +1,15 @@
package org.jeecg.modules.taskapprovalopinion.service; package org.jeecg.modules.taskapprovalopinion.service;
import org.jeecg.modules.taskapprovalopinion.entity.TaskApprovalOpinion; import org.jeecg.modules.taskapprovalopinion.entity.TaskApprovalOpinion;
import org.jeecg.modules.taskapprovalopinion.dto.SupplementApprovalOpinionDTO;
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
/** /**
* 审批意见快照 Service。 * 审批意见快照 Service。
*/ */
public interface ITaskApprovalOpinionService extends IService<TaskApprovalOpinion> { public interface ITaskApprovalOpinionService extends IService<TaskApprovalOpinion> {
/**
* 保存增补审批意见,仅写入 task_approval_opinion。
*/
void saveSupplementOpinion(SupplementApprovalOpinionDTO supplementDTO);
} }
@@ -1,14 +1,217 @@
package org.jeecg.modules.taskapprovalopinion.service.impl; 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 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.entity.TaskApprovalOpinion;
import org.jeecg.modules.taskapprovalopinion.mapper.TaskApprovalOpinionMapper; import org.jeecg.modules.taskapprovalopinion.mapper.TaskApprovalOpinionMapper;
import org.jeecg.modules.taskapprovalopinion.service.ITaskApprovalOpinionService; 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.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
import java.util.List;
import java.util.Map;
/** /**
* 审批意见快照 Service 实现。 * 审批意见快照 Service 实现。
*/ */
@Slf4j
@Service @Service
public class TaskApprovalOpinionServiceImpl extends ServiceImpl<TaskApprovalOpinionMapper, TaskApprovalOpinion> implements ITaskApprovalOpinionService { public class TaskApprovalOpinionServiceImpl extends ServiceImpl<TaskApprovalOpinionMapper, TaskApprovalOpinion> 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<JSONObject> 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<String> 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<ExtActFlowData> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(ExtActFlowData::getProcessInstId, processInstanceId);
List<ExtActFlowData> 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<Map<String, Object>> rows = jdbcTemplate.queryForList(
"select business_id, flow_code, sys_org_code from task_task where id = ?",
opinion.getTaskTaskId());
if (rows.isEmpty()) {
return;
}
Map<String, Object> 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<String, Object> row, String key) {
for (Map.Entry<String, Object> 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;
}
}
} }