| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261 |
- package com.ruoyi.app.unifiedorder;
- import com.alibaba.fastjson2.JSONArray;
- import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
- import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
- import com.ruoyi.app.unifiedorder.dto.UnifiedOrderListItem;
- import com.ruoyi.app.unifiedorder.dto.UnifiedOrderPageView;
- import com.ruoyi.system.domain.PosOrder;
- import com.ruoyi.system.domain.PosStore;
- import com.ruoyi.system.domain.flash.FlashDeliveryOrder;
- import com.ruoyi.system.mapper.PosOrderMapper;
- import com.ruoyi.system.mapper.PosStoreMapper;
- import com.ruoyi.system.mapper.flash.FlashDeliveryOrderMapper;
- import org.springframework.stereotype.Service;
- import java.util.ArrayList;
- import java.util.Date;
- import java.util.HashMap;
- import java.util.HashSet;
- import java.util.List;
- import java.util.Map;
- import java.util.Objects;
- import java.util.Set;
- /**
- * 统一订单列表查询:外卖与闪送两路各取 size+1 条,Java 按游标全序归并,读时聚合零写路径。
- * 待付款与退款·售后 tab 闪送侧恒空,直接跳过闪送路;来源单选时跳过另一路。
- * dinein/pickup 是外卖路按 pos_order.type 的子集筛选(堂食=2、自取=1、takeaway=0 纯外送),
- * 其游标编码相应为 dinein/pickup,同源翻页精确到 id 决胜。
- */
- @Service
- public class UnifiedOrderQueryService {
- /** 每页条数上限。 */
- private static final int MAX_PAGE_SIZE = 50;
- /** unifiedStatus 的判定优先级:售后优先于状态,与 tab 互斥性一致。 */
- private static final List<UnifiedOrderTab> STATUS_RESOLUTION_ORDER = List.of(
- UnifiedOrderTab.REFUND, UnifiedOrderTab.UNPAID, UnifiedOrderTab.ACTIVE,
- UnifiedOrderTab.COMPLETED, UnifiedOrderTab.CANCELLED);
- /** 闪送只可能命中这三个 tab。 */
- private static final List<UnifiedOrderTab> FLASH_STATUS_RESOLUTION_ORDER = List.of(
- UnifiedOrderTab.ACTIVE, UnifiedOrderTab.COMPLETED, UnifiedOrderTab.CANCELLED);
- private final PosOrderMapper posOrderMapper;
- private final FlashDeliveryOrderMapper flashOrderMapper;
- private final PosStoreMapper posStoreMapper;
- public UnifiedOrderQueryService(PosOrderMapper posOrderMapper,
- FlashDeliveryOrderMapper flashOrderMapper,
- PosStoreMapper posStoreMapper) {
- this.posOrderMapper = posOrderMapper;
- this.flashOrderMapper = flashOrderMapper;
- this.posStoreMapper = posStoreMapper;
- }
- /** 查询统一列表:size 服务端钳制 1-50;cursor 为空表示首页。 */
- public UnifiedOrderPageView query(Long userId, UnifiedOrderTab tab, OrderSource source,
- UnifiedCursor cursor, int size) {
- int limit = Math.max(1, Math.min(MAX_PAGE_SIZE, size));
- List<Row> rows = new ArrayList<>();
- if (source == null || source.queriesPosOrder()) {
- OrderSource takeawayTag = source == null ? OrderSource.TAKEAWAY : source;
- Page<PosOrder> page = posOrderMapper.selectPage(
- new Page<>(1, limit + 1, false), takeawayWrapper(userId, tab, cursor, source));
- for (PosOrder order : page.getRecords()) {
- rows.add(new Row(UnifiedCursor.of(safeTime(order.getCretim()), takeawayTag, order.getId()), order, null));
- }
- }
- if (tab.queriesFlash() && (source == null || source == OrderSource.FLASH)) {
- Page<FlashDeliveryOrder> page = flashOrderMapper.selectPage(
- new Page<>(1, limit + 1, false), flashWrapper(userId, tab, cursor));
- for (FlashDeliveryOrder order : page.getRecords()) {
- rows.add(new Row(UnifiedCursor.of(safeTime(order.getCreateTime()), OrderSource.FLASH, order.getId()), null, order));
- }
- }
- rows.sort(java.util.Comparator.comparing(Row::key, UnifiedCursor.DISPLAY_ORDER));
- boolean hasMore = rows.size() > limit;
- List<Row> displayed = hasMore ? rows.subList(0, limit) : rows;
- UnifiedOrderPageView view = new UnifiedOrderPageView();
- Map<Long, PosStore> stores = storesOf(displayed);
- List<UnifiedOrderListItem> items = new ArrayList<>(displayed.size());
- for (Row row : displayed) {
- items.add(row.takeaway() != null
- ? takeawayItem(row.takeaway(), stores)
- : flashItem(row.flash(), userId));
- }
- view.setList(items);
- view.setHasMore(hasMore);
- view.setNextCursor(hasMore && !displayed.isEmpty()
- ? displayed.get(displayed.size() - 1).key().encode() : null);
- return view;
- }
- /** 外卖路条件:用户 + 来源 type 过滤 + tab 谓词 + 游标推进,排序 cretim DESC, id DESC;source 为 all 时不限 type。 */
- private LambdaQueryWrapper<PosOrder> takeawayWrapper(Long userId, UnifiedOrderTab tab, UnifiedCursor cursor,
- OrderSource source) {
- LambdaQueryWrapper<PosOrder> wrapper = tab.posOrderWrapper()
- .eq(PosOrder::getUserId, userId);
- if (source != null) {
- wrapper.eq(PosOrder::getType, source.posOrderType());
- }
- wrapper.orderByDesc(PosOrder::getCretim)
- .orderByDesc(PosOrder::getId);
- // 游标推进按本路查询源判定:混排(source=all)按 takeaway,单选按所选源
- OrderSource advanceSource = source == null ? OrderSource.TAKEAWAY : source;
- if (cursor != null) {
- Date time = new Date(cursor.getTimeMillis());
- if (cursor.includesSameTimeAnyId(advanceSource)) {
- wrapper.le(PosOrder::getCretim, time);
- } else if (cursor.includesSameTimeLowerId(advanceSource)) {
- wrapper.and(w -> w.lt(PosOrder::getCretim, time)
- .or(x -> x.eq(PosOrder::getCretim, time).lt(PosOrder::getId, cursor.getOrderId())));
- } else {
- wrapper.lt(PosOrder::getCretim, time);
- }
- }
- return wrapper;
- }
- /** 闪送路条件:寄件人或收件人 + tab 谓词 + 游标推进,排序 create_time DESC, id DESC。 */
- private LambdaQueryWrapper<FlashDeliveryOrder> flashWrapper(Long userId, UnifiedOrderTab tab, UnifiedCursor cursor) {
- LambdaQueryWrapper<FlashDeliveryOrder> wrapper = tab.flashWrapper()
- .and(w -> w.eq(FlashDeliveryOrder::getUserId, userId)
- .or().eq(FlashDeliveryOrder::getReceiverUserId, userId))
- .orderByDesc(FlashDeliveryOrder::getCreateTime)
- .orderByDesc(FlashDeliveryOrder::getId);
- if (cursor != null) {
- Date time = new Date(cursor.getTimeMillis());
- if (cursor.includesSameTimeAnyId(OrderSource.FLASH)) {
- wrapper.le(FlashDeliveryOrder::getCreateTime, time);
- } else if (cursor.includesSameTimeLowerId(OrderSource.FLASH)) {
- wrapper.and(w -> w.lt(FlashDeliveryOrder::getCreateTime, time)
- .or(x -> x.eq(FlashDeliveryOrder::getCreateTime, time)
- .lt(FlashDeliveryOrder::getId, cursor.getOrderId())));
- } else {
- wrapper.lt(FlashDeliveryOrder::getCreateTime, time);
- }
- }
- return wrapper;
- }
- /** 外卖条目按门店 ID 批量查 pos_store,一次回填店铺名称/头像。 */
- private Map<Long, PosStore> storesOf(List<Row> displayed) {
- Set<Long> mdIds = new HashSet<>();
- for (Row row : displayed) {
- if (row.takeaway() != null && row.takeaway().getMdId() != null) {
- mdIds.add(row.takeaway().getMdId());
- }
- }
- Map<Long, PosStore> stores = new HashMap<>();
- if (!mdIds.isEmpty()) {
- for (PosStore store : posStoreMapper.selectBatchIds(mdIds)) {
- if (store != null && store.getId() != null) {
- stores.put(store.getId().longValue(), store);
- }
- }
- }
- return stores;
- }
- private UnifiedOrderListItem takeawayItem(PosOrder order, Map<Long, PosStore> stores) {
- UnifiedOrderListItem item = new UnifiedOrderListItem();
- item.setSourceType("takeaway");
- item.setRole("sender");
- item.setOrderId(order.getId());
- item.setOrderNo(order.getDdId());
- item.setUnifiedStatus(resolveTakeawayStatus(order));
- item.setCreateTime(order.getCretim() == null ? null : order.getCretim().getTime());
- item.setAmount(order.getAmount() == null ? null : order.getAmount().longValue());
- item.setHasAfterSale(order.getAfterSaleStatus() != null && order.getAfterSaleStatus() > 0);
- item.setType(order.getType());
- item.setState(order.getState());
- item.setDeliveryStatus(order.getDeliveryStatus());
- item.setPayStatus(order.getPayStatus());
- item.setPayType(order.getPayType());
- item.setAfterSaleStatus(order.getAfterSaleStatus());
- // 店铺已删或 mdId 缺失时回退订单创建时的快照 posName/logo
- PosStore store = order.getMdId() == null ? null : stores.get(order.getMdId());
- item.setStoreName(store != null ? store.getPosName() : order.getPosName());
- item.setStoreAvatar(store != null ? store.getLogo() : order.getLogo());
- item.setGoodsCount(takeawayGoodsCount(order.getFood()));
- item.setCollectPayment(order.getCollectPayment());
- return item;
- }
- /** 商品件数:food 快照数组各行 number 求和;food 为空或非法返回 null。 */
- private Integer takeawayGoodsCount(String food) {
- if (food == null || food.isBlank()) {
- return null;
- }
- try {
- JSONArray rows = JSONArray.parseArray(food);
- int count = 0;
- for (int i = 0; i < rows.size(); i++) {
- Integer num = rows.getJSONObject(i).getInteger("number");
- if (num != null) {
- count += num;
- }
- }
- return count;
- } catch (RuntimeException e) {
- return null;
- }
- }
- private UnifiedOrderListItem flashItem(FlashDeliveryOrder order, Long userId) {
- UnifiedOrderListItem item = new UnifiedOrderListItem();
- item.setSourceType("flash");
- item.setRole(userId != null && userId.equals(order.getUserId()) ? "sender" : "receiver");
- item.setOrderId(order.getId());
- item.setOrderNo(order.getOrderNo());
- item.setUnifiedStatus(resolveFlashStatus(order));
- item.setCreateTime(order.getCreateTime() == null ? null : order.getCreateTime().getTime());
- item.setAmount(order.getAmount());
- item.setCurrency(order.getCurrency());
- item.setHasAfterSale(false);
- item.setStatus(order.getStatus());
- item.setOrderVersion(order.getVersion());
- item.setServiceType(order.getServiceType());
- item.setDeliveryType(order.getDeliveryType());
- item.setVehicleType(order.getVehicleType());
- item.setDeliveryMode(order.getDeliveryMode());
- item.setScheduledPickupStartAt(order.getScheduledPickupStartAt());
- item.setScheduledPickupEndAt(order.getScheduledPickupEndAt());
- item.setPickupAddress(order.getPickupAddress());
- item.setPickupDetailAddress(order.getPickupAddressDetail());
- item.setDeliveryAddress(order.getDeliveryAddress());
- item.setDeliveryDetailAddress(order.getDeliveryAddressDetail());
- item.setPackageType(order.getPackageType());
- item.setQuantity(order.getQuantity());
- item.setTipAmount(order.getTipAmount());
- return item;
- }
- private String resolveTakeawayStatus(PosOrder order) {
- for (UnifiedOrderTab tab : STATUS_RESOLUTION_ORDER) {
- if (tab.matches(order)) {
- return tab.code();
- }
- }
- return null;
- }
- private String resolveFlashStatus(FlashDeliveryOrder order) {
- for (UnifiedOrderTab tab : FLASH_STATUS_RESOLUTION_ORDER) {
- if (tab.matches(order)) {
- return tab.code();
- }
- }
- return null;
- }
- private static long safeTime(Date time) {
- return time == null ? 0L : time.getTime();
- }
- /** 归并中间行:游标键 + 单侧实体。 */
- private record Row(UnifiedCursor key, PosOrder takeaway, FlashDeliveryOrder flash) {
- }
- }
|