feat:机器上可以查询全部订单

This commit is contained in:
dzc committed 2026-09-07 10:34:38 +08:00
1 parent ec39c72f7e
commit 1bf4ad3dd8
8 files changed
+270 -1

No files matched your search

+6
View File
@@ -61,3 +61,9 @@ gen_code
### node ###
node_modules
### AI 辅助工具 ###
.video_agent
.mimosa
.v2c
.zcode
@@ -0,0 +1,38 @@
package com.bsd.pjcloud.hard.api.dto.hard;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.time.LocalDate;
import java.util.List;
/**
* 终端交易记录查询参数。
*
* 设备 ID 是唯一的数据范围入口:scope 为空或 DEVICE 时仅查询本机订单,
* scope 为 MERCHANT 时按服务端解析的终端所属商户查询全部设备订单,
* 客户端不能通过本接口指定其他商户或用户范围。
*/
@Data
public class TerminalOrderRecordQueryDto {
@NotNull(message = "设备ID不能为空")
@Schema(description = "当前终端设备ID", requiredMode = Schema.RequiredMode.REQUIRED)
private Long hardId;
@Schema(description = "开始日期,格式 yyyy-MM-dd")
private LocalDate startDate;
@Schema(description = "结束日期,格式 yyyy-MM-dd")
private LocalDate endDate;
@Schema(description = "数据范围:DEVICE 仅本机(默认),MERCHANT 当前终端所属商户全部设备")
private String scope;
@Schema(description = "订单状态编码集合,为空时查询全部状态")
private List<String> orderStatusCodes;
@Schema(description = "用餐时段编码,为空或 -1 时不区分")
private String hourType;
}
@@ -26,4 +26,7 @@ public class VerificationRecordQueryDto {
@Schema(description = "核销类型,目前仅支持 RESERVATION 预约核销;为空时同样按预约核销查询")
private String verificationType;
@Schema(description = "数据范围:DEVICE 仅本机(默认),MERCHANT 当前终端所属商户全部设备")
private String scope;
}
@@ -0,0 +1,61 @@
package com.bsd.pjcloud.hard.api.vo.android;
import lombok.Data;
import java.time.LocalDateTime;
/** 终端交易记录展示对象,仅返回交易记录列表所需字段。 */
@Data
public class TerminalOrderRecordVo {
/** 订单主键。 */
private Long orderId;
/** 业务订单号。 */
private String orderNo;
/** 订单类型稳定编码。 */
private String orderType;
/** 订单类型展示名称。 */
private String orderTypeName;
/** 订单状态稳定编码。 */
private String orderStatus;
/** 订单状态展示名称。 */
private String orderStatusName;
/** 支付方式稳定编码。 */
private String payType;
/** 支付方式展示名称。 */
private String payTypeName;
/** 下单用户姓名。 */
private String username;
/** 下单用户所属部门。 */
private String userDeptName;
/** 订单商品摘要。 */
private String productDesc;
/** 用餐时段编码。 */
private String hourType;
/** 商品总金额(分)。 */
private Integer totalPrice;
/** 额外支付(分)。 */
private Integer extraPrice;
/** 实际支付(分)。 */
private Integer payPrice;
/** 完成交易的设备名称;本机数据范围下与服务端解析的终端一致。 */
private String hardName;
/** 下单时间。 */
private LocalDateTime createTime;
}
@@ -28,6 +28,7 @@ import com.bsd.pjcloud.hard.api.vo.HardInvoiceVo;
import com.bsd.pjcloud.hard.api.vo.manager.HardManagerVo;
import com.bsd.pjcloud.hard.api.vo.android.HardAdUserVo;
import com.bsd.pjcloud.hard.api.vo.android.ReservationMenuQueryVo;
import com.bsd.pjcloud.hard.api.vo.android.TerminalOrderRecordVo;
import com.bsd.pjcloud.hard.api.vo.android.VerificationRecordVo;
import com.bsd.pjcloud.hard.api.vo.order.HardCarVo;
import com.bsd.pjcloud.hard.api.vo.order.HardAggregateOrderCodePayStatusVo;
@@ -67,6 +68,7 @@ public class HardApiController {
private final HardOrderTotalService hardOrderTotalService;
private final ReservationMenuQueryService reservationMenuQueryService;
private final VerificationRecordService verificationRecordService;
private final TerminalOrderRecordService terminalOrderRecordService;
private final HardTerminalFaceService hardTerminalFaceService;
private final HardTerminalPrintService hardTerminalPrintService;
@@ -485,6 +487,12 @@ public class HardApiController {
return R.ok(verificationRecordService.page(page, hardId, dto));
}
@PostMapping("/order-record/page")
@Operation(summary = "分页查询当前终端交易记录")
public R<Page<TerminalOrderRecordVo>> orderRecordPage(@ParameterObject Page<?> page, @RequestHeader("DEVICE-ID") Long hardId, @Valid @RequestBody TerminalOrderRecordQueryDto dto) {
return R.ok(terminalOrderRecordService.page(page, hardId, dto));
}
@GetMapping("/chart-latitude")
@Operation(summary = "统计每天、每周、每月、每年的交易人数和次数")
public R<HardChartLatitudeVo> chartLatitude(@RequestParam Long merchantId) {
@@ -0,0 +1,19 @@
package com.bsd.pjcloud.hard.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.bsd.pjcloud.hard.api.dto.hard.TerminalOrderRecordQueryDto;
import com.bsd.pjcloud.hard.api.vo.android.TerminalOrderRecordVo;
/** 终端交易记录查询服务。 */
public interface TerminalOrderRecordService {
/**
* 分页查询终端交易记录。
*
* @param page 分页参数,页码最小为 1、每页最大为 50
* @param hardId 当前请求头中的设备主键
* @param dto 数据范围、日期、状态和时段查询条件
* @return 已按下单时间倒序排列的终端交易记录分页
*/
Page<TerminalOrderRecordVo> page(Page<?> page, Long hardId, TerminalOrderRecordQueryDto dto);
}
@@ -0,0 +1,126 @@
package com.bsd.pjcloud.hard.service.impl;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.bsd.pjcloud.hard.api.constant.order.HardOrderStatusEnum;
import com.bsd.pjcloud.hard.api.constant.order.HardOrderTypeEnum;
import com.bsd.pjcloud.hard.api.constant.order.HardPayTypeEnum;
import com.bsd.pjcloud.hard.api.dto.hard.TerminalOrderRecordQueryDto;
import com.bsd.pjcloud.hard.api.dto.order.HardOrderDto;
import com.bsd.pjcloud.hard.api.entity.manager.HardManagerEntity;
import com.bsd.pjcloud.hard.api.vo.android.TerminalOrderRecordVo;
import com.bsd.pjcloud.hard.api.vo.order.HardOrderVo;
import com.bsd.pjcloud.hard.service.HardManagerService;
import com.bsd.pjcloud.hard.service.HardOrderService;
import com.bsd.pjcloud.hard.service.TerminalOrderRecordService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
/** 终端交易记录查询服务,复用订单管理端分页查询保证范围、分页和用户信息口径一致。 */
@Service
@RequiredArgsConstructor
public class TerminalOrderRecordServiceImpl implements TerminalOrderRecordService {
/** 全部数据范围:按终端所属商户查询商户下全部设备的交易记录。 */
private static final String SCOPE_MERCHANT = "MERCHANT";
/** 终端不区分用餐时段的编码。 */
private static final String HOUR_TYPE_ALL = "-1";
/** 设备服务,用于校验请求设备存在并解析所属商户。 */
private final HardManagerService hardManagerService;
/** 订单服务,用于按设备/商户、订单状态和下单时间分页查询。 */
private final HardOrderService hardOrderService;
@Override
public Page<TerminalOrderRecordVo> page(Page<?> page, Long hardId, TerminalOrderRecordQueryDto dto) {
if (!Objects.equals(hardId, dto.getHardId())) {
throw new RuntimeException("请求设备与查询设备不一致");
}
HardManagerEntity hard = hardManagerService.getById(hardId);
if (hard == null) {
throw new RuntimeException("设备不存在或无权访问");
}
LocalDate startDate = ObjectUtil.defaultIfNull(dto.getStartDate(), LocalDate.now());
LocalDate endDate = ObjectUtil.defaultIfNull(dto.getEndDate(), startDate);
if (endDate.isBefore(startDate)) {
throw new RuntimeException("结束日期不能早于开始日期");
}
HardOrderDto query = new HardOrderDto();
if (SCOPE_MERCHANT.equalsIgnoreCase(StrUtil.trimToEmpty(dto.getScope()))) {
// 全部数据:范围来自服务端解析的终端所属商户,客户端不能自行指定商户。
query.setMerchantId(hard.getMerchantId());
} else {
query.setHardId(hard.getId());
}
query.setCreateTimeList(new LocalDateTime[]{startDate.atStartOfDay(), endDate.atTime(23, 59, 59)});
query.setOrderStatusCodes(dto.getOrderStatusCodes());
if (StrUtil.isNotBlank(dto.getHourType()) && !HOUR_TYPE_ALL.equals(dto.getHourType().trim())) {
query.setHourType(dto.getHourType().trim());
}
long current = Math.max(1, page.getCurrent());
long size = Math.min(50, Math.max(1, page.getSize()));
// 订单范围、分页、用户和部门信息统一由订单服务处理,交易记录只负责转换展示字段。
Page<HardOrderVo> source = hardOrderService.scopePageList(new Page<>(current, size), query, null);
List<TerminalOrderRecordVo> records = source.getRecords().stream()
.map(TerminalOrderRecordServiceImpl::convert)
.toList();
Page<TerminalOrderRecordVo> result = new Page<>(source.getCurrent(), source.getSize(), source.getTotal());
result.setRecords(records);
return result;
}
/**
* 将订单查询结果转换为终端交易记录展示对象。
*
* @param order 订单分页查询结果
* @return 终端交易记录
*/
private static TerminalOrderRecordVo convert(HardOrderVo order) {
TerminalOrderRecordVo vo = new TerminalOrderRecordVo();
vo.setOrderId(order.getId());
vo.setOrderNo(StrUtil.blankToDefault(order.getOrderNo(), String.valueOf(order.getId())));
vo.setOrderType(order.getOrderType());
HardOrderTypeEnum orderType = HardOrderTypeEnum.valueOfByType(order.getOrderType());
vo.setOrderTypeName(orderType == null ? "其他类型" : orderType.getDescription());
vo.setOrderStatus(order.getOrderStatus());
// 状态枚举查找对未知编码抛异常,外卖/商城等终端外状态需安全降级。
vo.setOrderStatusName(resolveStatusName(order.getOrderStatus()));
vo.setPayType(order.getPayType());
HardPayTypeEnum payType = HardPayTypeEnum.valueOfByType(order.getPayType());
vo.setPayTypeName(payType == null ? "其他方式" : payType.getDescription());
vo.setUsername(StrUtil.blankToDefault(order.getUsername(), "未知用户"));
vo.setUserDeptName(order.getUserDeptName());
vo.setProductDesc(StrUtil.blankToDefault(order.getProductDesc(), "未知商品"));
vo.setHourType(order.getHourType());
vo.setTotalPrice(ObjectUtil.defaultIfNull(order.getTotalPrice(), 0));
vo.setExtraPrice(ObjectUtil.defaultIfNull(order.getExtraPrice(), 0));
vo.setPayPrice(ObjectUtil.defaultIfNull(order.getPayPrice(), 0));
vo.setHardName(order.getHardName());
vo.setCreateTime(order.getCreateTime());
return vo;
}
/** 状态枚举 {@code valueOfByType} 对未知编码会抛异常,这里安全降级为通用名称。 */
private static String resolveStatusName(String statusCode) {
if (StrUtil.isBlank(statusCode)) {
return "未知状态";
}
for (HardOrderStatusEnum status : HardOrderStatusEnum.values()) {
if (Objects.equals(statusCode, status.getType())) {
return status.getDescription();
}
}
return "其他状态";
}
}
@@ -30,6 +30,9 @@ public class VerificationRecordServiceImpl implements VerificationRecordService
/** 当前接口支持的预约核销类型协议值。 */
private static final String TYPE_RESERVATION = "RESERVATION";
/** 全部数据范围:按终端所属商户查询商户下全部设备的核销记录。 */
private static final String SCOPE_MERCHANT = "MERCHANT";
/** 设备服务,用于校验请求设备存在且与查询设备一致。 */
private final HardManagerService hardManagerService;
@@ -64,7 +67,12 @@ public class VerificationRecordServiceImpl implements VerificationRecordService
}
HardOrderDto query = new HardOrderDto();
query.setHardId(hard.getId());
if (SCOPE_MERCHANT.equalsIgnoreCase(StrUtil.trimToEmpty(dto.getScope()))) {
// 全部数据:范围来自服务端解析的终端所属商户,客户端不能自行指定商户。
query.setMerchantId(hard.getMerchantId());
} else {
query.setHardId(hard.getId());
}
query.setOrderType(HardOrderTypeEnum.RESERVE.getType());
query.setApptIdOrApptRuleIdNotNull(true);
query.setOrderStatusCodes(List.of(HardOrderStatusEnum.CANCEL.getType()));