打印机相关实现

This commit is contained in:
张松 2025-02-25 16:54:17 +08:00
parent 5719fdef74
commit c1ff2084f6
6 changed files with 217 additions and 343 deletions

View File

@ -52,7 +52,7 @@ public class PrintMqListener {
throw new RuntimeException("订单信息不存在");
}
getPrintMachine(orderInfo.getShopId(), "cash", "normal", "order").forEach(machine -> {
getPrintMachine(orderInfo.getShopId(), "cash", "one", "order").forEach(machine -> {
printerHandler.handleRequest(machine, orderInfo);
// printPlaceTicket(isReturn, machine, orderInfo, shopInfo);
});

View File

@ -1,5 +1,6 @@
package com.czg.account.dto.print;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
@ -23,6 +24,7 @@ public class PrinterEditDTO {
/**
* ip地址
*/
@NotBlank(message = "地址不为空")
private String address;
/**
@ -39,6 +41,7 @@ public class PrinterEditDTO {
/**
* 打印机品牌
*/
@NotBlank(message = "打印机品牌不为空")
private String contentType;

View File

@ -66,12 +66,27 @@ public class FeiPrinter extends PrinterHandler implements PrinterImpl{
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(getPickupNum(orderInfo), orderInfo.getCreateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")),
orderDetail.getProductName(), orderDetail.getNum(), remark, orderDetail.getProGroupInfo());
sendPrintRequest(machine.getAddress(), content, "1");
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]); // 可以解开注释用于日志存储
}
@ -100,7 +115,7 @@ public class FeiPrinter extends PrinterHandler implements PrinterImpl{
.setOutNumber(orderInfo.getTakeCode()).setPrintTitle("结算单")
.setRemark(orderInfo.getRemark()).setDiscountAmount(orderInfo.getOriginAmount().subtract(orderInfo.getPayAmount()).toPlainString());
String string = buildOrderPrintData(printInfoDTO, detailList);
sendPrintRequest(machine.getAddress(), string, printerNum);
sendPrintRequest(machine.getAddress(), string, null, printerNum);
// shopPrintLogService.save(machine, "结算单", resp[0], resp[1]);
}
@ -116,128 +131,102 @@ public class FeiPrinter extends PrinterHandler implements PrinterImpl{
return DigestUtils.sha1Hex(FeiPrinter.USER + FeiPrinter.UKEY + timeStamp);
}
@Override
public String getStartSplitSign() {
return "";
}
@Override
public String getEndSplitSign() {
return "";
}
private PrintSignLabel printSignLabel = new PrintSignLabel()
.setBr("<BR>")
.setCut("PCUT")
.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
public String buildOrderPrintData(PrintInfoDTO printInfoDTO, List<OrderDetail> detailList) {
StringBuilder data = new StringBuilder();
data.append(StrUtil.format("<CB>{}</CB><BR>", printInfoDTO.getShopName()));
data.append("<BR>");
data.append(StrUtil.format("<C><BOLD>{}【{}】</C></BOLD><BR>", printInfoDTO.getPrintTitle(), printInfoDTO.getPickupNum()));
data.append("<BR>");
data.append(StrUtil.format("订单号:{}<BR>", printInfoDTO.getOrderNo()));
data.append(StrUtil.format("交易时间:{}<BR>", printInfoDTO.getTradeDate()));
data.append(StrUtil.format("收银员:{}<BR>", printInfoDTO.getOperator()));
data.append("<BR>");
data.append("品名 数量 小计<BR>");
data.append("--------------------------------<BR>");
for (OrderDetail detail : detailList) {
String productName = detail.getProductName();
String number = detail.getNum().stripTrailingZeros().toPlainString();
String amount = toPlainStr(detail.getPayAmount().toPlainString());
//58mm的机器,一行打印16个汉字,32个字母; 80mm的机器,一行打印24个汉字,48个字母
//展示4列 b1代表名称列占用14个字节 b2单价列6个字节 b3数量列3个字节 b4金额列6个字节-->这里的字节数可按自己需求自由改写14+6+3+6再加上代码写的3个空格就是32了58mm打印机一行总占32字节
//String row = FeieYunUtil.getRow(productName, "",number, amount, 14, 6,3, 6)
//展示3列 b1代表名称列占用20个字节 b2单价列0个字节 b3数量列3个字节 b4金额列6个字节-->这里的字节数可按自己需求自由改写20+0+3+6再加上代码写的3个空格就是32了58mm打印机一行总占32字节
String row = getRow(productName, "", number, amount, 20, 0, 3, 6);
data.append(row);
if (StrUtil.isNotBlank(detail.getSkuName())) {
data.append("规格:").append(detail.getSkuName()).append("<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(" - %s".formatted(proName), "", "%d.00".formatted(qty), "0.00", 20, 0, 3, 6);
data.append(subRow);
}
}
if (ObjectUtil.isNotNull(printInfoDTO.getDiscountAmount())) {
data.append("--------------------------------<BR>");
data.append(StrUtil.format("原价:{}<BR>", toPlainStr(printInfoDTO.getOriginalAmount())));
data.append(StrUtil.format("折扣:-{}<BR>", toPlainStr(printInfoDTO.getDiscountAmount())));
}
data.append("--------------------------------<BR>");
String t = "" + printInfoDTO.getPayAmount();
if (printInfoDTO.isReturn()) {
data.append(StrUtil.format("<B>应退:{}</B><BR>", t));
} else {
data.append(StrUtil.format("<B>应收:{}</B><BR>", t));
}
data.append("--------------------------------<BR>");
if (ObjectUtil.isNotEmpty(printInfoDTO.getPayType()) && ObjectUtil.isNotNull(printInfoDTO.getPayType()) && printInfoDTO.getPayType().equals("deposit")) {
data.append(StrUtil.format("储值:{}<BR>", toPlainStr(printInfoDTO.getOriginalAmount())));
data.append(StrUtil.format("积分:{}<BR>", printInfoDTO.getIntegral()));
}
data.append(StrUtil.format("余额:{}<BR>", toPlainStr(printInfoDTO.getBalance())));
data.append("--------------------------------<BR>");
if (StrUtil.isNotBlank(printInfoDTO.getRemark())) {
data.append(StrUtil.format("<L><BOLD>备注:{}</BOLD></L><BR>", printInfoDTO.getRemark()));
}
data.append("打印时间:").append(DateUtil.date().toDateStr()).append("<BR>");
data.append("<CUT>");
return data.toString();
}
// @Override
// public String buildOrderPrintData(PrintInfoDTO printInfoDTO, List<OrderDetail> detailList) {
// StringBuilder data = new StringBuilder();
// data.append(StrUtil.format("<CB>{}</CB><BR>", printInfoDTO.getShopName()));
// data.append("<BR>");
// data.append(StrUtil.format("<C><BOLD>{}【{}】</C></BOLD><BR>", printInfoDTO.getPrintTitle(), printInfoDTO.getPickupNum()));
// data.append("<BR>");
// data.append(StrUtil.format("订单号:{}<BR>", printInfoDTO.getOrderNo()));
// data.append(StrUtil.format("交易时间:{}<BR>", printInfoDTO.getTradeDate()));
// data.append(StrUtil.format("收银员:{}<BR>", printInfoDTO.getOperator()));
// data.append("<BR>");
// data.append("品名 数量 小计<BR>");
// data.append("--------------------------------<BR>");
// for (OrderDetail detail : detailList) {
// String productName = detail.getProductName();
// String number = detail.getNum().stripTrailingZeros().toPlainString();
// String amount = toPlainStr(detail.getPayAmount().toPlainString());
// //58mm的机器,一行打印16个汉字,32个字母; 80mm的机器,一行打印24个汉字,48个字母
// //展示4列 b1代表名称列占用14个字节 b2单价列6个字节 b3数量列3个字节 b4金额列6个字节-->这里的字节数可按自己需求自由改写14+6+3+6再加上代码写的3个空格就是32了58mm打印机一行总占32字节
// //String row = FeieYunUtil.getRow(productName, "",number, amount, 14, 6,3, 6)
// //展示3列 b1代表名称列占用20个字节 b2单价列0个字节 b3数量列3个字节 b4金额列6个字节-->这里的字节数可按自己需求自由改写20+0+3+6再加上代码写的3个空格就是32了58mm打印机一行总占32字节
// String row = getRow(productName, "", number, amount, 20, 0, 3, 6);
// data.append(row);
// if (StrUtil.isNotBlank(detail.getSkuName())) {
// data.append("规格:").append(detail.getSkuName()).append("<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(" - %s".formatted(proName), "", "%d.00".formatted(qty), "0.00", 20, 0, 3, 6);
// data.append(subRow);
// }
// }
// if (ObjectUtil.isNotNull(printInfoDTO.getDiscountAmount())) {
// data.append("--------------------------------<BR>");
// data.append(StrUtil.format("原价:{}<BR>", toPlainStr(printInfoDTO.getOriginalAmount())));
// data.append(StrUtil.format("折扣:-{}<BR>", toPlainStr(printInfoDTO.getDiscountAmount())));
// }
// data.append("--------------------------------<BR>");
// String t = "" + printInfoDTO.getPayAmount();
// if (printInfoDTO.isReturn()) {
// data.append(StrUtil.format("<B>应退:{}</B><BR>", t));
// } else {
// data.append(StrUtil.format("<B>应收:{}</B><BR>", t));
// }
// data.append("--------------------------------<BR>");
// if (ObjectUtil.isNotEmpty(printInfoDTO.getPayType()) && ObjectUtil.isNotNull(printInfoDTO.getPayType()) && printInfoDTO.getPayType().equals("deposit")) {
// data.append(StrUtil.format("储值:{}<BR>", toPlainStr(printInfoDTO.getOriginalAmount())));
// data.append(StrUtil.format("积分:{}<BR>", printInfoDTO.getIntegral()));
// }
// data.append(StrUtil.format("余额:{}<BR>", toPlainStr(printInfoDTO.getBalance())));
// data.append("--------------------------------<BR>");
// if (StrUtil.isNotBlank(printInfoDTO.getRemark())) {
// data.append(StrUtil.format("<L><BOLD>备注:{}</BOLD></L><BR>", printInfoDTO.getRemark()));
// }
// data.append("打印时间:").append(DateUtil.date().toDateStr()).append("<BR>");
// data.append("<CUT>");
// return data.toString();
// }
/**
* 构建打印内容
*/
@Override
public String buildDishPrintData(String pickupNumber, String date, String productName,
BigDecimal number, String remark, String proGroupInfo) {
StringBuilder builder = new StringBuilder()
.append("<CB>").append(pickupNumber).append("</CB><BR>")
.append("<L>时间: ").append(date).append(" </L><BR>")
.append("<B><BOLD>").append(productName).append(" x ")
.append(number.stripTrailingZeros().toPlainString()).append("</BOLD></B><BR>")
.append("<B><BOLD>").append(StrUtil.emptyToDefault(remark, "")).append("</BOLD></B><BR>");
if (StrUtil.isNotBlank(proGroupInfo) && JSONUtil.isTypeJSONArray(proGroupInfo)) {
JSONArray subItems = JSONUtil.parseArray(proGroupInfo);
for (int i = 0; i < subItems.size(); i++) {
builder.append("<B>(").append(i + 1).append(")")
.append(subItems.getJSONObject(i).getStr("proName"))
.append(" x ").append(subItems.getJSONObject(i).getInt("number"))
.append("</B><BR>");
}
}
return builder.toString();
}
// @Override
// public String buildDishPrintData(String pickupNumber, String date, String productName,
// BigDecimal number, String remark, String proGroupInfo) {
// StringBuilder builder = new StringBuilder()
// .append("<CB>").append(pickupNumber).append("</CB><BR>")
// .append("<L>时间: ").append(date).append(" </L><BR>")
// .append("<B><BOLD>").append(productName).append(" x ")
// .append(number.stripTrailingZeros().toPlainString()).append("</BOLD></B><BR>")
// .append("<B><BOLD>").append(StrUtil.emptyToDefault(remark, "")).append("</BOLD></B><BR>");
//
// if (StrUtil.isNotBlank(proGroupInfo) && JSONUtil.isTypeJSONArray(proGroupInfo)) {
// JSONArray subItems = JSONUtil.parseArray(proGroupInfo);
// for (int i = 0; i < subItems.size(); i++) {
// builder.append("<B>(").append(i + 1).append(")")
// .append(subItems.getJSONObject(i).getStr("proName"))
// .append(" x ").append(subItems.getJSONObject(i).getInt("number"))
// .append("</B><BR>");
// }
// }
// return builder.toString();
// }
@Override
public <R> R sendPrintRequest(String address, String metaPrintData, String printerNum) {
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<>();

View File

@ -34,7 +34,6 @@ public interface PrinterImpl {
private String[] l;
private String[] qr;
private String cut;
}
@ -46,45 +45,26 @@ public interface PrinterImpl {
*/
// String buildOrderPrintData(PrinterHandler.PrintInfoDTO printInfoDTO, List<OrderDetail> detailList);
/**
* 构建菜品单打印数据
*
* @param pickupNumber 取餐号
* @param date 时间
* @param productName 商品名
* @param number 数量
* @param remark 备注
* @param proGroupInfo 套餐信息
* @return 元数据
*/
String buildDishPrintData(String pickupNumber, String date, String productName, BigDecimal number, String remark, String proGroupInfo);
/**
* 发送打印请求
*
* @param address 打印地址
* @param metaPrintData 打印元数据
* @param voiceData 语音信息
* @param printNum 打印联数
* @param <R> 返回数据类型
* @return 打印结果
*/
<R> R sendPrintRequest(String address, String metaPrintData, String printNum);
<R> R sendPrintRequest(String address, String metaPrintData, String voiceData, String printNum);
/**
* 获取当前打印机标签信息
*
* @return 标签信息
*/
PrintSignLabel getSignLabelInfo();
/**
* 分割起始标签 <S>
*
* @return 标签
*/
String getStartSplitSign();
/**
* 分割结束标签 </S>
*
* @return 标签
*/
String getEndSplitSign();
/**
* 获取对齐后的小票明细行数据
@ -170,7 +150,7 @@ public interface PrinterImpl {
// data.append("<OUT:30>");
// data.append("<BR>");
data.append(getFormatLabel(StrUtil.format("订单号:{}", printInfoDTO.getOrderNo()), signLabelInfo.s))
.append(signLabelInfo.br);
.append(signLabelInfo.br);
// data.append(StrUtil.format("<S>订单号:{}</S><BR>", printInfoDTO.getOrderNo()));
data.append(getFormatLabel(StrUtil.format("交易时间:{}", printInfoDTO.getTradeDate()), signLabelInfo.s))
.append(signLabelInfo.br);
@ -193,7 +173,7 @@ public interface PrinterImpl {
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(detail.getSkuName(), signLabelInfo.s))
data.append(getFormatLabel(StrUtil.format("规格:{}", detail.getSkuName()), signLabelInfo.s))
.append(signLabelInfo.br);
// data.append("<S>规格:").append(detail.getSkuName()).append("</S><BR>");
}
@ -232,7 +212,7 @@ public interface PrinterImpl {
.append(signLabelInfo.br);
// data.append("<F>应退").append(t).append("</F><BR>");
} else {
data.append(getFormatLabel(StrUtil.format("应收:{}", t) , signLabelInfo.f))
data.append(getFormatLabel(StrUtil.format("应收:{}", t), signLabelInfo.f))
.append(signLabelInfo.br);
// data.append(StrUtil.format("<F>应收:{}</F><BR>", t));
}
@ -273,6 +253,74 @@ public interface PrinterImpl {
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.bold, 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.bold, 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 = cn.hutool.json.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);
// builder.append("<OUT:150>");
// builder.append("<PCUT>");
return builder.toString();
}
/**
* 按字符数补足空格英文数字时使用
@ -331,6 +379,7 @@ public interface PrinterImpl {
* @return
*/
default String getStringByEnter(String string, int length) {
PrintSignLabel signLabelInfo = getSignLabelInfo();
StringBuilder result = new StringBuilder();
while (!string.isEmpty()) {
int pos = 0, byteCount = 0;
@ -340,7 +389,7 @@ public interface PrinterImpl {
byteCount += charByteLen;
pos = i + 1;
}
result.append(getStartSplitSign()).append(string, 0, pos).append(getEndSplitSign());
result.append(signLabelInfo.s[0]).append(string, 0, pos).append(signLabelInfo.s[1]);
string = string.substring(pos);
if (!string.isEmpty()) {
result.append("<BR>");

View File

@ -26,9 +26,14 @@ import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
/**
* 云享印打印机
*
* @author Administrator
*/
@Slf4j
@Component
public class YxyPrinter extends PrinterHandler {
public class YxyPrinter extends PrinterHandler implements PrinterImpl {
//请求地址
private static final String URL_STR = "https://ioe.car900.com/v1/openApi/dev/customPrint.json";
@ -42,6 +47,9 @@ public class YxyPrinter extends PrinterHandler {
@Resource
private ShopInfoService shopInfoService;
@Resource
private RestTemplate restTemplate;
public YxyPrinter() {
super("yxyPrinter");
}
@ -55,20 +63,20 @@ public class YxyPrinter extends PrinterHandler {
.setQr(new String[]{"<QR>", "</QR>"})
.setCenter(new String[]{"<CB>", "</CB>"})
.setBold(new String[]{"<BOLD>", "</BOLD>"});
@Override
public PrinterImpl.PrintSignLabel getSignLabelInfo() {
return printSignLabel;
}
/**
* 打印票据
*/
public static String printTickets(String voiceJson, Integer actWay, Integer cn, String devName, String data) {
log.info("开始请求云享印,请求数据:{}, {}", voiceJson, data);
@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
@ -79,16 +87,15 @@ public class YxyPrinter extends PrinterHandler {
//参数
MultiValueMap<String, Object> multiValueMap = new LinkedMultiValueMap<>();
multiValueMap.add("token", param.get("TOKEN"));
multiValueMap.add("devName", devName);
multiValueMap.add("actWay", actWay);
multiValueMap.add("cn", cn);
multiValueMap.add("data", data);
multiValueMap.add("voiceJson", voiceJson);
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);
RestTemplate restTemplate = new RestTemplate();
HttpHeaders header = new HttpHeaders();
header.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
@ -97,7 +104,7 @@ public class YxyPrinter extends PrinterHandler {
httpEntity, String.class);
log.info("请求云享印成功,响应数据: {}", httpResponse);
return httpResponse;
return (R) httpResponse;
}
@Override
@ -108,7 +115,7 @@ public class YxyPrinter extends PrinterHandler {
orderDetail.getNum().intValue(), orderDetail.getSkuName(), orderDetail.getRemark(), orderDetail.getProGroupInfo());
// String voiceJson = "{\"bizType\":\"2\",\"content\":\"您有一笔新的订单,请及时处理\"}";
String voiceJson = "{\"bizType\":\"2\",\"content\":\"\"}";
printTickets(voiceJson, 3, 1, machine.getAddress(), data);
// sendPrintRequest(voiceJson, 3, 1, machine.getAddress(), data);
}
@Override
@ -131,14 +138,14 @@ public class YxyPrinter extends PrinterHandler {
.setOutNumber(orderInfo.getTakeCode()).setPrintTitle("结算单")
.setRemark(orderInfo.getRemark()).setDiscountAmount(orderInfo.getOriginAmount().subtract(orderInfo.getPayAmount()).toPlainString());
String data = getCashPrintData(printInfoDTO, detailList);
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 = printTickets(voiceJson, 3, Integer.valueOf(printerNum), machine.getAddress(), data);
String resp = sendPrintRequest(machine.getAddress(), data, voiceJson, printerNum);
// shopPrintLogService.save(machine, printType, data, resp);
}
@ -222,178 +229,4 @@ public class YxyPrinter extends PrinterHandler {
}
// 按字符数补足空格英文数字时使用
public static String addSpace(String str, int size) {
return StrUtil.fillAfter(str, ' ', size);
}
// 按固定长度拆分字符串按字符拆分
public static 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 字节数补空格用于中文排版
public static String titleAddSpace(String str, int b1) {
int byteLen = StrUtil.bytes(str, CharsetUtil.CHARSET_GBK).length;
return StrUtil.fillAfter(str, ' ', b1 - byteLen);
}
// 判断字符串是否全为英文GBK编码下每个字符均为 1 字节
public static boolean isEn(String str) {
return StrUtil.bytes(str, CharsetUtil.CHARSET_GBK).length == str.length();
}
// 将字符串按 GBK 字节长度拆分每段包装在 <S> 标签内并用 <BR> 换行
public static String getStringByEnter(int length, String string) {
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("<S>").append(string, 0, pos).append("</S>");
string = string.substring(pos);
if (!string.isEmpty()) {
result.append("<BR>");
}
}
return result.toString();
}
/**
* 获取对齐后的小票明细行数据
* 例如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>标签
*/
public static String getRow(String title, String price, String num, String total,
int b1, int b2, int b3, int b4) {
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("<S>").append(title).append(otherStr).append("</S>");
} else {
// 品名超出一行进行拆分
List<String> lines = isEn(title)
// 英文按 b1 个字符拆分
? getStrList(title, b1)
// 中文按 b1/2 个字符拆分
: getStrList(title, b1 / 2);
// 第一行拼接其它字段
String firstLine = titleAddSpace(lines.getFirst(), b1);
sb.append("<S>").append(firstLine).append(otherStr).append("</S><BR>");
// 剩余的行单独换行输出
for (int i = 1; i < lines.size(); i++) {
sb.append("<S>").append(lines.get(i)).append("</S><BR>");
}
}
sb.append("<BR>");
return sb.toString();
}
private static String toPlainStr(String str) {
if (StrUtil.isBlank(str)) {
return "0";
}
return NumberUtil.roundDown(new BigDecimal(str), 2).toPlainString();
}
public static String getCashPrintData(PrintInfoDTO printInfoDTO, List<OrderDetail> detailList) {
StringBuilder data = new StringBuilder();
data.append(StrUtil.format("<C><F>{}</F></C><BR>", printInfoDTO.getShopName()));
data.append("<BR>");
data.append("<OUT:30>");
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(StrUtil.format("<S>订单号:{}</S><BR>", printInfoDTO.getOrderNo()));
data.append(StrUtil.format("<S>交易时间:{}</S><BR>", printInfoDTO.getTradeDate()));
data.append(StrUtil.format("<S>收银员:{}</S><BR>", printInfoDTO.getOperator()));
data.append("<OUT:15>");
data.append("<BR>");
data.append("<S>品名 数量 小计</S><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("<S>规格:").append(detail.getSkuName()).append("</S><BR>");
}
String proGroupInfo = detail.getProGroupInfo();
if (StrUtil.isBlank(proGroupInfo)) {
continue;
}
if (!JSONUtil.isTypeJSONArray(proGroupInfo)) {
continue;
}
JSONArray subItems = cn.hutool.json.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("<S>--------------------------------</S><BR>");
data.append(StrUtil.format("<S>原价:{}</S><BR>", toPlainStr(printInfoDTO.getOriginalAmount())));
data.append(StrUtil.format("<S>折扣:-{}</S><BR>", toPlainStr(printInfoDTO.getDiscountAmount())));
}
data.append("<S>--------------------------------</S><BR>");
String t = "" + printInfoDTO.getPayAmount();
if (printInfoDTO.isReturn()) {
data.append("<F>应退").append(t).append("</F><BR>");
data.append(StrUtil.format("<F>应收:{}</F><BR>", t));
} else {
data.append(StrUtil.format("<F>应收:{}</F><BR>", t));
}
data.append("<S>--------------------------------</S><BR>");
if (ObjectUtil.isNotEmpty(printInfoDTO.getPayType()) && ObjectUtil.isNotNull(printInfoDTO.getPayType()) && "deposit".equals(printInfoDTO.getPayType())) {
data.append(StrUtil.format("<S>储值:{}</S><BR>", toPlainStr(printInfoDTO.getOriginalAmount())));
data.append(StrUtil.format("<S>积分:{}</S><BR>", printInfoDTO.getIntegral()));
}
data.append(StrUtil.format("<S>余额:{}</S><BR>", toPlainStr(printInfoDTO.getBalance())));
data.append("<S>--------------------------------</S><BR>");
if (StrUtil.isNotBlank(printInfoDTO.getRemark())) {
data.append(StrUtil.format("<L><BOLD>备注:{}</BOLD></L><BR>", printInfoDTO.getRemark()));
}
if (Objects.nonNull(printInfoDTO.getOutNumber())) {
data.append("<QR>".concat(printInfoDTO.getOutNumber()).concat("</QR><BR>"));
}
data.append("<S>打印时间:").append(DateUtil.date().toDateStr()).append("</S><BR>");
data.append("<OUT:180>");
data.append("<PCUT>");
return data.toString();
}
}

View File

@ -52,7 +52,7 @@ public class PrintMachineServiceImpl extends ServiceImpl<PrintMachineMapper, Pri
throw new ApiNotPrintException("打印机不存在");
}
BeanUtil.copyProperties(printerEditDTO, printerEditDTO);
BeanUtil.copyProperties(printerEditDTO, printMachine);
return updateById(printMachine);
}
}