feat(glt): 添加送水订单自动派单功能
- 在ShopStoreRider实体中增加经纬度字段用于定位 - 创建GltTicketOrderAutoDispatch10584Task定时任务处理自动派单 - 实现GltTicketOrderAutoDispatchService服务类进行距离计算和派单逻辑 - 支持按距离最近原则自动分配配送员给待配送订单 - 集成坐标解析和Haversine距离计算算法 - 实现多租户环境下的自动派单配置开关 - 添加配送员在途订单数限制和并发控制机制
This commit is contained in:
@@ -0,0 +1,355 @@
|
|||||||
|
package com.gxwebsoft.glt.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
import com.gxwebsoft.glt.entity.GltTicketOrder;
|
||||||
|
import com.gxwebsoft.glt.entity.GltUserTicket;
|
||||||
|
import com.gxwebsoft.shop.entity.ShopStoreRider;
|
||||||
|
import com.gxwebsoft.shop.entity.ShopOrder;
|
||||||
|
import com.gxwebsoft.shop.entity.ShopOrderGoods;
|
||||||
|
import com.gxwebsoft.shop.entity.ShopUserAddress;
|
||||||
|
import com.gxwebsoft.shop.service.ShopOrderGoodsService;
|
||||||
|
import com.gxwebsoft.shop.service.ShopOrderService;
|
||||||
|
import com.gxwebsoft.shop.service.ShopStoreRiderService;
|
||||||
|
import com.gxwebsoft.shop.service.ShopUserAddressService;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 送水订单自动派单:
|
||||||
|
* - 扫描待配送且未指派配送员的 glt_ticket_order;
|
||||||
|
* - 取收货地址坐标(优先 ShopOrder.addressLat/addressLng 订单快照;兜底 addressId -> shop_user_address.lat/lng);
|
||||||
|
* - 在同门店、在线、启用、开启自动派单且有坐标的配送员中,按距离最近优先;
|
||||||
|
* - 派单写入 glt_ticket_order.rider_id(即配送员 userId),并同步商城订单 riderId/deliveryStatus(复用 accept 逻辑)。
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class GltTicketOrderAutoDispatchService {
|
||||||
|
|
||||||
|
private final GltTicketOrderService gltTicketOrderService;
|
||||||
|
private final GltUserTicketService gltUserTicketService;
|
||||||
|
private final ShopStoreRiderService shopStoreRiderService;
|
||||||
|
private final ShopUserAddressService shopUserAddressService;
|
||||||
|
private final ShopOrderService shopOrderService;
|
||||||
|
private final ShopOrderGoodsService shopOrderGoodsService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自动派单(按距离最近)。
|
||||||
|
*
|
||||||
|
* @param tenantId 租户ID
|
||||||
|
* @param batchSize 单次扫描最大处理条数
|
||||||
|
* @return 成功派单数量
|
||||||
|
*/
|
||||||
|
public int autoDispatchWaitingOrders(Integer tenantId, int batchSize) {
|
||||||
|
if (tenantId == null || tenantId <= 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (batchSize <= 0) {
|
||||||
|
batchSize = 50;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<GltTicketOrder> waiting = gltTicketOrderService.list(
|
||||||
|
new LambdaQueryWrapper<GltTicketOrder>()
|
||||||
|
.select(GltTicketOrder::getId, GltTicketOrder::getUserTicketId, GltTicketOrder::getStoreId, GltTicketOrder::getAddressId, GltTicketOrder::getCreateTime)
|
||||||
|
.eq(GltTicketOrder::getTenantId, tenantId)
|
||||||
|
.eq(GltTicketOrder::getDeleted, 0)
|
||||||
|
.and(w -> w.eq(GltTicketOrder::getStatus, 0).or().isNull(GltTicketOrder::getStatus))
|
||||||
|
.and(w -> w.eq(GltTicketOrder::getDeliveryStatus, GltTicketOrderService.DELIVERY_STATUS_WAITING)
|
||||||
|
.or().isNull(GltTicketOrder::getDeliveryStatus))
|
||||||
|
.and(w -> w.isNull(GltTicketOrder::getRiderId).or().eq(GltTicketOrder::getRiderId, 0))
|
||||||
|
.orderByAsc(GltTicketOrder::getCreateTime)
|
||||||
|
.orderByAsc(GltTicketOrder::getId)
|
||||||
|
.last("limit " + batchSize)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (waiting == null || waiting.isEmpty()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dispatched = 0;
|
||||||
|
// 简化实现:按门店分组,避免对同一门店重复查配送员/在途单数。
|
||||||
|
Map<Integer, CandidatePool> poolByStoreId = new HashMap<>();
|
||||||
|
|
||||||
|
for (GltTicketOrder order : waiting) {
|
||||||
|
if (order == null || order.getId() == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
LngLat receiver = resolveReceiverLngLat(tenantId, order);
|
||||||
|
if (receiver == null) {
|
||||||
|
log.debug("自动派单跳过:无法获取收货坐标 - tenantId={}, ticketOrderId={}, addressId={}",
|
||||||
|
tenantId, order.getId(), order.getAddressId());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Integer storeId = order.getStoreId();
|
||||||
|
int storeKey = storeId == null ? -1 : storeId;
|
||||||
|
CandidatePool pool = poolByStoreId.computeIfAbsent(storeKey, k -> buildCandidatePool(tenantId, storeId));
|
||||||
|
if (pool == null || pool.candidates.isEmpty()) {
|
||||||
|
log.debug("自动派单跳过:无可用配送员 - tenantId={}, ticketOrderId={}, storeId={}",
|
||||||
|
tenantId, order.getId(), storeId);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ShopStoreRider best = pickNearest(pool, receiver);
|
||||||
|
if (best == null || best.getUserId() == null || best.getUserId() <= 0) {
|
||||||
|
log.debug("自动派单跳过:未选出配送员 - tenantId={}, ticketOrderId={}, storeId={}",
|
||||||
|
tenantId, order.getId(), storeId);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 复用“接单”的原子更新 + 同步商城订单逻辑;这里的 riderId 即配送员 userId。
|
||||||
|
gltTicketOrderService.accept(order.getId(), best.getUserId(), tenantId);
|
||||||
|
dispatched++;
|
||||||
|
|
||||||
|
// 派单成功后,更新 pool 中该骑手的在途数(便于同批次后续订单使用 maxOnhandOrders)
|
||||||
|
pool.onhandCount.merge(best.getUserId(), 1, Integer::sum);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// accept 本身包含幂等条件(riderId 为空才会写入);此处吞掉异常,避免一单影响整批。
|
||||||
|
log.warn("自动派单失败 - tenantId={}, ticketOrderId={}, storeId={}, riderUserId={}",
|
||||||
|
tenantId, order.getId(), storeId, best.getUserId(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dispatched;
|
||||||
|
}
|
||||||
|
|
||||||
|
private CandidatePool buildCandidatePool(Integer tenantId, Integer storeId) {
|
||||||
|
List<ShopStoreRider> riders = shopStoreRiderService.list(
|
||||||
|
new LambdaQueryWrapper<ShopStoreRider>()
|
||||||
|
.eq(ShopStoreRider::getTenantId, tenantId)
|
||||||
|
.eq(ShopStoreRider::getIsDelete, 0)
|
||||||
|
.eq(ShopStoreRider::getStatus, 1)
|
||||||
|
.eq(ShopStoreRider::getWorkStatus, 1) // 仅在线
|
||||||
|
.eq(ShopStoreRider::getAutoDispatchEnabled, 1)
|
||||||
|
.eq(storeId != null, ShopStoreRider::getStoreId, storeId)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (riders == null || riders.isEmpty()) {
|
||||||
|
return new CandidatePool(List.of(), Map.of());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 过滤无 userId/无坐标,并提前解析坐标(避免每单重复 parse)
|
||||||
|
List<ShopStoreRider> candidates = riders.stream()
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.filter(r -> r.getUserId() != null && r.getUserId() > 0)
|
||||||
|
.filter(r -> parseLngLat(r.getLongitude(), r.getLatitude()) != null)
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
if (candidates.isEmpty()) {
|
||||||
|
return new CandidatePool(List.of(), Map.of());
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Integer> riderUserIds = candidates.stream().map(ShopStoreRider::getUserId).distinct().toList();
|
||||||
|
Map<Integer, Integer> onhand = loadOnhandCounts(tenantId, riderUserIds);
|
||||||
|
return new CandidatePool(candidates, onhand);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<Integer, Integer> loadOnhandCounts(Integer tenantId, List<Integer> riderUserIds) {
|
||||||
|
if (riderUserIds == null || riderUserIds.isEmpty()) {
|
||||||
|
return new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 统计各配送员“未完成”的在途单数:10/20/30
|
||||||
|
QueryWrapper<GltTicketOrder> qw = new QueryWrapper<>();
|
||||||
|
qw.select("rider_id AS riderId", "COUNT(1) AS cnt")
|
||||||
|
.eq("tenant_id", tenantId)
|
||||||
|
.eq("deleted", 0)
|
||||||
|
.in("rider_id", riderUserIds)
|
||||||
|
.in("delivery_status",
|
||||||
|
GltTicketOrderService.DELIVERY_STATUS_WAITING,
|
||||||
|
GltTicketOrderService.DELIVERY_STATUS_DELIVERING,
|
||||||
|
GltTicketOrderService.DELIVERY_STATUS_WAIT_CONFIRM
|
||||||
|
)
|
||||||
|
.groupBy("rider_id");
|
||||||
|
|
||||||
|
Map<Integer, Integer> map = new HashMap<>();
|
||||||
|
List<Map<String, Object>> rows = gltTicketOrderService.listMaps(qw);
|
||||||
|
if (rows == null || rows.isEmpty()) {
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
for (Map<String, Object> row : rows) {
|
||||||
|
if (row == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Object riderIdObj = row.get("riderId");
|
||||||
|
Object cntObj = row.get("cnt");
|
||||||
|
if (!(riderIdObj instanceof Number) || !(cntObj instanceof Number)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
map.put(((Number) riderIdObj).intValue(), ((Number) cntObj).intValue());
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ShopStoreRider pickNearest(CandidatePool pool, LngLat receiver) {
|
||||||
|
// 优先距离;距离相同用 dispatchPriority 兜底(越大越优先);再用 userId 稳定排序
|
||||||
|
return pool.candidates.stream()
|
||||||
|
.filter(r -> {
|
||||||
|
Integer userId = r.getUserId();
|
||||||
|
if (userId == null || userId <= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int max = r.getMaxOnhandOrders() == null ? 0 : r.getMaxOnhandOrders();
|
||||||
|
if (max <= 0) {
|
||||||
|
return true; // 0表示不限制
|
||||||
|
}
|
||||||
|
int onhand = pool.onhandCount.getOrDefault(userId, 0);
|
||||||
|
return onhand < max;
|
||||||
|
})
|
||||||
|
.min(Comparator
|
||||||
|
.comparingDouble((ShopStoreRider r) -> distanceMeters(receiver, parseLngLat(r.getLongitude(), r.getLatitude())))
|
||||||
|
.thenComparingInt((ShopStoreRider r) -> -(r.getDispatchPriority() == null ? 0 : r.getDispatchPriority()))
|
||||||
|
.thenComparing(r -> r.getUserId() == null ? Integer.MAX_VALUE : r.getUserId())
|
||||||
|
)
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double distanceMeters(LngLat a, LngLat b) {
|
||||||
|
if (a == null || b == null) {
|
||||||
|
return Double.POSITIVE_INFINITY;
|
||||||
|
}
|
||||||
|
// Haversine
|
||||||
|
double lat1 = Math.toRadians(a.lat);
|
||||||
|
double lat2 = Math.toRadians(b.lat);
|
||||||
|
double dLat = lat2 - lat1;
|
||||||
|
double dLng = Math.toRadians(b.lng - a.lng);
|
||||||
|
double sinLat = Math.sin(dLat / 2);
|
||||||
|
double sinLng = Math.sin(dLng / 2);
|
||||||
|
double aa = sinLat * sinLat + Math.cos(lat1) * Math.cos(lat2) * sinLng * sinLng;
|
||||||
|
double c = 2 * Math.atan2(Math.sqrt(aa), Math.sqrt(1 - aa));
|
||||||
|
return 6371000.0 * c; // Earth radius (meters)
|
||||||
|
}
|
||||||
|
|
||||||
|
private LngLat resolveReceiverLngLat(Integer tenantId, GltTicketOrder order) {
|
||||||
|
if (order == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1) 优先使用“商城订单快照坐标”(ShopOrder.addressLat/addressLng),避免地址表坐标被事后修改影响历史订单派单。
|
||||||
|
LngLat byOrderSnapshot = resolveReceiverLngLatFromShopOrderSnapshot(tenantId, order);
|
||||||
|
if (byOrderSnapshot != null) {
|
||||||
|
return byOrderSnapshot;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2) 兜底:用地址表坐标(适用于没有关联商城订单的水票下单等场景)
|
||||||
|
Integer addressId = order.getAddressId();
|
||||||
|
if (addressId == null || addressId <= 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ShopUserAddress addr = shopUserAddressService.getOne(new LambdaQueryWrapper<ShopUserAddress>()
|
||||||
|
.select(ShopUserAddress::getLat, ShopUserAddress::getLng)
|
||||||
|
.eq(ShopUserAddress::getId, addressId)
|
||||||
|
.eq(ShopUserAddress::getTenantId, tenantId)
|
||||||
|
.last("limit 1"));
|
||||||
|
return addr == null ? null : parseLngLat(addr.getLng(), addr.getLat());
|
||||||
|
}
|
||||||
|
|
||||||
|
private LngLat resolveReceiverLngLatFromShopOrderSnapshot(Integer tenantId, GltTicketOrder ticketOrder) {
|
||||||
|
Integer userTicketId = ticketOrder.getUserTicketId();
|
||||||
|
if (userTicketId == null || userTicketId <= 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
GltUserTicket userTicket = gltUserTicketService.getOne(new LambdaQueryWrapper<GltUserTicket>()
|
||||||
|
.select(GltUserTicket::getOrderId, GltUserTicket::getOrderNo, GltUserTicket::getOrderGoodsId)
|
||||||
|
.eq(GltUserTicket::getTenantId, tenantId)
|
||||||
|
.eq(GltUserTicket::getDeleted, 0)
|
||||||
|
.eq(GltUserTicket::getId, userTicketId)
|
||||||
|
.last("limit 1"));
|
||||||
|
if (userTicket == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Integer shopOrderId = userTicket.getOrderId();
|
||||||
|
String shopOrderNo = userTicket.getOrderNo();
|
||||||
|
|
||||||
|
// 兼容:历史数据只写了 orderGoodsId
|
||||||
|
if (shopOrderId == null && !StringUtils.hasText(shopOrderNo) && userTicket.getOrderGoodsId() != null) {
|
||||||
|
ShopOrderGoods og = shopOrderGoodsService.getOne(new LambdaQueryWrapper<ShopOrderGoods>()
|
||||||
|
.select(ShopOrderGoods::getOrderId)
|
||||||
|
.eq(ShopOrderGoods::getTenantId, tenantId)
|
||||||
|
.eq(ShopOrderGoods::getId, userTicket.getOrderGoodsId())
|
||||||
|
.last("limit 1"));
|
||||||
|
if (og != null) {
|
||||||
|
shopOrderId = og.getOrderId();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LambdaQueryWrapper<ShopOrder> qw = new LambdaQueryWrapper<ShopOrder>()
|
||||||
|
.select(ShopOrder::getAddressLat, ShopOrder::getAddressLng)
|
||||||
|
.eq(ShopOrder::getTenantId, tenantId)
|
||||||
|
.eq(ShopOrder::getDeleted, 0)
|
||||||
|
.last("limit 1");
|
||||||
|
if (shopOrderId != null && shopOrderId > 0) {
|
||||||
|
qw.eq(ShopOrder::getOrderId, shopOrderId);
|
||||||
|
} else if (StringUtils.hasText(shopOrderNo)) {
|
||||||
|
qw.eq(ShopOrder::getOrderNo, shopOrderNo);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
ShopOrder shopOrder = shopOrderService.getOne(qw);
|
||||||
|
if (shopOrder == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return parseLngLat(shopOrder.getAddressLng(), shopOrder.getAddressLat());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static LngLat parseLngLat(String lngRaw, String latRaw) {
|
||||||
|
Double lng = parseDoubleOrNull(lngRaw);
|
||||||
|
Double lat = parseDoubleOrNull(latRaw);
|
||||||
|
if (lng == null || lat == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 若明显是 (lat,lng) 则交换
|
||||||
|
if (Math.abs(lng) <= 90 && Math.abs(lat) > 90 && Math.abs(lat) <= 180) {
|
||||||
|
double tmp = lng;
|
||||||
|
lng = lat;
|
||||||
|
lat = tmp;
|
||||||
|
}
|
||||||
|
if (Math.abs(lat) > 90 || Math.abs(lng) > 180) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new LngLat(lng, lat);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Double parseDoubleOrNull(String raw) {
|
||||||
|
if (raw == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String s = raw.trim();
|
||||||
|
if (s.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return Double.parseDouble(s);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private record LngLat(double lng, double lat) {
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class CandidatePool {
|
||||||
|
final List<ShopStoreRider> candidates;
|
||||||
|
final Map<Integer, Integer> onhandCount;
|
||||||
|
|
||||||
|
CandidatePool(List<ShopStoreRider> candidates, Map<Integer, Integer> onhandCount) {
|
||||||
|
this.candidates = candidates;
|
||||||
|
this.onhandCount = new HashMap<>(onhandCount == null ? Map.of() : onhandCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
package com.gxwebsoft.glt.task;
|
||||||
|
|
||||||
|
import com.gxwebsoft.common.core.annotation.IgnoreTenant;
|
||||||
|
import com.gxwebsoft.glt.service.GltTicketOrderAutoDispatchService;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GLT 送水订单自动派单任务(tenantId=10584):
|
||||||
|
* - 扫描未指派配送员的待配送订单(glt_ticket_order.delivery_status=10 且 rider_id 为空/0)
|
||||||
|
* - 依据收货坐标(优先 ShopOrder.addressLat/addressLng 订单快照;兜底地址表 lat/lng)与 配送员坐标(shop_store_rider.longitude/latitude) 计算距离,派给最近的配送员
|
||||||
|
* - 写入 rider_id(配送员 userId),并同步关联商城订单的 riderId/deliveryStatus(复用 accept 逻辑)
|
||||||
|
*
|
||||||
|
* 默认不启用;需要在配置中显式打开:
|
||||||
|
* - glt.ticket.dispatch10584.enabled=true
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@ConditionalOnProperty(prefix = "glt.ticket.dispatch10584", name = "enabled", havingValue = "true", matchIfMissing = false)
|
||||||
|
public class GltTicketOrderAutoDispatch10584Task {
|
||||||
|
|
||||||
|
private static final int TENANT_ID = 10584;
|
||||||
|
|
||||||
|
private final GltTicketOrderAutoDispatchService gltTicketOrderAutoDispatchService;
|
||||||
|
|
||||||
|
private final AtomicBoolean running = new AtomicBoolean(false);
|
||||||
|
|
||||||
|
@Value("${glt.ticket.dispatch10584.batchSize:50}")
|
||||||
|
private int batchSize;
|
||||||
|
|
||||||
|
@Scheduled(cron = "${glt.ticket.dispatch10584.cron:0/20 * * * * ?}")
|
||||||
|
@IgnoreTenant("定时任务无登录态,需忽略租户隔离;内部使用 tenantId=10584 精确过滤")
|
||||||
|
public void run() {
|
||||||
|
if (!running.compareAndSet(false, true)) {
|
||||||
|
log.warn("送水订单自动派单任务仍在执行中,本轮跳过 - tenantId={}", TENANT_ID);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
int n = gltTicketOrderAutoDispatchService.autoDispatchWaitingOrders(TENANT_ID, batchSize);
|
||||||
|
if (n > 0) {
|
||||||
|
log.info("送水订单自动派单完成 - tenantId={}, dispatched={}", TENANT_ID, n);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
running.set(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -55,6 +55,12 @@ public class ShopStoreRider implements Serializable {
|
|||||||
@Schema(description = "接单状态:0休息/下线;1在线;2忙碌")
|
@Schema(description = "接单状态:0休息/下线;1在线;2忙碌")
|
||||||
private Integer workStatus;
|
private Integer workStatus;
|
||||||
|
|
||||||
|
@Schema(description = "经度")
|
||||||
|
private String longitude;
|
||||||
|
|
||||||
|
@Schema(description = "纬度")
|
||||||
|
private String latitude;
|
||||||
|
|
||||||
@Schema(description = "是否开启自动派单:1是;0否")
|
@Schema(description = "是否开启自动派单:1是;0否")
|
||||||
private Integer autoDispatchEnabled;
|
private Integer autoDispatchEnabled;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user