Commit 5e45ca3d by 王志超

feat: 子工单分批流转逻辑处理

parent 479f9a08
......@@ -721,6 +721,33 @@ public class ChangeFlowBiz {
log.info("[NEW_CHANGE_FLOW_CONFIRM_EXEC_PLAN] 主工单流转成功,flowId:{}, nextNodeId:{}",
flowId, ownerApproveNodeId);
return ownerApproveNodeId;
case NEW_CHANGE_FLOW_OWNER_APPROVE:
case NEW_CHANGE_FLOW_ADMIN_APPROVE:
case NEW_CHANGE_FLOW_QUALITY_APPROVE:
// 部门负责人、质量部负责人、变更管理员审批节点:检查所有子单是否都已审批通过
return null;
case NEW_CHANGE_FLOW_EXE:
// todo:
// 这些节点检查所有子单是否都已完成(FINISHED或CANCELLED)
if (!checkAllSubFlowsFinishedForMainFlow(changeRecord.getId())) {
throw ExceptionFactory.createBiz(ResponseCode.BAD_REQUEST,
"存在子单未完成,无法提交主工单");
}
// 所有子单都已完成,提交主工单到下一节点
String mainFlowNextNodeId = flowService.submitFlow(flowId.toString(), flowDataDTO, uid,
ChangeFlowEnum.NEW_CHANGE_FLOW.getTopoId(), JSON.toJSONString(content), true,
FlowxOperationEnum.SUBMIT.getName(), "所有子单已完成,主工单流转", changeRecord.getCreateTime());
changeRecord.setFlowNode(mainFlowNextNodeId);
changeRecord.setUpdateTime(DateUtils.getCurrentTime());
changeFlowService.updateRecord(changeRecord);
log.info("[NEW_CHANGE_FLOW] 主工单流转成功,flowId:{}, node:{}, nextNodeId:{}",
flowId, node, mainFlowNextNodeId);
return mainFlowNextNodeId;
case NEW_CHANGE_FLOW_CONFIRM:
// todo:
return null;
case CHANGE_FLOW_CONFIRM:
Integer changeResult = changeFlowSubmitReq.getChangeResult();
ChangeResultEnum changeResultStatus = ChangeResultEnum.getByStatus(changeResult);
......@@ -1732,4 +1759,25 @@ public class ChangeFlowBiz {
);
}
/**
* 检查主工单下所有子单是否都已完成(供主工单流转时调用)
* 条件:status = FINISHED 或 CANCELLED
*
* @param changeRecordId 主工单ID
* @return true 表示所有子单都已完成
*/
public boolean checkAllSubFlowsFinishedForMainFlow(Long changeRecordId) {
// 查询该主工单下所有子单
List<ChangeSubFlowRecord> allSubFlows = changeSubFlowRecordMapper.selectByChangeRecordId(changeRecordId);
if (CollectionUtils.isEmpty(allSubFlows)) {
return false;
}
// 检查是否所有子单都满足条件:状态是 FINISHED 或 CANCELLED
return allSubFlows.stream().allMatch(subFlow ->
ChangeSubFlowStatusEnum.FINISHED.getStatus().equals(subFlow.getStatus())
|| ChangeSubFlowStatusEnum.CANCELLED.getStatus().equals(subFlow.getStatus())
);
}
}
......@@ -5,6 +5,7 @@ import com.netease.mail.yanxuan.change.biz.config.AppConfig;
import com.netease.mail.yanxuan.change.biz.meta.exception.ExceptionFactory;
import com.netease.mail.yanxuan.change.biz.service.ChangeFlowExecService;
import com.netease.mail.yanxuan.change.biz.service.ChangeFlowService;
import com.netease.mail.yanxuan.change.biz.service.ChangeSubFlowFileService;
import com.netease.mail.yanxuan.change.biz.service.ChangeSubFlowRecordService;
import com.netease.mail.yanxuan.change.biz.service.ChangeSubFlowService;
import com.netease.mail.yanxuan.change.biz.service.rpc.FlowService;
......@@ -15,7 +16,9 @@ import com.netease.mail.yanxuan.change.biz.util.PageUtils;
import com.netease.mail.yanxuan.change.common.bean.RequestLocalBean;
import com.netease.mail.yanxuan.change.common.bean.ResponseCode;
import com.netease.mail.yanxuan.change.common.enums.ChangeFlowEnum;
import com.netease.mail.yanxuan.change.common.enums.ChangeResultEnum;
import com.netease.mail.yanxuan.change.common.enums.ChangeSubFlowStatusEnum;
import com.netease.mail.yanxuan.change.common.enums.FileTypeEnum;
import com.netease.mail.yanxuan.change.common.enums.FlowOperationTypeEnum;
import com.netease.mail.yanxuan.change.common.enums.FlowxOperationEnum;
import com.netease.mail.yanxuan.change.common.util.DateUtils;
......@@ -23,10 +26,12 @@ import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.netease.mail.yanxuan.change.dal.entity.ChangeExecRecord;
import com.netease.mail.yanxuan.change.dal.entity.ChangeRecord;
import com.netease.mail.yanxuan.change.dal.entity.ChangeSubFlowFile;
import com.netease.mail.yanxuan.change.dal.entity.ChangeSubFlowRecord;
import com.netease.mail.yanxuan.change.dal.mapper.ChangeRecordMapper;
import com.netease.mail.yanxuan.change.dal.mapper.ChangeSubFlowRecordMapper;
import com.netease.mail.yanxuan.change.dal.meta.model.req.ChangeExecConfigReq;
import com.netease.mail.yanxuan.change.dal.meta.model.req.ChangeFlowFile;
import com.netease.mail.yanxuan.change.dal.meta.model.req.ChangeFlowListQueryReq;
import com.netease.mail.yanxuan.change.dal.meta.model.req.ChangeFlowSubmitReq;
import com.netease.mail.yanxuan.change.dal.meta.model.req.ChangeSubFlowCreateReq;
......@@ -42,11 +47,11 @@ import com.netease.mail.yanxuan.change.integration.flow.ius.rsp.IusUserInfoRsp;
import com.netease.yanxuan.flowx.sdk.meta.controller.communal.AjaxResponse;
import com.netease.yanxuan.flowx.sdk.meta.dto.base.FlowDataDTO;
import com.netease.yanxuan.flowx.sdk.meta.dto.flow.FlowCreateReqDTO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
......@@ -56,46 +61,23 @@ import java.util.stream.Collectors;
@Component
@Slf4j
@RequiredArgsConstructor
public class ChangeSubFlowBiz {
@Autowired
private ChangeSubFlowService changeSubFlowService;
@Autowired
private FlowService flowService;
@Autowired
private ChangeFlowExecService changeFlowExecService;
@Autowired
private ChangeFlowService changeFlowService;
@Autowired
private ChangeSubFlowRecordService changeSubFlowRecordService;
@Autowired
private ChangeSubFlowRecordMapper changeSubFlowRecordMapper;
@Autowired
private ChangeRecordMapper changeRecordMapper;
@Autowired
private ChangeFlowBiz changeFlowBiz;
@Autowired
private ChangeExecRecordBiz changeExecRecordBiz;
@Autowired
private DepartmentLeaderBiz departmentLeaderBiz;
@Autowired
private IusRpcService iusRpcService;
@Autowired
private IusService iusService;
@Autowired
private AppConfig appConfig;
private final ChangeSubFlowService changeSubFlowService;
private final FlowService flowService;
private final ChangeFlowExecService changeFlowExecService;
private final ChangeFlowService changeFlowService;
private final ChangeSubFlowRecordService changeSubFlowRecordService;
private final ChangeSubFlowRecordMapper changeSubFlowRecordMapper;
private final ChangeRecordMapper changeRecordMapper;
private final ChangeFlowBiz changeFlowBiz;
private final ChangeExecRecordBiz changeExecRecordBiz;
private final DepartmentLeaderBiz departmentLeaderBiz;
private final IusRpcService iusRpcService;
private final IusService iusService;
private final AppConfig appConfig;
private final ChangeSubFlowFileService changeSubFlowFileService;
public String createAndSubmit(@Valid ChangeSubFlowCreateReq changeSubFlowCreateReq) {
......@@ -345,35 +327,42 @@ public class ChangeSubFlowBiz {
return subFlowRecord.getSubFlowNode();
case CHANGE_SUB_FLOW_CONFIRM:
// 提交执行结果节点,需要填写完成时间和完成情况
Long finishTime = changeSubFlowSubmitReq.getChangeExecFinishTime();
String finishDesc = changeSubFlowSubmitReq.getChangeExecFinishDesc();
Assert.notNull(finishTime, "行动完成时间不可为空");
Assert.isTrue(StringUtils.isNotBlank(finishDesc), "行动完成情况不可为空");
// 更新完成信息(更新所有关联的行动项)
List<ChangeExecRecord> allExecRecords = changeFlowExecService.getBySubFlowRecordId(subFlowRecord.getId());
for (ChangeExecRecord exec : allExecRecords) {
exec.setChangeExecFinishTime(finishTime);
exec.setChangeExecFinishDesc(finishDesc);
exec.setUpdateTime(DateUtils.getCurrentTime());
changeFlowExecService.update(exec);
}
// 提交到结束节点
String endNodeId = flowService.submitFlow(subFlowId, flowDataDTO, uid,
ChangeFlowEnum.CHANGE_SUB_FLOW.getTopoId(), JSON.toJSONString(content), true,
FlowxOperationEnum.SUBMIT.getName(), "提交工单", subFlowRecord.getCreateTime());
// 更新行动工单节点ID
subFlowRecord.setSubFlowNode(endNodeId);
// TODO: 根据业务逻辑设置状态 subFlowRecord.setStatus(...)
subFlowRecord.setUpdateTime(DateUtils.getCurrentTime());
changeSubFlowRecordService.update(subFlowRecord);
// 提交执行结果节点,填写变更结论
Integer subFlowChangeResult = changeSubFlowSubmitReq.getChangeResult();
ChangeResultEnum subFlowResultStatus = ChangeResultEnum.getByStatus(subFlowChangeResult);
if (subFlowResultStatus == null) {
throw ExceptionFactory.createBiz(ResponseCode.BAD_REQUEST, "变更结论类型错误");
}
// TODO: 子流程完成后,检查主流程是否可以进入确认节点
log.info("[CHANGE_SUB_FLOW_CONFIRM] 子流程完成,subFlowId:{}, subFlowRecordId:{}", subFlowId, subFlowRecord.getId());
// 填写变更结论和备注到子单记录
subFlowRecord.setChangeResult(subFlowResultStatus.getStatus());
subFlowRecord.setRemark(changeSubFlowSubmitReq.getRemark());
return endNodeId;
// 处理子单的变更结果文件(所有结论类型都需要保存文件)
List<ChangeFlowFile> subFlowResultFiles = changeSubFlowSubmitReq.getChangeResultFiles();
if (CollectionUtils.isNotEmpty(subFlowResultFiles)) {
// 先删除旧文件
changeSubFlowFileService.deleteBySubFlowRecordIdAndType(subFlowRecord.getId(), FileTypeEnum.CHANGE_RESULT_INFO);
// 保存新文件
List<ChangeSubFlowFile> fileList = buildChangeFileRecordForSubFlow(
subFlowRecord.getId(), subFlowResultFiles, FileTypeEnum.CHANGE_RESULT_INFO.getType());
fileList.forEach(changeSubFlowFileService::saveRecord);
}
switch (subFlowResultStatus) {
case FINISH_ALL:
case FINISH_PART:
return handleSubFlowFinish(subFlowRecord, changeSubFlowSubmitReq, flowDataDTO, uid, content, subFlowResultStatus);
case CANCEL:
return handleSubFlowCancel(subFlowRecord, changeSubFlowSubmitReq, flowDataDTO, uid, content);
case DELAY:
return handleSubFlowDelay(subFlowRecord, changeSubFlowSubmitReq);
default:
throw ExceptionFactory.createBiz(ResponseCode.BAD_REQUEST, "不支持的变更结论类型");
}
default:
throw ExceptionFactory.createBiz(ResponseCode.BAD_REQUEST, "不支持的子流程节点类型");
......@@ -419,6 +408,100 @@ public class ChangeSubFlowBiz {
}
/**
* 处理子单完成(FINISH_ALL / FINISH_PART)
*/
private String handleSubFlowFinish(ChangeSubFlowRecord subFlowRecord, ChangeSubFlowSubmitReq req,
FlowDataDTO flowDataDTO, String uid, Object content, ChangeResultEnum resultStatus) {
// 提交子单流程到结束节点
String endNodeId = flowService.submitFlow(subFlowRecord.getSubFlowId(), flowDataDTO, uid,
ChangeFlowEnum.CHANGE_SUB_FLOW.getTopoId(), JSON.toJSONString(content), true,
FlowxOperationEnum.SUBMIT.getName(), "提交执行结果", subFlowRecord.getCreateTime());
// 更新子单状态为FINISHED
subFlowRecord.setSubFlowNode(endNodeId);
subFlowRecord.setStatus(ChangeSubFlowStatusEnum.FINISHED.getStatus());
subFlowRecord.setUpdateTime(DateUtils.getCurrentTime());
changeSubFlowRecordService.update(subFlowRecord);
log.info("[handleSubFlowFinish] 子单完成,subFlowId:{}, result:{}", subFlowRecord.getSubFlowId(), resultStatus);
return endNodeId;
}
/**
* 处理子单取消(CANCEL)
*/
private String handleSubFlowCancel(ChangeSubFlowRecord subFlowRecord, ChangeSubFlowSubmitReq req,
FlowDataDTO flowDataDTO, String uid, Object content) {
// 1. 取消原因必填
if (StringUtils.isBlank(req.getCancelReason())) {
throw ExceptionFactory.createBiz(ResponseCode.BAD_REQUEST, "变更取消原因不可为空");
}
// 2. 保存取消原因
subFlowRecord.setCancelReason(req.getCancelReason());
// 3. 提交子单流程到结束节点
String cancelNodeId = flowService.submitFlow(subFlowRecord.getSubFlowId(), flowDataDTO, uid,
ChangeFlowEnum.CHANGE_SUB_FLOW.getTopoId(), JSON.toJSONString(content), true,
FlowxOperationEnum.SUBMIT.getName(), "取消工单", subFlowRecord.getCreateTime());
// 5. 更新子单状态为CANCELLED
subFlowRecord.setSubFlowNode(cancelNodeId);
subFlowRecord.setStatus(ChangeSubFlowStatusEnum.CANCELLED.getStatus());
subFlowRecord.setUpdateTime(DateUtils.getCurrentTime());
changeSubFlowRecordService.update(subFlowRecord);
log.info("[handleSubFlowCancel] 子单已取消,subFlowId:{}, reason:{}", subFlowRecord.getSubFlowId(), req.getCancelReason());
return cancelNodeId;
}
/**
* 处理子单延期(DELAY)
*/
private String handleSubFlowDelay(ChangeSubFlowRecord subFlowRecord, ChangeSubFlowSubmitReq req) {
// 1. 验证延期时间
Long changeConfirmResultTime = req.getChangeConfirmResultTime();
Long tomorrowSpecificTime = DateUtils.getTomorrowSpecificTime("00:00:00");
if (changeConfirmResultTime == null || changeConfirmResultTime < tomorrowSpecificTime) {
throw ExceptionFactory.createBiz(ResponseCode.BAD_REQUEST, "时间不可晚于下次执行时间");
}
// 2. 更新子单延期时间,不流转工单
subFlowRecord.setChangeConfirmResultTime(changeConfirmResultTime);
subFlowRecord.setUpdateTime(DateUtils.getCurrentTime());
changeSubFlowRecordService.update(subFlowRecord);
log.info("[handleSubFlowDelay] 子单延期,subFlowId:{}, delayTime:{}", subFlowRecord.getSubFlowId(), changeConfirmResultTime);
// 延期不流转工单,返回null
return null;
}
/**
* 构建子单文件记录
*
* @param subFlowRecordId 子单ID
* @param files 文件列表
* @param type 文件类型
* @return 文件记录列表
*/
private List<ChangeSubFlowFile> buildChangeFileRecordForSubFlow(Long subFlowRecordId,
List<ChangeFlowFile> files, Integer type) {
return files.stream().map(f -> {
ChangeSubFlowFile file = new ChangeSubFlowFile();
file.setSubFlowRecordId(subFlowRecordId);
file.setFileType(type);
file.setFileName(f.getFileName());
file.setFileUrl(f.getFileUrl());
file.setCreateTime(DateUtils.getCurrentTime());
file.setUpdateTime(DateUtils.getCurrentTime());
return file;
}).collect(Collectors.toList());
}
/**
* 批量流转所有子单到下一节点,并流转主工单
*
* @param changeRecordId 主工单ID
......
package com.netease.mail.yanxuan.change.biz.service;
import java.util.List;
import com.netease.mail.yanxuan.change.common.enums.FileTypeEnum;
import com.netease.mail.yanxuan.change.dal.entity.ChangeSubFlowFile;
/**
* 子单文件服务
*/
public interface ChangeSubFlowFileService {
/**
* 保存文件
*/
void saveRecord(ChangeSubFlowFile file);
/**
* 批量保存文件
*/
void batchSaveRecord(List<ChangeSubFlowFile> files);
/**
* 根据子单记录ID查询文件列表
*/
List<ChangeSubFlowFile> getFileList(Long subFlowRecordId);
/**
* 根据子单记录ID删除文件
*/
Integer deleteBySubFlowRecordId(Long subFlowRecordId);
/**
* 根据子单记录ID和文件类型删除文件
*/
void deleteBySubFlowRecordIdAndType(Long subFlowRecordId, FileTypeEnum type);
}
package com.netease.mail.yanxuan.change.biz.service.impl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.netease.mail.yanxuan.change.biz.service.ChangeSubFlowFileService;
import com.netease.mail.yanxuan.change.common.enums.FileTypeEnum;
import com.netease.mail.yanxuan.change.dal.entity.ChangeSubFlowFile;
import com.netease.mail.yanxuan.change.dal.mapper.ChangeSubFlowFileMapper;
/**
* 子单文件服务实现
*/
@Service
public class ChangeSubFlowFileServiceImpl implements ChangeSubFlowFileService {
@Autowired
private ChangeSubFlowFileMapper changeSubFlowFileMapper;
@Override
public void saveRecord(ChangeSubFlowFile file) {
changeSubFlowFileMapper.insertSelective(file);
}
@Override
public void batchSaveRecord(List<ChangeSubFlowFile> files) {
changeSubFlowFileMapper.insertList(files);
}
@Override
public List<ChangeSubFlowFile> getFileList(Long subFlowRecordId) {
return changeSubFlowFileMapper.selectBySubFlowRecordId(subFlowRecordId);
}
@Override
public Integer deleteBySubFlowRecordId(Long subFlowRecordId) {
return changeSubFlowFileMapper.deleteBySubFlowRecordId(subFlowRecordId);
}
@Override
public void deleteBySubFlowRecordIdAndType(Long subFlowRecordId, FileTypeEnum type) {
changeSubFlowFileMapper.deleteBySubFlowRecordIdAndType(subFlowRecordId, type.getType());
}
}
package com.netease.mail.yanxuan.change.dal.entity;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 子单文件实体
*/
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Data
@Entity
@Table(name = "TB_YX_QC_CHANGE_SUB_FLOW_FILE")
public class ChangeSubFlowFile {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
/**
* 子单记录ID
*/
private Long subFlowRecordId;
/**
* 文件名
*/
private String fileName;
/**
* 文件URL
*/
private String fileUrl;
/**
* 文件类型
* @see com.netease.mail.yanxuan.change.common.enums.FileTypeEnum
*/
private Integer fileType;
/**
* 创建时间
*/
private Long createTime;
/**
* 更新时间
*/
private Long updateTime;
}
......@@ -89,6 +89,27 @@ public class ChangeSubFlowRecord {
private String rejectReason;
/**
* 变更结论(提交执行结果时填写)
* @see com.netease.mail.yanxuan.change.common.enums.ChangeResultEnum
*/
private Integer changeResult;
/**
* 备注
*/
private String remark;
/**
* 取消原因
*/
private String cancelReason;
/**
* 变更确认结果时间(延期时使用)
*/
private Long changeConfirmResultTime;
/**
* 创建时间
*/
private Long createTime;
......
package com.netease.mail.yanxuan.change.dal.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import com.netease.mail.yanxuan.change.dal.entity.ChangeSubFlowFile;
/**
* 子单文件 Mapper
*/
@Mapper
public interface ChangeSubFlowFileMapper extends tk.mybatis.mapper.common.Mapper<ChangeSubFlowFile> {
/**
* 根据子单记录ID查询文件列表
*/
@Select("SELECT * FROM TB_YX_QC_CHANGE_SUB_FLOW_FILE WHERE sub_flow_record_id = #{subFlowRecordId}")
List<ChangeSubFlowFile> selectBySubFlowRecordId(@Param("subFlowRecordId") Long subFlowRecordId);
/**
* 批量插入文件
*/
@Insert({ "<script>",
"insert into TB_YX_QC_CHANGE_SUB_FLOW_FILE(sub_flow_record_id, file_type, file_name, file_url, create_time, update_time) values ",
"<foreach collection='list' item='item' index='index' separator=','>",
"(#{item.subFlowRecordId}, #{item.fileType}, #{item.fileName}, #{item.fileUrl}, #{item.createTime}, #{item.updateTime})",
"</foreach>", "</script>" })
void insertList(List<ChangeSubFlowFile> files);
/**
* 根据子单记录ID删除文件
*/
@Delete("delete from TB_YX_QC_CHANGE_SUB_FLOW_FILE where sub_flow_record_id = #{subFlowRecordId}")
Integer deleteBySubFlowRecordId(@Param("subFlowRecordId") Long subFlowRecordId);
/**
* 根据子单记录ID和文件类型删除文件
*/
@Delete("delete from TB_YX_QC_CHANGE_SUB_FLOW_FILE where sub_flow_record_id = #{subFlowRecordId} and file_type = #{type}")
void deleteBySubFlowRecordIdAndType(@Param("subFlowRecordId") Long subFlowRecordId, @Param("type") Integer type);
}
......@@ -55,5 +55,31 @@ public class ChangeSubFlowSubmitReq {
* 拒绝原因(审批不通过时必填)
*/
private String rejectReason;
/**
* 变更结论(提交执行结果时使用)
* @see com.netease.mail.yanxuan.change.common.enums.ChangeResultEnum
*/
private Integer changeResult;
/**
* 备注
*/
private String remark;
/**
* 取消原因(变更结论为取消时必填)
*/
private String cancelReason;
/**
* 变更确认结果时间(延期时必填)
*/
private Long changeConfirmResultTime;
/**
* 变更结果文件列表
*/
private List<ChangeFlowFile> changeResultFiles;
}
......@@ -13,12 +13,16 @@
<result column="change_commander" jdbcType="VARCHAR" property="changeCommander" />
<result column="change_plan_approved" jdbcType="TINYINT" property="changePlanApproved" />
<result column="reject_reason" jdbcType="VARCHAR" property="rejectReason" />
<result column="change_result" jdbcType="INTEGER" property="changeResult" />
<result column="remark" jdbcType="VARCHAR" property="remark" />
<result column="cancel_reason" jdbcType="VARCHAR" property="cancelReason" />
<result column="change_confirm_result_time" jdbcType="BIGINT" property="changeConfirmResultTime" />
<result column="create_time" jdbcType="BIGINT" property="createTime" />
<result column="update_time" jdbcType="BIGINT" property="updateTime" />
</resultMap>
<sql id="Base_Column_List">
id, change_record_id, sub_flow_id, sub_flow_node, status, approver, change_exec_user_email, change_exec_department, change_commander, change_plan_approved, reject_reason, create_time, update_time
id, change_record_id, sub_flow_id, sub_flow_node, status, approver, change_exec_user_email, change_exec_department, change_commander, change_plan_approved, reject_reason, change_result, remark, cancel_reason, change_confirm_result_time, create_time, update_time
</sql>
<select id="selectByCondition" resultMap="BaseResultMap" parameterType="com.netease.mail.yanxuan.change.dal.meta.model.req.ChangeSubFlowListQueryReq">
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment