|
@@ -15,6 +15,7 @@ import com.zksy.ops.domain.WorkOrderLog;
|
|
|
import com.zksy.ops.domain.vo.WorkOrderLogVO;
|
|
import com.zksy.ops.domain.vo.WorkOrderLogVO;
|
|
|
import com.zksy.ops.domain.vo.WorkOrderPushVO;
|
|
import com.zksy.ops.domain.vo.WorkOrderPushVO;
|
|
|
import com.zksy.ops.domain.vo.WorkOrderVO;
|
|
import com.zksy.ops.domain.vo.WorkOrderVO;
|
|
|
|
|
+import com.zksy.ops.domain.vo.MobileAssignableUserVO;
|
|
|
import com.zksy.ops.enums.WorkOrderDelayApplyStatusEnum;
|
|
import com.zksy.ops.enums.WorkOrderDelayApplyStatusEnum;
|
|
|
import com.zksy.common.core.domain.entity.SysDictData;
|
|
import com.zksy.common.core.domain.entity.SysDictData;
|
|
|
import com.zksy.system.service.ISysDictDataService;
|
|
import com.zksy.system.service.ISysDictDataService;
|
|
@@ -46,6 +47,7 @@ import com.zksy.ops.dto.WorkOrderVerifyDTO;
|
|
|
import com.zksy.ops.service.WorkOrderService;
|
|
import com.zksy.ops.service.WorkOrderService;
|
|
|
import com.zksy.ops.support.OpsAssignScopeSupport;
|
|
import com.zksy.ops.support.OpsAssignScopeSupport;
|
|
|
import com.zksy.system.service.ISysUserService;
|
|
import com.zksy.system.service.ISysUserService;
|
|
|
|
|
+import com.zksy.system.service.ISysMenuService;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
import org.springframework.beans.factory.annotation.Value;
|
|
import org.springframework.beans.factory.annotation.Value;
|
|
@@ -62,7 +64,6 @@ import java.util.Date;
|
|
|
import java.util.HashMap;
|
|
import java.util.HashMap;
|
|
|
import java.util.HashSet;
|
|
import java.util.HashSet;
|
|
|
import java.util.List;
|
|
import java.util.List;
|
|
|
-import java.util.Locale;
|
|
|
|
|
import java.util.Map;
|
|
import java.util.Map;
|
|
|
import java.util.Objects;
|
|
import java.util.Objects;
|
|
|
import java.util.Set;
|
|
import java.util.Set;
|
|
@@ -105,11 +106,9 @@ public class WorkOrderServiceImpl extends ServiceImpl<WorkOrderMapper, WorkOrder
|
|
|
*/
|
|
*/
|
|
|
private static final long DEFAULT_PAGE_SIZE = 10L;
|
|
private static final long DEFAULT_PAGE_SIZE = 10L;
|
|
|
|
|
|
|
|
- /**
|
|
|
|
|
- * 框架数据范围参数名,与 DataScopeAspect.DATA_SCOPE 保持一致。
|
|
|
|
|
- * zksy-system 模块不依赖 zksy-framework(DataScopeAspect 所在模块),故此处使用字面量。
|
|
|
|
|
- */
|
|
|
|
|
- private static final String DATA_SCOPE = "dataScope";
|
|
|
|
|
|
|
+ private static final String PERM_DISPATCH = "ops:workOrder:dispatch";
|
|
|
|
|
+ private static final String PERM_PROCESS = "ops:workOrder:process";
|
|
|
|
|
+ private static final String PERM_AUDIT = "ops:workOrder:audit";
|
|
|
|
|
|
|
|
@Value("${minio.endpoint}")
|
|
@Value("${minio.endpoint}")
|
|
|
private String minioEndpoint;
|
|
private String minioEndpoint;
|
|
@@ -142,6 +141,9 @@ public class WorkOrderServiceImpl extends ServiceImpl<WorkOrderMapper, WorkOrder
|
|
|
@Autowired
|
|
@Autowired
|
|
|
private ISysUserService sysUserService;
|
|
private ISysUserService sysUserService;
|
|
|
|
|
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private ISysMenuService sysMenuService;
|
|
|
|
|
+
|
|
|
@Autowired
|
|
@Autowired
|
|
|
private ISysDictDataService sysDictDataService;
|
|
private ISysDictDataService sysDictDataService;
|
|
|
|
|
|
|
@@ -170,6 +172,37 @@ public class WorkOrderServiceImpl extends ServiceImpl<WorkOrderMapper, WorkOrder
|
|
|
return voPage;
|
|
return voPage;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public Page<WorkOrderVO> findMobilePage(WorkOrderPageDTO query) {
|
|
|
|
|
+ return findMobilePage(query, false);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public Page<WorkOrderVO> findMobilePendingPage(WorkOrderPageDTO query) {
|
|
|
|
|
+ return findMobilePage(query, true);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private Page<WorkOrderVO> findMobilePage(WorkOrderPageDTO query, boolean pending) {
|
|
|
|
|
+ WorkOrderPageDTO condition = query == null ? new WorkOrderPageDTO() : query;
|
|
|
|
|
+ long pageNum = condition.getPageNum() == null || condition.getPageNum() < 1 ? 1L : condition.getPageNum();
|
|
|
|
|
+ long pageSize = condition.getPageSize() == null || condition.getPageSize() < 1 ? DEFAULT_PAGE_SIZE : Math.min(condition.getPageSize(), 100L);
|
|
|
|
|
+ Long userId = currentUserId();
|
|
|
|
|
+ if (userId == null) {
|
|
|
|
|
+ return new Page<>(pageNum, pageSize);
|
|
|
|
|
+ }
|
|
|
|
|
+ LambdaQueryWrapper<WorkOrder> wrapper = buildFilterWrapper(condition, true);
|
|
|
|
|
+ applyMobileScope(wrapper, userId, pending);
|
|
|
|
|
+ wrapper.orderByAsc(WorkOrder::getOrderLevel)
|
|
|
|
|
+ .orderByAsc(WorkOrder::getOrderStatus)
|
|
|
|
|
+ .orderByDesc(WorkOrder::getFaultTime)
|
|
|
|
|
+ .orderByDesc(WorkOrder::getCreateTime);
|
|
|
|
|
+ Page<WorkOrderVO> result = toVOPage(this.page(new Page<>(pageNum, pageSize), wrapper));
|
|
|
|
|
+ fillUserName(result.getRecords());
|
|
|
|
|
+ fillDeviceInfo(result.getRecords());
|
|
|
|
|
+ fillSourceNumbers(result.getRecords());
|
|
|
|
|
+ return result;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* 实体分页转出参分页:分页元信息(总数/页码/每页条数)原样保留,records 逐条转出参。
|
|
* 实体分页转出参分页:分页元信息(总数/页码/每页条数)原样保留,records 逐条转出参。
|
|
|
*
|
|
*
|
|
@@ -201,7 +234,9 @@ public class WorkOrderServiceImpl extends ServiceImpl<WorkOrderMapper, WorkOrder
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 不叠加状态筛选,否则点击某个状态后其它状态的计数会全部变成 0
|
|
// 不叠加状态筛选,否则点击某个状态后其它状态的计数会全部变成 0
|
|
|
- List<Map<String, Object>> rows = baseMapper.countByStatus(buildFilterWrapper(condition, false));
|
|
|
|
|
|
|
+ LambdaQueryWrapper<WorkOrder> wrapper = buildFilterWrapper(condition, false);
|
|
|
|
|
+ applyPcScope(wrapper);
|
|
|
|
|
+ List<Map<String, Object>> rows = baseMapper.countByStatus(wrapper);
|
|
|
long total = 0L;
|
|
long total = 0L;
|
|
|
if (!CollectionUtils.isEmpty(rows)) {
|
|
if (!CollectionUtils.isEmpty(rows)) {
|
|
|
for (Map<String, Object> row : rows) {
|
|
for (Map<String, Object> row : rows) {
|
|
@@ -231,9 +266,26 @@ public class WorkOrderServiceImpl extends ServiceImpl<WorkOrderMapper, WorkOrder
|
|
|
WorkOrderDetailVO detail = new WorkOrderDetailVO();
|
|
WorkOrderDetailVO detail = new WorkOrderDetailVO();
|
|
|
detail.setOrder(vo);
|
|
detail.setOrder(vo);
|
|
|
detail.setLogs(listLogs(orderId));
|
|
detail.setLogs(listLogs(orderId));
|
|
|
|
|
+ detail.setAttachmentBaseUrl(attachmentBaseUrl());
|
|
|
return detail;
|
|
return detail;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ private String attachmentBaseUrl() {
|
|
|
|
|
+ if (StringUtils.isBlank(minioEndpoint) || StringUtils.isBlank(minioBucket)) {
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+ return minioEndpoint.replaceAll("/+$", "") + "/" + minioBucket + "/";
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public WorkOrderDetailVO getMobileDetail(Long orderId) {
|
|
|
|
|
+ WorkOrder order = getOrderById(orderId);
|
|
|
|
|
+ if (!isMobileManagementVisible(order, currentUserId())) {
|
|
|
|
|
+ throw new ServiceException("无权查看该工单");
|
|
|
|
|
+ }
|
|
|
|
|
+ return getDetail(orderId);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
@Override
|
|
@Override
|
|
|
public List<WorkOrderLogVO> listLogs(Long orderId) {
|
|
public List<WorkOrderLogVO> listLogs(Long orderId) {
|
|
|
if (orderId == null) {
|
|
if (orderId == null) {
|
|
@@ -261,6 +313,24 @@ public class WorkOrderServiceImpl extends ServiceImpl<WorkOrderMapper, WorkOrder
|
|
|
return assignScopeSupport.assignableUsers(deptId);
|
|
return assignScopeSupport.assignableUsers(deptId);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public List<MobileAssignableUserVO> mobileAssignableUsers(String type) {
|
|
|
|
|
+ String permission;
|
|
|
|
|
+ if ("handler".equals(type)) {
|
|
|
|
|
+ permission = PERM_PROCESS;
|
|
|
|
|
+ } else if ("reviewer".equals(type)) {
|
|
|
|
|
+ permission = PERM_AUDIT;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ throw new ServiceException("候选人类型不正确");
|
|
|
|
|
+ }
|
|
|
|
|
+ return assignScopeSupport.assignableUsersInScope().stream()
|
|
|
|
|
+ .filter(this::isNormalUser)
|
|
|
|
|
+ .filter(user -> userHasPermission(user.getUserId(), permission))
|
|
|
|
|
+ .map(user -> new MobileAssignableUserVO(user.getUserId(), userLabel(user), user.getDeptId(),
|
|
|
|
|
+ user.getDept() == null ? null : user.getDept().getDeptName()))
|
|
|
|
|
+ .collect(Collectors.toList());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
@Override
|
|
@Override
|
|
|
public List<WorkOrderPushVO> listPendingOrOverdue(Date now) {
|
|
public List<WorkOrderPushVO> listPendingOrOverdue(Date now) {
|
|
|
Date currentTime = now == null ? new Date() : now;
|
|
Date currentTime = now == null ? new Date() : now;
|
|
@@ -295,10 +365,6 @@ public class WorkOrderServiceImpl extends ServiceImpl<WorkOrderMapper, WorkOrder
|
|
|
}
|
|
}
|
|
|
workOrder.setOrderStatus(WorkOrderStatusEnum.PENDING_DISPATCH.getCode());
|
|
workOrder.setOrderStatus(WorkOrderStatusEnum.PENDING_DISPATCH.getCode());
|
|
|
workOrder.setDelayApplyStatus(WorkOrderDelayApplyStatusEnum.NONE.getCode());
|
|
workOrder.setDelayApplyStatus(WorkOrderDelayApplyStatusEnum.NONE.getCode());
|
|
|
- // 数据按部门隔离:默认归属创建人所在部门(框架 DataScopeAspect 依据该字段过滤)
|
|
|
|
|
- if (workOrder.getDeptId() == null) {
|
|
|
|
|
- workOrder.setDeptId(assignScopeSupport.currentDeptId());
|
|
|
|
|
- }
|
|
|
|
|
workOrder.setCreateTime(now);
|
|
workOrder.setCreateTime(now);
|
|
|
workOrder.setCreateBy(currentUserId());
|
|
workOrder.setCreateBy(currentUserId());
|
|
|
workOrder.setUpdateTime(now);
|
|
workOrder.setUpdateTime(now);
|
|
@@ -360,7 +426,6 @@ public class WorkOrderServiceImpl extends ServiceImpl<WorkOrderMapper, WorkOrder
|
|
|
workOrder.setFaultTime(alarm.getCreateTime() == null
|
|
workOrder.setFaultTime(alarm.getCreateTime() == null
|
|
|
? now
|
|
? now
|
|
|
: java.sql.Timestamp.valueOf(alarm.getCreateTime()));
|
|
: java.sql.Timestamp.valueOf(alarm.getCreateTime()));
|
|
|
- workOrder.setDeptId(assignScopeSupport.currentDeptId());
|
|
|
|
|
workOrder.setOrderStatus(WorkOrderStatusEnum.PENDING_DISPATCH.getCode());
|
|
workOrder.setOrderStatus(WorkOrderStatusEnum.PENDING_DISPATCH.getCode());
|
|
|
workOrder.setDelayApplyStatus(WorkOrderDelayApplyStatusEnum.NONE.getCode());
|
|
workOrder.setDelayApplyStatus(WorkOrderDelayApplyStatusEnum.NONE.getCode());
|
|
|
workOrder.setCreateTime(now);
|
|
workOrder.setCreateTime(now);
|
|
@@ -408,8 +473,6 @@ public class WorkOrderServiceImpl extends ServiceImpl<WorkOrderMapper, WorkOrder
|
|
|
workOrder.setDeviceId(equipmentId);
|
|
workOrder.setDeviceId(equipmentId);
|
|
|
workOrder.setOrderLevel(normalizeWorkOrderLevel(mapHazardLevelToOrderLevel(hazardLevel)));
|
|
workOrder.setOrderLevel(normalizeWorkOrderLevel(mapHazardLevelToOrderLevel(hazardLevel)));
|
|
|
workOrder.setOrderDesc(hazardDesc);
|
|
workOrder.setOrderDesc(hazardDesc);
|
|
|
- // 数据按部门隔离:默认归属创建人所在部门(框架 DataScopeAspect 依据该字段过滤)
|
|
|
|
|
- workOrder.setDeptId(assignScopeSupport.currentDeptId());
|
|
|
|
|
workOrder.setOrderStatus(WorkOrderStatusEnum.PENDING_DISPATCH.getCode());
|
|
workOrder.setOrderStatus(WorkOrderStatusEnum.PENDING_DISPATCH.getCode());
|
|
|
workOrder.setDelayApplyStatus(WorkOrderDelayApplyStatusEnum.NONE.getCode());
|
|
workOrder.setDelayApplyStatus(WorkOrderDelayApplyStatusEnum.NONE.getCode());
|
|
|
workOrder.setPlanFinishTime(planFinishTime);
|
|
workOrder.setPlanFinishTime(planFinishTime);
|
|
@@ -448,21 +511,22 @@ public class WorkOrderServiceImpl extends ServiceImpl<WorkOrderMapper, WorkOrder
|
|
|
if (!Objects.equals(WorkOrderStatusEnum.PENDING_DISPATCH.getCode(), order.getOrderStatus())) {
|
|
if (!Objects.equals(WorkOrderStatusEnum.PENDING_DISPATCH.getCode(), order.getOrderStatus())) {
|
|
|
throw new ServiceException("仅待派单工单允许派单");
|
|
throw new ServiceException("仅待派单工单允许派单");
|
|
|
}
|
|
}
|
|
|
|
|
+ requireDispatchScope(order);
|
|
|
assignScopeSupport.validateAssignUserInScope(handlerId);
|
|
assignScopeSupport.validateAssignUserInScope(handlerId);
|
|
|
SysUser handler = sysUserService.selectUserById(handlerId);
|
|
SysUser handler = sysUserService.selectUserById(handlerId);
|
|
|
if (handler == null || !UserConstants.NORMAL.equals(String.valueOf(handler.getStatus())) || !UserConstants.NORMAL.equals(String.valueOf(handler.getDelFlag()))) {
|
|
if (handler == null || !UserConstants.NORMAL.equals(String.valueOf(handler.getStatus())) || !UserConstants.NORMAL.equals(String.valueOf(handler.getDelFlag()))) {
|
|
|
throw new ServiceException("责任人不存在或已停用");
|
|
throw new ServiceException("责任人不存在或已停用");
|
|
|
}
|
|
}
|
|
|
|
|
+ requireUserPermission(handlerId, PERM_PROCESS, "责任人");
|
|
|
assignScopeSupport.validateAssignUserInScope(verifyUserId);
|
|
assignScopeSupport.validateAssignUserInScope(verifyUserId);
|
|
|
SysUser verifier = sysUserService.selectUserById(verifyUserId);
|
|
SysUser verifier = sysUserService.selectUserById(verifyUserId);
|
|
|
if (verifier == null || !UserConstants.NORMAL.equals(String.valueOf(verifier.getStatus())) || !UserConstants.NORMAL.equals(String.valueOf(verifier.getDelFlag()))) {
|
|
if (verifier == null || !UserConstants.NORMAL.equals(String.valueOf(verifier.getStatus())) || !UserConstants.NORMAL.equals(String.valueOf(verifier.getDelFlag()))) {
|
|
|
throw new ServiceException("核验人不存在或已停用");
|
|
throw new ServiceException("核验人不存在或已停用");
|
|
|
}
|
|
}
|
|
|
|
|
+ requireUserPermission(verifyUserId, PERM_AUDIT, "核验人");
|
|
|
|
|
|
|
|
Date now = new Date();
|
|
Date now = new Date();
|
|
|
this.update(updateWrapper(id).set(WorkOrder::getOrderStatus, WorkOrderStatusEnum.PENDING_ACCEPT.getCode()).set(WorkOrder::getReceiveUser, handlerId).set(WorkOrder::getVerifyUser, verifyUserId)
|
|
this.update(updateWrapper(id).set(WorkOrder::getOrderStatus, WorkOrderStatusEnum.PENDING_ACCEPT.getCode()).set(WorkOrder::getReceiveUser, handlerId).set(WorkOrder::getVerifyUser, verifyUserId)
|
|
|
- // 数据归属部门跟随派单指定的责任人
|
|
|
|
|
- .set(handler.getDeptId() != null, WorkOrder::getDeptId, handler.getDeptId())
|
|
|
|
|
// 计划完成时间:派单时可设定/修改,为空则保留原值
|
|
// 计划完成时间:派单时可设定/修改,为空则保留原值
|
|
|
.set(dto.getPlanFinishTime() != null, WorkOrder::getPlanFinishTime, dto.getPlanFinishTime())
|
|
.set(dto.getPlanFinishTime() != null, WorkOrder::getPlanFinishTime, dto.getPlanFinishTime())
|
|
|
.eq(WorkOrder::getOrderStatus, WorkOrderStatusEnum.PENDING_DISPATCH.getCode()));
|
|
.eq(WorkOrder::getOrderStatus, WorkOrderStatusEnum.PENDING_DISPATCH.getCode()));
|
|
@@ -477,6 +541,7 @@ public class WorkOrderServiceImpl extends ServiceImpl<WorkOrderMapper, WorkOrder
|
|
|
@Transactional(rollbackFor = Exception.class)
|
|
@Transactional(rollbackFor = Exception.class)
|
|
|
public boolean accept(Long orderId, WorkOrderOperateDTO dto) {
|
|
public boolean accept(Long orderId, WorkOrderOperateDTO dto) {
|
|
|
WorkOrder order = getOrderById(orderId);
|
|
WorkOrder order = getOrderById(orderId);
|
|
|
|
|
+ requireDeviceCompanyScope(order);
|
|
|
requireResponsible(order, currentUserId(), "核查接单");
|
|
requireResponsible(order, currentUserId(), "核查接单");
|
|
|
requireStatus(order, WorkOrderStatusEnum.PENDING_ACCEPT, "仅待接单工单允许核查接单");
|
|
requireStatus(order, WorkOrderStatusEnum.PENDING_ACCEPT, "仅待接单工单允许核查接单");
|
|
|
// 核查接单必须上传现场情况附件
|
|
// 核查接单必须上传现场情况附件
|
|
@@ -496,13 +561,14 @@ public class WorkOrderServiceImpl extends ServiceImpl<WorkOrderMapper, WorkOrder
|
|
|
@Transactional(rollbackFor = Exception.class)
|
|
@Transactional(rollbackFor = Exception.class)
|
|
|
public boolean process(Long orderId, WorkOrderOperateDTO dto) {
|
|
public boolean process(Long orderId, WorkOrderOperateDTO dto) {
|
|
|
WorkOrder order = getOrderById(orderId);
|
|
WorkOrder order = getOrderById(orderId);
|
|
|
|
|
+ requireDeviceCompanyScope(order);
|
|
|
requireResponsible(order, currentUserId(), "处置");
|
|
requireResponsible(order, currentUserId(), "处置");
|
|
|
Integer status = order.getOrderStatus();
|
|
Integer status = order.getOrderStatus();
|
|
|
if (!WorkOrderStatusEnum.canProcess(status)) {
|
|
if (!WorkOrderStatusEnum.canProcess(status)) {
|
|
|
throw new ServiceException("当前工单状态不允许处置");
|
|
throw new ServiceException("当前工单状态不允许处置");
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 已接单/延期中 → 处理中;处理中保持原状态,支持多次处置
|
|
|
|
|
|
|
+ // 已接单/延期中处置后进入处理中;处理中不允许重复提交处置
|
|
|
Integer targetStatus = (Objects.equals(WorkOrderStatusEnum.ACCEPTED.getCode(), status)
|
|
Integer targetStatus = (Objects.equals(WorkOrderStatusEnum.ACCEPTED.getCode(), status)
|
|
|
|| Objects.equals(WorkOrderStatusEnum.DELAYING.getCode(), status))
|
|
|| Objects.equals(WorkOrderStatusEnum.DELAYING.getCode(), status))
|
|
|
? WorkOrderStatusEnum.PROCESSING.getCode()
|
|
? WorkOrderStatusEnum.PROCESSING.getCode()
|
|
@@ -518,6 +584,7 @@ public class WorkOrderServiceImpl extends ServiceImpl<WorkOrderMapper, WorkOrder
|
|
|
@Transactional(rollbackFor = Exception.class)
|
|
@Transactional(rollbackFor = Exception.class)
|
|
|
public boolean submitVerify(Long orderId, WorkOrderOperateDTO dto) {
|
|
public boolean submitVerify(Long orderId, WorkOrderOperateDTO dto) {
|
|
|
WorkOrder order = getOrderById(orderId);
|
|
WorkOrder order = getOrderById(orderId);
|
|
|
|
|
+ requireDeviceCompanyScope(order);
|
|
|
requireResponsible(order, currentUserId(), "提交验收");
|
|
requireResponsible(order, currentUserId(), "提交验收");
|
|
|
Integer status = order.getOrderStatus();
|
|
Integer status = order.getOrderStatus();
|
|
|
if (!WorkOrderStatusEnum.canSubmitVerify(status)) {
|
|
if (!WorkOrderStatusEnum.canSubmitVerify(status)) {
|
|
@@ -544,6 +611,8 @@ public class WorkOrderServiceImpl extends ServiceImpl<WorkOrderMapper, WorkOrder
|
|
|
throw new ServiceException("验收结果不能为空");
|
|
throw new ServiceException("验收结果不能为空");
|
|
|
}
|
|
}
|
|
|
WorkOrder order = getOrderById(id);
|
|
WorkOrder order = getOrderById(id);
|
|
|
|
|
+ requireDeviceCompanyScope(order);
|
|
|
|
|
+ requireVerifier(order, currentUserId(), "验收");
|
|
|
requireStatus(order, WorkOrderStatusEnum.PENDING_VERIFY, "仅待验收工单允许验收");
|
|
requireStatus(order, WorkOrderStatusEnum.PENDING_VERIFY, "仅待验收工单允许验收");
|
|
|
|
|
|
|
|
Date now = new Date();
|
|
Date now = new Date();
|
|
@@ -576,14 +645,20 @@ public class WorkOrderServiceImpl extends ServiceImpl<WorkOrderMapper, WorkOrder
|
|
|
public boolean cancel(Long orderId, WorkOrderOperateDTO dto) {
|
|
public boolean cancel(Long orderId, WorkOrderOperateDTO dto) {
|
|
|
Long id = requireOrderId(orderId);
|
|
Long id = requireOrderId(orderId);
|
|
|
WorkOrder order = getOrderById(id);
|
|
WorkOrder order = getOrderById(id);
|
|
|
|
|
+ if (!isMobileManagementVisible(order, currentUserId())) {
|
|
|
|
|
+ throw new ServiceException("无权取消该工单");
|
|
|
|
|
+ }
|
|
|
if (!WorkOrderStatusEnum.canCancel(order.getOrderStatus())) {
|
|
if (!WorkOrderStatusEnum.canCancel(order.getOrderStatus())) {
|
|
|
- throw new ServiceException("当前工单状态不允许取消");
|
|
|
|
|
|
|
+ throw new ServiceException("仅待派单、待接单工单允许取消");
|
|
|
}
|
|
}
|
|
|
if (StringUtils.isEmpty(dto.getContent())) {
|
|
if (StringUtils.isEmpty(dto.getContent())) {
|
|
|
throw new ServiceException("请填写取消原因");
|
|
throw new ServiceException("请填写取消原因");
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
boolean updated = transition(id, order.getOrderStatus(), WorkOrderStatusEnum.CANCELLED.getCode(), null);
|
|
boolean updated = transition(id, order.getOrderStatus(), WorkOrderStatusEnum.CANCELLED.getCode(), null);
|
|
|
|
|
+ if (!updated) {
|
|
|
|
|
+ throw new ServiceException("工单状态已变更,请刷新后重试");
|
|
|
|
|
+ }
|
|
|
writeLog(id, WorkOrderLogOperTypeEnum.CANCEL, buildDesc("原因", dto.getContent()), dto.getAttachUrl());
|
|
writeLog(id, WorkOrderLogOperTypeEnum.CANCEL, buildDesc("原因", dto.getContent()), dto.getAttachUrl());
|
|
|
return updated;
|
|
return updated;
|
|
|
}
|
|
}
|
|
@@ -593,6 +668,7 @@ public class WorkOrderServiceImpl extends ServiceImpl<WorkOrderMapper, WorkOrder
|
|
|
public boolean applyDelay(Long orderId, WorkOrderDelayApplyDTO dto) {
|
|
public boolean applyDelay(Long orderId, WorkOrderDelayApplyDTO dto) {
|
|
|
Long id = requireOrderId(orderId);
|
|
Long id = requireOrderId(orderId);
|
|
|
WorkOrder order = getOrderById(id);
|
|
WorkOrder order = getOrderById(id);
|
|
|
|
|
+ requireDeviceCompanyScope(order);
|
|
|
requireResponsible(order, currentUserId(), "申请延期");
|
|
requireResponsible(order, currentUserId(), "申请延期");
|
|
|
requireStatus(order, WorkOrderStatusEnum.PROCESSING, "仅处理中工单允许申请延期");
|
|
requireStatus(order, WorkOrderStatusEnum.PROCESSING, "仅处理中工单允许申请延期");
|
|
|
if (!Objects.equals(WorkOrderDelayApplyStatusEnum.NONE.getCode(), order.getDelayApplyStatus())) {
|
|
if (!Objects.equals(WorkOrderDelayApplyStatusEnum.NONE.getCode(), order.getDelayApplyStatus())) {
|
|
@@ -621,6 +697,9 @@ public class WorkOrderServiceImpl extends ServiceImpl<WorkOrderMapper, WorkOrder
|
|
|
throw new ServiceException("延期审核结果不能为空");
|
|
throw new ServiceException("延期审核结果不能为空");
|
|
|
}
|
|
}
|
|
|
WorkOrder order = getOrderById(id);
|
|
WorkOrder order = getOrderById(id);
|
|
|
|
|
+ requireDeviceCompanyScope(order);
|
|
|
|
|
+ requireVerifier(order, currentUserId(), "延期审核");
|
|
|
|
|
+ requireStatus(order, WorkOrderStatusEnum.PROCESSING, "仅处理中工单允许延期审核");
|
|
|
if (!Objects.equals(WorkOrderDelayApplyStatusEnum.PENDING_AUDIT.getCode(), order.getDelayApplyStatus())) {
|
|
if (!Objects.equals(WorkOrderDelayApplyStatusEnum.PENDING_AUDIT.getCode(), order.getDelayApplyStatus())) {
|
|
|
throw new ServiceException("该工单没有待审核的延期申请");
|
|
throw new ServiceException("该工单没有待审核的延期申请");
|
|
|
}
|
|
}
|
|
@@ -656,17 +735,16 @@ public class WorkOrderServiceImpl extends ServiceImpl<WorkOrderMapper, WorkOrder
|
|
|
return true;
|
|
return true;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /**
|
|
|
|
|
- * 构建工单分页查询条件(含数据权限片段与设备类别收窄)
|
|
|
|
|
- */
|
|
|
|
|
|
|
+ /** 构建 PC 端工单分页查询条件(含参与人数据权限与设备类别收窄)。 */
|
|
|
private LambdaQueryWrapper<WorkOrder> buildQueryWrapper(WorkOrderPageDTO condition) {
|
|
private LambdaQueryWrapper<WorkOrder> buildQueryWrapper(WorkOrderPageDTO condition) {
|
|
|
LambdaQueryWrapper<WorkOrder> wrapper = buildFilterWrapper(condition, true);
|
|
LambdaQueryWrapper<WorkOrder> wrapper = buildFilterWrapper(condition, true);
|
|
|
|
|
+ applyPcScope(wrapper);
|
|
|
wrapper.orderByAsc(WorkOrder::getOrderLevel).orderByAsc(WorkOrder::getOrderStatus).orderByDesc(WorkOrder::getFaultTime).orderByDesc(WorkOrder::getCreateTime);
|
|
wrapper.orderByAsc(WorkOrder::getOrderLevel).orderByAsc(WorkOrder::getOrderStatus).orderByDesc(WorkOrder::getFaultTime).orderByDesc(WorkOrder::getCreateTime);
|
|
|
return wrapper;
|
|
return wrapper;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * 构建工单筛选条件(数据权限片段 + 业务条件 + 设备类别收窄),列表查询与状态统计共用。
|
|
|
|
|
|
|
+ * 构建工单业务筛选条件,PC 与移动端查询共用。
|
|
|
*
|
|
*
|
|
|
* <p>返回值刻意不含 orderBy:状态统计要按状态分组,带排序在 MySQL ONLY_FULL_GROUP_BY 下会报错。</p>
|
|
* <p>返回值刻意不含 orderBy:状态统计要按状态分组,带排序在 MySQL ONLY_FULL_GROUP_BY 下会报错。</p>
|
|
|
*
|
|
*
|
|
@@ -677,11 +755,6 @@ public class WorkOrderServiceImpl extends ServiceImpl<WorkOrderMapper, WorkOrder
|
|
|
private LambdaQueryWrapper<WorkOrder> buildFilterWrapper(WorkOrderPageDTO condition, boolean withStatus) {
|
|
private LambdaQueryWrapper<WorkOrder> buildFilterWrapper(WorkOrderPageDTO condition, boolean withStatus) {
|
|
|
LambdaQueryWrapper<WorkOrder> wrapper = new LambdaQueryWrapper<>();
|
|
LambdaQueryWrapper<WorkOrder> wrapper = new LambdaQueryWrapper<>();
|
|
|
|
|
|
|
|
- String dataScope = dataScopeSql(condition);
|
|
|
|
|
- if (StringUtils.isNotEmpty(dataScope)) {
|
|
|
|
|
- wrapper.apply(dataScope);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
wrapper.eq(condition.getOrderLevel() != null, WorkOrder::getOrderLevel, condition.getOrderLevel())
|
|
wrapper.eq(condition.getOrderLevel() != null, WorkOrder::getOrderLevel, condition.getOrderLevel())
|
|
|
.eq(condition.getDelayApplyStatus() != null, WorkOrder::getDelayApplyStatus, condition.getDelayApplyStatus())
|
|
.eq(condition.getDelayApplyStatus() != null, WorkOrder::getDelayApplyStatus, condition.getDelayApplyStatus())
|
|
|
.eq(StringUtils.isNotEmpty(condition.getDeviceId()), WorkOrder::getDeviceId, condition.getDeviceId())
|
|
.eq(StringUtils.isNotEmpty(condition.getDeviceId()), WorkOrder::getDeviceId, condition.getDeviceId())
|
|
@@ -720,6 +793,117 @@ public class WorkOrderServiceImpl extends ServiceImpl<WorkOrderMapper, WorkOrder
|
|
|
return wrapper;
|
|
return wrapper;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /** PC 端数据范围:普通用户仅可见自己创建、接单或验收的工单,超级管理员不受限制。 */
|
|
|
|
|
+ private void applyPcScope(LambdaQueryWrapper<WorkOrder> wrapper) {
|
|
|
|
|
+ if (assignScopeSupport.isAdmin()) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ Long userId = currentUserId();
|
|
|
|
|
+ if (userId == null) {
|
|
|
|
|
+ wrapper.eq(WorkOrder::getOrderId, -1L);
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ wrapper.and(w -> w.eq(WorkOrder::getCreateBy, userId)
|
|
|
|
|
+ .or().eq(WorkOrder::getReceiveUser, userId)
|
|
|
|
|
+ .or().eq(WorkOrder::getVerifyUser, userId));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /** 移动端“我的工单/待办工单”最终数据范围。 */
|
|
|
|
|
+ private void applyMobileScope(LambdaQueryWrapper<WorkOrder> wrapper, Long userId, boolean pending) {
|
|
|
|
|
+ String companySql = currentCompanyEquipmentSql();
|
|
|
|
|
+ int hasDispatch = SecurityUtils.hasPermi(PERM_DISPATCH) ? 1 : 0;
|
|
|
|
|
+ if (pending) {
|
|
|
|
|
+ wrapper.apply("((device_id IS NOT NULL AND " + companySql + " AND (" +
|
|
|
|
|
+ "({1}=1 AND order_status=0) OR " +
|
|
|
|
|
+ "(receive_user={0} AND order_status IN (1,2,3,6)) OR " +
|
|
|
|
|
+ "(verify_user={0} AND (order_status=4 OR (order_status=3 AND delay_apply_status=1))))) OR " +
|
|
|
|
|
+ "(device_id IS NULL AND (((create_by={0} AND {1}=1 AND order_status=0)) OR " +
|
|
|
|
|
+ "(receive_user={0} AND order_status IN (1,2,3,6)) OR " +
|
|
|
|
|
+ "(verify_user={0} AND (order_status=4 OR (order_status=3 AND delay_apply_status=1))))))",
|
|
|
|
|
+ userId, hasDispatch);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ wrapper.apply("((device_id IS NOT NULL AND " + companySql + " AND " +
|
|
|
|
|
+ "(create_by={0} OR receive_user={0} OR verify_user={0} OR ({1}=1 AND order_status=0))) OR " +
|
|
|
|
|
+ "(device_id IS NULL AND (create_by={0} OR receive_user={0} OR verify_user={0})))",
|
|
|
|
|
+ userId, hasDispatch);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private String currentCompanyEquipmentSql() {
|
|
|
|
|
+ Set<Integer> parentIds = currentCompanyParentTypeIds();
|
|
|
|
|
+ if (parentIds.isEmpty()) {
|
|
|
|
|
+ return "1=0";
|
|
|
|
|
+ }
|
|
|
|
|
+ String ids = parentIds.stream().sorted().map(String::valueOf).collect(Collectors.joining(","));
|
|
|
|
|
+ return "EXISTS (SELECT 1 FROM app_user.equipment_base meb " +
|
|
|
|
|
+ "INNER JOIN app_user.equipment_type met ON met.id=meb.equipment_type_id " +
|
|
|
|
|
+ "WHERE meb.equipment_id=app_user.work_order.device_id AND met.parent_id IN (" + ids + "))";
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private Set<Integer> currentCompanyParentTypeIds() {
|
|
|
|
|
+ return assignScopeSupport.currentCompanyEquipmentParentTypeIds();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private boolean isMobileManagementVisible(WorkOrder order, Long userId) {
|
|
|
|
|
+ if (order == null || userId == null) return false;
|
|
|
|
|
+ boolean participant = Objects.equals(order.getCreateBy(), userId)
|
|
|
|
|
+ || Objects.equals(order.getReceiveUser(), userId)
|
|
|
|
|
+ || Objects.equals(order.getVerifyUser(), userId);
|
|
|
|
|
+ if (StringUtils.isEmpty(order.getDeviceId())) return participant;
|
|
|
|
|
+ return isDeviceInCurrentCompany(order.getDeviceId())
|
|
|
|
|
+ && (participant || (SecurityUtils.hasPermi(PERM_DISPATCH)
|
|
|
|
|
+ && Objects.equals(order.getOrderStatus(), WorkOrderStatusEnum.PENDING_DISPATCH.getCode())));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private boolean isDeviceInCurrentCompany(String deviceId) {
|
|
|
|
|
+ if (StringUtils.isEmpty(deviceId)) return true;
|
|
|
|
|
+ EquipmentBase equipment = equipmentBaseMapper.selectById(deviceId);
|
|
|
|
|
+ if (equipment == null || equipment.getEquipmentTypeId() == null) return false;
|
|
|
|
|
+ EquipmentType type = equipmentTypeMapper.selectById(equipment.getEquipmentTypeId());
|
|
|
|
|
+ return type != null && type.getParentId() != null && currentCompanyParentTypeIds().contains(type.getParentId());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void requireDeviceCompanyScope(WorkOrder order) {
|
|
|
|
|
+ if (order != null && StringUtils.isNotEmpty(order.getDeviceId()) && !isDeviceInCurrentCompany(order.getDeviceId())) {
|
|
|
|
|
+ throw new ServiceException("无权操作其他公司范围的工单");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void requireDispatchScope(WorkOrder order) {
|
|
|
|
|
+ Long userId = currentUserId();
|
|
|
|
|
+ if (StringUtils.isEmpty(order.getDeviceId())) {
|
|
|
|
|
+ if (!Objects.equals(order.getCreateBy(), userId)) {
|
|
|
|
|
+ throw new ServiceException("无设备工单仅创建人可以派单");
|
|
|
|
|
+ }
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ requireDeviceCompanyScope(order);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void requireVerifier(WorkOrder order, Long userId, String operation) {
|
|
|
|
|
+ if (!Objects.equals(order.getVerifyUser(), userId)) {
|
|
|
|
|
+ throw new ServiceException("仅指定核验人可以" + operation);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private boolean isNormalUser(SysUser user) {
|
|
|
|
|
+ return user != null && UserConstants.NORMAL.equals(String.valueOf(user.getStatus()))
|
|
|
|
|
+ && UserConstants.NORMAL.equals(String.valueOf(user.getDelFlag()));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private boolean userHasPermission(Long userId, String permission) {
|
|
|
|
|
+ if (userId == null) return false;
|
|
|
|
|
+ if (SecurityUtils.isAdmin(userId)) return true;
|
|
|
|
|
+ Set<String> permissions = sysMenuService.selectMenuPermsByUserId(userId);
|
|
|
|
|
+ return permissions != null && SecurityUtils.hasPermi(permissions, permission);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void requireUserPermission(Long userId, String permission, String label) {
|
|
|
|
|
+ if (!userHasPermission(userId, permission)) {
|
|
|
|
|
+ throw new ServiceException(label + "未配置所需工单操作权限");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* Map 值转 Long:兼容不同驱动下 COUNT(*) 返回 Integer / Long / BigInteger / String 的差异
|
|
* Map 值转 Long:兼容不同驱动下 COUNT(*) 返回 Integer / Long / BigInteger / String 的差异
|
|
|
*/
|
|
*/
|
|
@@ -734,38 +918,13 @@ public class WorkOrderServiceImpl extends ServiceImpl<WorkOrderMapper, WorkOrder
|
|
|
return StringUtils.isNumeric(text) ? Long.valueOf(text) : null;
|
|
return StringUtils.isNumeric(text) ? Long.valueOf(text) : null;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /**
|
|
|
|
|
- * 解析并剥离数据权限片段中多余的 AND / OR 前缀。
|
|
|
|
|
- *
|
|
|
|
|
- * <p>DataScopeAspect 注入的片段形如 {@code AND (...)},而 wrapper.apply 会自动追加 AND,
|
|
|
|
|
- * 故此处仅保留条件本体。</p>
|
|
|
|
|
- */
|
|
|
|
|
- private String dataScopeSql(WorkOrderPageDTO condition) {
|
|
|
|
|
- Map<String, Object> params = condition.getParams();
|
|
|
|
|
- if (params == null || params.isEmpty()) {
|
|
|
|
|
- return null;
|
|
|
|
|
- }
|
|
|
|
|
- Object dataScope = params.get(DATA_SCOPE);
|
|
|
|
|
- if (dataScope == null) {
|
|
|
|
|
- return null;
|
|
|
|
|
- }
|
|
|
|
|
- String sql = String.valueOf(dataScope).trim();
|
|
|
|
|
- String upper = sql.toUpperCase(Locale.ROOT);
|
|
|
|
|
- if (upper.startsWith("AND ")) {
|
|
|
|
|
- sql = sql.substring(4).trim();
|
|
|
|
|
- } else if (upper.startsWith("OR ")) {
|
|
|
|
|
- sql = sql.substring(3).trim();
|
|
|
|
|
- }
|
|
|
|
|
- return sql.length() == 0 ? null : sql;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
/**
|
|
/**
|
|
|
* 按设备父类别收窄工单查询范围(业务口径过滤)。
|
|
* 按设备父类别收窄工单查询范围(业务口径过滤)。
|
|
|
*
|
|
*
|
|
|
* <p>过滤链路:work_order.device_id → equipment_base.equipment_id
|
|
* <p>过滤链路:work_order.device_id → equipment_base.equipment_id
|
|
|
* → equipment_base.equipment_type_id → equipment_type.id → equipment_type.parent_id。
|
|
* → equipment_base.equipment_type_id → equipment_type.id → equipment_type.parent_id。
|
|
|
* 采用 EXISTS 子查询而非 JOIN,避免设备表一对多时放大分页结果集,也不影响已有的
|
|
* 采用 EXISTS 子查询而非 JOIN,避免设备表一对多时放大分页结果集,也不影响已有的
|
|
|
- * 数据权限片段(dataScope)与 MyBatis-Plus 分页计数。</p>
|
|
|
|
|
|
|
+ * 参与人数据权限与 MyBatis-Plus 分页计数。</p>
|
|
|
*
|
|
*
|
|
|
* <p>parentTypeId 通过 MyBatis-Plus 的 apply 占位符 {0} 注入,由框架做 SQL 注入检查,不拼接原始入参。</p>
|
|
* <p>parentTypeId 通过 MyBatis-Plus 的 apply 占位符 {0} 注入,由框架做 SQL 注入检查,不拼接原始入参。</p>
|
|
|
*
|
|
*
|
|
@@ -1022,8 +1181,9 @@ public class WorkOrderServiceImpl extends ServiceImpl<WorkOrderMapper, WorkOrder
|
|
|
item.setOrderStatus(status);
|
|
item.setOrderStatus(status);
|
|
|
item.setOrderStatusDesc(WorkOrderStatusEnum.getDescByCode(status));
|
|
item.setOrderStatusDesc(WorkOrderStatusEnum.getDescByCode(status));
|
|
|
item.setOrderLevel(order.getOrderLevel());
|
|
item.setOrderLevel(order.getOrderLevel());
|
|
|
- item.setDeptId(order.getDeptId());
|
|
|
|
|
|
|
+ item.setCreateBy(order.getCreateBy());
|
|
|
item.setReceiveUser(order.getReceiveUser());
|
|
item.setReceiveUser(order.getReceiveUser());
|
|
|
|
|
+ item.setVerifyUser(order.getVerifyUser());
|
|
|
item.setDeviceId(order.getDeviceId());
|
|
item.setDeviceId(order.getDeviceId());
|
|
|
item.setDeviceCode(resolveDeviceCode(order.getDeviceId()));
|
|
item.setDeviceCode(resolveDeviceCode(order.getDeviceId()));
|
|
|
item.setOrderDesc(order.getOrderDesc());
|
|
item.setOrderDesc(order.getOrderDesc());
|