package com.doumee.core.utils.xpyun;
|
|
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSONArray;
|
import com.alibaba.fastjson.JSONObject;
|
import com.doumee.biz.system.SystemDictDataBiz;
|
import com.doumee.core.constants.Constants;
|
import com.doumee.core.utils.HttpsUtil;
|
import lombok.extern.slf4j.Slf4j;
|
import org.apache.commons.lang3.StringUtils;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.stereotype.Service;
|
|
import java.nio.charset.StandardCharsets;
|
import java.security.MessageDigest;
|
import java.text.SimpleDateFormat;
|
import java.util.Date;
|
import java.util.List;
|
|
/**
|
* 芯烨云打印机API服务
|
*/
|
@Slf4j
|
@Service
|
public class XpyunPrintService {
|
|
private static final String BASE_URL = "https://open.xpyun.net/api/openapi/xprinter/";
|
|
@Autowired
|
private SystemDictDataBiz systemDictDataBiz;
|
|
/**
|
* 添加打印机
|
*/
|
public XpyunResponse addPrinter(String sn, String name) {
|
JSONObject body = buildBaseRequest();
|
JSONArray printerContent = new JSONArray();
|
JSONObject printer = new JSONObject();
|
printer.put("sn", sn);
|
printer.put("name", name);
|
printerContent.add(printer);
|
body.put("printerContent", printerContent);
|
return callApi("addPrinters", body);
|
}
|
|
/**
|
* 删除打印机
|
*/
|
public XpyunResponse deletePrinter(String sn) {
|
JSONObject body = buildBaseRequest();
|
JSONArray snlist = new JSONArray();
|
snlist.add(sn);
|
body.put("snlist", snlist);
|
return callApi("delPrinters", body);
|
}
|
|
/**
|
* 查询打印机状态
|
*/
|
public XpyunResponse queryPrinterStatus(String sn) {
|
JSONObject body = buildBaseRequest();
|
body.put("sn", sn);
|
return callApi("queryPrinterStatus", body);
|
}
|
|
/**
|
* 打印标签
|
*/
|
public XpyunResponse printLabel(String sn, String content) {
|
JSONObject body = buildBaseRequest();
|
body.put("sn", sn);
|
body.put("content", content);
|
return callApi("printLabel", body);
|
}
|
|
/**
|
* 构建订单标签内容 (60mm × 60mm = 480 × 480 dots)
|
*
|
* 布局:
|
* shopName sn/countSn
|
* 订单编号:code 下单时间:xxx
|
* 收件信息:张三(手机尾号1234)
|
* 订单行李:
|
* 行李箱×1 双肩包×2
|
* 订单备注
|
* xxxxxxx
|
*/
|
public String buildOrderLabel(String shopName, String orderCode, String createTime,
|
String takeUser, String takePhone,
|
String goodsInfo, String remark,
|
String snLabel) {
|
StringBuilder sb = new StringBuilder();
|
sb.append("<PAGE>");
|
sb.append("<WIDTH>480</WIDTH>");
|
sb.append("<HEIGHT>480</HEIGHT>");
|
|
// 第1行: shopName 左侧, snLabel 右侧
|
sb.append("<TEXT X=\"8\" Y=\"8\" W=\"320\" H=\"28\" T=\"16\">")
|
.append(escapeXml(shopName)).append("</TEXT>");
|
sb.append("<TEXT X=\"340\" Y=\"8\" W=\"140\" H=\"28\" T=\"14\">")
|
.append(escapeXml(snLabel)).append("</TEXT>");
|
|
// 第2行: 订单编号 + 下单时间
|
sb.append("<TEXT X=\"8\" Y=\"44\" W=\"340\" H=\"24\" T=\"13\">")
|
.append("订单编号:").append(escapeXml(orderCode)).append("</TEXT>");
|
sb.append("<TEXT X=\"356\" Y=\"44\" W=\"124\" H=\"24\" T=\"13\">")
|
.append(escapeXml(createTime)).append("</TEXT>");
|
|
// 订单编号条形码
|
sb.append("<C128 X=\"8\" Y=\"72\" W=\"464\" H=\"56\" T=\"")
|
.append(escapeXml(orderCode)).append("\"/>");
|
|
// 第4行: 收件信息
|
String contactInfo = takeUser != null ? takeUser : "";
|
if (takePhone != null && takePhone.length() >= 4) {
|
contactInfo += "(手机尾号" + takePhone.substring(takePhone.length() - 4) + ")";
|
}
|
sb.append("<TEXT X=\"8\" Y=\"140\" W=\"464\" H=\"24\" T=\"13\">")
|
.append("收件信息:").append(escapeXml(contactInfo)).append("</TEXT>");
|
|
// 第5行: 订单行李
|
sb.append("<TEXT X=\"8\" Y=\"172\" W=\"464\" H=\"24\" T=\"13\">")
|
.append("订单行李:</TEXT>");
|
if (StringUtils.isNotBlank(goodsInfo)) {
|
sb.append("<TEXT X=\"8\" Y=\"200\" W=\"464\" H=\"24\" T=\"12\">")
|
.append(escapeXml(goodsInfo)).append("</TEXT>");
|
}
|
|
// 订单备注
|
if (StringUtils.isNotBlank(remark)) {
|
sb.append("<TEXT X=\"8\" Y=\"240\" W=\"464\" H=\"24\" T=\"13\">")
|
.append("订单备注:</TEXT>");
|
sb.append("<TEXT X=\"8\" Y=\"268\" W=\"464\" H=\"48\" T=\"12\">")
|
.append(escapeXml(remark)).append("</TEXT>");
|
}
|
|
sb.append("</PAGE>");
|
return sb.toString();
|
}
|
|
// ========== 私有方法 ==========
|
|
private JSONObject buildBaseRequest() {
|
String user = systemDictDataBiz.queryByCode(Constants.XPYUN_CONFIG, Constants.XPYUN_USER).getCode();
|
String userKey = systemDictDataBiz.queryByCode(Constants.XPYUN_CONFIG, Constants.XPYUN_USER_KEY).getCode();
|
long timestamp = System.currentTimeMillis() / 1000;
|
String sign = sha1(user + userKey + timestamp);
|
|
JSONObject body = new JSONObject();
|
body.put("user", user);
|
body.put("timestamp", timestamp);
|
body.put("sign", sign);
|
return body;
|
}
|
|
private XpyunResponse callApi(String endpoint, JSONObject body) {
|
try {
|
String url = BASE_URL + endpoint;
|
String result = HttpsUtil.postJson(url, body.toJSONString());
|
if (result == null) {
|
log.error("芯烨云API调用失败: endpoint={}, 响应为空", endpoint);
|
XpyunResponse resp = new XpyunResponse();
|
resp.setCode(-1);
|
resp.setMsg("响应为空");
|
return resp;
|
}
|
return JSON.parseObject(result, XpyunResponse.class);
|
} catch (Exception e) {
|
log.error("芯烨云API调用异常: endpoint={}, error={}", endpoint, e.getMessage(), e);
|
XpyunResponse resp = new XpyunResponse();
|
resp.setCode(-1);
|
resp.setMsg(e.getMessage());
|
return resp;
|
}
|
}
|
|
private static String sha1(String input) {
|
try {
|
MessageDigest md = MessageDigest.getInstance("SHA-1");
|
byte[] digest = md.digest(input.getBytes(StandardCharsets.UTF_8));
|
StringBuilder sb = new StringBuilder();
|
for (byte b : digest) {
|
sb.append(String.format("%02x", b));
|
}
|
return sb.toString();
|
} catch (Exception e) {
|
throw new RuntimeException("SHA-1计算失败", e);
|
}
|
}
|
|
private static String escapeXml(String text) {
|
if (text == null) return "";
|
return text.replace("&", "&")
|
.replace("<", "<")
|
.replace(">", ">")
|
.replace("\"", """)
|
.replace("'", "'");
|
}
|
}
|