docs(erp): 补充服务器部署模块注释

dev
zch 4 days ago
parent f33d1070ff
commit 36d2b95420

@ -1,10 +1,6 @@
package org.dromara.oa.erp.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.tenant.core.TenantEntity;
@ -13,6 +9,10 @@ import java.io.Serial;
/**
* erp_server_deploy
* <p>
* /
* 便
* deployCode isCurrent
*
* @author zch
* @date 2026-06-03
@ -26,68 +26,75 @@ public class ErpServerDeploy extends TenantEntity {
private static final long serialVersionUID = 1L;
/**
* ID
* ID
*/
@TableId(value = "deploy_id", type = IdType.ASSIGN_ID)
private Long deployId;
/**
*
*
*/
private String deployCode;
/**
*
* erp_server_info serverCode
*/
private String serverCode;
/**
*
* deployCode 1
*/
private Integer version;
/**
* 1 0
* <p>
* 1 deployCode 0
* 稿0
*/
private String isCurrent;
/**
* /
* /500
*/
private String deployPath;
/**
*
* 80808080,80818080-80901-65535
*/
private String deployPort;
/**
* 1 0
* 1 0访
*/
private String portExposed;
/**
* /
* /"部署CRM后端服务"
*/
private String deployPurpose;
/**
* ID
* ID sys_user ID
*/
private Long personId;
/**
* OSS ID
* OSS IDID
*/
private String ossId;
/**
* deploy_status
* deploy_status稿///
* <p>
* flowStatus 稿DRAFTAPPROVINGCOMPLETEDINVALID
*/
private String deployStatus;
/**
* wf_business_status
* wf_business_status稿///退///
* <p>
* Warm-Flow
*/
private String flowStatus;
@ -97,13 +104,13 @@ public class ErpServerDeploy extends TenantEntity {
private String remark;
/**
* 0 1
* 0 1MyBatis-Plus
*/
@TableLogic
private String delFlag;
/**
*
* MPJ sys_user
*/
@TableField(exist = false)
private String personName;

@ -12,6 +12,9 @@ import java.io.Serial;
/**
* erp_server_deploy_log
* <p>
* JSON
*
*
* @author zch
* @date 2026-06-03
@ -25,28 +28,28 @@ public class ErpServerDeployLog extends TenantEntity {
private static final long serialVersionUID = 1L;
/**
* ID
* ID
*/
@TableId(value = "log_id", type = IdType.AUTO)
private Long logId;
/**
* ID
* ID erp_server_deploy deploy_id
*/
private Long deployId;
/**
* JSON
* JSON field/label/oldValue/newValue
*/
private String changeContent;
/**
*
* "部署项 SD20260603001 第 2 版变更"
*/
private String changeSummary;
/**
* 0 1
* 0 1MyBatis-Plus
*/
@TableLogic
private String delFlag;

@ -14,6 +14,10 @@ import java.util.Date;
/**
* erp_server_info
* <p>
* /
*
* serverCode isCurrent
*
* @author zch
* @date 2026-06-03
@ -27,123 +31,132 @@ public class ErpServerInfo extends TenantEntity {
private static final long serialVersionUID = 1L;
/**
* ID
* ID
*/
@TableId(value = "server_id", type = IdType.ASSIGN_ID)
private Long serverId;
/**
*
*
*/
private String serverCode;
/**
*
* "CRM生产服务器""测试环境服务器"
*/
private String serverName;
/**
*
* serverCode 1
*/
private Integer version;
/**
* 1 0
* <p>
* 1 serverCode 0
* 稿0
*/
private String isCurrent;
/**
* server_type
* server_typelocal=cloud=
*/
private String serverType;
/**
* acquisition_type
* acquisition_typepurchase=lease=
*/
private String acquisitionType;
/**
* os_type
* os_type Linux/Windows
*/
private String osType;
/**
* IP1 0
* IP1 0访
*/
private String hasPublicIp;
/**
* IP
* IPIPIPv4IPv6
*/
private String ipAddress;
/**
*
*
*/
private String location;
/**
*
*
*/
private BigDecimal purchaseAmount;
/**
*
* Dell/HP/Lenovo serverType local
*/
private String brand;
/**
*
* PowerEdge R740 serverType local
*/
private String model;
/**
*
* CPU//
*/
private String hardwareSpec;
/**
*
*
*/
private Date leaseStartDate;
/**
*
*
*/
private Date leaseEndDate;
/**
*
*
*/
private Integer leasePackageYears;
/**
*
*
*/
private BigDecimal leaseAmount;
/**
* server_status
* server_status稿///
* <p>
* flowStatus 稿DRAFTAPPROVINGCOMPLETEDINVALID
*/
private String serverStatus;
/**
* wf_business_status
* wf_business_status稿///退///
* <p>
* Warm-Flow
*/
private String flowStatus;
/**
* JSON
* JSONcpu/memory/disk/bandwidth/region
* <p>
* Token
*/
private String extAttr;
/**
*
*
*/
private String remark;
/**
* 0 1
* 0 1MyBatis-Plus
*/
@TableLogic
private String delFlag;

@ -37,17 +37,18 @@ import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.*;
import java.util.regex.Pattern;
/**
* Service
* <p>
*
* 1.
* 2. Warm-Flow 稿/退/
* 3.
* 4.
* 5.
*
* @author zch
* @date 2026-06-03
@ -57,7 +58,7 @@ import java.util.regex.Pattern;
@Service
public class ErpServerDeployServiceImpl implements IErpServerDeployService {
/** 服务器部署操作流程编码 */
/** 服务器部署操作流程编码(对应 Warm-Flow 中的流程定义编码) */
public static final String FLOW_CODE_DEPLOY = "OASD";
/**
@ -65,35 +66,57 @@ public class ErpServerDeployServiceImpl implements IErpServerDeployService {
*/
private static final String DEPLOY_CODE_RULE = "1036";
private static final String YES = "1";
private static final String NO = "0";
private static final String YES = "1"; // 是
private static final String NO = "0"; // 否
/** 端口格式正则:支持单端口(8080)、逗号分隔(8080,8081)、端口范围(8080-8090) */
private static final Pattern PORT_PATTERN = Pattern.compile("^\\d{1,5}(-\\d{1,5})?(,\\d{1,5}(-\\d{1,5})?)*$");
/** 危险路径字符正则:防止命令注入,禁止分号、管道符、反引号、美元符号、重定向符、换行等 */
private static final Pattern DANGEROUS_PATH_PATTERN = Pattern.compile("[;&|`$<>\\r\\n]");
private final ErpServerDeployMapper baseMapper;
private final ErpServerDeployLogMapper deployLogMapper;
private final ErpServerInfoMapper serverInfoMapper;
private final ErpServerDeployMapper baseMapper; // 部署信息 Mapper
private final ErpServerDeployLogMapper deployLogMapper; // 部署变更日志 Mapper
private final ErpServerInfoMapper serverInfoMapper; // 服务器基础信息 Mapper用于校验服务器状态
/** 远程工作流服务Dubbo 调用,用于发起流程、删除流程实例) */
@DubboReference(timeout = 30000)
private RemoteWorkflowService remoteWorkflowService;
/** 远程编码规则服务Dubbo 调用,用于自动生成部署编号) */
@DubboReference(timeout = 30000)
private RemoteCodeRuleService remoteCodeRuleService;
/**
* ID
* <p>
*
*
* @param deployId ID
* @return VOnull
*/
@Override
public ErpServerDeployVo queryById(Long deployId) {
// 查询部署基本信息
ErpServerDeployVo vo = queryOneById(deployId);
if (vo == null) {
return null;
}
// 补充变更日志列表
vo.setServerDeployLogList(queryLogs(deployId));
// 补充同编码的历史版本列表
if (StringUtils.isNotBlank(vo.getDeployCode())) {
vo.setVersionList(queryVersions(vo.getDeployCode()));
}
return vo;
}
/**
* ID
*
* @param deployId ID
* @return VOnull
*/
private ErpServerDeployVo queryOneById(Long deployId) {
// 使用 MPJ 构造器查询,过滤已删除记录
MPJLambdaWrapper<ErpServerDeploy> lqw = JoinWrappers.lambda(ErpServerDeploy.class)
.selectAll(ErpServerDeploy.class)
.eq(ErpServerDeploy::getDelFlag, NO)
@ -102,14 +125,28 @@ public class ErpServerDeployServiceImpl implements IErpServerDeployService {
return list.isEmpty() ? null : list.get(0);
}
/**
*
*
* @param bo
* @param pageQuery
* @return
*/
@Override
public TableDataInfo<ErpServerDeployVo> queryPageList(ErpServerDeployBo bo, PageQuery pageQuery) {
// 构建查询条件并按创建时间倒序
MPJLambdaWrapper<ErpServerDeploy> lqw = buildQueryWrapper(bo);
lqw.orderByDesc(ErpServerDeploy::getCreateTime);
Page<ErpServerDeployVo> result = baseMapper.selectCustomErpServerDeployVoList(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
*
*
* @param bo
* @return
*/
@Override
public List<ErpServerDeployVo> queryList(ErpServerDeployBo bo) {
MPJLambdaWrapper<ErpServerDeploy> lqw = buildQueryWrapper(bo);
@ -117,6 +154,14 @@ public class ErpServerDeployServiceImpl implements IErpServerDeployService {
return baseMapper.selectCustomErpServerDeployVoList(lqw);
}
/**
*
* <p>
*
*
* @param deployCode
* @return
*/
@Override
public List<ErpServerDeployVo> queryVersions(String deployCode) {
if (StringUtils.isBlank(deployCode)) {
@ -130,6 +175,12 @@ public class ErpServerDeployServiceImpl implements IErpServerDeployService {
return baseMapper.selectCustomErpServerDeployVoList(lqw);
}
/**
*
*
* @param deployId ID
* @return
*/
private List<ErpServerDeployLogVo> queryLogs(Long deployId) {
return deployLogMapper.selectVoList(new LambdaQueryWrapper<ErpServerDeployLog>()
.eq(ErpServerDeployLog::getDeployId, deployId)
@ -137,6 +188,14 @@ public class ErpServerDeployServiceImpl implements IErpServerDeployService {
.orderByDesc(ErpServerDeployLog::getCreateTime));
}
/**
*
* <p>
* BO like/eq
*
* @param bo BO
* @return MPJ
*/
private MPJLambdaWrapper<ErpServerDeploy> buildQueryWrapper(ErpServerDeployBo bo) {
return JoinWrappers.lambda(ErpServerDeploy.class)
.selectAll(ErpServerDeploy.class)
@ -151,38 +210,71 @@ public class ErpServerDeployServiceImpl implements IErpServerDeployService {
.eq(StringUtils.isNotBlank(bo.getIsCurrent()), ErpServerDeploy::getIsCurrent, bo.getIsCurrent());
}
/**
* 稿
* <p>
* 稿
*
*
* @param bo BO
* @return VO
*/
@Override
@Transactional(rollbackFor = Exception.class)
public ErpServerDeployVo draft(ErpServerDeployBo bo) {
// 准备数据:校验服务器状态、生成编号、计算版本号
prepareForSave(bo, false);
// 行级锁锁定同编码的所有版本记录,防止并发版本号冲突
lockVersionRows(bo.getDeployCode());
// 设置草稿状态
bo.setDeployStatus(OAStatusEnum.DRAFT.getStatus());
bo.setFlowStatus(BusinessStatusEnum.DRAFT.getStatus());
bo.setIsCurrent(NO);
// 保存(新建版本或更新现有记录)
saveDraftOrVersion(bo);
return queryById(bo.getDeployId());
}
/**
*
* <p>
*
*
* 使 @GlobalTransactional OA +
*
* @param bo BO
* @return VO
* @throws ServiceException //
*/
@Override
@Transactional(rollbackFor = Exception.class)
@GlobalTransactional(rollbackFor = Exception.class)
public ErpServerDeployVo submitAndStartFlow(ErpServerDeployBo bo) {
// 准备数据并设置流程编码
prepareForSave(bo, true);
// 行级锁防止并发版本冲突
lockVersionRows(bo.getDeployCode());
// 清理被退回或撤销的旧流程实例,避免流程引擎中残留数据
deleteReturnedOrCanceledInstance(bo.getDeployId());
// 校验同一部署编码下没有其他审批中的版本
checkNoApprovingVersion(bo.getDeployCode(), bo.getDeployId());
// 设置审批中状态
bo.setDeployStatus(OAStatusEnum.APPROVING.getStatus());
bo.setFlowStatus(BusinessStatusEnum.WAITING.getStatus());
bo.setIsCurrent(NO);
// 保存数据(新建版本或更新现有记录)
saveDraftOrVersion(bo);
// 填充工作流变量和业务扩展信息
fillWorkflowParams(bo);
// 构建远程流程启动请求
RemoteStartProcess startProcess = new RemoteStartProcess();
startProcess.setBusinessId(String.valueOf(bo.getDeployId()));
startProcess.setFlowCode(bo.getFlowCode());
startProcess.setVariables(bo.getVariables());
startProcess.setBizExt(bo.getBizExt());
bo.getBizExt().setBusinessId(startProcess.getBusinessId());
// 调用远程工作流服务发起流程
boolean started = remoteWorkflowService.startCompleteTask(startProcess);
if (!started) {
throw new ServiceException("服务器部署流程发起异常");
@ -190,37 +282,68 @@ public class ErpServerDeployServiceImpl implements IErpServerDeployService {
return queryById(bo.getDeployId());
}
/**
* BO
* <p>
*
*
* @param bo BO
* @return
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean updateByBo(ErpServerDeployBo bo) {
if (bo.getDeployId() == null) {
throw new ServiceException("部署ID不能为空");
}
// 校验关联服务器是否已审批通过
checkServerActive(bo.getServerCode());
// BO转Entity
ErpServerDeploy update = MapstructUtils.convert(bo, ErpServerDeploy.class);
// 保存前字段校验
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
* 稿
* <p>
*
* - //
* -
*
*
* @param bo BO
*/
private void saveDraftOrVersion(ErpServerDeployBo bo) {
// 查询现有记录
ErpServerDeploy existing = bo.getDeployId() == null ? null : baseMapper.selectById(bo.getDeployId());
// 判断是否需要创建新版本
boolean createNewVersion = existing == null || shouldCreateNewVersion(existing);
ErpServerDeploy oldCurrent = null;
// 如果创建新版本且有部署编码,先获取旧当前版本(用于变更日志对比)
if (createNewVersion && StringUtils.isNotBlank(bo.getDeployCode())) {
oldCurrent = getCurrentVersion(bo.getDeployCode());
}
if (createNewVersion) {
// 清空ID让数据库生成新记录
bo.setDeployId(null);
// 计算下一个版本号
bo.setVersion(calcNextVersion(bo.getDeployCode()));
// BO转Entity
ErpServerDeploy add = MapstructUtils.convert(bo, ErpServerDeploy.class);
// 保存前校验
validEntityBeforeSave(add);
if (baseMapper.insert(add) <= 0) {
throw new ServiceException("保存部署信息失败");
}
// 回写生成的ID到BO
bo.setDeployId(add.getDeployId());
// 如果有旧当前版本,生成变更日志
saveChangeLogIfNeeded(add, oldCurrent);
return;
}
// 不需要新版本:直接更新现有记录
if (bo.getVersion() == null) {
bo.setVersion(existing.getVersion());
}
@ -229,20 +352,37 @@ public class ErpServerDeployServiceImpl implements IErpServerDeployService {
if (baseMapper.updateById(update) <= 0) {
throw new ServiceException("更新部署信息失败");
}
// 替换变更日志(先删后建)
replaceChangeLogIfNeeded(update, getCurrentVersion(update.getDeployCode()));
}
/**
*
* <p>
* COMPLETEDFINISHisCurrent=1
*
* @param existing
* @return true=false=
*/
private boolean shouldCreateNewVersion(ErpServerDeploy existing) {
return OAStatusEnum.COMPLETED.getStatus().equals(existing.getDeployStatus())
|| BusinessStatusEnum.FINISH.getStatus().equals(existing.getFlowStatus())
|| YES.equals(existing.getIsCurrent());
}
/**
*
*
* @param bo BO
* @param submit true=false=稿
*/
private void prepareForSave(ErpServerDeployBo bo, boolean submit) {
if (bo == null) {
throw new ServiceException("部署信息不能为空");
}
// 校验关联服务器是否存在且已审批通过
checkServerActive(bo.getServerCode());
// 如果没有部署编码,调用远程编码规则服务自动生成
if (StringUtils.isBlank(bo.getDeployCode())) {
String code = remoteCodeRuleService.selectCodeRuleCode(DEPLOY_CODE_RULE);
if (StringUtils.isBlank(code)) {
@ -250,14 +390,24 @@ public class ErpServerDeployServiceImpl implements IErpServerDeployService {
}
bo.setDeployCode(code);
}
// 新记录且未指定版本号时,自动计算下一个版本号
if (bo.getVersion() == null && bo.getDeployId() == null) {
bo.setVersion(calcNextVersion(bo.getDeployCode()));
}
// 提交审批时设置流程编码
if (submit) {
bo.setFlowCode(FLOW_CODE_DEPLOY);
}
}
/**
*
* <p>
* +1
*
* @param deployCode
* @return 1
*/
private Integer calcNextVersion(String deployCode) {
if (StringUtils.isBlank(deployCode)) {
return 1;
@ -265,6 +415,7 @@ public class ErpServerDeployServiceImpl implements IErpServerDeployService {
List<ErpServerDeploy> list = baseMapper.selectList(new LambdaQueryWrapper<ErpServerDeploy>()
.eq(ErpServerDeploy::getDeployCode, deployCode)
.eq(ErpServerDeploy::getDelFlag, NO));
// 取最大版本号 +1如果没有记录则返回1
return list.stream()
.map(ErpServerDeploy::getVersion)
.filter(Objects::nonNull)
@ -272,6 +423,13 @@ public class ErpServerDeployServiceImpl implements IErpServerDeployService {
.orElse(0) + 1;
}
/**
*
* <p>
* 使 SELECT ... FOR UPDATE
*
* @param deployCode
*/
private void lockVersionRows(String deployCode) {
if (StringUtils.isBlank(deployCode)) {
return;
@ -283,6 +441,14 @@ public class ErpServerDeployServiceImpl implements IErpServerDeployService {
.last("for update"));
}
/**
* 退
* <p>
* 退BACKCANCEL
*
*
* @param deployId ID
*/
private void deleteReturnedOrCanceledInstance(Long deployId) {
if (deployId == null) {
return;
@ -291,6 +457,7 @@ public class ErpServerDeployServiceImpl implements IErpServerDeployService {
if (existing == null) {
return;
}
// 仅在退回或撤销状态下才需要清理
if (BusinessStatusEnum.BACK.getStatus().equals(existing.getFlowStatus())
|| BusinessStatusEnum.CANCEL.getStatus().equals(existing.getFlowStatus())) {
boolean deleted = remoteWorkflowService.deleteInstance(Collections.singletonList(deployId));
@ -300,6 +467,15 @@ public class ErpServerDeployServiceImpl implements IErpServerDeployService {
}
}
/**
*
* <p>
*
*
* @param deployCode
* @param currentDeployId ID
* @throws ServiceException
*/
private void checkNoApprovingVersion(String deployCode, Long currentDeployId) {
Long count = baseMapper.selectCount(new LambdaQueryWrapper<ErpServerDeploy>()
.eq(ErpServerDeploy::getDeployCode, deployCode)
@ -311,10 +487,19 @@ public class ErpServerDeployServiceImpl implements IErpServerDeployService {
}
}
/**
*
* <p>
* COMPLETED
*
* @param serverCode
* @throws ServiceException //
*/
private void checkServerActive(String serverCode) {
if (StringUtils.isBlank(serverCode)) {
throw new ServiceException("请选择关联服务器");
}
// 查询当前生效版本的服务器
ErpServerInfo server = serverInfoMapper.selectOne(new LambdaQueryWrapper<ErpServerInfo>()
.eq(ErpServerInfo::getServerCode, serverCode)
.eq(ErpServerInfo::getIsCurrent, YES)
@ -323,11 +508,20 @@ public class ErpServerDeployServiceImpl implements IErpServerDeployService {
if (server == null) {
throw new ServiceException("关联服务器不存在或尚未生效");
}
// 服务器必须已审批通过才能发起部署
if (!OAStatusEnum.COMPLETED.getStatus().equals(server.getServerStatus())) {
throw new ServiceException("关联服务器尚未审批通过,无法发起部署操作");
}
}
/**
*
* <p>
*
*
* @param entity
* @throws ServiceException
*/
private void validEntityBeforeSave(ErpServerDeploy entity) {
if (entity == null) {
throw new ServiceException("部署信息不能为空");
@ -344,24 +538,44 @@ public class ErpServerDeployServiceImpl implements IErpServerDeployService {
if (StringUtils.isBlank(entity.getDeployPurpose())) {
throw new ServiceException("部署用途不能为空");
}
// 部署路径安全校验(防命令注入)
validDeployPath(entity.getDeployPath());
// 部署端口格式校验
validDeployPort(entity.getDeployPort());
}
/**
*
* <p>
* 500
*
* @param deployPath
*/
private void validDeployPath(String deployPath) {
if (deployPath.length() > 500) {
throw new ServiceException("部署位置长度不能超过500个字符");
}
// 检测危险字符,防止命令注入
if (DANGEROUS_PATH_PATTERN.matcher(deployPath).find()) {
throw new ServiceException("部署位置不能包含命令连接符或换行等危险字符");
}
}
/**
*
* <p>
* (8080)(8080,8081)(8080-8090)
* 1-65535
*
* @param deployPort
*/
private void validDeployPort(String deployPort) {
// 去除空格后进行格式匹配
String normalized = deployPort.replace(" ", "");
if (!PORT_PATTERN.matcher(normalized).matches()) {
throw new ServiceException("部署端口格式不正确,支持单端口、逗号分隔端口或端口范围");
}
// 逐个校验端口范围的有效性
for (String item : normalized.split(",")) {
String[] range = item.split("-");
int start = parsePort(range[0]);
@ -372,6 +586,13 @@ public class ErpServerDeployServiceImpl implements IErpServerDeployService {
}
}
/**
*
*
* @param port
* @return
* @throws ServiceException 1-65535
*/
private int parsePort(String port) {
int value;
try {
@ -385,6 +606,12 @@ public class ErpServerDeployServiceImpl implements IErpServerDeployService {
return value;
}
/**
*
*
* @param deployCode
* @return null
*/
private ErpServerDeploy getCurrentVersion(String deployCode) {
return baseMapper.selectOne(new LambdaQueryWrapper<ErpServerDeploy>()
.eq(ErpServerDeploy::getDeployCode, deployCode)
@ -393,14 +620,25 @@ public class ErpServerDeployServiceImpl implements IErpServerDeployService {
.last("limit 1"));
}
/**
*
* <p>
*
* 1
*
* @param newVersion
* @param oldVersion null
*/
private void saveChangeLogIfNeeded(ErpServerDeploy newVersion, ErpServerDeploy oldVersion) {
if (oldVersion == null || newVersion.getVersion() == null || newVersion.getVersion() <= 1) {
return;
}
// 对比字段差异
List<Map<String, Object>> changes = buildChanges(oldVersion, newVersion);
if (changes.isEmpty()) {
return;
}
// 构建变更日志并保存
ErpServerDeployLog log = new ErpServerDeployLog();
log.setDeployId(newVersion.getDeployId());
log.setChangeContent(JSONUtil.toJsonStr(changes));
@ -408,12 +646,31 @@ public class ErpServerDeployServiceImpl implements IErpServerDeployService {
deployLogMapper.insert(log);
}
/**
*
* <p>
*
*
* @param newVersion
* @param oldVersion
*/
private void replaceChangeLogIfNeeded(ErpServerDeploy newVersion, ErpServerDeploy oldVersion) {
// 先删除该部署的所有旧变更日志
deployLogMapper.delete(new LambdaQueryWrapper<ErpServerDeployLog>()
.eq(ErpServerDeployLog::getDeployId, newVersion.getDeployId()));
// 重新生成变更日志
saveChangeLogIfNeeded(newVersion, oldVersion);
}
/**
*
* <p>
*
*
* @param oldVersion
* @param newVersion
* @return field/label/oldValue/newValue
*/
private List<Map<String, Object>> buildChanges(ErpServerDeploy oldVersion, ErpServerDeploy newVersion) {
List<Map<String, Object>> changes = new ArrayList<>();
addChange(changes, "server_code", "关联服务器", oldVersion.getServerCode(), newVersion.getServerCode());
@ -426,6 +683,17 @@ public class ErpServerDeployServiceImpl implements IErpServerDeployService {
return changes;
}
/**
*
* <p>
*
*
* @param changes
* @param field
* @param label
* @param oldValue
* @param newValue
*/
private void addChange(List<Map<String, Object>> changes, String field, String label, Object oldValue, Object newValue) {
if (Objects.equals(oldValue, newValue)) {
return;
@ -438,8 +706,16 @@ public class ErpServerDeployServiceImpl implements IErpServerDeployService {
changes.add(change);
}
/**
*
* <p>
* ID
*
* @param bo BO
*/
private void fillWorkflowParams(ErpServerDeployBo bo) {
bo.setFlowCode(FLOW_CODE_DEPLOY);
// 设置流程变量putIfAbsent 避免覆盖前端传入的自定义变量)
Map<String, Object> vars = bo.getVariables();
vars.putIfAbsent("deployCode", bo.getDeployCode());
vars.putIfAbsent("serverCode", bo.getServerCode());
@ -447,6 +723,7 @@ public class ErpServerDeployServiceImpl implements IErpServerDeployService {
vars.put("ignore", true);
bo.setVariables(vars);
// 设置业务扩展信息(用于工作流待办列表展示)
RemoteFlowInstanceBizExt bizExt = bo.getBizExt();
if (StringUtils.isBlank(bizExt.getBusinessTitle())) {
bizExt.setBusinessTitle(bo.getDeployCode() + "服务器部署审批");
@ -457,10 +734,21 @@ public class ErpServerDeployServiceImpl implements IErpServerDeployService {
bo.setBizExt(bizExt);
}
/**
*
* <p>
* 稿DRAFT
*
*
* @param ids ID
* @param isValid
* @return
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if (isValid) {
// 逐条校验:仅草稿状态可删除
for (Long id : ids) {
ErpServerDeploy deploy = baseMapper.selectById(id);
if (deploy == null) {
@ -472,46 +760,84 @@ public class ErpServerDeployServiceImpl implements IErpServerDeployService {
}
}
}
// 先删除关联的变更日志
deployLogMapper.delete(new LambdaQueryWrapper<ErpServerDeployLog>().in(ErpServerDeployLog::getDeployId, ids));
// 再删除部署记录(逻辑删除)
return baseMapper.deleteByIds(ids) > 0;
}
/**
* OASD
* <p>
* Warm-Flow ProcessEvent
*
*
* @param processEvent
*/
@EventListener(condition = "#processEvent.flowCode == 'OASD'")
@Transactional(rollbackFor = Exception.class)
public void processHandler(ProcessEvent processEvent) {
// 在事件对应的租户上下文中执行,确保多租户数据隔离
TenantHelper.dynamic(processEvent.getTenantId(), () -> handleProcessEvent(processEvent));
}
/**
*
* <p>
*
* - WAITING APPROVING
* - FINISH COMPLETED
* - INVALID/TERMINATION/ INVALID
* - BACK/CANCEL退/ DRAFT稿
*
* @param processEvent
*/
public void handleProcessEvent(ProcessEvent processEvent) {
log.info("服务器部署流程事件: {}", processEvent);
ErpServerDeploy deploy = baseMapper.selectById(Long.valueOf(processEvent.getBusinessId()));
if (deploy == null) {
return;
}
// 更新流程状态
deploy.setFlowStatus(processEvent.getStatus());
// 根据流程状态联动更新业务状态
if (Objects.equals(processEvent.getStatus(), BusinessStatusEnum.WAITING.getStatus())) {
// 审批中
deploy.setDeployStatus(OAStatusEnum.APPROVING.getStatus());
} else if (Objects.equals(processEvent.getStatus(), BusinessStatusEnum.FINISH.getStatus())) {
// 审批通过:设为已生效并激活当前版本
deploy.setDeployStatus(OAStatusEnum.COMPLETED.getStatus());
activateCurrentVersion(deploy);
} else if (Objects.equals(processEvent.getStatus(), BusinessStatusEnum.INVALID.getStatus())
|| Objects.equals(processEvent.getStatus(), BusinessStatusEnum.TERMINATION.getStatus())) {
// 失效或终止:设为已作废
deploy.setDeployStatus(OAStatusEnum.INVALID.getStatus());
deploy.setIsCurrent(NO);
} else if (Objects.equals(processEvent.getStatus(), BusinessStatusEnum.BACK.getStatus())
|| Objects.equals(processEvent.getStatus(), BusinessStatusEnum.CANCEL.getStatus())) {
// 退回或撤销:回退为草稿状态
deploy.setDeployStatus(OAStatusEnum.DRAFT.getStatus());
deploy.setIsCurrent(NO);
}
baseMapper.updateById(deploy);
}
/**
*
* <p>
* isCurrent 01
*
*
* @param deploy
*/
private void activateCurrentVersion(ErpServerDeploy deploy) {
// 将同编码的其他版本全部置为非当前版本
baseMapper.update(null, new LambdaUpdateWrapper<ErpServerDeploy>()
.set(ErpServerDeploy::getIsCurrent, NO)
.eq(ErpServerDeploy::getDeployCode, deploy.getDeployCode())
.eq(ErpServerDeploy::getDelFlag, NO)
.ne(ErpServerDeploy::getDeployId, deploy.getDeployId()));
// 当前版本置为生效
deploy.setIsCurrent(YES);
}
}

@ -33,18 +33,18 @@ import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.*;
import java.util.regex.Pattern;
/**
* Service
* <p>
*
* 1.
* 2. Warm-Flow 稿/退/
* 3.
* 4. IPIPv4/IPv6
* 5. /
*
* @author zch
* @date 2026-06-03
@ -54,7 +54,7 @@ import java.util.regex.Pattern;
@Service
public class ErpServerInfoServiceImpl implements IErpServerInfoService {
/** 服务器登记流程编码 */
/** 服务器登记流程编码(对应 Warm-Flow 中的流程定义编码) */
public static final String FLOW_CODE_SERVER = "OASR";
/**
@ -62,43 +62,71 @@ public class ErpServerInfoServiceImpl implements IErpServerInfoService {
*/
private static final String SERVER_CODE_RULE = "1035";
private static final String YES = "1";
private static final String NO = "0";
private static final String LOCAL_SERVER = "local";
private static final String LEASE = "lease";
private static final String YES = "1"; // 是
private static final String NO = "0"; // 否
private static final String LOCAL_SERVER = "local"; // 本地服务器类型标识
private static final String LEASE = "lease"; // 租赁获取方式标识
/** IPv4地址正则 */
private static final Pattern IPV4_PATTERN = Pattern.compile(
"^(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}$");
/** IPv6候选正则仅做初步筛选后续再结合冒号和长度判断 */
private static final Pattern IPV6_CANDIDATE_PATTERN = Pattern.compile("^[0-9a-fA-F:]+$");
/** 扩展属性允许的白名单字段集合 */
private static final Set<String> EXT_ATTR_ALLOWED_KEYS = Set.of(
"cpu", "memory", "disk", "bandwidth", "region", "zone", "instanceId", "vendor",
"consoleUrl", "assetNo", "warrantyNo", "cabinetNo", "rackNo", "networkArea",
"ownerDept", "backupPolicy", "monitorPolicy", "description");
private final ErpServerInfoMapper baseMapper;
private final ErpServerInfoMapper baseMapper; // 服务器基础信息 Mapper
/** 远程工作流服务Dubbo 调用,用于发起流程、删除流程实例) */
@DubboReference(timeout = 30000)
private RemoteWorkflowService remoteWorkflowService;
/** 远程编码规则服务Dubbo 调用,用于自动生成服务器编号) */
@DubboReference(timeout = 30000)
private RemoteCodeRuleService remoteCodeRuleService;
/**
* ID
* <p>
*
*
* @param serverId ID
* @return VOnull
*/
@Override
public ErpServerInfoVo queryById(Long serverId) {
ErpServerInfoVo vo = baseMapper.selectVoById(serverId);
// 补充同编码的历史版本列表
if (vo != null && StringUtils.isNotBlank(vo.getServerCode())) {
vo.setVersionList(queryVersions(vo.getServerCode()));
}
return vo;
}
/**
*
*
* @param bo
* @param pageQuery
* @return
*/
@Override
public TableDataInfo<ErpServerInfoVo> queryPageList(ErpServerInfoBo bo, PageQuery pageQuery) {
// 构建查询条件并按创建时间倒序
MPJLambdaWrapper<ErpServerInfo> lqw = buildQueryWrapper(bo);
lqw.orderByDesc(ErpServerInfo::getCreateTime);
Page<ErpServerInfoVo> result = baseMapper.selectCustomErpServerInfoVoList(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
*
*
* @param bo
* @return
*/
@Override
public List<ErpServerInfoVo> queryList(ErpServerInfoBo bo) {
MPJLambdaWrapper<ErpServerInfo> lqw = buildQueryWrapper(bo);
@ -106,6 +134,14 @@ public class ErpServerInfoServiceImpl implements IErpServerInfoService {
return baseMapper.selectCustomErpServerInfoVoList(lqw);
}
/**
*
* <p>
*
*
* @param serverCode
* @return
*/
@Override
public List<ErpServerInfoVo> queryVersions(String serverCode) {
if (StringUtils.isBlank(serverCode)) {
@ -119,6 +155,14 @@ public class ErpServerInfoServiceImpl implements IErpServerInfoService {
return baseMapper.selectCustomErpServerInfoVoList(lqw);
}
/**
*
* <p>
* BO like/eq
*
* @param bo BO
* @return MPJ
*/
private MPJLambdaWrapper<ErpServerInfo> buildQueryWrapper(ErpServerInfoBo bo) {
return JoinWrappers.lambda(ErpServerInfo.class)
.selectAll(ErpServerInfo.class)
@ -133,38 +177,71 @@ public class ErpServerInfoServiceImpl implements IErpServerInfoService {
.eq(StringUtils.isNotBlank(bo.getIsCurrent()), ErpServerInfo::getIsCurrent, bo.getIsCurrent());
}
/**
* 稿
* <p>
* 稿
*
*
* @param bo BO
* @return VO
*/
@Override
@Transactional(rollbackFor = Exception.class)
public ErpServerInfoVo draft(ErpServerInfoBo bo) {
// 准备数据:生成编号、计算版本号
prepareForSave(bo, false);
// 行级锁锁定同编码的所有版本记录,防止并发版本号冲突
lockVersionRows(bo.getServerCode());
// 设置草稿状态
bo.setServerStatus(OAStatusEnum.DRAFT.getStatus());
bo.setFlowStatus(BusinessStatusEnum.DRAFT.getStatus());
bo.setIsCurrent(NO);
// 保存(新建版本或更新现有记录)
saveDraftOrVersion(bo);
return queryById(bo.getServerId());
}
/**
*
* <p>
*
*
* 使 @GlobalTransactional OA +
*
* @param bo BO
* @return VO
* @throws ServiceException /
*/
@Override
@Transactional(rollbackFor = Exception.class)
@GlobalTransactional(rollbackFor = Exception.class)
public ErpServerInfoVo submitAndStartFlow(ErpServerInfoBo bo) {
// 准备数据并设置流程编码
prepareForSave(bo, true);
// 行级锁防止并发版本冲突
lockVersionRows(bo.getServerCode());
// 清理被退回或撤销的旧流程实例
deleteReturnedOrCanceledInstance(bo.getServerId());
// 校验同一服务器编码下没有其他审批中的版本
checkNoApprovingVersion(bo.getServerCode(), bo.getServerId());
// 设置审批中状态
bo.setServerStatus(OAStatusEnum.APPROVING.getStatus());
bo.setFlowStatus(BusinessStatusEnum.WAITING.getStatus());
bo.setIsCurrent(NO);
// 保存数据(新建版本或更新现有记录)
saveDraftOrVersion(bo);
// 填充工作流变量和业务扩展信息
fillWorkflowParams(bo);
// 构建远程流程启动请求
RemoteStartProcess startProcess = new RemoteStartProcess();
startProcess.setBusinessId(String.valueOf(bo.getServerId()));
startProcess.setFlowCode(bo.getFlowCode());
startProcess.setVariables(bo.getVariables());
startProcess.setBizExt(bo.getBizExt());
bo.getBizExt().setBusinessId(startProcess.getBusinessId());
// 调用远程工作流服务发起流程
boolean started = remoteWorkflowService.startCompleteTask(startProcess);
if (!started) {
throw new ServiceException("服务器登记流程发起异常");
@ -172,31 +249,58 @@ public class ErpServerInfoServiceImpl implements IErpServerInfoService {
return queryById(bo.getServerId());
}
/**
* BO
* <p>
*
*
* @param bo BO
* @return
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean updateByBo(ErpServerInfoBo bo) {
if (bo.getServerId() == null) {
throw new ServiceException("服务器ID不能为空");
}
// BO转Entity
ErpServerInfo entity = MapstructUtils.convert(bo, ErpServerInfo.class);
// 保存前字段校验
validEntityBeforeSave(entity);
return baseMapper.updateById(entity) > 0;
}
/**
* 稿
* <p>
*
* - //
* -
*
* @param bo BO
*/
private void saveDraftOrVersion(ErpServerInfoBo bo) {
// 查询现有记录
ErpServerInfo existing = bo.getServerId() == null ? null : baseMapper.selectById(bo.getServerId());
// 判断是否需要创建新版本
boolean createNewVersion = existing == null || shouldCreateNewVersion(existing);
if (createNewVersion) {
// 清空ID让数据库生成新记录
bo.setServerId(null);
// 计算下一个版本号
bo.setVersion(calcNextVersion(bo.getServerCode()));
// BO转Entity
ErpServerInfo add = MapstructUtils.convert(bo, ErpServerInfo.class);
// 保存前校验
validEntityBeforeSave(add);
if (baseMapper.insert(add) <= 0) {
throw new ServiceException("保存服务器信息失败");
}
// 回写生成的ID到BO
bo.setServerId(add.getServerId());
return;
}
// 不需要新版本:直接更新现有记录
if (bo.getVersion() == null) {
bo.setVersion(existing.getVersion());
}
@ -207,6 +311,14 @@ public class ErpServerInfoServiceImpl implements IErpServerInfoService {
}
}
/**
*
* <p>
* COMPLETEDFINISHisCurrent=1
*
* @param existing
* @return true=false=
*/
private boolean shouldCreateNewVersion(ErpServerInfo existing) {
// 已生效版本是线上可用快照,变更必须新增版本审批,不能直接覆盖原记录。
return OAStatusEnum.COMPLETED.getStatus().equals(existing.getServerStatus())
@ -214,10 +326,17 @@ public class ErpServerInfoServiceImpl implements IErpServerInfoService {
|| YES.equals(existing.getIsCurrent());
}
/**
*
*
* @param bo BO
* @param submit true=false=稿
*/
private void prepareForSave(ErpServerInfoBo bo, boolean submit) {
if (bo == null) {
throw new ServiceException("服务器信息不能为空");
}
// 如果没有服务器编码,调用远程编码规则服务自动生成
if (StringUtils.isBlank(bo.getServerCode())) {
String code = remoteCodeRuleService.selectCodeRuleCode(SERVER_CODE_RULE);
if (StringUtils.isBlank(code)) {
@ -225,14 +344,24 @@ public class ErpServerInfoServiceImpl implements IErpServerInfoService {
}
bo.setServerCode(code);
}
// 新记录且未指定版本号时,自动计算下一个版本号
if (bo.getVersion() == null && bo.getServerId() == null) {
bo.setVersion(calcNextVersion(bo.getServerCode()));
}
// 提交审批时设置流程编码
if (submit) {
bo.setFlowCode(FLOW_CODE_SERVER);
}
}
/**
*
* <p>
* +1
*
* @param serverCode
* @return 1
*/
private Integer calcNextVersion(String serverCode) {
if (StringUtils.isBlank(serverCode)) {
return 1;
@ -240,6 +369,7 @@ public class ErpServerInfoServiceImpl implements IErpServerInfoService {
List<ErpServerInfo> list = baseMapper.selectList(new LambdaQueryWrapper<ErpServerInfo>()
.eq(ErpServerInfo::getServerCode, serverCode)
.eq(ErpServerInfo::getDelFlag, NO));
// 取最大版本号 +1如果没有记录则返回1
return list.stream()
.map(ErpServerInfo::getVersion)
.filter(Objects::nonNull)
@ -247,6 +377,13 @@ public class ErpServerInfoServiceImpl implements IErpServerInfoService {
.orElse(0) + 1;
}
/**
*
* <p>
* 使 SELECT ... FOR UPDATE
*
* @param serverCode
*/
private void lockVersionRows(String serverCode) {
if (StringUtils.isBlank(serverCode)) {
return;
@ -258,6 +395,14 @@ public class ErpServerInfoServiceImpl implements IErpServerInfoService {
.last("for update"));
}
/**
* 退
* <p>
* 退BACKCANCEL
*
*
* @param serverId ID
*/
private void deleteReturnedOrCanceledInstance(Long serverId) {
if (serverId == null) {
return;
@ -266,6 +411,7 @@ public class ErpServerInfoServiceImpl implements IErpServerInfoService {
if (existing == null) {
return;
}
// 仅在退回或撤销状态下才需要清理
if (BusinessStatusEnum.BACK.getStatus().equals(existing.getFlowStatus())
|| BusinessStatusEnum.CANCEL.getStatus().equals(existing.getFlowStatus())) {
boolean deleted = remoteWorkflowService.deleteInstance(Collections.singletonList(serverId));
@ -275,6 +421,15 @@ public class ErpServerInfoServiceImpl implements IErpServerInfoService {
}
}
/**
*
* <p>
*
*
* @param serverCode
* @param currentServerId ID
* @throws ServiceException
*/
private void checkNoApprovingVersion(String serverCode, Long currentServerId) {
Long count = baseMapper.selectCount(new LambdaQueryWrapper<ErpServerInfo>()
.eq(ErpServerInfo::getServerCode, serverCode)
@ -286,6 +441,17 @@ public class ErpServerInfoServiceImpl implements IErpServerInfoService {
}
}
/**
*
* <p>
*
* -
* -
* IP
*
* @param entity
* @throws ServiceException
*/
private void validEntityBeforeSave(ErpServerInfo entity) {
if (entity == null) {
throw new ServiceException("服务器信息不能为空");
@ -299,6 +465,7 @@ public class ErpServerInfoServiceImpl implements IErpServerInfoService {
if (StringUtils.isBlank(entity.getAcquisitionType())) {
throw new ServiceException("请选择获取方式");
}
// 本地服务器必填品牌和型号
if (LOCAL_SERVER.equals(entity.getServerType())) {
if (StringUtils.isBlank(entity.getBrand())) {
throw new ServiceException("本地服务器必须填写品牌");
@ -307,6 +474,7 @@ public class ErpServerInfoServiceImpl implements IErpServerInfoService {
throw new ServiceException("本地服务器必须填写型号");
}
}
// 租赁服务器必填租赁起止日期
if (LEASE.equals(entity.getAcquisitionType())) {
if (entity.getLeaseStartDate() == null || entity.getLeaseEndDate() == null) {
throw new ServiceException("租赁服务器必须填写租赁起止日期");
@ -315,21 +483,34 @@ public class ErpServerInfoServiceImpl implements IErpServerInfoService {
throw new ServiceException("租赁结束日期不能早于起始日期");
}
}
// IP地址格式校验
validIpAddress(entity.getIpAddress());
// 金额非负校验
validNonNegativeAmount(entity.getPurchaseAmount(), "购买金额不能小于0");
validNonNegativeAmount(entity.getLeaseAmount(), "租赁金额不能小于0");
// 扩展属性安全校验(敏感词检测 + 白名单校验)
validExtAttr(entity.getExtAttr());
}
/**
* IP
* <p>
* IPIPIPv4IPv6
* IPv4使IPv6
*
* @param ipAddress IP
*/
private void validIpAddress(String ipAddress) {
if (StringUtils.isBlank(ipAddress)) {
return;
}
// 按逗号、分号、空格分隔多个IP
String[] items = ipAddress.split("[,;\\s]+");
for (String item : items) {
if (StringUtils.isBlank(item)) {
continue;
}
// 先尝试IPv4匹配不匹配再尝试IPv6候选校验
if (!IPV4_PATTERN.matcher(item).matches()
&& !(item.contains(":") && item.length() <= 45 && IPV6_CANDIDATE_PATTERN.matcher(item).matches())) {
throw new ServiceException("IP地址格式不正确");
@ -337,16 +518,33 @@ public class ErpServerInfoServiceImpl implements IErpServerInfoService {
}
}
/**
*
*
* @param amount
* @param message
*/
private void validNonNegativeAmount(java.math.BigDecimal amount, String message) {
if (amount != null && amount.signum() < 0) {
throw new ServiceException(message);
}
}
/**
*
* <p>
*
* 1. password/secret/token//
* 2. JSONJSON
* 3.
*
* @param extAttr JSON
*/
private void validExtAttr(String extAttr) {
if (StringUtils.isBlank(extAttr)) {
return;
}
// 敏感词检测将key转为小写并去除分隔符后匹配
String lower = extAttr.toLowerCase(Locale.ROOT);
String normalized = lower.replace("_", "").replace("-", "").replace(" ", "");
String[] sensitiveKeys = {"password", "passwd", "pwd", "secret", "privatekey", "accesskey", "apikey",
@ -356,9 +554,11 @@ public class ErpServerInfoServiceImpl implements IErpServerInfoService {
throw new ServiceException("扩展属性禁止保存密码、密钥、Token 等敏感凭据");
}
}
// JSON格式校验
if (!JSONUtil.isTypeJSONObject(extAttr)) {
throw new ServiceException("扩展属性必须是JSON对象");
}
// 白名单字段校验
JSONObject jsonObject = JSONUtil.parseObj(extAttr);
for (String key : jsonObject.keySet()) {
if (!EXT_ATTR_ALLOWED_KEYS.contains(key)) {
@ -367,8 +567,16 @@ public class ErpServerInfoServiceImpl implements IErpServerInfoService {
}
}
/**
*
* <p>
*
*
* @param bo BO
*/
private void fillWorkflowParams(ErpServerInfoBo bo) {
bo.setFlowCode(FLOW_CODE_SERVER);
// 设置流程变量putIfAbsent 避免覆盖前端传入的自定义变量)
Map<String, Object> vars = bo.getVariables();
vars.putIfAbsent("serverCode", bo.getServerCode());
vars.putIfAbsent("serverName", bo.getServerName());
@ -377,6 +585,7 @@ public class ErpServerInfoServiceImpl implements IErpServerInfoService {
vars.put("ignore", true);
bo.setVariables(vars);
// 设置业务扩展信息(用于工作流待办列表展示)
RemoteFlowInstanceBizExt bizExt = bo.getBizExt();
if (StringUtils.isBlank(bizExt.getBusinessTitle())) {
bizExt.setBusinessTitle(bo.getServerName() + "服务器登记审批");
@ -387,9 +596,19 @@ public class ErpServerInfoServiceImpl implements IErpServerInfoService {
bo.setBizExt(bizExt);
}
/**
*
* <p>
* 稿DRAFT
*
* @param ids ID
* @param isValid
* @return
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if (isValid) {
// 逐条校验:仅草稿状态可删除
for (Long id : ids) {
ErpServerInfo info = baseMapper.selectById(id);
if (info == null) {
@ -404,42 +623,78 @@ public class ErpServerInfoServiceImpl implements IErpServerInfoService {
return baseMapper.deleteByIds(ids) > 0;
}
/**
* OASR
* <p>
* Warm-Flow ProcessEvent
*
*
* @param processEvent
*/
@EventListener(condition = "#processEvent.flowCode == 'OASR'")
@Transactional(rollbackFor = Exception.class)
public void processHandler(ProcessEvent processEvent) {
// 在事件对应的租户上下文中执行,确保多租户数据隔离
TenantHelper.dynamic(processEvent.getTenantId(), () -> handleProcessEvent(processEvent));
}
/**
*
* <p>
*
* - WAITING APPROVING
* - FINISH COMPLETED
* - INVALID/TERMINATION/ INVALID
* - BACK/CANCEL退/ DRAFT稿
*
* @param processEvent
*/
public void handleProcessEvent(ProcessEvent processEvent) {
log.info("服务器登记流程事件: {}", processEvent);
ErpServerInfo server = baseMapper.selectById(Long.valueOf(processEvent.getBusinessId()));
if (server == null) {
return;
}
// 更新流程状态
server.setFlowStatus(processEvent.getStatus());
// 根据流程状态联动更新业务状态
if (Objects.equals(processEvent.getStatus(), BusinessStatusEnum.WAITING.getStatus())) {
// 审批中
server.setServerStatus(OAStatusEnum.APPROVING.getStatus());
} else if (Objects.equals(processEvent.getStatus(), BusinessStatusEnum.FINISH.getStatus())) {
// 审批通过:设为已生效并激活当前版本
server.setServerStatus(OAStatusEnum.COMPLETED.getStatus());
activateCurrentVersion(server);
} else if (Objects.equals(processEvent.getStatus(), BusinessStatusEnum.INVALID.getStatus())
|| Objects.equals(processEvent.getStatus(), BusinessStatusEnum.TERMINATION.getStatus())) {
// 失效或终止:设为已作废
server.setServerStatus(OAStatusEnum.INVALID.getStatus());
server.setIsCurrent(NO);
} else if (Objects.equals(processEvent.getStatus(), BusinessStatusEnum.BACK.getStatus())
|| Objects.equals(processEvent.getStatus(), BusinessStatusEnum.CANCEL.getStatus())) {
// 退回或撤销:回退为草稿状态
server.setServerStatus(OAStatusEnum.DRAFT.getStatus());
server.setIsCurrent(NO);
}
baseMapper.updateById(server);
}
/**
*
* <p>
* isCurrent 01
*
*
* @param server
*/
private void activateCurrentVersion(ErpServerInfo server) {
// 将同编码的其他版本全部置为非当前版本
baseMapper.update(null, new LambdaUpdateWrapper<ErpServerInfo>()
.set(ErpServerInfo::getIsCurrent, NO)
.eq(ErpServerInfo::getServerCode, server.getServerCode())
.eq(ErpServerInfo::getDelFlag, NO)
.ne(ErpServerInfo::getServerId, server.getServerId()));
// 当前版本置为生效
server.setIsCurrent(YES);
}
}

Loading…
Cancel
Save