打印移动到order模块
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
package com.czg.service.order.mapper;
|
||||
|
||||
import com.mybatisflex.core.BaseMapper;
|
||||
import com.czg.order.entity.MqLog;
|
||||
|
||||
/**
|
||||
* 映射层。
|
||||
*
|
||||
* @author zs
|
||||
* @since 2025-02-21
|
||||
*/
|
||||
public interface MqLogMapper extends BaseMapper<MqLog> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
package com.czg.service.order.print;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.czg.account.entity.PrintMachine;
|
||||
import com.czg.account.entity.ShopInfo;
|
||||
import com.czg.account.service.ShopInfoService;
|
||||
import com.czg.order.entity.OrderDetail;
|
||||
import com.czg.order.entity.OrderInfo;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Administrator
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class FeiPrinter extends PrinterHandler implements PrinterImpl {
|
||||
@Resource
|
||||
private RestTemplate restTemplate;
|
||||
|
||||
@Resource
|
||||
private ShopInfoService shopInfoService;
|
||||
|
||||
// API 地址
|
||||
private static final String URL = "http://api.feieyun.cn/Api/Open/";
|
||||
|
||||
// 飞鹅云 API 账号
|
||||
private static final String USER = "chaozhanggui2022@163.com";
|
||||
private static final String UKEY = "UfWkhXxSkeSSscsU";
|
||||
|
||||
public FeiPrinter() {
|
||||
super("fePrinter");
|
||||
}
|
||||
|
||||
private final PrintSignLabel printSignLabel = new PrintSignLabel()
|
||||
.setBr("<BR>")
|
||||
|
||||
.setCut("")
|
||||
.setF(new String[]{"<F>", "</F>"})
|
||||
.setL(new String[]{"<L>", "</L>"})
|
||||
.setS(new String[]{"", ""})
|
||||
.setF(new String[]{"<B>", "</B>"})
|
||||
.setQr(new String[]{"<QR>", "</QR>"})
|
||||
.setCenter(new String[]{"<CB>", "</CB>"})
|
||||
.setBold(new String[]{"<BOLD>", "</BOLD>"});
|
||||
@Override
|
||||
public PrintSignLabel getSignLabelInfo() {
|
||||
return printSignLabel;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void normalDishesPrint(OrderInfo orderInfo, OrderDetail orderDetail, PrintMachine machine) {
|
||||
String remark = orderDetail.getRemark();
|
||||
String content = buildDishPrintData(false, getPickupNum(orderInfo), orderInfo.getCreateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")),
|
||||
orderDetail.getProductName(), orderDetail.getSkuName(), orderDetail.getNum(), remark, orderDetail.getProGroupInfo());
|
||||
sendPrintRequest(machine.getAddress(), content, null,"1");
|
||||
|
||||
// shopPrintLogService.save(machine, "新订单", resp[0], resp[1]); // 可以解开注释用于日志存储
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void returnDishesPrint(OrderInfo orderInfo, OrderDetail orderDetail, PrintMachine machine) {
|
||||
String remark = orderDetail.getRemark();
|
||||
String content = buildDishPrintData(true, getPickupNum(orderInfo), orderInfo.getCreateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")),
|
||||
orderDetail.getProductName(), orderDetail.getSkuName(), orderDetail.getReturnNum(), remark, orderDetail.getProGroupInfo());
|
||||
sendPrintRequest(machine.getAddress(), content, null,"1");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void returnOrderPrint(OrderInfo orderInfo, PrintMachine machine, String balance, List<OrderDetail> detailList) {
|
||||
ShopInfo shopInfo = shopInfoService.getById(orderInfo.getShopId());
|
||||
String printerNum = "1";
|
||||
if (StrUtil.isNotBlank(machine.getPrintQty())) {
|
||||
printerNum = machine.getPrintQty().split("\\^")[1];
|
||||
}
|
||||
|
||||
PrintInfoDTO printInfoDTO = new PrintInfoDTO().setShopName(shopInfo.getShopName())
|
||||
.setPrintType("普通打印").setPickupNum(getPickupNum(orderInfo))
|
||||
.setOrderNo(orderInfo.getOrderNo()).setTradeDate(DateUtil.date().toDateStr()).setOperator("【POS-1】001").setPayAmount(orderInfo.getPayAmount().toPlainString())
|
||||
.setOriginalAmount(orderInfo.getOriginAmount().toPlainString()).setReturn(isReturn(orderInfo))
|
||||
.setBalance(balance).setPayType((ObjectUtil.isEmpty(orderInfo.getPayType()) || ObjectUtil.isNull(orderInfo.getPayType()) ? "" : orderInfo.getPayType())).setIntegral("0")
|
||||
.setOutNumber(orderInfo.getTakeCode()).setPrintTitle("结算单")
|
||||
.setRemark(orderInfo.getRemark()).setDiscountAmount(orderInfo.getOriginAmount().subtract(orderInfo.getPayAmount()).toPlainString());
|
||||
String string = buildOrderPrintData(printInfoDTO, detailList);
|
||||
sendPrintRequest(machine.getAddress(), string, null, printerNum);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void normalOrderPrint(OrderInfo orderInfo, PrintMachine machine, String balance, List<OrderDetail> detailList) {
|
||||
ShopInfo shopInfo = shopInfoService.getById(orderInfo.getShopId());
|
||||
String printerNum = "1";
|
||||
if (StrUtil.isNotBlank(machine.getPrintQty())) {
|
||||
printerNum = machine.getPrintQty().split("\\^")[1];
|
||||
}
|
||||
|
||||
PrintInfoDTO printInfoDTO = new PrintInfoDTO().setShopName(shopInfo.getShopName())
|
||||
.setPrintType("普通打印").setPickupNum(getPickupNum(orderInfo))
|
||||
.setOrderNo(orderInfo.getOrderNo()).setTradeDate(DateUtil.date().toDateStr()).setOperator("【POS-1】001").setPayAmount(orderInfo.getPayAmount().toPlainString())
|
||||
.setOriginalAmount(orderInfo.getOriginAmount().toPlainString()).setReturn(isReturn(orderInfo))
|
||||
.setBalance(balance).setPayType((ObjectUtil.isEmpty(orderInfo.getPayType()) || ObjectUtil.isNull(orderInfo.getPayType()) ? "" : orderInfo.getPayType())).setIntegral("0")
|
||||
.setOutNumber(orderInfo.getTakeCode()).setPrintTitle("结算单")
|
||||
.setRemark(orderInfo.getRemark()).setDiscountAmount(orderInfo.getOriginAmount().subtract(orderInfo.getPayAmount()).toPlainString());
|
||||
String string = buildOrderPrintData(printInfoDTO, detailList);
|
||||
sendPrintRequest(machine.getAddress(), string, null, printerNum);
|
||||
// shopPrintLogService.save(machine, "结算单", resp[0], resp[1]);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void callNumPrint(PrintMachine machine, String callNum, String shopName, String tableName, String tableNote, String preNum, String codeUrl, LocalDateTime takeTime, String shopNote) {
|
||||
String voiceJson = "{\"bizType\":\"2\",\"content\":\"您有一条新的排号记录\"}";
|
||||
String resp = buildCallTicketData(shopName, tableName, callNum, preNum, codeUrl,shopNote, takeTime);
|
||||
sendPrintRequest(machine.getAddress(), resp, voiceJson, "1");
|
||||
// shopPrintLogService.save(machine, "叫号单", data, resp);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成签名
|
||||
*/
|
||||
private static String signature(String timeStamp) {
|
||||
return DigestUtils.sha1Hex(FeiPrinter.USER + FeiPrinter.UKEY + timeStamp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R> R sendPrintRequest(String address, String metaPrintData, String voiceData, String printerNum) {
|
||||
log.info("飞蛾打印机开始发送打印请求, 设备地址: {}, 元数据: {}", address, metaPrintData);
|
||||
String time = String.valueOf(System.currentTimeMillis() / 1000);
|
||||
MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
|
||||
formData.add("user", USER);
|
||||
formData.add("stime", time);
|
||||
formData.add("sig", signature(time));
|
||||
formData.add("apiname", "Open_printMsg");
|
||||
formData.add("sn", address);
|
||||
formData.add("content", metaPrintData);
|
||||
formData.add("times", printerNum == null ? "1" : printerNum);
|
||||
|
||||
try {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
||||
|
||||
HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(formData, headers);
|
||||
|
||||
String result = restTemplate.postForObject(URL, requestEntity, String.class);
|
||||
log.info("打印结果: {}", result);
|
||||
return (R) result;
|
||||
} catch (Exception e) {
|
||||
log.error("打印请求失败: {}", e.getMessage());
|
||||
throw new RuntimeException("飞蛾打印请求失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.czg.service.order.print;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* 打印机责任链初始化
|
||||
* @author Administrator
|
||||
*/
|
||||
@Configuration
|
||||
public class PrintConfig {
|
||||
|
||||
@Resource
|
||||
private List<PrinterHandler> printers;
|
||||
|
||||
// 初始化责任链
|
||||
@PostConstruct
|
||||
public void initChain() {
|
||||
// 检查打印处理器列表是否为空
|
||||
if (printers != null && !printers.isEmpty()) {
|
||||
for (int i = 0; i < printers.size() - 1; i++) {
|
||||
// 设置当前处理器的下一个处理器
|
||||
printers.get(i).setNextPrinter(printers.get(i + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
public PrinterHandler printerHandler() {
|
||||
// 返回责任链的起始处理器
|
||||
return printers.getFirst();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,428 @@
|
||||
package com.czg.service.order.print;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.czg.account.dto.PrintOrderDetailDTO;
|
||||
import com.czg.account.entity.*;
|
||||
import com.czg.account.service.CallQueueService;
|
||||
import com.czg.account.service.CallTableService;
|
||||
import com.czg.account.service.ShopInfoService;
|
||||
import com.czg.account.service.ShopUserService;
|
||||
import com.czg.config.RedisCst;
|
||||
import com.czg.order.entity.OrderDetail;
|
||||
import com.czg.order.entity.OrderInfo;
|
||||
import com.czg.order.service.OrderDetailService;
|
||||
import com.czg.order.service.OrderInfoService;
|
||||
import com.czg.product.entity.ProdSku;
|
||||
import com.czg.product.entity.Product;
|
||||
import com.czg.product.service.ProdSkuService;
|
||||
import com.czg.product.service.ProductService;
|
||||
import com.czg.resp.CzgResult;
|
||||
import com.czg.service.RedisService;
|
||||
import com.czg.service.order.enums.OrderStatusEnums;
|
||||
import com.czg.system.dto.SysParamsDTO;
|
||||
import com.czg.system.service.SysParamsService;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.Data;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.dubbo.config.annotation.DubboReference;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author Administrator
|
||||
*/
|
||||
@Slf4j
|
||||
@ToString
|
||||
public abstract class PrinterHandler {
|
||||
@Setter
|
||||
protected PrinterHandler nextPrinter;
|
||||
protected String printerBrand;
|
||||
|
||||
@Resource
|
||||
protected OrderDetailService orderDetailService;
|
||||
@Resource
|
||||
protected OrderInfoService orderInfoService;
|
||||
@Resource
|
||||
protected RedisService redisService;
|
||||
|
||||
@DubboReference
|
||||
protected SysParamsService sysParamsService;
|
||||
@DubboReference
|
||||
protected ShopUserService shopUserService;
|
||||
@DubboReference
|
||||
protected CallQueueService callQueueService;
|
||||
@DubboReference
|
||||
protected CallTableService callTableService;
|
||||
@DubboReference
|
||||
protected ShopInfoService shopInfoService;
|
||||
@DubboReference
|
||||
protected ProductService productService;
|
||||
@DubboReference
|
||||
protected ProdSkuService prodSkuService;
|
||||
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public static class PrintDetailInfo {
|
||||
private boolean isPrint;
|
||||
// private boolean isReturn;
|
||||
private long orderId;
|
||||
private long detailId;
|
||||
private BigDecimal printNum;
|
||||
private BigDecimal printReturnNum;
|
||||
}
|
||||
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public static class PrintInfoDTO {
|
||||
// 打印标题 退款单/结算单
|
||||
private String printTitle;
|
||||
private String shopName;
|
||||
private String printType;
|
||||
private String pickupNum;
|
||||
private String orderNo;
|
||||
private String tradeDate;
|
||||
private String operator;
|
||||
private String payAmount;
|
||||
private String originalAmount;
|
||||
private String balance;
|
||||
private String payType;
|
||||
private String integral;
|
||||
private String remark;
|
||||
private String outNumber;
|
||||
private String discountAmount;
|
||||
private String discountRadio;
|
||||
// 是否退款单
|
||||
private boolean isReturn;
|
||||
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public static class DetailInfo {
|
||||
private String num;
|
||||
private String productName;
|
||||
private String amount;
|
||||
private String skuName;
|
||||
private String prodGroupInfo;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public PrinterHandler(String printerBrand) {
|
||||
this.printerBrand = printerBrand;
|
||||
}
|
||||
|
||||
public void handleRequest(PrintMachine machine, OrderInfo orderInfo, Long callQueueId) {
|
||||
if (canHandleRequest(machine.getContentType(), machine.getConnectionType())) {
|
||||
log.info("打印机: {}, 订单信息: {}", machine.getName(), orderInfo);
|
||||
print(machine, orderInfo, callQueueId);
|
||||
} else if (nextPrinter != null) {
|
||||
log.info("当前打印机无法处理: {},将请求传递给下一个打印机:{}...", this.printerBrand, nextPrinter.printerBrand);
|
||||
nextPrinter.handleRequest(machine, orderInfo, callQueueId);
|
||||
} else {
|
||||
log.warn("未找到匹配打印机");
|
||||
}
|
||||
}
|
||||
|
||||
boolean canHandleRequest(String currentBrand, String connectType) {
|
||||
log.info("handle判断是否可处理: {}, 连接类型: {}, handler类型: {}", currentBrand, connectType, printerBrand);
|
||||
if (StrUtil.isBlank(printerBrand)) {
|
||||
throw new RuntimeException("打印机品牌未赋值");
|
||||
}
|
||||
return printerBrand.equals(currentBrand) && "network".equals(connectType);
|
||||
}
|
||||
|
||||
protected List<OrderDetail> getCanPrintOrderDetails(boolean partPrint, Long orderId, List<OrderDetail> tbOrderDetailList, List<?> categoryIds) {
|
||||
List<Long> productIds = tbOrderDetailList.stream().map(OrderDetail::getProductId).collect(Collectors.toList());
|
||||
|
||||
Map<Long, Boolean> canPrintProMap = partPrint || categoryIds.isEmpty() ? new HashMap<>() :
|
||||
productService.list(new QueryWrapper().in(Product::getCategoryId, categoryIds).in(Product::getId, productIds))
|
||||
.stream().collect(Collectors.toMap(Product::getId, i -> true));
|
||||
|
||||
ArrayList<OrderDetail> orderDetails = new ArrayList<>();
|
||||
tbOrderDetailList.forEach(item -> {
|
||||
Object o = redisService.get(RedisCst.getPrintOrderDetailKey(orderId, item.getId()));
|
||||
|
||||
if (item.getIsPrint() != null && item.getIsPrint() == 1 && (canPrintProMap.get(item.getProductId()) != null || !partPrint)) {
|
||||
item.setReturnNum(item.getReturnNum() == null ? BigDecimal.ZERO : item.getReturnNum());
|
||||
PrintDetailInfo printDetailInfo = o != null ? JSONObject.parseObject((String) o, PrintDetailInfo.class) : null;
|
||||
if (printDetailInfo != null) {
|
||||
if (item.getNum().compareTo(printDetailInfo.getPrintNum()) <= 0) {
|
||||
log.info("此菜品已打印, {} {} {}", item.getProductName(), item.getSkuName(), printDetailInfo);
|
||||
}
|
||||
|
||||
if (item.getReturnNum().compareTo(printDetailInfo.getPrintReturnNum()) <= 0) {
|
||||
log.info("此退菜菜品已打印, {} {} {}", item.getProductName(), item.getSkuName(), printDetailInfo);
|
||||
}
|
||||
item.setNum(item.getNum().subtract(printDetailInfo.getPrintNum()));
|
||||
item.setReturnNum(item.getReturnNum().subtract(printDetailInfo.getPrintReturnNum()));
|
||||
orderDetails.add(item);
|
||||
}else {
|
||||
orderDetails.add(item);
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
log.info("此菜品不在打印分类或属于免打, {} {} {}", item.getProductName(), item.getSkuName(), item.getId());
|
||||
}
|
||||
});
|
||||
|
||||
return orderDetails;
|
||||
}
|
||||
|
||||
protected void print(PrintMachine machine, OrderInfo orderInfo, Long callQueueId) {
|
||||
String printMethod = machine.getPrintMethod();
|
||||
if (StrUtil.isBlank(printMethod) && StrUtil.isBlank(machine.getPrintType())) {
|
||||
throw new RuntimeException("打印机配置为空");
|
||||
}
|
||||
|
||||
// 订单打印
|
||||
if (StrUtil.isNotBlank(printMethod) && !"queue".equals(printMethod)) {
|
||||
log.info("准备开始打印订单或菜品单");
|
||||
// 查询订单详情
|
||||
List<OrderDetail> orderDetailList = orderDetailService.list(new QueryWrapper().eq(OrderDetail::getOrderId, orderInfo.getId()));
|
||||
//仅打印后厨一菜一品
|
||||
switch (printMethod) {
|
||||
case "one" -> onlyKitchen(machine, orderInfo, orderDetailList);
|
||||
case "normal" ->
|
||||
//仅打印前台
|
||||
onlyFrontDesk(machine, orderInfo, orderDetailList);
|
||||
case "all" -> {
|
||||
//全部打印 前台+后厨
|
||||
onlyFrontDesk(machine, orderInfo, orderDetailList);
|
||||
onlyKitchen(machine, orderInfo, orderDetailList);
|
||||
}
|
||||
default -> log.warn("未知打印类型: {}", printMethod);
|
||||
}
|
||||
} else {
|
||||
log.info("准备开始打印叫号单");
|
||||
if (StrUtil.isBlank(machine.getPrintType())) {
|
||||
return;
|
||||
}
|
||||
|
||||
JSONArray options = JSONArray.parseArray(machine.getPrintType());
|
||||
if (options == null || options.isEmpty()) {
|
||||
log.warn("打印机: {}, 未配置: print_type", machine.getId());
|
||||
return;
|
||||
}
|
||||
//是否包含排队取号
|
||||
if (!options.contains("queue")) {
|
||||
log.warn("打印机: {}, 此打印机不包含排队叫号打印", machine.getId());
|
||||
return;
|
||||
}
|
||||
// if (printDTO == null) {
|
||||
// return;
|
||||
// }
|
||||
onlyCallNumPrint(machine, callQueueId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 仅打印制作单「厨房」
|
||||
*/
|
||||
private void onlyKitchen(PrintMachine machine, OrderInfo orderInfo, List<OrderDetail> tbOrderDetailList) {
|
||||
// 判断订单是否是先付费或者已结算
|
||||
if (!"after-pay".equals(orderInfo.getPayMode()) && (OrderStatusEnums.UNPAID.getCode().equals(orderInfo.getStatus()) || OrderStatusEnums.CANCELLED.getCode().equals(orderInfo.getStatus()))) {
|
||||
log.warn("此订单未支付, 订单信息: {}", orderInfo);
|
||||
return;
|
||||
}
|
||||
|
||||
List<?> categoryIds = JSONObject.parseObject(StrUtil.emptyToDefault(machine.getCategoryIds(), "[]"), List.class);
|
||||
if (StrUtil.isEmpty(machine.getClassifyPrint())) {
|
||||
log.error("分类打印是空, classifyPrint: {}", machine.getClassifyPrint());
|
||||
return;
|
||||
}
|
||||
|
||||
// 已打印详情信息
|
||||
Map<Long, OrderDetail> detailMap = tbOrderDetailList.stream().map(item -> BeanUtil.copyProperties(item, OrderDetail.class)).collect(Collectors.toMap(OrderDetail::getId, i -> i));
|
||||
tbOrderDetailList = getCanPrintOrderDetails("1".equals(machine.getClassifyPrint()), orderInfo.getId(), tbOrderDetailList, categoryIds);
|
||||
tbOrderDetailList.parallelStream().filter(o -> ObjectUtil.defaultIfNull(o.getIsPrint(), 0) == 1).forEach(item -> {
|
||||
log.info("开始打印菜品,商品名:{}", item.getProductName());
|
||||
Integer isWaitCall = ObjectUtil.defaultIfNull(item.getIsWaitCall(), 0);
|
||||
if (isWaitCall == 1) {
|
||||
if (!item.getProductName().contains("【等叫】")) {
|
||||
item.setProductName("【等叫】" + item.getProductName());
|
||||
}
|
||||
}
|
||||
Integer isTemporary = ObjectUtil.defaultIfNull(item.getIsTemporary(), 0);
|
||||
if (isTemporary == 1) {
|
||||
item.setProductId(0L);
|
||||
item.setSkuId(0L);
|
||||
if (!item.getProductName().contains("【临】")) {
|
||||
item.setProductName("【临】" + item.getProductName());
|
||||
}
|
||||
}
|
||||
boolean isGift = item.getPackAmount().compareTo(BigDecimal.ZERO) == 0;
|
||||
if (isGift && !item.getProductName().contains("【赠】")) {
|
||||
item.setProductName("【赠】" + item.getProductName());
|
||||
}
|
||||
// 台位费不打印
|
||||
if (item.getProductId().equals(-999L)) {
|
||||
log.info("台位费商品,不打印");
|
||||
return;
|
||||
}
|
||||
// ProdSku sku = prodSkuService.getById(item.getSkuId());
|
||||
// if (isTemporary == 0 && sku == null) {
|
||||
// log.error("商品不存在, id: {}", item.getSkuId());
|
||||
// return;
|
||||
// } else if (isTemporary == 1) {
|
||||
// sku = new ProdSku();
|
||||
// }
|
||||
|
||||
|
||||
// String remark = StrUtil.isNotBlank(sku.getSpecInfo()) ? sku.getSpecInfo() : "";
|
||||
// item.setRemark(remark);
|
||||
if (item.getReturnNum().compareTo(BigDecimal.ZERO) > 0) {
|
||||
returnDishesPrint(orderInfo, item, machine);
|
||||
}
|
||||
|
||||
if (item.getNum().compareTo(BigDecimal.ZERO) > 0) {
|
||||
normalDishesPrint(orderInfo, item, machine);
|
||||
}
|
||||
|
||||
// 保存已打印信息
|
||||
OrderDetail orderDetail = detailMap.get(item.getId());
|
||||
redisService.set(RedisCst.getPrintOrderDetailKey(orderInfo.getId(), item.getId()), JSONObject.toJSONString(new PrintDetailInfo().setPrint(item.getIsPrint() == 1).setDetailId(item.getId())
|
||||
.setPrintNum(orderDetail.getNum()).setPrintReturnNum(orderDetail.getReturnNum())), 3600 * 24);
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 仅打印结算单「前台」
|
||||
*/
|
||||
private void onlyFrontDesk(PrintMachine machine, OrderInfo orderInfo, List<OrderDetail> tbOrderDetailList) {
|
||||
// 判断订单是否是先付费或者已结算
|
||||
if (OrderStatusEnums.UNPAID.getCode().equals(orderInfo.getStatus()) || OrderStatusEnums.CANCELLED.getCode().equals(orderInfo.getStatus())) {
|
||||
log.warn("此订单未支付或已取消, 订单信息: {}", orderInfo);
|
||||
return;
|
||||
}
|
||||
|
||||
if (tbOrderDetailList.isEmpty()) {
|
||||
log.info("待打印列表为空");
|
||||
return;
|
||||
}
|
||||
List<PrintOrderDetailDTO> detailList = new ArrayList<>();
|
||||
tbOrderDetailList.forEach(it -> {
|
||||
Integer isTemporary = ObjectUtil.defaultIfNull(it.getIsTemporary(), 0);
|
||||
String remark = "";
|
||||
if (isTemporary == 0) {
|
||||
ProdSku prodSku = prodSkuService.getById(it.getSkuId());
|
||||
if (ObjectUtil.isNotEmpty(prodSku) && ObjectUtil.isNotEmpty(prodSku.getSpecInfo())) {
|
||||
remark = prodSku.getSpecInfo();
|
||||
}
|
||||
}
|
||||
Integer isWaitCall = ObjectUtil.defaultIfNull(it.getIsWaitCall(), 0);
|
||||
if (isWaitCall == 1) {
|
||||
it.setProductName("【等叫】%s".formatted(it.getProductName()));
|
||||
}
|
||||
if (isTemporary == 1) {
|
||||
it.setProductName("【临】%s".formatted(it.getProductName()));
|
||||
}
|
||||
it.setPackAmount(it.getPackAmount() == null ? BigDecimal.ZERO : it.getPackAmount());
|
||||
boolean isGift = it.getPackAmount().compareTo(BigDecimal.ZERO) == 0;
|
||||
if (isGift) {
|
||||
it.setProductName("【赠】%s".formatted(it.getProductName()));
|
||||
}
|
||||
BigDecimal unitPrice = it.getPrice();
|
||||
if (isGift) {
|
||||
unitPrice = BigDecimal.ZERO;
|
||||
}
|
||||
PrintOrderDetailDTO detail = new PrintOrderDetailDTO(it.getProductName(), it.getNum().toString(), unitPrice.stripTrailingZeros().toPlainString(), remark, it.getProGroupInfo());
|
||||
detailList.add(detail);
|
||||
|
||||
});
|
||||
String balance = "0";
|
||||
|
||||
if ("deposit".equals(orderInfo.getPayType())) {
|
||||
ShopUser user = shopUserService.getOne(new QueryWrapper().eq(ShopUser::getShopId, orderInfo.getShopId()).eq(ShopUser::getUserId, orderInfo.getUserId()));
|
||||
if (ObjectUtil.isNotEmpty(user) && ObjectUtil.isNotEmpty(user.getAmount())) {
|
||||
balance = user.getAmount().toPlainString();
|
||||
}
|
||||
}
|
||||
|
||||
if (!detailList.isEmpty()) {
|
||||
if (isReturn(orderInfo)) {
|
||||
returnOrderPrint(orderInfo, machine, balance, tbOrderDetailList);
|
||||
} else {
|
||||
normalOrderPrint(orderInfo, machine, balance, tbOrderDetailList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印排队小票
|
||||
*/
|
||||
private void onlyCallNumPrint(PrintMachine machine, Long callQueueId) {
|
||||
if (callQueueId == null) {
|
||||
log.warn("打印叫号小票失败,id为空");
|
||||
}
|
||||
|
||||
CallQueue queue = callQueueService.getById(callQueueId);
|
||||
if (queue == null) {
|
||||
log.warn("叫号记录不存在");
|
||||
return;
|
||||
}
|
||||
|
||||
CzgResult<SysParamsDTO> paramsByCode = sysParamsService.getParamsByCode("call_page_url");
|
||||
SysParamsDTO params = paramsByCode.getData();
|
||||
String callUrl = null;
|
||||
if (params != null && StrUtil.isNotBlank(params.getParamValue())) {
|
||||
callUrl = params.getParamValue();
|
||||
}
|
||||
|
||||
CallTable tbCallTable = callTableService.getById(queue.getCallTableId());
|
||||
ShopInfo shopInfo = shopInfoService.getById(queue.getShopId());
|
||||
callNumPrint(machine, queue.getCallNum(), shopInfo.getShopName(), tbCallTable.getName(), tbCallTable.getNote(), String.valueOf(callQueueService.count(new QueryWrapper()
|
||||
.eq(CallQueue::getShopId, queue.getShopId())
|
||||
.eq(CallQueue::getCallTableId, queue.getCallTableId())
|
||||
.lt(CallQueue::getId, queue.getId())
|
||||
.in(CallQueue::getState, 0, 1))), callUrl == null ? "未配置页面" : StrUtil.format(callUrl, queue.getShopId(), queue.getId()), queue.getCreateTime(),
|
||||
StrUtil.format("过号顺延{}桌 {}桌后需重新排号 谢谢理解!", tbCallTable.getPostponeNum(), tbCallTable.getPostponeNum()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取取餐号
|
||||
*/
|
||||
protected static String getPickupNum(OrderInfo orderInfo) {
|
||||
return StrUtil.isBlank(orderInfo.getTableName()) ? orderInfo.getTakeCode() : orderInfo.getTableName();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据订单信息判断是否是退单
|
||||
*
|
||||
* @param orderInfo 顶动感信息
|
||||
* @return 是否退款
|
||||
*/
|
||||
protected static boolean isReturn(OrderInfo orderInfo) {
|
||||
return ArrayUtil.contains(new String[]{"refunding", "part-refund", "refund"}, orderInfo.getStatus());
|
||||
}
|
||||
|
||||
|
||||
protected abstract void normalDishesPrint(OrderInfo orderInfo, OrderDetail orderDetail, PrintMachine machine);
|
||||
|
||||
protected abstract void returnDishesPrint(OrderInfo orderInfo, OrderDetail orderDetail, PrintMachine machine);
|
||||
|
||||
protected abstract void returnOrderPrint(OrderInfo orderInfo, PrintMachine machine, String balance, List<OrderDetail> detailList);
|
||||
|
||||
protected abstract void normalOrderPrint(OrderInfo orderInfo, PrintMachine machine, String balance, List<OrderDetail> detailList);
|
||||
|
||||
protected abstract void callNumPrint(PrintMachine machine, String callNum, String shopName, String tableName, String tableNote, String preNum,
|
||||
String codeUrl, LocalDateTime takeTime, String shopNote);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,480 @@
|
||||
package com.czg.service.order.print;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
import cn.hutool.core.util.NumberUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONArray;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.czg.order.entity.OrderDetail;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 打印机具体打印方法接口,提供打印元数据获取,具体打印机实现对应方法即可
|
||||
*
|
||||
* @author Administrator
|
||||
*/
|
||||
public interface PrinterImpl {
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
class PrintSignLabel {
|
||||
private String[] center;
|
||||
private String[] centerBold;
|
||||
private String[] bold;
|
||||
private String br;
|
||||
private String[] s;
|
||||
private String[] f;
|
||||
private String[] l;
|
||||
private String[] qr;
|
||||
private String cut;
|
||||
private String out;
|
||||
|
||||
public String getOut(int num) {
|
||||
if (out != null) {
|
||||
return StrUtil.format("<{}:{}>", out, num);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 构建订单打印元数据
|
||||
* @param printInfoDTO 打印信息
|
||||
* @param detailList 订单详情内容
|
||||
* @return 元数据
|
||||
*/
|
||||
// String buildOrderPrintData(PrinterHandler.PrintInfoDTO printInfoDTO, List<OrderDetail> detailList);
|
||||
|
||||
|
||||
/**
|
||||
* 发送打印请求
|
||||
*
|
||||
* @param address 打印地址
|
||||
* @param metaPrintData 打印元数据
|
||||
* @param voiceData 语音信息
|
||||
* @param printNum 打印联数
|
||||
* @param <R> 返回数据类型
|
||||
* @return 打印结果
|
||||
*/
|
||||
<R> R sendPrintRequest(String address, String metaPrintData, String voiceData, String printNum);
|
||||
|
||||
/**
|
||||
* 获取当前打印机标签信息
|
||||
*
|
||||
* @return 标签信息
|
||||
*/
|
||||
PrintSignLabel getSignLabelInfo();
|
||||
|
||||
|
||||
/**
|
||||
* 获取对齐后的小票明细行数据
|
||||
* 例如:58mm 机器一行打印16个汉字/32个字母;80mm机器打印24个汉字/48个字母。
|
||||
*
|
||||
* @param title 品名
|
||||
* @param price 单价
|
||||
* @param num 数量
|
||||
* @param total 小计
|
||||
* @param b1 品名占用字节数
|
||||
* @param b2 单价占用字节数
|
||||
* @param b3 数量占用字节数
|
||||
* @param b4 小计占用字节数
|
||||
* @return 格式化后的行数据(带<S>和<BR>标签)
|
||||
*/
|
||||
default String getRow(String title, String price, String num, String total,
|
||||
int b1, int b2, int b3, int b4) {
|
||||
PrintSignLabel signLabelInfo = getSignLabelInfo();
|
||||
price = addSpace(price, b2);
|
||||
num = addSpace(num, b3);
|
||||
total = addSpace(total, b4);
|
||||
String otherStr = " %s%s %s".formatted(price, num, total);
|
||||
|
||||
int titleByteLen = StrUtil.bytes(title, CharsetUtil.CHARSET_GBK).length;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
if (titleByteLen <= b1) {
|
||||
// 品名可以在一行显示,直接补足空格
|
||||
title = titleAddSpace(title, b1);
|
||||
sb.append(getFormatLabel(title + otherStr, signLabelInfo.s));
|
||||
// sb.append(startSplitSign).append(title).append(otherStr).append(endSplitSign);
|
||||
} else {
|
||||
// 品名超出一行,进行拆分
|
||||
List<String> lines = isEn(title)
|
||||
// 英文按 b1 个字符拆分
|
||||
? getStrList(title, b1)
|
||||
// 中文按 b1/2 个字符拆分
|
||||
: getStrList(title, b1 / 2);
|
||||
|
||||
// 第一行拼接其它字段
|
||||
String firstLine = titleAddSpace(lines.getFirst(), b1);
|
||||
sb.append(getFormatLabel(firstLine + otherStr, signLabelInfo.s)).append(signLabelInfo.br);
|
||||
// sb.append(startSplitSign).append(firstLine).append(otherStr).append(endSplitSign).append("<BR>");
|
||||
|
||||
// 剩余的行单独换行输出
|
||||
for (int i = 1; i < lines.size(); i++) {
|
||||
sb.append(getFormatLabel(lines.get(i), signLabelInfo.s)).append(signLabelInfo.br);
|
||||
// sb.append(startSplitSign).append(lines.get(i)).append(endSplitSign).append("BR>");
|
||||
}
|
||||
}
|
||||
sb.append("<BR>");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
default String getFormatLabel(String text, String[]... labels) {
|
||||
StringBuilder str = new StringBuilder();
|
||||
for (String[] label : labels) {
|
||||
str.append(label[0]);
|
||||
}
|
||||
|
||||
str.append(text);
|
||||
for (int i = labels.length - 1; i >= 0; i--) {
|
||||
str.append(labels[i][1]);
|
||||
}
|
||||
return str.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建订单打印元数据
|
||||
*
|
||||
* @param printInfoDTO 打印信息
|
||||
* @param detailList 订单详情
|
||||
* @return 订单打印元数据
|
||||
*/
|
||||
default String buildOrderPrintData(PrinterHandler.PrintInfoDTO printInfoDTO, List<OrderDetail> detailList) {
|
||||
PrintSignLabel signLabelInfo = getSignLabelInfo();
|
||||
StringBuilder data = new StringBuilder();
|
||||
data.append(getFormatLabel(printInfoDTO.getShopName(), signLabelInfo.center, signLabelInfo.f)).append(signLabelInfo.br);
|
||||
// data.append(StrUtil.format("<C><F>{}</F></C><BR>", printInfoDTO.getShopName()));
|
||||
// data.append("<BR>");
|
||||
data.append(signLabelInfo.br);
|
||||
// data.append("<OUT:30>");
|
||||
data.append(getFormatLabel(StrUtil.format("{}【{}】", printInfoDTO.getPrintTitle(), printInfoDTO.getPickupNum()), signLabelInfo.center, signLabelInfo.bold))
|
||||
.append(signLabelInfo.br)
|
||||
.append(signLabelInfo.br);
|
||||
// data.append(StrUtil.format("<C><BOLD>{}【{}】</BOLD></C><BR>", printInfoDTO.getPrintTitle(), printInfoDTO.getPickupNum()));
|
||||
//if (Objects.nonNull(printInfoDTO.getOutNumber())) {
|
||||
// data.append(StrUtil.format("<CB><BOLD>{}</BOLD></CB>",printInfoDTO.getOutNumber()));
|
||||
//}
|
||||
// data.append("<OUT:30>");
|
||||
// data.append("<BR>");
|
||||
data.append(getFormatLabel(StrUtil.format("订单号:{}", printInfoDTO.getOrderNo()), signLabelInfo.s))
|
||||
.append(signLabelInfo.br);
|
||||
// data.append(StrUtil.format("<S>订单号:{}</S><BR>", printInfoDTO.getOrderNo()));
|
||||
data.append(getFormatLabel(StrUtil.format("交易时间:{}", printInfoDTO.getTradeDate()), signLabelInfo.s))
|
||||
.append(signLabelInfo.br);
|
||||
// data.append(StrUtil.format("<S>交易时间:{}</S><BR>", printInfoDTO.getTradeDate()));
|
||||
data.append(getFormatLabel(StrUtil.format("收银员:{}", printInfoDTO.getOperator()), signLabelInfo.s))
|
||||
.append(signLabelInfo.br);
|
||||
// data.append(StrUtil.format("<S>收银员:{}</S><BR>", printInfoDTO.getOperator()));
|
||||
data.append(signLabelInfo.br);
|
||||
data.append(signLabelInfo.br);
|
||||
// data.append("<OUT:15>");
|
||||
// data.append("<BR>");
|
||||
data.append(getFormatLabel("品名 数量 小计", signLabelInfo.s))
|
||||
.append(signLabelInfo.br);
|
||||
// data.append("<S>品名 数量 小计</S><BR>");
|
||||
data.append(getFormatLabel("--------------------------------", signLabelInfo.s))
|
||||
.append(signLabelInfo.br);
|
||||
// data.append("<S>--------------------------------</S><BR>");
|
||||
for (OrderDetail detail : detailList) {
|
||||
String number = detail.getNum().stripTrailingZeros().toPlainString();
|
||||
String row = getRow(detail.getProductName(), "", number, toPlainStr(detail.getPayAmount().stripTrailingZeros().toPlainString()), 20, 0, 3, 6);
|
||||
data.append(row);
|
||||
if (StrUtil.isNotBlank(detail.getSkuName())) {
|
||||
data.append(getFormatLabel(StrUtil.format("规格:{}", detail.getSkuName()), signLabelInfo.s))
|
||||
.append(signLabelInfo.br);
|
||||
// data.append("<S>规格:").append(detail.getSkuName()).append("</S><BR>");
|
||||
}
|
||||
String proGroupInfo = detail.getProGroupInfo();
|
||||
if (StrUtil.isBlank(proGroupInfo)) {
|
||||
continue;
|
||||
}
|
||||
if (!JSONUtil.isTypeJSONArray(proGroupInfo)) {
|
||||
continue;
|
||||
}
|
||||
JSONArray subItems = JSONUtil.parseArray(proGroupInfo);
|
||||
for (int i = 0; i < subItems.size(); i++) {
|
||||
String proName = subItems.getJSONObject(i).getStr("proName");
|
||||
int qty = subItems.getJSONObject(i).getInt("number");
|
||||
String subRow = getRow(" - " + proName, "", qty + ".00", "0.00", 20, 0, 3, 6);
|
||||
data.append(subRow);
|
||||
}
|
||||
}
|
||||
if (ObjectUtil.isNotNull(printInfoDTO.getDiscountAmount())) {
|
||||
data.append(getFormatLabel("--------------------------------", signLabelInfo.s))
|
||||
.append(signLabelInfo.br);
|
||||
// data.append("<S>--------------------------------</S><BR>");
|
||||
data.append(getFormatLabel(StrUtil.format("原价:{}", toPlainStr(printInfoDTO.getOriginalAmount())), signLabelInfo.s))
|
||||
.append(signLabelInfo.br);
|
||||
// data.append(StrUtil.format("<S>原价:{}</S><BR>", toPlainStr(printInfoDTO.getOriginalAmount())));
|
||||
data.append(getFormatLabel(StrUtil.format("折扣:-{}", toPlainStr(printInfoDTO.getDiscountAmount())), signLabelInfo.s))
|
||||
.append(signLabelInfo.br);
|
||||
// data.append(StrUtil.format("<S>折扣:-{}</S><BR>", toPlainStr(printInfoDTO.getDiscountAmount())));
|
||||
}
|
||||
data.append(getFormatLabel("--------------------------------", signLabelInfo.s))
|
||||
.append(signLabelInfo.br);
|
||||
// data.append("<S>--------------------------------</S><BR>");
|
||||
String t = "¥" + printInfoDTO.getPayAmount();
|
||||
if (printInfoDTO.isReturn()) {
|
||||
data.append(getFormatLabel(StrUtil.format("应退:{}", t), signLabelInfo.f))
|
||||
.append(signLabelInfo.br);
|
||||
// data.append("<F>应退").append(t).append("</F><BR>");
|
||||
} else {
|
||||
data.append(getFormatLabel(StrUtil.format("应收:{}", t), signLabelInfo.f))
|
||||
.append(signLabelInfo.br);
|
||||
// data.append(StrUtil.format("<F>应收:{}</F><BR>", t));
|
||||
}
|
||||
data.append(getFormatLabel("--------------------------------", signLabelInfo.s))
|
||||
.append(signLabelInfo.br);
|
||||
// data.append("<S>--------------------------------</S><BR>");
|
||||
if (ObjectUtil.isNotEmpty(printInfoDTO.getPayType()) && ObjectUtil.isNotNull(printInfoDTO.getPayType()) && "deposit".equals(printInfoDTO.getPayType())) {
|
||||
data.append(getFormatLabel(StrUtil.format("储值:{}", toPlainStr(printInfoDTO.getOriginalAmount())), signLabelInfo.s))
|
||||
.append(signLabelInfo.br);
|
||||
// data.append(StrUtil.format("<S>储值:{}</S><BR>", toPlainStr(printInfoDTO.getOriginalAmount())));
|
||||
data.append(getFormatLabel(StrUtil.format("积分:{}", printInfoDTO.getIntegral()), signLabelInfo.s))
|
||||
.append(signLabelInfo.br);
|
||||
// data.append(StrUtil.format("<S>积分:{}</S><BR>", printInfoDTO.getIntegral()));
|
||||
}
|
||||
data.append(getFormatLabel(StrUtil.format("余额:{}", toPlainStr(printInfoDTO.getBalance())), signLabelInfo.s))
|
||||
.append(signLabelInfo.br);
|
||||
// data.append(StrUtil.format("<S>余额:{}</S><BR>", toPlainStr(printInfoDTO.getBalance())));
|
||||
data.append(getFormatLabel("--------------------------------", signLabelInfo.s))
|
||||
.append(signLabelInfo.br);
|
||||
// data.append("<S>--------------------------------</S><BR>");
|
||||
if (StrUtil.isNotBlank(printInfoDTO.getRemark())) {
|
||||
data.append(getFormatLabel(StrUtil.format("备注:{}", printInfoDTO.getRemark()), signLabelInfo.l, signLabelInfo.bold))
|
||||
.append(signLabelInfo.br);
|
||||
// data.append(StrUtil.format("<L><BOLD>备注:{}</BOLD></L><BR>", printInfoDTO.getRemark()));
|
||||
}
|
||||
if (Objects.nonNull(printInfoDTO.getOutNumber())) {
|
||||
data.append(getFormatLabel(printInfoDTO.getOutNumber(), signLabelInfo.center, signLabelInfo.qr))
|
||||
.append(signLabelInfo.br);
|
||||
// data.append("<QR>".concat(printInfoDTO.getOutNumber()).concat("</QR><BR>"));
|
||||
}
|
||||
data.append(getFormatLabel(StrUtil.format("打印时间:{}", DateUtil.date().toString()), signLabelInfo.s))
|
||||
.append(signLabelInfo.br)
|
||||
.append(signLabelInfo.br);
|
||||
// data.append("<S>打印时间:").append(DateUtil.date().toDateStr()).append("</S><BR>");
|
||||
// data.append("<OUT:180>");
|
||||
data.append(signLabelInfo.getOut(180));
|
||||
data.append(signLabelInfo.cut);
|
||||
// data.append("<PCUT>");
|
||||
return data.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建菜品单打印数据
|
||||
*
|
||||
* @param pickupNumber 取餐号
|
||||
* @param date 时间
|
||||
* @param productName 商品名
|
||||
* @param skuName 规格名称
|
||||
* @param number 数量
|
||||
* @param remark 备注
|
||||
* @param proGroupInfo 套餐信息
|
||||
* @return 元数据
|
||||
*/
|
||||
default String buildDishPrintData(boolean isReturn, String pickupNumber, String date, String productName, String skuName, BigDecimal number, String remark, String proGroupInfo) {
|
||||
PrintSignLabel signLabelInfo = getSignLabelInfo();
|
||||
StringBuilder builder = new StringBuilder();
|
||||
if (isReturn) {
|
||||
builder.append(getFormatLabel(StrUtil.format("{}【退】", pickupNumber), signLabelInfo.center, signLabelInfo.bold))
|
||||
.append(signLabelInfo.br)
|
||||
.append(signLabelInfo.br);
|
||||
// builder.append("<C><B>").append(pickupNumber).append("【退】</B></C><BR><BR>");
|
||||
} else {
|
||||
builder.append(getFormatLabel(pickupNumber, signLabelInfo.center, signLabelInfo.bold))
|
||||
.append(signLabelInfo.br)
|
||||
.append(signLabelInfo.br);
|
||||
// builder.append("<C><B>").append(pickupNumber).append("</B></C><BR><BR>");
|
||||
}
|
||||
builder.append(getFormatLabel(StrUtil.format("时间: {}", date), signLabelInfo.l, signLabelInfo.s))
|
||||
.append(signLabelInfo.br)
|
||||
.append(signLabelInfo.br);
|
||||
// builder.append("<S><L>时间: ").append(date).append(" </L></S><BR><BR><BR>");
|
||||
if (productName.length() > 4 || skuName.length() > 4) {
|
||||
builder.append(getFormatLabel(StrUtil.format("{} x {}", productName, number.stripTrailingZeros().toPlainString()), signLabelInfo.l))
|
||||
.append(signLabelInfo.br);
|
||||
// builder.append("<CS:32>").append(productName).append(" x ").append(number).append("</CS><BR>");
|
||||
if (StrUtil.isNotBlank(skuName)) {
|
||||
builder.append(getFormatLabel(skuName, signLabelInfo.l)).append(signLabelInfo.br);
|
||||
// builder.append("<CS:32>").append(skuName).append(" </CS><BR>");
|
||||
}
|
||||
} else {
|
||||
builder.append(getFormatLabel(StrUtil.format("{} x ", productName), signLabelInfo.bold));
|
||||
// builder.append("<B>").append(productName).append(" x ").append(number).append("</B><BR>");
|
||||
if (StrUtil.isNotBlank(skuName)) {
|
||||
builder.append(getFormatLabel(skuName, signLabelInfo.bold))
|
||||
.append(signLabelInfo.br);
|
||||
// builder.append("<B>").append(skuName).append(" </B><BR>");
|
||||
}
|
||||
}
|
||||
if (StrUtil.isNotBlank(remark)) {
|
||||
builder.append(signLabelInfo.br);
|
||||
builder.append(getFormatLabel(StrUtil.format("备注:{}", remark), signLabelInfo.s, signLabelInfo.l))
|
||||
.append(signLabelInfo.br);
|
||||
// builder.append("<S><L>备注: ").append(note).append(" </L></S><BR>");
|
||||
}
|
||||
if (!StrUtil.isBlank(proGroupInfo) && JSONUtil.isTypeJSONArray(proGroupInfo)) {
|
||||
JSONArray subItems = JSONUtil.parseArray(proGroupInfo);
|
||||
for (int i = 0; i < subItems.size(); i++) {
|
||||
String proName = subItems.getJSONObject(i).getStr("proName");
|
||||
int qty = subItems.getJSONObject(i).getInt("number");
|
||||
builder.append(StrUtil.format("({}) x ", proName))
|
||||
.append(signLabelInfo.br);
|
||||
// builder.append("<CS:32>(").append(i + 1).append(")").append(proName).append(" x ").append(qty).append("</CS><BR>");
|
||||
}
|
||||
}
|
||||
builder.append(signLabelInfo.br)
|
||||
.append(signLabelInfo.getOut(150))
|
||||
.append(signLabelInfo.cut);
|
||||
// builder.append("<OUT:150>");
|
||||
// builder.append("<PCUT>");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建叫号元数据
|
||||
* @param shopName 店铺名称
|
||||
* @param tableName 表名
|
||||
* @param callNum 号码
|
||||
* @param preNum 前面还有几桌
|
||||
* @param codeUrl 二维码地址
|
||||
* @param shopNote 店铺备注
|
||||
* @param takeTime 取号时间
|
||||
* @return 元数据
|
||||
*/
|
||||
default String buildCallTicketData(String shopName, String tableName, String callNum, String preNum, String codeUrl, String shopNote, LocalDateTime takeTime) {
|
||||
PrintSignLabel signLabelInfo = getSignLabelInfo();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(getFormatLabel(shopName, signLabelInfo.center, signLabelInfo.bold))
|
||||
.append(signLabelInfo.br)
|
||||
.append(signLabelInfo.br)
|
||||
.append(getFormatLabel(StrUtil.format("{} {}", tableName, callNum), signLabelInfo.center, signLabelInfo.bold))
|
||||
.append(signLabelInfo.br)
|
||||
.append(getFormatLabel(StrUtil.format("前面有{}桌", preNum), signLabelInfo.center))
|
||||
.append(signLabelInfo.br)
|
||||
.append(getFormatLabel("怕过号扫一扫", signLabelInfo.center, signLabelInfo.bold))
|
||||
.append(signLabelInfo.br)
|
||||
.append(getFormatLabel(codeUrl, signLabelInfo.center, signLabelInfo.qr))
|
||||
.append(signLabelInfo.br)
|
||||
.append("--------------------------------").append(signLabelInfo.br)
|
||||
.append(getFormatLabel(shopNote, signLabelInfo.s))
|
||||
.append(signLabelInfo.br)
|
||||
.append("--------------------------------").append(signLabelInfo.br)
|
||||
.append(getFormatLabel(StrUtil.format("取号时间:{}", DateUtil.format(takeTime, "yyyy-MM-dd HH:mm:ss")), signLabelInfo.s))
|
||||
.append(signLabelInfo.br)
|
||||
.append(getFormatLabel(StrUtil.format("打印时间:{}", DateUtil.format(DateUtil.date(), "yyyy-MM-dd HH:mm:ss")), signLabelInfo.s))
|
||||
.append(signLabelInfo.br)
|
||||
.append(signLabelInfo.cut);
|
||||
// sb.append("<C><B>").append(shopName).append("</B></C><BR><BR>")
|
||||
// .append("------------------------<BR>")
|
||||
// .append(StrUtil.format(StrUtil.format("<C><B>{} {}</B></C><BR>", tableName, callNum)))
|
||||
// .append(StrUtil.format("<C>前面有{}桌</C><BR>", preNum))
|
||||
// .append(StrUtil.format("<C><QR>{}</QR></C><BR>", codeUrl))
|
||||
// .append("<C><B>怕过号扫一扫<B></C><BR>")
|
||||
// .append("------------------------<BR>")
|
||||
// .append(StrUtil.format("<S>{}</S><BR>", shopNote))
|
||||
// .append("------------------------<BR>").append("<S>取号时间:").append(DateUtil.format(takeTime, "yyyy-MM-dd HH:mm:ss"))
|
||||
// .append("</S><BR>").append("<S>打印时间:").append(DateUtil.format(DateUtil.date(), "yyyy-MM-dd HH:mm:ss")).append("</S><BR>")
|
||||
// .append("<OUT:180>").append("<PCUT>");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 按字符数补足空格(英文、数字时使用)
|
||||
*
|
||||
* @param str 对应字符串
|
||||
* @param size 总长度
|
||||
* @return 填充之后的字符串
|
||||
*/
|
||||
default String addSpace(String str, int size) {
|
||||
return StrUtil.fillAfter(str, ' ', size);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按固定长度拆分字符串(按字符拆分)
|
||||
*
|
||||
* @param inputString 字符串
|
||||
* @param length 每个长度
|
||||
* @return 分割后的集合
|
||||
*/
|
||||
default List<String> getStrList(String inputString, int length) {
|
||||
List<String> list = new ArrayList<>();
|
||||
for (int i = 0; i < inputString.length(); i += length) {
|
||||
list.add(StrUtil.sub(inputString, i, Math.min(i + length, inputString.length())));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 判断字符串是否全为英文(GBK编码下,每个字符均为 1 字节)
|
||||
*
|
||||
* @param str 字符
|
||||
* @return 是否英文
|
||||
*/
|
||||
default boolean isEn(String str) {
|
||||
return StrUtil.bytes(str, CharsetUtil.CHARSET_GBK).length == str.length();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 GBK 字节数补空格(用于中文排版)
|
||||
*
|
||||
* @param str 字符串
|
||||
* @param b1 总长度
|
||||
* @return 添加间距的字符串
|
||||
*/
|
||||
default String titleAddSpace(String str, int b1) {
|
||||
int byteLen = StrUtil.bytes(str, CharsetUtil.CHARSET_GBK).length;
|
||||
return StrUtil.fillAfter(str, ' ', b1 - byteLen);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取填充字符串, 并且换行
|
||||
*
|
||||
* @param length 长度
|
||||
* @param string 字符串
|
||||
* @return
|
||||
*/
|
||||
default String getStringByEnter(String string, int length) {
|
||||
PrintSignLabel signLabelInfo = getSignLabelInfo();
|
||||
StringBuilder result = new StringBuilder();
|
||||
while (!string.isEmpty()) {
|
||||
int pos = 0, byteCount = 0;
|
||||
for (int i = 0; i < string.length(); i++) {
|
||||
int charByteLen = StrUtil.bytes(string.substring(i, i + 1), CharsetUtil.CHARSET_GBK).length;
|
||||
if (byteCount + charByteLen > length) break;
|
||||
byteCount += charByteLen;
|
||||
pos = i + 1;
|
||||
}
|
||||
result.append(signLabelInfo.s[0]).append(string, 0, pos).append(signLabelInfo.s[1]);
|
||||
string = string.substring(pos);
|
||||
if (!string.isEmpty()) {
|
||||
result.append("<BR>");
|
||||
}
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取规格化的字符串
|
||||
*
|
||||
* @param str 字符串
|
||||
* @return 返回规格化字符串
|
||||
*/
|
||||
default String toPlainStr(String str) {
|
||||
if (StrUtil.isBlank(str)) {
|
||||
return "0";
|
||||
}
|
||||
return NumberUtil.roundDown(new BigDecimal(str), 2).toPlainString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
package com.czg.service.order.print;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.crypto.SecureUtil;
|
||||
import com.czg.account.entity.PrintMachine;
|
||||
import com.czg.account.entity.ShopInfo;
|
||||
import com.czg.account.service.ShopInfoService;
|
||||
import com.czg.order.entity.OrderDetail;
|
||||
import com.czg.order.entity.OrderInfo;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 云享印打印机
|
||||
*
|
||||
* @author Administrator
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class YxyPrinter extends PrinterHandler implements PrinterImpl {
|
||||
|
||||
//请求地址
|
||||
private static final String URL_STR = "https://ioe.car900.com/v1/openApi/dev/customPrint.json";
|
||||
//APPID
|
||||
private static final String APP_ID = "ZF544";
|
||||
//USERCODE
|
||||
private static final String USER_CODE = "ZF544";
|
||||
//APPSECRET
|
||||
private static final String APP_SECRET = "2022bsjZF544GAH";
|
||||
|
||||
@Resource
|
||||
private ShopInfoService shopInfoService;
|
||||
|
||||
@Resource
|
||||
private RestTemplate restTemplate;
|
||||
|
||||
public YxyPrinter() {
|
||||
super("yxyPrinter");
|
||||
}
|
||||
|
||||
private PrintSignLabel printSignLabel = new PrintSignLabel()
|
||||
.setBr("<BR>")
|
||||
.setCut("<PCUT>")
|
||||
.setOut("OUT")
|
||||
.setF(new String[]{"<F>", "</F>"})
|
||||
.setL(new String[]{"<L>", "</L>"})
|
||||
.setS(new String[]{"<S>", "</S>"})
|
||||
.setQr(new String[]{"<QR>", "</QR>"})
|
||||
.setCenter(new String[]{"<C>", "</C>"})
|
||||
.setBold(new String[]{"<B>", "</B>"});
|
||||
|
||||
@Override
|
||||
public PrintSignLabel getSignLabelInfo() {
|
||||
return printSignLabel;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public <R> R sendPrintRequest(String address, String metaPrintData, String voiceData, String printNum) {
|
||||
log.info("开始请求云享印,请求数据:{}, {}", voiceData, metaPrintData);
|
||||
//设备名称
|
||||
//行为方式 1:只打印数据 2:只播放信息 3:打印数据并播放信息
|
||||
// actWay = 3;
|
||||
//打印联数
|
||||
// int cn = 1;
|
||||
//打印内容
|
||||
//播报语音数据体,字段参考文档IOT_XY_API11001
|
||||
String time = String.valueOf(System.currentTimeMillis());
|
||||
String uuid = UUID.randomUUID().toString();
|
||||
|
||||
Map<String, String> param = getToken(time, uuid);
|
||||
//参数
|
||||
MultiValueMap<String, Object> multiValueMap = new LinkedMultiValueMap<>();
|
||||
multiValueMap.add("token", param.get("TOKEN"));
|
||||
multiValueMap.add("devName", address);
|
||||
multiValueMap.add("actWay", 3);
|
||||
multiValueMap.add("cn", printNum);
|
||||
multiValueMap.add("data", metaPrintData);
|
||||
multiValueMap.add("voiceJson", voiceData);
|
||||
multiValueMap.add("appId", APP_ID);
|
||||
multiValueMap.add("timestamp", time);
|
||||
multiValueMap.add("requestId", uuid);
|
||||
multiValueMap.add("userCode", USER_CODE);
|
||||
HttpHeaders header = new HttpHeaders();
|
||||
header.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
||||
|
||||
HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(multiValueMap, header);
|
||||
String httpResponse = restTemplate.postForObject(URL_STR,
|
||||
httpEntity, String.class);
|
||||
|
||||
log.info("请求云享印成功,响应数据: {}", httpResponse);
|
||||
return (R) httpResponse;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void normalDishesPrint(OrderInfo orderInfo, OrderDetail orderDetail, PrintMachine machine) {
|
||||
String buildDishPrintData = buildDishPrintData(false, getPickupNum(orderInfo), DateUtil.format(orderDetail.getCreateTime(), "yyyy-MM-dd HH:mm:ss"), orderDetail.getProductName(), orderDetail.getSkuName(),
|
||||
orderDetail.getNum(), orderDetail.getRemark(), orderDetail.getProGroupInfo());
|
||||
// String voiceJson = "{\"bizType\":\"2\",\"content\":\"您有一笔新的订单,请及时处理\"}";
|
||||
String voiceJson = "{\"bizType\":\"2\",\"content\":\"\"}";
|
||||
sendPrintRequest(machine.getAddress(), buildDishPrintData, voiceJson, "1");
|
||||
// sendPrintRequest(voiceJson, 3, 1, machine.getAddress(), data);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void returnDishesPrint(OrderInfo orderInfo, OrderDetail orderDetail, PrintMachine machine) {
|
||||
String buildDishPrintData = buildDishPrintData(true, getPickupNum(orderInfo), DateUtil.format(orderDetail.getCreateTime(), "yyyy-MM-dd HH:mm:ss"), orderDetail.getProductName(), orderDetail.getSkuName(),
|
||||
orderDetail.getReturnNum(), orderDetail.getRemark(), orderDetail.getProGroupInfo());
|
||||
// String voiceJson = "{\"bizType\":\"2\",\"content\":\"您有一笔新的订单,请及时处理\"}";
|
||||
String voiceJson = "{\"bizType\":\"2\",\"content\":\"\"}";
|
||||
sendPrintRequest(machine.getAddress(), buildDishPrintData, voiceJson, "1");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void returnOrderPrint(OrderInfo orderInfo, PrintMachine machine, String balance, List<OrderDetail> detailList) {
|
||||
ShopInfo shopInfo = shopInfoService.getById(orderInfo.getShopId());
|
||||
PrintInfoDTO printInfoDTO = new PrintInfoDTO().setShopName(shopInfo.getShopName()).setPrintType("普通打印").setPickupNum(getPickupNum(orderInfo))
|
||||
.setOrderNo(orderInfo.getOrderNo()).setTradeDate(DateUtil.date().toDateStr()).setOperator("【POS-1】001").setPayAmount(orderInfo.getPayAmount().toPlainString())
|
||||
.setOriginalAmount(orderInfo.getOriginAmount().toPlainString()).setReturn(isReturn(orderInfo))
|
||||
.setBalance(balance).setPayType((ObjectUtil.isEmpty(orderInfo.getPayType()) || ObjectUtil.isNull(orderInfo.getPayType()) ? "" : orderInfo.getPayType())).setIntegral("0")
|
||||
.setOutNumber(orderInfo.getTakeCode()).setPrintTitle("结算单")
|
||||
.setRemark(orderInfo.getRemark()).setDiscountAmount(orderInfo.getOriginAmount().subtract(orderInfo.getPayAmount()).toPlainString());
|
||||
|
||||
String data = buildOrderPrintData(printInfoDTO, detailList);
|
||||
String voiceJson = "{\"PbizType\":\"2\",\"content\":\"您有一笔新的订单,请及时处理\"}";
|
||||
// String voiceJson = "{\"bizType\":\"2\",\"content\":\"\"}";
|
||||
String printerNum = "1";
|
||||
if (StrUtil.isNotBlank(machine.getPrintQty())) {
|
||||
printerNum = machine.getPrintQty().split("\\^")[1];
|
||||
}
|
||||
String resp = sendPrintRequest(machine.getAddress(), data, voiceJson, printerNum);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void normalOrderPrint(OrderInfo orderInfo, PrintMachine machine, String balance, List<OrderDetail> detailList) {
|
||||
ShopInfo shopInfo = shopInfoService.getById(orderInfo.getShopId());
|
||||
PrintInfoDTO printInfoDTO = new PrintInfoDTO().setShopName(shopInfo.getShopName()).setPrintType("普通打印").setPickupNum(getPickupNum(orderInfo))
|
||||
.setOrderNo(orderInfo.getOrderNo()).setTradeDate(DateUtil.date().toDateStr()).setOperator("【POS-1】001").setPayAmount(orderInfo.getPayAmount().toPlainString())
|
||||
.setOriginalAmount(orderInfo.getOriginAmount().toPlainString()).setReturn(isReturn(orderInfo))
|
||||
.setBalance(balance).setPayType((ObjectUtil.isEmpty(orderInfo.getPayType()) || ObjectUtil.isNull(orderInfo.getPayType()) ? "" : orderInfo.getPayType())).setIntegral("0")
|
||||
.setOutNumber(orderInfo.getTakeCode()).setPrintTitle("结算单")
|
||||
.setRemark(orderInfo.getRemark()).setDiscountAmount(orderInfo.getOriginAmount().subtract(orderInfo.getPayAmount()).toPlainString());
|
||||
|
||||
String data = buildOrderPrintData(printInfoDTO, detailList);
|
||||
String voiceJson = "{\"PbizType\":\"2\",\"content\":\"您有一笔新的订单,请及时处理\"}";
|
||||
// String voiceJson = "{\"bizType\":\"2\",\"content\":\"\"}";
|
||||
String printerNum = "1";
|
||||
if (StrUtil.isNotBlank(machine.getPrintQty())) {
|
||||
printerNum = machine.getPrintQty().split("\\^")[1];
|
||||
}
|
||||
String resp = sendPrintRequest(machine.getAddress(), data, voiceJson, printerNum);
|
||||
// shopPrintLogService.save(machine, printType, data, resp);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void callNumPrint(PrintMachine machine, String callNum, String shopName, String tableName, String tableNote, String preNum, String codeUrl, LocalDateTime takeTime, String shopNote) {
|
||||
String resp = buildCallTicketData(shopName, tableName, callNum, preNum, codeUrl,shopNote, takeTime);
|
||||
sendPrintRequest(machine.getAddress(), resp, null, "1");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取TOKEN值
|
||||
*
|
||||
* @param timestamp 时间戳,13位
|
||||
* @param requestId 请求ID,自定义
|
||||
* @return token信息
|
||||
*/
|
||||
private static Map<String, String> getToken(String timestamp, String requestId) {
|
||||
StringBuilder token = new StringBuilder();
|
||||
StringBuilder encode = new StringBuilder();
|
||||
SortedMap<String, Object> map = new TreeMap<>();
|
||||
map.put("appId", APP_ID);
|
||||
map.put("timestamp", timestamp);
|
||||
map.put("requestId", requestId);
|
||||
map.put("userCode", USER_CODE);
|
||||
for (Map.Entry<String, Object> next : map.entrySet()) {
|
||||
String key = next.getKey();
|
||||
Object value = next.getValue();
|
||||
token.append(key).append(value);
|
||||
encode.append(key).append("=").append(value).append("&");
|
||||
}
|
||||
Map<String, String> finalMap = new HashMap<>();
|
||||
finalMap.put("ENCODE", encode.toString());
|
||||
finalMap.put("TOKEN", SecureUtil.md5(token + APP_SECRET).toUpperCase());
|
||||
return finalMap;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.czg.service.order.service.impl;
|
||||
|
||||
import com.czg.order.entity.MqLog;
|
||||
import com.czg.order.service.MqLogService;
|
||||
import com.czg.service.order.mapper.MqLogMapper;
|
||||
import com.mybatisflex.spring.service.impl.ServiceImpl;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 服务层实现。
|
||||
*
|
||||
* @author zs
|
||||
* @since 2025-02-21
|
||||
*/
|
||||
@Service
|
||||
public class MqLogServiceImpl extends ServiceImpl<MqLogMapper, MqLog> implements MqLogService{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.czg.service.order.mapper.MqLogMapper">
|
||||
|
||||
</mapper>
|
||||
Reference in New Issue
Block a user