|
|
@@ -16,7 +16,8 @@ import com.zksy.ops.domain.vo.WorkOrderLogVO;
|
|
|
import com.zksy.ops.domain.vo.WorkOrderPushVO;
|
|
|
import com.zksy.ops.domain.vo.WorkOrderVO;
|
|
|
import com.zksy.ops.enums.WorkOrderDelayApplyStatusEnum;
|
|
|
-import com.zksy.ops.enums.WorkOrderLevelEnum;
|
|
|
+import com.zksy.common.core.domain.entity.SysDictData;
|
|
|
+import com.zksy.system.service.ISysDictDataService;
|
|
|
import com.zksy.ops.enums.WorkOrderLogOperTypeEnum;
|
|
|
import com.zksy.ops.enums.WorkOrderStatusEnum;
|
|
|
import com.zksy.base.mapper.EquipmentBaseMapper;
|
|
|
@@ -47,6 +48,7 @@ import com.zksy.ops.support.OpsAssignScopeSupport;
|
|
|
import com.zksy.system.service.ISysUserService;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.beans.factory.annotation.Value;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
import org.springframework.util.CollectionUtils;
|
|
|
@@ -109,6 +111,12 @@ public class WorkOrderServiceImpl extends ServiceImpl<WorkOrderMapper, WorkOrder
|
|
|
*/
|
|
|
private static final String DATA_SCOPE = "dataScope";
|
|
|
|
|
|
+ @Value("${minio.endpoint}")
|
|
|
+ private String minioEndpoint;
|
|
|
+
|
|
|
+ @Value("${minio.bucket}")
|
|
|
+ private String minioBucket;
|
|
|
+
|
|
|
@Autowired
|
|
|
private WorkOrderLogMapper workOrderLogMapper;
|
|
|
|
|
|
@@ -134,6 +142,11 @@ public class WorkOrderServiceImpl extends ServiceImpl<WorkOrderMapper, WorkOrder
|
|
|
@Autowired
|
|
|
private ISysUserService sysUserService;
|
|
|
|
|
|
+ @Autowired
|
|
|
+ private ISysDictDataService sysDictDataService;
|
|
|
+
|
|
|
+ private static final String WORK_ORDER_LEVEL_DICT = "work_order_level";
|
|
|
+
|
|
|
@Autowired
|
|
|
private OpsAssignScopeSupport assignScopeSupport;
|
|
|
|
|
|
@@ -272,9 +285,11 @@ public class WorkOrderServiceImpl extends ServiceImpl<WorkOrderMapper, WorkOrder
|
|
|
throw new ServiceException("故障描述不能为空");
|
|
|
}
|
|
|
Date now = new Date();
|
|
|
+ workOrder.setMaintenanceBeforeImg(normalizeAttachmentPaths(workOrder.getMaintenanceBeforeImg()));
|
|
|
+ workOrder.setMaintenanceAfterImg(normalizeAttachmentPaths(workOrder.getMaintenanceAfterImg()));
|
|
|
workOrder.setOrderId(null);
|
|
|
workOrder.setOrderNo(generateOrderNo());
|
|
|
- workOrder.setOrderLevel(WorkOrderLevelEnum.getByCode(workOrder.getOrderLevel()).getCode());
|
|
|
+ workOrder.setOrderLevel(normalizeWorkOrderLevel(workOrder.getOrderLevel()));
|
|
|
if (workOrder.getFaultTime() == null) {
|
|
|
workOrder.setFaultTime(now);
|
|
|
}
|
|
|
@@ -338,9 +353,8 @@ public class WorkOrderServiceImpl extends ServiceImpl<WorkOrderMapper, WorkOrder
|
|
|
WorkOrder workOrder = new WorkOrder();
|
|
|
workOrder.setOrderNo(generateOrderNo());
|
|
|
workOrder.setDeviceId(deviceId);
|
|
|
- workOrder.setOrderLevel(orderLevel == null
|
|
|
- ? mapAlarmLevelToOrderLevel(alarm.getAlarmLevel()).getCode()
|
|
|
- : WorkOrderLevelEnum.getByCode(orderLevel).getCode());
|
|
|
+ workOrder.setOrderLevel(normalizeWorkOrderLevel(orderLevel == null
|
|
|
+ ? mapAlarmLevelToOrderLevel(alarm.getAlarmLevel()) : orderLevel));
|
|
|
workOrder.setOrderDesc(StringUtils.isNotEmpty(orderDesc) ? orderDesc : buildAlarmOrderDesc(alarm));
|
|
|
workOrder.setFaultTime(alarm.getCreateTime() == null
|
|
|
? now
|
|
|
@@ -390,7 +404,7 @@ public class WorkOrderServiceImpl extends ServiceImpl<WorkOrderMapper, WorkOrder
|
|
|
WorkOrder workOrder = new WorkOrder();
|
|
|
workOrder.setOrderNo(generateOrderNo());
|
|
|
workOrder.setDeviceId(equipmentId);
|
|
|
- workOrder.setOrderLevel(mapHazardLevelToOrderLevel(hazardLevel).getCode());
|
|
|
+ workOrder.setOrderLevel(normalizeWorkOrderLevel(mapHazardLevelToOrderLevel(hazardLevel)));
|
|
|
workOrder.setOrderDesc(hazardDesc);
|
|
|
// 数据按部门隔离:默认归属创建人所在部门(框架 DataScopeAspect 依据该字段过滤)
|
|
|
workOrder.setDeptId(assignScopeSupport.currentDeptId());
|
|
|
@@ -398,7 +412,7 @@ public class WorkOrderServiceImpl extends ServiceImpl<WorkOrderMapper, WorkOrder
|
|
|
workOrder.setDelayApplyStatus(WorkOrderDelayApplyStatusEnum.NONE.getCode());
|
|
|
workOrder.setPlanFinishTime(planFinishTime);
|
|
|
if (StringUtils.isNotEmpty(hazardImages)) {
|
|
|
- workOrder.setMaintenanceBeforeImg(hazardImages);
|
|
|
+ workOrder.setMaintenanceBeforeImg(normalizeAttachmentPaths(hazardImages));
|
|
|
}
|
|
|
workOrder.setFaultTime(now);
|
|
|
workOrder.setCreateTime(now);
|
|
|
@@ -423,6 +437,10 @@ public class WorkOrderServiceImpl extends ServiceImpl<WorkOrderMapper, WorkOrder
|
|
|
if (handlerId == null) {
|
|
|
throw new ServiceException("责任人不能为空");
|
|
|
}
|
|
|
+ Long verifyUserId = dto.getVerifyUser();
|
|
|
+ if (verifyUserId == null) {
|
|
|
+ throw new ServiceException("核验人不能为空");
|
|
|
+ }
|
|
|
WorkOrder order = getOrderById(id);
|
|
|
if (!Objects.equals(WorkOrderStatusEnum.PENDING_DISPATCH.getCode(), order.getOrderStatus())) {
|
|
|
throw new ServiceException("仅待派单工单允许派单");
|
|
|
@@ -432,16 +450,22 @@ public class WorkOrderServiceImpl extends ServiceImpl<WorkOrderMapper, WorkOrder
|
|
|
if (handler == null || !UserConstants.NORMAL.equals(String.valueOf(handler.getStatus())) || !UserConstants.NORMAL.equals(String.valueOf(handler.getDelFlag()))) {
|
|
|
throw new ServiceException("责任人不存在或已停用");
|
|
|
}
|
|
|
+ assignScopeSupport.validateAssignUserInScope(verifyUserId);
|
|
|
+ SysUser verifier = sysUserService.selectUserById(verifyUserId);
|
|
|
+ if (verifier == null || !UserConstants.NORMAL.equals(String.valueOf(verifier.getStatus())) || !UserConstants.NORMAL.equals(String.valueOf(verifier.getDelFlag()))) {
|
|
|
+ throw new ServiceException("核验人不存在或已停用");
|
|
|
+ }
|
|
|
|
|
|
Date now = new Date();
|
|
|
- this.update(updateWrapper(id).set(WorkOrder::getOrderStatus, WorkOrderStatusEnum.PENDING_ACCEPT.getCode()).set(WorkOrder::getReceiveUser, handlerId).set(WorkOrder::getDispatchUser, currentUserId()).set(WorkOrder::getDispatchTime, now)
|
|
|
+ this.update(updateWrapper(id).set(WorkOrder::getOrderStatus, WorkOrderStatusEnum.PENDING_ACCEPT.getCode()).set(WorkOrder::getReceiveUser, handlerId).set(WorkOrder::getVerifyUser, verifyUserId).set(WorkOrder::getDispatchUser, currentUserId()).set(WorkOrder::getDispatchTime, now)
|
|
|
// 数据归属部门跟随派单指定的责任人
|
|
|
.set(handler.getDeptId() != null, WorkOrder::getDeptId, handler.getDeptId())
|
|
|
// 计划完成时间:派单时可设定/修改,为空则保留原值
|
|
|
.set(dto.getPlanFinishTime() != null, WorkOrder::getPlanFinishTime, dto.getPlanFinishTime())
|
|
|
.eq(WorkOrder::getOrderStatus, WorkOrderStatusEnum.PENDING_DISPATCH.getCode()));
|
|
|
|
|
|
- String logContent = "派单给责任人:" + userLabel(handler) + (StringUtils.isEmpty(dto.getRemarks()) ? "" : ",备注:" + dto.getRemarks());
|
|
|
+ String logContent = "派单给责任人:" + userLabel(handler) + ",核验人:" + userLabel(verifier)
|
|
|
+ + (StringUtils.isEmpty(dto.getRemarks()) ? "" : ",备注:" + dto.getRemarks());
|
|
|
writeLog(id, WorkOrderLogOperTypeEnum.DISPATCH, logContent, null);
|
|
|
return true;
|
|
|
}
|
|
|
@@ -453,14 +477,15 @@ public class WorkOrderServiceImpl extends ServiceImpl<WorkOrderMapper, WorkOrder
|
|
|
requireResponsible(order, currentUserId(), "核查接单");
|
|
|
requireStatus(order, WorkOrderStatusEnum.PENDING_ACCEPT, "仅待接单工单允许核查接单");
|
|
|
// 核查接单必须上传现场情况附件
|
|
|
- if (StringUtils.isEmpty(dto.getAttachUrl())) {
|
|
|
+ String attachUrl = normalizeAttachmentPaths(dto.getAttachUrl());
|
|
|
+ if (StringUtils.isEmpty(attachUrl)) {
|
|
|
throw new ServiceException("核查接单必须上传现场情况附件");
|
|
|
}
|
|
|
|
|
|
Long id = order.getOrderId();
|
|
|
// 维修前图片固定来源于核查接单上传的现场情况附件
|
|
|
- boolean updated = transition(id, WorkOrderStatusEnum.PENDING_ACCEPT.getCode(), WorkOrderStatusEnum.ACCEPTED.getCode(), wrapper -> wrapper.set(WorkOrder::getMaintenanceBeforeImg, dto.getAttachUrl()));
|
|
|
- writeLog(id, WorkOrderLogOperTypeEnum.ACCEPT, buildDesc("", dto.getContent()), dto.getAttachUrl());
|
|
|
+ boolean updated = transition(id, WorkOrderStatusEnum.PENDING_ACCEPT.getCode(), WorkOrderStatusEnum.ACCEPTED.getCode(), wrapper -> wrapper.set(WorkOrder::getMaintenanceBeforeImg, attachUrl));
|
|
|
+ writeLog(id, WorkOrderLogOperTypeEnum.ACCEPT, buildDesc("", dto.getContent()), attachUrl);
|
|
|
return updated;
|
|
|
}
|
|
|
|
|
|
@@ -496,13 +521,14 @@ public class WorkOrderServiceImpl extends ServiceImpl<WorkOrderMapper, WorkOrder
|
|
|
throw new ServiceException("仅处理中/延期中工单允许提交验收");
|
|
|
}
|
|
|
// 提交验收必须上传维修后的情况附件
|
|
|
- if (StringUtils.isEmpty(dto.getAttachUrl())) {
|
|
|
+ String attachUrl = normalizeAttachmentPaths(dto.getAttachUrl());
|
|
|
+ if (StringUtils.isEmpty(attachUrl)) {
|
|
|
throw new ServiceException("提交验收必须上传维修后的情况附件");
|
|
|
}
|
|
|
|
|
|
// 附件已在上方强制必填,直接写入工单维修后图片
|
|
|
- boolean updated = transition(order.getOrderId(), status, WorkOrderStatusEnum.PENDING_VERIFY.getCode(), wrapper -> wrapper.set(WorkOrder::getMaintenanceAfterImg, dto.getAttachUrl()));
|
|
|
- writeLog(order.getOrderId(), WorkOrderLogOperTypeEnum.SUBMIT_VERIFY, buildDesc("", dto.getContent()), dto.getAttachUrl());
|
|
|
+ boolean updated = transition(order.getOrderId(), status, WorkOrderStatusEnum.PENDING_VERIFY.getCode(), wrapper -> wrapper.set(WorkOrder::getMaintenanceAfterImg, attachUrl));
|
|
|
+ writeLog(order.getOrderId(), WorkOrderLogOperTypeEnum.SUBMIT_VERIFY, buildDesc("", dto.getContent()), attachUrl);
|
|
|
return updated;
|
|
|
}
|
|
|
|
|
|
@@ -835,6 +861,43 @@ public class WorkOrderServiceImpl extends ServiceImpl<WorkOrderMapper, WorkOrder
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ String normalizeAttachmentPaths(String value) {
|
|
|
+ if (value == null) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ return Arrays.stream(value.split(","))
|
|
|
+ .map(String::trim)
|
|
|
+ .filter(path -> !path.isEmpty())
|
|
|
+ .map(this::normalizeAttachmentPath)
|
|
|
+ .collect(Collectors.joining(","));
|
|
|
+ }
|
|
|
+
|
|
|
+ private String normalizeAttachmentPath(String value) {
|
|
|
+ String path = value;
|
|
|
+ String base = StringUtils.isBlank(minioEndpoint) || StringUtils.isBlank(minioBucket)
|
|
|
+ ? "" : minioEndpoint.replaceAll("/+$", "") + "/" + minioBucket + "/";
|
|
|
+ if (!base.isEmpty() && path.startsWith(base)) {
|
|
|
+ path = path.substring(base.length());
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ java.net.URI uri = java.net.URI.create(path);
|
|
|
+ String decodedPath = uri.getPath();
|
|
|
+ if (uri.isAbsolute() || uri.getRawAuthority() != null || uri.getRawQuery() != null
|
|
|
+ || uri.getRawFragment() != null || decodedPath == null
|
|
|
+ || decodedPath.contains("\\") || decodedPath.contains("//")
|
|
|
+ || Arrays.stream(decodedPath.split("/")).anyMatch(part -> ".".equals(part) || "..".equals(part))) {
|
|
|
+ throw new IllegalArgumentException();
|
|
|
+ }
|
|
|
+ path = "/" + path.replaceFirst("^/+", "");
|
|
|
+ if ("/".equals(path)) {
|
|
|
+ throw new IllegalArgumentException();
|
|
|
+ }
|
|
|
+ return path;
|
|
|
+ } catch (IllegalArgumentException ex) {
|
|
|
+ throw new ServiceException("工单附件必须使用有效的 MinIO 相对路径");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 写入工单操作日志(操作人取当前登录用户)
|
|
|
*/
|
|
|
@@ -843,7 +906,7 @@ public class WorkOrderServiceImpl extends ServiceImpl<WorkOrderMapper, WorkOrder
|
|
|
logEntry.setWorkOrderId(orderId);
|
|
|
logEntry.setOperType(operType.getCode());
|
|
|
logEntry.setOperDesc(operDesc);
|
|
|
- logEntry.setAttachUrl(attachUrl);
|
|
|
+ logEntry.setAttachUrl(normalizeAttachmentPaths(attachUrl));
|
|
|
logEntry.setOperUserId(currentUserId());
|
|
|
logEntry.setOperUserName(currentUserName());
|
|
|
logEntry.setOperTime(new Date());
|
|
|
@@ -869,25 +932,41 @@ public class WorkOrderServiceImpl extends ServiceImpl<WorkOrderMapper, WorkOrder
|
|
|
/**
|
|
|
* 隐患等级映射工单优先级:0-重大→紧急 3-轻微→低 其余→一般
|
|
|
*/
|
|
|
- private WorkOrderLevelEnum mapHazardLevelToOrderLevel(String hazardLevel) {
|
|
|
- if ("0".equals(hazardLevel)) {
|
|
|
- return WorkOrderLevelEnum.URGENT;
|
|
|
- }
|
|
|
- if ("3".equals(hazardLevel)) {
|
|
|
- return WorkOrderLevelEnum.LOW;
|
|
|
- }
|
|
|
- return WorkOrderLevelEnum.NORMAL;
|
|
|
+ private Integer mapHazardLevelToOrderLevel(String hazardLevel) {
|
|
|
+ if ("0".equals(hazardLevel)) return 0;
|
|
|
+ if ("3".equals(hazardLevel)) return 2;
|
|
|
+ return 1;
|
|
|
}
|
|
|
|
|
|
/** 报警等级映射工单优先级:1级最高为紧急,4级最低为低,其余为一般。 */
|
|
|
- private WorkOrderLevelEnum mapAlarmLevelToOrderLevel(Integer alarmLevel) {
|
|
|
- if (alarmLevel == null || alarmLevel == 1) {
|
|
|
- return WorkOrderLevelEnum.URGENT;
|
|
|
- }
|
|
|
- if (alarmLevel == 4) {
|
|
|
- return WorkOrderLevelEnum.LOW;
|
|
|
+ private Integer mapAlarmLevelToOrderLevel(Integer alarmLevel) {
|
|
|
+ if (alarmLevel == null || alarmLevel == 1) return 0;
|
|
|
+ if (alarmLevel == 4) return 2;
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ private Integer normalizeWorkOrderLevel(Integer value) {
|
|
|
+ SysDictData query = new SysDictData();
|
|
|
+ query.setDictType(WORK_ORDER_LEVEL_DICT);
|
|
|
+ query.setStatus("0");
|
|
|
+ List<SysDictData> values = sysDictDataService.selectDictDataList(query);
|
|
|
+ if (values == null) values = Collections.emptyList();
|
|
|
+ if (value == null) {
|
|
|
+ for (SysDictData item : values) {
|
|
|
+ if ("0".equals(item.getStatus()) && "Y".equals(item.getIsDefault())) {
|
|
|
+ try {
|
|
|
+ return Integer.valueOf(item.getDictValue());
|
|
|
+ } catch (NumberFormatException ignored) {
|
|
|
+ throw new ServiceException("工单优先级默认字典值必须为整数");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ throw new ServiceException("请配置启用的工单优先级默认字典项");
|
|
|
}
|
|
|
- return WorkOrderLevelEnum.NORMAL;
|
|
|
+ boolean valid = values.stream().anyMatch(item -> "0".equals(item.getStatus())
|
|
|
+ && String.valueOf(value).equals(item.getDictValue()));
|
|
|
+ if (!valid) throw new ServiceException("工单优先级无效");
|
|
|
+ return value;
|
|
|
}
|
|
|
|
|
|
/** 生成报警转工单时的默认问题描述。 */
|