package com.sinata.appointment.service;
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.sinata.appointment.config.MiniStpUtil;
|
import com.sinata.appointment.constants.ApprovalInstanceStatus;
|
import com.sinata.appointment.constants.ApprovalNodeCode;
|
import com.sinata.appointment.constants.ApprovalTaskStatus;
|
import com.sinata.appointment.constants.BizErrorCode;
|
import com.sinata.appointment.dto.MiniApprovalTodoVo;
|
import com.sinata.appointment.dto.MiniApprovalActionRequest;
|
import com.sinata.appointment.dto.MiniHandlerApprovalActionRequest;
|
import com.sinata.appointment.dto.MiniHandlerApprovalTodoVo;
|
import com.sinata.appointment.entity.AppointmentOrder;
|
import com.sinata.appointment.entity.AppointmentVehicle;
|
import com.sinata.appointment.entity.AppointmentVisitor;
|
import com.sinata.appointment.entity.ApprovalInstance;
|
import com.sinata.appointment.entity.ApprovalTask;
|
import com.sinata.appointment.entity.BizApprovalNodeConfig;
|
import com.sinata.appointment.entity.BizVisitReason;
|
import com.sinata.appointment.entity.MpPassAccessArea;
|
import com.sinata.appointment.entity.MpPassLocalUnit;
|
import com.sinata.appointment.entity.MpVisitor;
|
import com.sinata.appointment.exception.BizException;
|
import com.sinata.appointment.mapper.AppointmentOrderMapper;
|
import com.sinata.appointment.mapper.AppointmentVehicleMapper;
|
import com.sinata.appointment.mapper.AppointmentVisitorMapper;
|
import com.sinata.appointment.mapper.ApprovalInstanceMapper;
|
import com.sinata.appointment.mapper.ApprovalTaskMapper;
|
import com.sinata.appointment.mapper.BizApprovalNodeConfigMapper;
|
import com.sinata.appointment.mapper.BizVisitReasonMapper;
|
import com.sinata.appointment.mapper.MpVisitorMapper;
|
import com.sinata.appointment.mapper.MpPassAccessAreaMapper;
|
import com.sinata.appointment.mapper.MpPassLocalUnitMapper;
|
import java.time.LocalDate;
|
import java.util.ArrayList;
|
import java.util.LinkedHashSet;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.Objects;
|
import java.util.Set;
|
import java.util.stream.Stream;
|
import java.util.stream.Collectors;
|
import java.util.LinkedHashMap;
|
import lombok.extern.slf4j.Slf4j;
|
import lombok.RequiredArgsConstructor;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.util.StringUtils;
|
import com.sinata.appointment.util.UuidAssert;
|
|
@Slf4j
|
@Service
|
@RequiredArgsConstructor
|
public class MiniHandlerApprovalApplicationService {
|
|
private final ApprovalTaskMapper approvalTaskMapper;
|
private final ApprovalInstanceMapper approvalInstanceMapper;
|
private final AppointmentOrderMapper appointmentOrderMapper;
|
private final AppointmentVisitorMapper appointmentVisitorMapper;
|
private final AppointmentVehicleMapper appointmentVehicleMapper;
|
private final MpVisitorMapper mpVisitorMapper;
|
private final BizVisitReasonMapper bizVisitReasonMapper;
|
private final ApprovalEngineService approvalEngineService;
|
private final IntegrationWechatService integrationWechatService;
|
private final PostApprovalOrchestrationService postApprovalOrchestrationService;
|
private final BizApprovalNodeConfigMapper bizApprovalNodeConfigMapper;
|
private final MpPassAccessAreaMapper mpPassAccessAreaMapper;
|
private final MpPassLocalUnitMapper mpPassLocalUnitMapper;
|
private final ObjectMapper objectMapper;
|
|
public IPage<MiniApprovalTodoVo> pageMyTodoAll(long page, long size) {
|
return pageMyTodoAll(page, size, null, null);
|
}
|
|
public IPage<MiniApprovalTodoVo> pageMyTodoAll(
|
long page, long size, String visitedUserNameKeyword, LocalDate visitDate) {
|
long uid = MiniStpUtil.getLoginIdAsLong();
|
List<ApprovalTask> tasks =
|
approvalTaskMapper.selectList(
|
new LambdaQueryWrapper<ApprovalTask>()
|
.eq(ApprovalTask::getAssigneeUserId, uid)
|
.eq(ApprovalTask::getTaskStatus, ApprovalTaskStatus.PENDING)
|
.orderByDesc(ApprovalTask::getCreateTime)
|
.orderByDesc(ApprovalTask::getId));
|
if (tasks.isEmpty()) {
|
return new Page<>(page, size);
|
}
|
List<Long> instanceIds =
|
tasks.stream()
|
.map(ApprovalTask::getInstanceId)
|
.filter(Objects::nonNull)
|
.toList();
|
Map<Long, ApprovalInstance> instanceMap = loadInstanceMap(instanceIds);
|
List<Long> orderIds =
|
instanceMap.values().stream()
|
.map(ApprovalInstance::getOrderId)
|
.filter(Objects::nonNull)
|
.toList();
|
Map<Long, AppointmentOrder> orderMap = loadOrderMap(orderIds);
|
Map<Long, String> visitorDisplayMap = loadVisitorDisplayMap(orderIds);
|
Map<Long, String> plateTextMap = loadPlateTextMap(orderIds);
|
Map<String, String> reasonNameMap = loadReasonNameMap(orderMap.values());
|
Map<String, String> nodeNameMap = loadNodeNameMap();
|
List<MiniApprovalTodoVo> rowsAll =
|
tasks.stream()
|
.filter(t -> matchTodoFilters(t, instanceMap, orderMap, visitorDisplayMap, visitedUserNameKeyword, visitDate))
|
.map(t -> toMiniTodoVo(t, instanceMap, orderMap, nodeNameMap, visitorDisplayMap, plateTextMap, reasonNameMap))
|
.toList();
|
return slicePage(page, size, rowsAll);
|
}
|
|
public IPage<MiniHandlerApprovalTodoVo> pageMyTodo(long page, long size) {
|
return pageMyTodo(page, size, null, null);
|
}
|
|
public IPage<MiniHandlerApprovalTodoVo> pageMyTodo(
|
long page, long size, String visitedUserNameKeyword, LocalDate visitDate) {
|
long uid = MiniStpUtil.getLoginIdAsLong();
|
List<ApprovalTask> tasks =
|
approvalTaskMapper.selectList(
|
new LambdaQueryWrapper<ApprovalTask>()
|
.eq(ApprovalTask::getAssigneeUserId, uid)
|
.eq(ApprovalTask::getNodeCode, ApprovalNodeCode.LEVEL1_HANDLER)
|
.eq(ApprovalTask::getTaskStatus, ApprovalTaskStatus.PENDING)
|
.orderByDesc(ApprovalTask::getCreateTime)
|
.orderByDesc(ApprovalTask::getId));
|
if (tasks.isEmpty()) {
|
return new Page<>(page, size);
|
}
|
List<Long> instanceIds =
|
tasks.stream()
|
.map(ApprovalTask::getInstanceId)
|
.filter(Objects::nonNull)
|
.toList();
|
Map<Long, ApprovalInstance> instanceMap = loadInstanceMap(instanceIds);
|
List<Long> orderIds =
|
instanceMap.values().stream()
|
.map(ApprovalInstance::getOrderId)
|
.filter(Objects::nonNull)
|
.toList();
|
Map<Long, AppointmentOrder> orderMap = loadOrderMap(orderIds);
|
Map<Long, String> visitorDisplayMap = loadVisitorDisplayMap(orderIds);
|
List<MiniHandlerApprovalTodoVo> rowsAll =
|
tasks.stream()
|
.filter(t -> matchTodoFilters(t, instanceMap, orderMap, visitorDisplayMap, visitedUserNameKeyword, visitDate))
|
.map(t -> toTodoVo(t, instanceMap, orderMap))
|
.toList();
|
return slicePage(page, size, rowsAll);
|
}
|
|
@Transactional(rollbackFor = Exception.class)
|
public void handleAction(MiniHandlerApprovalActionRequest req) {
|
long uid = MiniStpUtil.getLoginIdAsLong();
|
ApprovalTask task = approvalTaskMapper.selectById(req.getTaskId());
|
if (task == null || (task.getDelFlag() != null && task.getDelFlag() == 1)) {
|
throw new BizException(BizErrorCode.APPROVAL_TASK_NOT_FOUND, "审批任务不存在");
|
}
|
UuidAssert.match(task, req.getTaskUuid());
|
if (!ApprovalNodeCode.LEVEL1_HANDLER.equals(task.getNodeCode())) {
|
throw new BizException(BizErrorCode.AUTH_FORBIDDEN, "仅支持经办人一级审批");
|
}
|
if (!ApprovalTaskStatus.PENDING.equals(task.getTaskStatus())) {
|
throw new BizException(BizErrorCode.APPROVAL_CONFLICT, "任务已处理");
|
}
|
if (!Objects.equals(task.getAssigneeUserId(), uid)) {
|
throw new BizException(BizErrorCode.AUTH_FORBIDDEN, "无权处理该任务");
|
}
|
String comment = req.getComment() == null ? null : req.getComment().trim();
|
|
ApprovalInstance inst = approvalInstanceMapper.selectById(task.getInstanceId());
|
if (inst == null || (inst.getDelFlag() != null && inst.getDelFlag() == 1)) {
|
throw new BizException(BizErrorCode.ORDER_NOT_FOUND, "审批实例不存在");
|
}
|
AppointmentOrder order = appointmentOrderMapper.selectById(inst.getOrderId());
|
if (order == null || (order.getDelFlag() != null && order.getDelFlag() == 1)) {
|
throw new BizException(BizErrorCode.ORDER_NOT_FOUND, "预约单不存在");
|
}
|
|
if (Boolean.FALSE.equals(req.getApprove())) {
|
if (!StringUtils.hasText(comment)) {
|
throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, "审批意见不能为空");
|
}
|
validateRejectCommentLength(comment);
|
task.setTaskStatus(ApprovalTaskStatus.REJECTED);
|
task.setComment(comment);
|
approvalTaskMapper.updateById(task);
|
approvalEngineService.rejectInstance(inst, comment);
|
postApprovalOrchestrationService.onOrderRejected(order, comment);
|
return;
|
}
|
|
fillOrderApprovalExtraFields(order, req);
|
appointmentOrderMapper.updateById(order);
|
|
task.setTaskStatus(ApprovalTaskStatus.APPROVED);
|
task.setComment(comment);
|
approvalTaskMapper.updateById(task);
|
approvalEngineService.markGroupSkippedExcept(task);
|
approvalEngineService.rebuildAfterHandlerApproved(task, inst, order);
|
ApprovalInstance latest = approvalInstanceMapper.selectById(inst.getId());
|
if (ApprovalInstanceStatus.APPROVED.equals(latest.getStatus())) {
|
AppointmentOrder fresh = appointmentOrderMapper.selectById(order.getId());
|
postApprovalOrchestrationService.onOrderFullyApproved(fresh);
|
return;
|
}
|
if (ApprovalInstanceStatus.IN_PROGRESS.equals(latest.getStatus())) {
|
try {
|
integrationWechatService.notifyCurrentApprovers(order, latest.getId());
|
} catch (Exception ex) {
|
log.warn("notify current approvers failed, orderId={}", order.getId(), ex);
|
}
|
}
|
}
|
|
@Transactional(rollbackFor = Exception.class)
|
public void handleOtherAction(MiniApprovalActionRequest req) {
|
long uid = MiniStpUtil.getLoginIdAsLong();
|
ApprovalTask task = approvalTaskMapper.selectById(req.getTaskId());
|
if (task == null || (task.getDelFlag() != null && task.getDelFlag() == 1)) {
|
throw new BizException(BizErrorCode.APPROVAL_TASK_NOT_FOUND, "审批任务不存在");
|
}
|
UuidAssert.match(task, req.getTaskUuid());
|
if (ApprovalNodeCode.LEVEL1_HANDLER.equals(task.getNodeCode())) {
|
throw new BizException(BizErrorCode.AUTH_FORBIDDEN, "经办人一级请走专用审批接口");
|
}
|
if (!ApprovalTaskStatus.PENDING.equals(task.getTaskStatus())) {
|
throw new BizException(BizErrorCode.APPROVAL_CONFLICT, "任务已处理");
|
}
|
if (!Objects.equals(task.getAssigneeUserId(), uid)) {
|
throw new BizException(BizErrorCode.AUTH_FORBIDDEN, "无权处理该任务");
|
}
|
|
ApprovalInstance inst = approvalInstanceMapper.selectById(task.getInstanceId());
|
if (inst == null || (inst.getDelFlag() != null && inst.getDelFlag() == 1)) {
|
throw new BizException(BizErrorCode.ORDER_NOT_FOUND, "审批实例不存在");
|
}
|
AppointmentOrder order = appointmentOrderMapper.selectById(inst.getOrderId());
|
if (order == null || (order.getDelFlag() != null && order.getDelFlag() == 1)) {
|
throw new BizException(BizErrorCode.ORDER_NOT_FOUND, "预约单不存在");
|
}
|
|
String comment = req.getComment() == null ? null : req.getComment().trim();
|
appendNoticeIdsIfNeeded(task, req.getNoticeIds());
|
if (Boolean.FALSE.equals(req.getApprove())) {
|
if (StringUtils.hasText(comment)) {
|
validateRejectCommentLength(comment);
|
}
|
String reason = StringUtils.hasText(comment) ? comment : "拒绝";
|
task.setTaskStatus(ApprovalTaskStatus.REJECTED);
|
task.setComment(reason);
|
approvalTaskMapper.updateById(task);
|
approvalEngineService.rejectInstance(inst, reason);
|
postApprovalOrchestrationService.onOrderRejected(order, reason);
|
return;
|
}
|
|
task.setTaskStatus(ApprovalTaskStatus.APPROVED);
|
task.setComment(comment);
|
approvalTaskMapper.updateById(task);
|
approvalEngineService.markGroupSkippedExcept(task);
|
if (approvalEngineService.isCurrentNodeComplete(inst)) {
|
approvalEngineService.advanceOrComplete(inst, order);
|
ApprovalInstance latest = approvalInstanceMapper.selectById(inst.getId());
|
if (ApprovalInstanceStatus.APPROVED.equals(latest.getStatus())) {
|
AppointmentOrder fresh = appointmentOrderMapper.selectById(order.getId());
|
postApprovalOrchestrationService.onOrderFullyApproved(fresh);
|
return;
|
}
|
if (ApprovalInstanceStatus.IN_PROGRESS.equals(latest.getStatus())) {
|
try {
|
integrationWechatService.notifyCurrentApprovers(order, latest.getId());
|
} catch (Exception ex) {
|
log.warn("notify current approvers failed, orderId={}", order.getId(), ex);
|
}
|
}
|
}
|
}
|
|
private void appendNoticeIdsIfNeeded(ApprovalTask task, List<Long> noticeIds) {
|
if (!ApprovalNodeCode.LEVEL3_LOCAL_DEPT_LEADER.equals(task.getNodeCode())) {
|
return;
|
}
|
List<Long> normalized = normalizeIds(noticeIds);
|
if (normalized.isEmpty()) {
|
return;
|
}
|
LinkedHashSet<Long> merged = new LinkedHashSet<>(parseNoticeIds(task.getNoticeIds()));
|
merged.addAll(normalized);
|
task.setNoticeIds(merged.stream().map(String::valueOf).collect(Collectors.joining(",")));
|
}
|
|
private List<Long> parseNoticeIds(String raw) {
|
if (!StringUtils.hasText(raw)) {
|
return List.of();
|
}
|
return Stream.of(raw.split(","))
|
.filter(StringUtils::hasText)
|
.map(String::trim)
|
.map(value -> {
|
try {
|
return Long.parseLong(value);
|
} catch (NumberFormatException ex) {
|
return null;
|
}
|
})
|
.filter(Objects::nonNull)
|
.filter(id -> id > 0)
|
.distinct()
|
.toList();
|
}
|
|
private Map<Long, AppointmentOrder> loadOrderMap(List<Long> orderIds) {
|
if (orderIds.isEmpty()) {
|
return Map.of();
|
}
|
List<AppointmentOrder> rows =
|
appointmentOrderMapper.selectList(
|
new LambdaQueryWrapper<AppointmentOrder>()
|
.eq(AppointmentOrder::getDelFlag, 0)
|
.in(AppointmentOrder::getId, orderIds));
|
return rows.stream().collect(Collectors.toMap(AppointmentOrder::getId, x -> x, (a, b) -> a));
|
}
|
|
private Map<Long, ApprovalInstance> loadInstanceMap(List<Long> instanceIds) {
|
if (instanceIds.isEmpty()) {
|
return Map.of();
|
}
|
List<ApprovalInstance> rows =
|
approvalInstanceMapper.selectList(
|
new LambdaQueryWrapper<ApprovalInstance>()
|
.eq(ApprovalInstance::getDelFlag, 0)
|
.in(ApprovalInstance::getId, instanceIds));
|
return rows.stream().collect(Collectors.toMap(ApprovalInstance::getId, x -> x, (a, b) -> a));
|
}
|
|
private MiniHandlerApprovalTodoVo toTodoVo(
|
ApprovalTask task,
|
Map<Long, ApprovalInstance> instanceMap,
|
Map<Long, AppointmentOrder> orderMap) {
|
MiniHandlerApprovalTodoVo vo = new MiniHandlerApprovalTodoVo();
|
vo.setTaskId(task.getId());
|
vo.setTaskUuid(task.getUuid());
|
vo.setCreateTime(task.getCreateTime());
|
ApprovalInstance inst = instanceMap.get(task.getInstanceId());
|
if (inst == null) {
|
return vo;
|
}
|
AppointmentOrder order = orderMap.get(inst.getOrderId());
|
if (order == null) {
|
return vo;
|
}
|
vo.setOrderId(order.getId());
|
vo.setOrderUuid(order.getUuid());
|
vo.setOrderNo(order.getOrderNo());
|
vo.setVisitedUserName(order.getVisitedUserName());
|
vo.setVisitStartDate(order.getVisitStartDate());
|
vo.setVisitEndDate(order.getVisitEndDate());
|
vo.setVisitReasonCode(order.getVisitReasonCode());
|
return vo;
|
}
|
|
private Map<String, String> loadNodeNameMap() {
|
List<BizApprovalNodeConfig> rows =
|
bizApprovalNodeConfigMapper.selectList(
|
new LambdaQueryWrapper<BizApprovalNodeConfig>()
|
.eq(BizApprovalNodeConfig::getDelFlag, 0)
|
.orderByAsc(BizApprovalNodeConfig::getSortOrder));
|
Map<String, String> out = new java.util.LinkedHashMap<>();
|
for (BizApprovalNodeConfig row : rows) {
|
out.put(row.getNodeCode(), row.getNodeName());
|
}
|
return out;
|
}
|
|
private MiniApprovalTodoVo toMiniTodoVo(
|
ApprovalTask task,
|
Map<Long, ApprovalInstance> instanceMap,
|
Map<Long, AppointmentOrder> orderMap,
|
Map<String, String> nodeNameMap,
|
Map<Long, String> visitorDisplayMap,
|
Map<Long, String> plateTextMap,
|
Map<String, String> reasonNameMap) {
|
MiniApprovalTodoVo vo = new MiniApprovalTodoVo();
|
vo.setTaskId(task.getId());
|
vo.setTaskUuid(task.getUuid());
|
vo.setCreateTime(task.getCreateTime());
|
vo.setNodeCode(task.getNodeCode());
|
vo.setNodeName(nodeNameMap.getOrDefault(task.getNodeCode(), task.getNodeCode()));
|
ApprovalInstance inst = instanceMap.get(task.getInstanceId());
|
if (inst == null) {
|
return vo;
|
}
|
AppointmentOrder order = orderMap.get(inst.getOrderId());
|
if (order == null) {
|
return vo;
|
}
|
vo.setOrderId(order.getId());
|
vo.setOrderUuid(order.getUuid());
|
vo.setOrderNo(order.getOrderNo());
|
vo.setVisitedUserName(order.getVisitedUserName());
|
vo.setVisitorDisplayText(visitorDisplayMap.get(order.getId()));
|
vo.setPlateNoText(plateTextMap.get(order.getId()));
|
vo.setVisitStartDate(order.getVisitStartDate());
|
vo.setVisitEndDate(order.getVisitEndDate());
|
vo.setVisitReasonCode(order.getVisitReasonCode());
|
vo.setVisitReasonText(buildVisitReasonText(order, reasonNameMap));
|
vo.setVisitTimeText(buildVisitTimeText(order));
|
return vo;
|
}
|
|
private void fillOrderApprovalExtraFields(AppointmentOrder order, MiniHandlerApprovalActionRequest req) {
|
List<Long> areaIds = normalizeIds(req.getPassAccessAreaIds());
|
if (areaIds.isEmpty()) {
|
throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, "通行区域不能为空");
|
}
|
List<MpPassAccessArea> areas =
|
mpPassAccessAreaMapper.selectList(
|
new LambdaQueryWrapper<MpPassAccessArea>()
|
.eq(MpPassAccessArea::getDelFlag, 0)
|
.in(MpPassAccessArea::getId, areaIds));
|
Map<Long, String> areaNameMap =
|
areas.stream()
|
.collect(Collectors.toMap(MpPassAccessArea::getId, MpPassAccessArea::getAreaName, (a, b) -> a));
|
List<String> areaNames = new ArrayList<>();
|
for (Long id : areaIds) {
|
String name = areaNameMap.get(id);
|
if (!StringUtils.hasText(name)) {
|
throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, "通行区域不存在: " + id);
|
}
|
areaNames.add(name);
|
}
|
|
boolean involve = Boolean.TRUE.equals(req.getInvolveOtherLocalUnit());
|
List<Long> unitIds = normalizeIds(req.getPassLocalUnitIds());
|
List<String> unitNames = List.of();
|
if (involve) {
|
if (unitIds.isEmpty()) {
|
throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, "涉及其他属地单位时,单位列表不能为空");
|
}
|
List<MpPassLocalUnit> units =
|
mpPassLocalUnitMapper.selectList(
|
new LambdaQueryWrapper<MpPassLocalUnit>()
|
.eq(MpPassLocalUnit::getDelFlag, 0)
|
.in(MpPassLocalUnit::getId, unitIds));
|
Map<Long, String> unitNameMap =
|
units.stream()
|
.collect(Collectors.toMap(MpPassLocalUnit::getId, MpPassLocalUnit::getUnitName, (a, b) -> a));
|
List<String> names = new ArrayList<>();
|
for (Long id : unitIds) {
|
String name = unitNameMap.get(id);
|
if (!StringUtils.hasText(name)) {
|
throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, "属地单位不存在: " + id);
|
}
|
names.add(name);
|
}
|
unitNames = names;
|
} else {
|
unitIds = List.of();
|
}
|
|
order.setPassAccessAreaIds(writeJson(areaIds));
|
order.setPassAccessAreaNames(writeJson(areaNames));
|
order.setInvolveOtherLocalUnit(involve);
|
order.setPassLocalUnitIds(writeJson(unitIds));
|
order.setPassLocalUnitNames(writeJson(unitNames));
|
}
|
|
private static List<Long> normalizeIds(List<Long> ids) {
|
if (ids == null || ids.isEmpty()) {
|
return List.of();
|
}
|
LinkedHashSet<Long> out = new LinkedHashSet<>();
|
for (Long id : ids) {
|
if (id != null && id > 0) {
|
out.add(id);
|
}
|
}
|
return out.stream().toList();
|
}
|
|
private void validateRejectCommentLength(String comment) {
|
if (comment.length() > 30) {
|
throw new BizException(BizErrorCode.AUTH_INVALID_CREDENTIALS, "驳回原因最多30个字");
|
}
|
}
|
|
private String writeJson(Object value) {
|
try {
|
return objectMapper.writeValueAsString(value);
|
} catch (JsonProcessingException ex) {
|
throw new BizException(BizErrorCode.AUTH_FORBIDDEN, "数据序列化失败");
|
}
|
}
|
|
private boolean matchTodoFilters(
|
ApprovalTask task,
|
Map<Long, ApprovalInstance> instanceMap,
|
Map<Long, AppointmentOrder> orderMap,
|
Map<Long, String> visitorDisplayMap,
|
String visitedUserNameKeyword,
|
LocalDate visitDate) {
|
ApprovalInstance inst = instanceMap.get(task.getInstanceId());
|
if (inst == null) {
|
return false;
|
}
|
AppointmentOrder order = orderMap.get(inst.getOrderId());
|
if (order == null) {
|
return false;
|
}
|
if (StringUtils.hasText(visitedUserNameKeyword)) {
|
String keyword = visitedUserNameKeyword.trim();
|
String visitorDisplayText = visitorDisplayMap.get(order.getId());
|
if (!StringUtils.hasText(visitorDisplayText) || !visitorDisplayText.contains(keyword)) {
|
return false;
|
}
|
}
|
if (visitDate != null) {
|
if (order.getVisitStartDate() == null || order.getVisitEndDate() == null) {
|
return false;
|
}
|
if (visitDate.isBefore(order.getVisitStartDate()) || visitDate.isAfter(order.getVisitEndDate())) {
|
return false;
|
}
|
}
|
return true;
|
}
|
|
private Map<Long, String> loadVisitorDisplayMap(List<Long> orderIds) {
|
if (orderIds == null || orderIds.isEmpty()) {
|
return Map.of();
|
}
|
List<AppointmentVisitor> rows =
|
appointmentVisitorMapper.selectList(
|
new LambdaQueryWrapper<AppointmentVisitor>()
|
.eq(AppointmentVisitor::getDelFlag, 0)
|
.in(AppointmentVisitor::getOrderId, orderIds)
|
.orderByAsc(AppointmentVisitor::getId));
|
Set<Long> visitorIds =
|
rows.stream()
|
.map(AppointmentVisitor::getMpVisitorId)
|
.filter(Objects::nonNull)
|
.collect(Collectors.toCollection(LinkedHashSet::new));
|
Map<Long, String> companyMap = loadVisitorCompanyMap(visitorIds);
|
Map<Long, List<String>> grouped = new LinkedHashMap<>();
|
for (AppointmentVisitor row : rows) {
|
if (row.getOrderId() == null) {
|
continue;
|
}
|
String name = trimToNull(row.getName());
|
if (!StringUtils.hasText(name)) {
|
continue;
|
}
|
String company = companyMap.get(row.getMpVisitorId());
|
String display = StringUtils.hasText(company) ? name + "(" + company + ")" : name;
|
grouped.computeIfAbsent(row.getOrderId(), key -> new ArrayList<>()).add(display);
|
}
|
Map<Long, String> result = new LinkedHashMap<>();
|
for (Map.Entry<Long, List<String>> entry : grouped.entrySet()) {
|
String joined = entry.getValue().stream().distinct().collect(Collectors.joining(","));
|
if (StringUtils.hasText(joined)) {
|
result.put(entry.getKey(), joined);
|
}
|
}
|
return result;
|
}
|
|
private Map<Long, String> loadVisitorCompanyMap(Set<Long> visitorIds) {
|
if (visitorIds == null || visitorIds.isEmpty()) {
|
return Map.of();
|
}
|
List<MpVisitor> rows =
|
mpVisitorMapper.selectList(
|
new LambdaQueryWrapper<MpVisitor>()
|
.eq(MpVisitor::getDelFlag, 0)
|
.in(MpVisitor::getId, visitorIds));
|
Map<Long, String> result = new LinkedHashMap<>();
|
for (MpVisitor row : rows) {
|
result.put(row.getId(), trimToNull(row.getVisitorCompany()));
|
}
|
return result;
|
}
|
|
private Map<Long, String> loadPlateTextMap(List<Long> orderIds) {
|
if (orderIds == null || orderIds.isEmpty()) {
|
return Map.of();
|
}
|
List<AppointmentVehicle> rows =
|
appointmentVehicleMapper.selectList(
|
new LambdaQueryWrapper<AppointmentVehicle>()
|
.eq(AppointmentVehicle::getDelFlag, 0)
|
.in(AppointmentVehicle::getOrderId, orderIds)
|
.orderByAsc(AppointmentVehicle::getId));
|
Map<Long, List<String>> grouped = new LinkedHashMap<>();
|
for (AppointmentVehicle row : rows) {
|
if (row.getOrderId() == null) {
|
continue;
|
}
|
String plateNo = trimToNull(row.getPlateNo());
|
if (!StringUtils.hasText(plateNo)) {
|
continue;
|
}
|
grouped.computeIfAbsent(row.getOrderId(), key -> new ArrayList<>()).add(plateNo);
|
}
|
Map<Long, String> result = new LinkedHashMap<>();
|
for (Map.Entry<Long, List<String>> entry : grouped.entrySet()) {
|
String joined = entry.getValue().stream().distinct().collect(Collectors.joining(","));
|
if (StringUtils.hasText(joined)) {
|
result.put(entry.getKey(), joined);
|
}
|
}
|
return result;
|
}
|
|
private Map<String, String> loadReasonNameMap(java.util.Collection<AppointmentOrder> orders) {
|
Set<String> codes =
|
orders.stream()
|
.map(AppointmentOrder::getVisitReasonCode)
|
.filter(StringUtils::hasText)
|
.map(String::trim)
|
.filter(code -> !"OTHER".equalsIgnoreCase(code))
|
.collect(Collectors.toCollection(LinkedHashSet::new));
|
if (codes.isEmpty()) {
|
return Map.of();
|
}
|
List<BizVisitReason> rows =
|
bizVisitReasonMapper.selectList(
|
new LambdaQueryWrapper<BizVisitReason>()
|
.eq(BizVisitReason::getDelFlag, 0)
|
.in(BizVisitReason::getReasonCode, codes));
|
return rows.stream().collect(Collectors.toMap(BizVisitReason::getReasonCode, BizVisitReason::getReasonName, (a, b) -> a));
|
}
|
|
private String buildVisitReasonText(AppointmentOrder order, Map<String, String> reasonNameMap) {
|
String reasonCode = trimToNull(order.getVisitReasonCode());
|
if ("OTHER".equalsIgnoreCase(reasonCode)) {
|
String other = trimToNull(order.getVisitReasonOther());
|
return StringUtils.hasText(other) ? other : "其他";
|
}
|
String reasonName = reasonNameMap.get(reasonCode);
|
return StringUtils.hasText(reasonName) ? reasonName : reasonCode;
|
}
|
|
private String buildVisitTimeText(AppointmentOrder order) {
|
if ("SINGLE".equals(order.getVisitTimeMode())) {
|
String slotLabel = switch (trimToNull(order.getVisitTimeSlot())) {
|
case "ALL_DAY" -> "00:00-23:59";
|
case "AM" -> "00:00-11:59";
|
case "PM" -> "12:00-23:59";
|
default -> "";
|
};
|
if (order.getVisitStartDate() == null) {
|
return slotLabel;
|
}
|
return StringUtils.hasText(slotLabel)
|
? order.getVisitStartDate() + " " + slotLabel
|
: order.getVisitStartDate().toString();
|
}
|
if (order.getVisitStartDate() == null && order.getVisitEndDate() == null) {
|
return "-";
|
}
|
if (Objects.equals(order.getVisitStartDate(), order.getVisitEndDate()) || order.getVisitEndDate() == null) {
|
return String.valueOf(order.getVisitStartDate());
|
}
|
return order.getVisitStartDate() + " 至 " + order.getVisitEndDate();
|
}
|
|
private String trimToNull(String text) {
|
if (text == null) {
|
return null;
|
}
|
String t = text.trim();
|
return t.isEmpty() ? null : t;
|
}
|
|
private <T> IPage<T> slicePage(long page, long size, List<T> rowsAll) {
|
long total = rowsAll == null ? 0 : rowsAll.size();
|
long current = Math.max(1L, page);
|
long pageSize = Math.max(1L, size);
|
int from = (int) Math.min(total, (current - 1) * pageSize);
|
int to = (int) Math.min(total, from + pageSize);
|
List<T> records = from >= to ? List.of() : rowsAll.subList(from, to);
|
Page<T> out = new Page<>(current, pageSize);
|
out.setTotal(total);
|
out.setRecords(records);
|
return out;
|
}
|
}
|