chore: 【ops】派单策略逻辑编写(暂时预留、后期设计接入)
This commit is contained in:
@@ -0,0 +1,62 @@
|
|||||||
|
package com.viewsh.module.ops.core.dispatch;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 派单推荐结果
|
||||||
|
* 包含推荐的执行人员及推荐理由
|
||||||
|
*
|
||||||
|
* @author lzh
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class AssigneeRecommendation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 推荐的执行人员ID
|
||||||
|
*/
|
||||||
|
private Long assigneeId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行人员姓名
|
||||||
|
*/
|
||||||
|
private String assigneeName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 匹配分数(0-100)
|
||||||
|
* 分数越高表示越匹配
|
||||||
|
*/
|
||||||
|
private Integer score;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 推荐理由
|
||||||
|
* 例如:"同区域、电量充足、当前空闲"
|
||||||
|
*/
|
||||||
|
private String reason;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建空推荐结果(表示没有合适的人员)
|
||||||
|
*/
|
||||||
|
public static AssigneeRecommendation none() {
|
||||||
|
return new AssigneeRecommendation(null, null, 0, "无可用人员");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建推荐结果
|
||||||
|
*/
|
||||||
|
public static AssigneeRecommendation of(Long assigneeId, String assigneeName, Integer score, String reason) {
|
||||||
|
return new AssigneeRecommendation(assigneeId, assigneeName, score, reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否有推荐结果
|
||||||
|
*/
|
||||||
|
public boolean hasRecommendation() {
|
||||||
|
return assigneeId != null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,127 @@
|
|||||||
|
package com.viewsh.module.ops.core.dispatch;
|
||||||
|
|
||||||
|
import com.viewsh.module.ops.enums.PriorityEnum;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 派单上下文
|
||||||
|
* 封装派单决策所需的所有信息
|
||||||
|
*
|
||||||
|
* @author lzh
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
public class DispatchContext {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 业务类型(CLEAN、REPAIR、SECURITY等)
|
||||||
|
*/
|
||||||
|
private String businessType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 工单ID
|
||||||
|
*/
|
||||||
|
private Long orderId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 区域ID
|
||||||
|
*/
|
||||||
|
private Long areaId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 优先级
|
||||||
|
*/
|
||||||
|
private PriorityEnum priority;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 技能要求(可选)
|
||||||
|
* Key: 技能类型, Value: 技能等级
|
||||||
|
*/
|
||||||
|
private Map<String, Integer> skillRequirements;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 排除的执行人员ID列表(可选)
|
||||||
|
* 例如:已分配过该工单的人员
|
||||||
|
*/
|
||||||
|
private Set<Long> excludedAssigneeIds;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 首选执行人员ID(可选)
|
||||||
|
* 例如:指定的保洁员
|
||||||
|
*/
|
||||||
|
private Long preferredAssigneeId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 扩展参数(可选)
|
||||||
|
* 用于传递业务特定的参数
|
||||||
|
*/
|
||||||
|
private Map<String, Object> extraParams;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建保洁派单上下文
|
||||||
|
*/
|
||||||
|
public static DispatchContext forCleaner(Long orderId, Long areaId, PriorityEnum priority) {
|
||||||
|
return DispatchContext.builder()
|
||||||
|
.businessType("CLEAN")
|
||||||
|
.orderId(orderId)
|
||||||
|
.areaId(areaId)
|
||||||
|
.priority(priority)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建安保派单上下文
|
||||||
|
*/
|
||||||
|
public static DispatchContext forSecurity(Long orderId, Long areaId, PriorityEnum priority) {
|
||||||
|
return DispatchContext.builder()
|
||||||
|
.businessType("SECURITY")
|
||||||
|
.orderId(orderId)
|
||||||
|
.areaId(areaId)
|
||||||
|
.priority(priority)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建维修派单上下文
|
||||||
|
*/
|
||||||
|
public static DispatchContext forRepair(Long orderId, Long areaId, PriorityEnum priority) {
|
||||||
|
return DispatchContext.builder()
|
||||||
|
.businessType("REPAIR")
|
||||||
|
.orderId(orderId)
|
||||||
|
.areaId(areaId)
|
||||||
|
.priority(priority)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取扩展参数
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <T> T getExtraParam(String key, Class<T> type) {
|
||||||
|
if (extraParams == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Object value = extraParams.get(key);
|
||||||
|
if (value == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (type.isInstance(value)) {
|
||||||
|
return (T) value;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加扩展参数
|
||||||
|
*/
|
||||||
|
public void addExtraParam(String key, Object value) {
|
||||||
|
if (this.extraParams == null) {
|
||||||
|
this.extraParams = new java.util.HashMap<>();
|
||||||
|
}
|
||||||
|
this.extraParams.put(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
package com.viewsh.module.ops.core.dispatch;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 派单引擎 - 纯决策层
|
||||||
|
* <p>
|
||||||
|
* 职责:
|
||||||
|
* 1. 根据策略推荐最合适的执行人员
|
||||||
|
* 2. 不涉及状态管理(队列状态、工单状态由各自服务管理)
|
||||||
|
* 3. 不涉及设备通知(由通知服务处理)
|
||||||
|
* <p>
|
||||||
|
* 设计原则:
|
||||||
|
* - 单一职责:只负责派单决策
|
||||||
|
* - 开闭原则:通过策略模式支持扩展
|
||||||
|
* - 依赖倒置:业务层依赖接口而非实现
|
||||||
|
*
|
||||||
|
* @author lzh
|
||||||
|
*/
|
||||||
|
public interface DispatchEngine {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 推荐执行人员(核心方法)
|
||||||
|
* <p>
|
||||||
|
* 根据派单上下文(区域、优先级、技能要求等)推荐最合适的执行人员
|
||||||
|
*
|
||||||
|
* @param context 派单上下文
|
||||||
|
* @return 推荐结果,如果没有合适的返回 AssigneeRecommendation.none()
|
||||||
|
*/
|
||||||
|
AssigneeRecommendation recommendAssignee(DispatchContext context);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量推荐执行人员
|
||||||
|
* <p>
|
||||||
|
* 用于场景:需要从多个候选人中选择最优人员,或需要备用人员
|
||||||
|
*
|
||||||
|
* @param context 派单上下文
|
||||||
|
* @param limit 返回结果数量限制
|
||||||
|
* @return 推荐结果列表,按匹配分数降序排序
|
||||||
|
*/
|
||||||
|
List<AssigneeRecommendation> recommendAssignees(DispatchContext context, int limit);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 评估是否可以打断当前任务
|
||||||
|
* <p>
|
||||||
|
* 用于P0紧急任务插队场景:判断是否可以打断当前执行人员正在执行的任务
|
||||||
|
*
|
||||||
|
* @param currentAssigneeId 当前执行任务的执行人员ID
|
||||||
|
* @param urgentContext 紧急任务的派单上下文
|
||||||
|
* @return 打断决策结果
|
||||||
|
*/
|
||||||
|
InterruptDecision evaluateInterrupt(Long currentAssigneeId, DispatchContext urgentContext);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册派单策略
|
||||||
|
* <p>
|
||||||
|
* 各业务线(保洁、安保、维修等)实现自己的派单策略,注册到引擎中
|
||||||
|
*
|
||||||
|
* @param strategy 派单策略实现
|
||||||
|
*/
|
||||||
|
void registerStrategy(DispatchStrategy strategy);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册业务类型与策略的映射
|
||||||
|
* <p>
|
||||||
|
* 建立业务类型(CLEAN/REPAIR/SECURITY)与策略名称的映射关系
|
||||||
|
*
|
||||||
|
* @param businessType 业务类型
|
||||||
|
* @param strategyName 策略名称
|
||||||
|
*/
|
||||||
|
void registerBusinessTypeStrategy(String businessType, String strategyName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据业务类型获取策略
|
||||||
|
*
|
||||||
|
* @param businessType 业务类型
|
||||||
|
* @return 派单策略,如果没有找到返回null
|
||||||
|
*/
|
||||||
|
DispatchStrategy getStrategyByBusinessType(String businessType);
|
||||||
|
}
|
||||||
@@ -0,0 +1,251 @@
|
|||||||
|
package com.viewsh.module.ops.core.dispatch;
|
||||||
|
|
||||||
|
import com.viewsh.module.ops.enums.PriorityEnum;
|
||||||
|
import jakarta.annotation.PostConstruct;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 派单引擎实现
|
||||||
|
* <p>
|
||||||
|
* 职责:
|
||||||
|
* 1. 管理派单策略的注册和查找
|
||||||
|
* 2. 根据业务类型路由到对应的策略
|
||||||
|
* 3. 提供统一的派单决策接口
|
||||||
|
* <p>
|
||||||
|
* 注意:
|
||||||
|
* - 这是纯决策层,不涉及任何状态管理
|
||||||
|
* - 队列状态、工单状态由各自服务管理
|
||||||
|
* - 设备通知由通知服务处理
|
||||||
|
*
|
||||||
|
* @author lzh
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class DispatchEngineImpl implements DispatchEngine {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 派单策略注册表
|
||||||
|
* Key: 策略名称
|
||||||
|
* Value: 策略实现
|
||||||
|
*/
|
||||||
|
private final Map<String, DispatchStrategy> strategyRegistry = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 业务类型与策略的映射
|
||||||
|
* Key: 业务类型(CLEAN、REPAIR、SECURITY)
|
||||||
|
* Value: 策略名称
|
||||||
|
*/
|
||||||
|
private final Map<String, String> businessTypeStrategyMap = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void init() {
|
||||||
|
log.info("派单引擎已初始化,等待策略注册...");
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========== 策略管理 ==========
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerStrategy(DispatchStrategy strategy) {
|
||||||
|
if (strategy == null) {
|
||||||
|
log.warn("尝试注册空策略,已忽略");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String strategyName = strategy.getName();
|
||||||
|
String businessType = strategy.getSupportedBusinessType();
|
||||||
|
|
||||||
|
strategyRegistry.put(strategyName, strategy);
|
||||||
|
|
||||||
|
// 自动注册业务类型映射
|
||||||
|
if (businessType != null && !businessType.isEmpty()) {
|
||||||
|
businessTypeStrategyMap.put(businessType, strategyName);
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("派单策略已注册: strategyName={}, businessType={}",
|
||||||
|
strategyName, businessType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerBusinessTypeStrategy(String businessType, String strategyName) {
|
||||||
|
if (businessType == null || businessType.isEmpty()) {
|
||||||
|
log.warn("业务类型为空,忽略注册");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strategyRegistry.containsKey(strategyName)) {
|
||||||
|
log.warn("策略不存在,无法注册映射: businessType={}, strategyName={}",
|
||||||
|
businessType, strategyName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
businessTypeStrategyMap.put(businessType, strategyName);
|
||||||
|
log.info("业务类型策略映射已注册: businessType={}, strategyName={}",
|
||||||
|
businessType, strategyName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DispatchStrategy getStrategyByBusinessType(String businessType) {
|
||||||
|
if (businessType == null || businessType.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String strategyName = businessTypeStrategyMap.get(businessType);
|
||||||
|
if (strategyName == null) {
|
||||||
|
log.debug("未找到业务类型对应的策略: businessType={}", businessType);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
DispatchStrategy strategy = strategyRegistry.get(strategyName);
|
||||||
|
if (strategy == null) {
|
||||||
|
log.warn("策略不存在: strategyName={}", strategyName);
|
||||||
|
}
|
||||||
|
|
||||||
|
return strategy;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========== 派单决策方法 ==========
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AssigneeRecommendation recommendAssignee(DispatchContext context) {
|
||||||
|
if (context == null) {
|
||||||
|
log.warn("派单上下文为空,无法推荐人员");
|
||||||
|
return AssigneeRecommendation.none();
|
||||||
|
}
|
||||||
|
|
||||||
|
String businessType = context.getBusinessType();
|
||||||
|
DispatchStrategy strategy = getStrategyByBusinessType(businessType);
|
||||||
|
|
||||||
|
if (strategy == null) {
|
||||||
|
log.warn("未找到业务类型对应的派单策略: businessType={}, orderId={}",
|
||||||
|
businessType, context.getOrderId());
|
||||||
|
return AssigneeRecommendation.none();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
AssigneeRecommendation recommendation = strategy.recommendAssignee(context);
|
||||||
|
if (recommendation != null && recommendation.hasRecommendation()) {
|
||||||
|
log.info("派单推荐成功: orderId={}, businessType={}, assigneeId={}, score={}, reason={}",
|
||||||
|
context.getOrderId(), businessType,
|
||||||
|
recommendation.getAssigneeId(),
|
||||||
|
recommendation.getScore(),
|
||||||
|
recommendation.getReason());
|
||||||
|
} else {
|
||||||
|
log.info("派单推荐无合适人员: orderId={}, businessType={}",
|
||||||
|
context.getOrderId(), businessType);
|
||||||
|
}
|
||||||
|
return recommendation;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("派单推荐异常: orderId={}, businessType={}",
|
||||||
|
context.getOrderId(), businessType, e);
|
||||||
|
return AssigneeRecommendation.none();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<AssigneeRecommendation> recommendAssignees(DispatchContext context, int limit) {
|
||||||
|
if (context == null) {
|
||||||
|
log.warn("派单上下文为空,无法推荐人员");
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
String businessType = context.getBusinessType();
|
||||||
|
DispatchStrategy strategy = getStrategyByBusinessType(businessType);
|
||||||
|
|
||||||
|
if (strategy == null) {
|
||||||
|
log.warn("未找到业务类型对应的派单策略: businessType={}, orderId={}",
|
||||||
|
businessType, context.getOrderId());
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
List<AssigneeRecommendation> recommendations = strategy.recommendAssignees(context, limit);
|
||||||
|
log.info("批量派单推荐完成: orderId={}, businessType={}, count={}",
|
||||||
|
context.getOrderId(), businessType,
|
||||||
|
recommendations != null ? recommendations.size() : 0);
|
||||||
|
return recommendations != null ? recommendations : Collections.emptyList();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("批量派单推荐异常: orderId={}, businessType={}",
|
||||||
|
context.getOrderId(), businessType, e);
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InterruptDecision evaluateInterrupt(Long currentAssigneeId, DispatchContext urgentContext) {
|
||||||
|
if (currentAssigneeId == null) {
|
||||||
|
log.warn("当前执行人员ID为空,无法评估打断");
|
||||||
|
return InterruptDecision.deny("当前执行人员ID为空", "请检查参数");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (urgentContext == null) {
|
||||||
|
log.warn("紧急任务上下文为空,无法评估打断");
|
||||||
|
return InterruptDecision.deny("紧急任务上下文为空", "请检查参数");
|
||||||
|
}
|
||||||
|
|
||||||
|
String businessType = urgentContext.getBusinessType();
|
||||||
|
DispatchStrategy strategy = getStrategyByBusinessType(businessType);
|
||||||
|
|
||||||
|
if (strategy == null) {
|
||||||
|
// 使用默认打断规则
|
||||||
|
InterruptDecision decision = defaultInterruptDecision(urgentContext);
|
||||||
|
log.info("使用默认打断规则: currentAssigneeId={}, urgentOrderId={}, canInterrupt={}",
|
||||||
|
currentAssigneeId, urgentContext.getOrderId(), decision.canInterrupt());
|
||||||
|
return decision;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
InterruptDecision decision = strategy.evaluateInterrupt(
|
||||||
|
currentAssigneeId,
|
||||||
|
null, // currentOrderId 可选
|
||||||
|
urgentContext
|
||||||
|
);
|
||||||
|
|
||||||
|
log.info("打断评估完成: currentAssigneeId={}, urgentOrderId={}, canInterrupt={}, reason={}",
|
||||||
|
currentAssigneeId, urgentContext.getOrderId(),
|
||||||
|
decision.canInterrupt(), decision.getReason());
|
||||||
|
|
||||||
|
return decision;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("打断评估异常: currentAssigneeId={}, urgentOrderId={}",
|
||||||
|
currentAssigneeId, urgentContext.getOrderId(), e);
|
||||||
|
return InterruptDecision.deny("评估异常", "使用默认处理");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 默认打断决策
|
||||||
|
* P0任务可以打断任何非P0任务
|
||||||
|
*/
|
||||||
|
private InterruptDecision defaultInterruptDecision(DispatchContext urgentContext) {
|
||||||
|
if (urgentContext.getPriority() != null && urgentContext.getPriority().isUrgent()) {
|
||||||
|
return InterruptDecision.allowByDefault();
|
||||||
|
}
|
||||||
|
return InterruptDecision.deny(
|
||||||
|
"紧急任务优先级不足",
|
||||||
|
"建议等待当前任务完成"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========== 查询方法 ==========
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有已注册的策略
|
||||||
|
*/
|
||||||
|
public List<DispatchStrategy> getAllStrategies() {
|
||||||
|
return new ArrayList<>(strategyRegistry.values());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有业务类型与策略的映射
|
||||||
|
*/
|
||||||
|
public Map<String, String> getAllBusinessTypeMappings() {
|
||||||
|
return new java.util.HashMap<>(businessTypeStrategyMap);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
package com.viewsh.module.ops.core.dispatch;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 派单策略接口
|
||||||
|
* <p>
|
||||||
|
* 各业务模块(保洁、安保、工程等)需要实现此接口,定义自己的派单逻辑
|
||||||
|
* <p>
|
||||||
|
* 职责:
|
||||||
|
* 1. 根据派单上下文推荐合适的执行人员
|
||||||
|
* 2. 判断是否可以打断当前任务
|
||||||
|
*
|
||||||
|
* @author lzh
|
||||||
|
*/
|
||||||
|
public interface DispatchStrategy {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 策略名称
|
||||||
|
* <p>
|
||||||
|
* 如:cleaner_area_priority, security_skill_match
|
||||||
|
* 命名规范:{业务类型}_{策略描述}
|
||||||
|
*
|
||||||
|
* @return 策略名称
|
||||||
|
*/
|
||||||
|
String getName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支持的业务类型
|
||||||
|
* <p>
|
||||||
|
* 如:CLEAN、REPAIR、SECURITY
|
||||||
|
*
|
||||||
|
* @return 业务类型
|
||||||
|
*/
|
||||||
|
String getSupportedBusinessType();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行派单策略,推荐执行人员
|
||||||
|
* <p>
|
||||||
|
* 根据派单上下文(区域、优先级、技能要求等)推荐最合适的执行人员
|
||||||
|
*
|
||||||
|
* @param context 派单上下文
|
||||||
|
* @return 推荐结果,如果没有合适的返回 AssigneeRecommendation.none()
|
||||||
|
*/
|
||||||
|
AssigneeRecommendation recommendAssignee(DispatchContext context);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量推荐执行人员
|
||||||
|
* <p>
|
||||||
|
* 用于场景:需要从多个候选人中选择,或需要备用人员
|
||||||
|
*
|
||||||
|
* @param context 派单上下文
|
||||||
|
* @param limit 返回结果数量限制
|
||||||
|
* @return 推荐结果列表,按匹配分数降序排序
|
||||||
|
*/
|
||||||
|
List<AssigneeRecommendation> recommendAssignees(DispatchContext context, int limit);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 评估是否可以打断当前任务
|
||||||
|
* <p>
|
||||||
|
* 当P0紧急任务需要插队时,判断是否可以打断当前执行的任务
|
||||||
|
*
|
||||||
|
* @param currentAssigneeId 当前执行任务的执行人员ID
|
||||||
|
* @param currentOrderId 当前正在执行的工单ID(可选)
|
||||||
|
* @param urgentContext 紧急任务的派单上下文
|
||||||
|
* @return 打断决策结果
|
||||||
|
*/
|
||||||
|
InterruptDecision evaluateInterrupt(Long currentAssigneeId, Long currentOrderId, DispatchContext urgentContext);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 默认实现:判断是否可以打断
|
||||||
|
* <p>
|
||||||
|
* 默认规则:P0任务可以打断任何非P0任务
|
||||||
|
*/
|
||||||
|
default InterruptDecision defaultEvaluateInterrupt(Long currentAssigneeId, Long currentOrderId,
|
||||||
|
DispatchContext urgentContext) {
|
||||||
|
if (urgentContext.getPriority() != null && urgentContext.getPriority().isUrgent()) {
|
||||||
|
return InterruptDecision.allowByDefault();
|
||||||
|
}
|
||||||
|
return InterruptDecision.deny(
|
||||||
|
"紧急任务优先级不足",
|
||||||
|
"建议等待当前任务完成"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
package com.viewsh.module.ops.core.dispatch;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打断决策结果
|
||||||
|
* 用于判断P0紧急任务是否可以打断当前正在执行的任务
|
||||||
|
*
|
||||||
|
* @author lzh
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class InterruptDecision {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否可以打断
|
||||||
|
*/
|
||||||
|
@Builder.Default
|
||||||
|
private boolean canInterrupt = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打断原因
|
||||||
|
* 例如:"紧急任务优先级更高"
|
||||||
|
*/
|
||||||
|
private String reason;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 建议操作
|
||||||
|
* 例如:"暂停当前任务"、"等待当前任务完成"
|
||||||
|
*/
|
||||||
|
private String suggestion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 可以打断
|
||||||
|
*/
|
||||||
|
public static InterruptDecision allow(String reason, String suggestion) {
|
||||||
|
return new InterruptDecision(true, reason, suggestion);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 不可以打断
|
||||||
|
*/
|
||||||
|
public static InterruptDecision deny(String reason, String suggestion) {
|
||||||
|
return new InterruptDecision(false, reason, suggestion);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 默认可以打断(P0任务)
|
||||||
|
*/
|
||||||
|
public static InterruptDecision allowByDefault() {
|
||||||
|
return InterruptDecision.allow(
|
||||||
|
"P0紧急任务优先级最高",
|
||||||
|
"建议暂停当前任务,立即执行P0任务"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 别名方法,用于更流畅的调用
|
||||||
|
* Lombok 会生成 isCanInterrupt(),这里提供 canInterrupt() 别名
|
||||||
|
*/
|
||||||
|
public boolean canInterrupt() {
|
||||||
|
return isCanInterrupt();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user