|
@@ -0,0 +1,181 @@
|
|
|
|
|
+package com.platform.service;
|
|
|
|
|
+
|
|
|
|
|
+import com.alibaba.fastjson.JSON;
|
|
|
|
|
+import com.platform.api.request.XpPrintImageReqVo;
|
|
|
|
|
+import com.platform.api.request.XpPrintReceiptReqVo;
|
|
|
|
|
+import com.platform.config.XpCloudProperties;
|
|
|
|
|
+import com.platform.exception.IotException;
|
|
|
|
|
+import io.github.dv996coding.vo.ObjectRestResponse;
|
|
|
|
|
+import io.github.dv996coding.vo.PrintOrderRequest;
|
|
|
|
|
+import jakarta.annotation.Resource;
|
|
|
|
|
+import lombok.RequiredArgsConstructor;
|
|
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
|
|
+import org.apache.commons.lang3.StringUtils;
|
|
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
|
|
+
|
|
|
|
|
+import java.nio.charset.StandardCharsets;
|
|
|
|
|
+import java.security.MessageDigest;
|
|
|
|
|
+import java.time.Instant;
|
|
|
|
|
+import java.util.UUID;
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 芯烨云打印服务
|
|
|
|
|
+ *
|
|
|
|
|
+ * @author assistant
|
|
|
|
|
+ */
|
|
|
|
|
+@Slf4j
|
|
|
|
|
+@Service
|
|
|
|
|
+@RequiredArgsConstructor
|
|
|
|
|
+public class XpCloudPrintService {
|
|
|
|
|
+
|
|
|
|
|
+ private final XpCloudProperties xpCloudProperties;
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 直接使用@Resource注入SDK服务
|
|
|
|
|
+ */
|
|
|
|
|
+ @Resource
|
|
|
|
|
+ private io.github.dv996coding.service.PrintService printService;
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 调用SDK执行图片打印
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param reqVo 业务请求参数
|
|
|
|
|
+ * @return 云端打印任务号
|
|
|
|
|
+ */
|
|
|
|
|
+ public String printImage(XpPrintImageReqVo reqVo) {
|
|
|
|
|
+ if (reqVo == null || StringUtils.isAnyBlank(reqVo.getSn(), reqVo.getImageUrl())) {
|
|
|
|
|
+ throw new IotException("打印参数不能为空");
|
|
|
|
|
+ }
|
|
|
|
|
+ if (reqVo.getCopies() == null || reqVo.getCopies() <= 0) {
|
|
|
|
|
+ throw new IotException("打印份数必须大于0");
|
|
|
|
|
+ }
|
|
|
|
|
+ try {
|
|
|
|
|
+ PrintOrderRequest request = new PrintOrderRequest(reqVo.getSn(), reqVo.getImageUrl());
|
|
|
|
|
+ request.setCopies(reqVo.getCopies());
|
|
|
|
|
+ request.setIdempotent(UUID.randomUUID().toString().replace("-", ""));
|
|
|
|
|
+ ObjectRestResponse<String> response = printService.printImage(request);
|
|
|
|
|
+ log.info("芯烨云图片打印完成, sn={}, code={}, msg={}, data={}",
|
|
|
|
|
+ reqVo.getSn(), response.getCode(), response.getMsg(), response.getData());
|
|
|
|
|
+ if (response.getCode() == null || response.getCode() != 0) {
|
|
|
|
|
+ throw new IotException("调用芯烨云打印失败:" + response.getMsg());
|
|
|
|
|
+ }
|
|
|
|
|
+ return response.getData();
|
|
|
|
|
+ } catch (IotException e) {
|
|
|
|
|
+ throw e;
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error("调用芯烨云图片打印异常, sn={}", reqVo.getSn(), e);
|
|
|
|
|
+ throw new IotException("调用芯烨云图片打印异常:" + e.getMessage());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 调用SDK执行小票订单打印
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param reqVo 小票订单打印请求
|
|
|
|
|
+ * @return 云端打印任务号
|
|
|
|
|
+ */
|
|
|
|
|
+ public String printReceipt(XpPrintReceiptReqVo reqVo) {
|
|
|
|
|
+ log.info("芯烨云小票打印, 入参:{}", JSON.toJSONString(reqVo));
|
|
|
|
|
+ if (reqVo == null || reqVo.getContent() == null || StringUtils.isAnyBlank(reqVo.getSn())) {
|
|
|
|
|
+ throw new IotException("打印参数不能为空");
|
|
|
|
|
+ }
|
|
|
|
|
+ if (reqVo.getExpiresIn() != null && (reqVo.getMode() == null || reqVo.getMode() != 1)) {
|
|
|
|
|
+ throw new IotException("设置expiresIn时,mode必须为1");
|
|
|
|
|
+ }
|
|
|
|
|
+ try {
|
|
|
|
|
+ String xmlContent = buildReceiptXml(reqVo.getContent());
|
|
|
|
|
+ PrintOrderRequest request = new PrintOrderRequest(reqVo.getSn(), xmlContent);
|
|
|
|
|
+ fillCommonParams(request);
|
|
|
|
|
+ request.setDirect(reqVo.getDirect());
|
|
|
|
|
+ request.setCopies(reqVo.getCopies());
|
|
|
|
|
+ request.setMode(reqVo.getMode());
|
|
|
|
|
+ if (StringUtils.isNotBlank(reqVo.getIdempotent())) {
|
|
|
|
|
+ request.setIdempotent(reqVo.getIdempotent());
|
|
|
|
|
+ }
|
|
|
|
|
+ if (reqVo.getRealTime() != null) {
|
|
|
|
|
+ request.setRealTime(reqVo.getRealTime());
|
|
|
|
|
+ }
|
|
|
|
|
+ if (reqVo.getSupportNativeInstruction() != null) {
|
|
|
|
|
+ request.setSupportNativeInstruction(reqVo.getSupportNativeInstruction());
|
|
|
|
|
+ }
|
|
|
|
|
+ if (reqVo.getExpiresIn() != null) {
|
|
|
|
|
+ request.setExpiresIn(reqVo.getExpiresIn());
|
|
|
|
|
+ }
|
|
|
|
|
+ log.info("芯烨云小票打印,请求参数:{}", JSON.toJSONString(request));
|
|
|
|
|
+ ObjectRestResponse<String> response = printService.print(request);
|
|
|
|
|
+ log.info("芯烨云小票打印完成, sn={}, code={}, msg={}, data={}",
|
|
|
|
|
+ reqVo.getSn(), response.getCode(), response.getMsg(), response.getData());
|
|
|
|
|
+ if (response.getCode() == null || response.getCode() != 0) {
|
|
|
|
|
+ throw new IotException("调用芯烨云小票打印失败:" + response.getMsg());
|
|
|
|
|
+ }
|
|
|
|
|
+ return response.getData();
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error("调用芯烨云小票打印异常, sn={}", reqVo.getSn(), e);
|
|
|
|
|
+ throw new IotException("调用芯烨云小票打印异常:" + e.getMessage());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 按前端对象拼接小票XML内容
|
|
|
|
|
+ */
|
|
|
|
|
+ private String buildReceiptXml(XpPrintReceiptReqVo.Content content) {
|
|
|
|
|
+ String line = "------------------------";
|
|
|
|
|
+ return "\n<CB>" + content.getCompanyName()
|
|
|
|
|
+ + "\n<CB>" + line
|
|
|
|
|
+ + "\n<L><N>客户名称:<BOLD>" + content.getCustomerName() + "</BOLD>"
|
|
|
|
|
+ + "\n<L><N>任务编号:<BOLD>" + content.getTaskNo() + "</BOLD>"
|
|
|
|
|
+ + "\n<L><N>接单时间:" + content.getAcceptTime()
|
|
|
|
|
+ + "\n<L><N>完成时间:" + content.getFinishTime()
|
|
|
|
|
+ + "\n<L><N>计重人:<BOLD>" + content.getWeigher() + "</BOLD>"
|
|
|
|
|
+ + "\n\n**************司机信息**************"
|
|
|
|
|
+ + "\n姓名:" + content.getDriverName()
|
|
|
|
|
+ + "\n手机号:" + content.getDriverMobile()
|
|
|
|
|
+ + "\n身份证:" + content.getDriverIdCard()
|
|
|
|
|
+ + "\n\n**************任务信息**************"
|
|
|
|
|
+ + "\n物料:" + content.getMaterialName()
|
|
|
|
|
+ + "\n规格:" + content.getMaterialSpec()
|
|
|
|
|
+ + "\n任务量:" + content.getTaskWeight()
|
|
|
|
|
+ + "\n皮重:<BOLD>" + content.getWeightSummary() + "</BOLD>"
|
|
|
|
|
+ + "\n\n**************车辆信息**************"
|
|
|
|
|
+ + "\n车牌号:" + content.getPlateNo()
|
|
|
|
|
+ + "\n车辆轴数: " + content.getVehicleAxleDesc()
|
|
|
|
|
+ + "\n\n**************目的地**************"
|
|
|
|
|
+ + "\n目的地:" + content.getDestination()
|
|
|
|
|
+ + "\n\n**************打印信息**************"
|
|
|
|
|
+ + "\n<L><N>打印时间:" + content.getPrintTime()
|
|
|
|
|
+ + "\n<L><N>打印次数:" + content.getPrintTimesDesc()
|
|
|
|
|
+ + "\n\n<C><BOLD>" + content.getCopyLabel() + "</BOLD>";
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 填充公共参数:user、timestamp、sign
|
|
|
|
|
+ */
|
|
|
|
|
+ private void fillCommonParams(PrintOrderRequest request) {
|
|
|
|
|
+ if (StringUtils.isAnyBlank(xpCloudProperties.getUser(), xpCloudProperties.getUserKey())) {
|
|
|
|
|
+ throw new IotException("芯烨配置不完整,请配置xp.dev.user和xp.dev.user-key");
|
|
|
|
|
+ }
|
|
|
|
|
+ String user = xpCloudProperties.getUser();
|
|
|
|
|
+ String timestamp = String.valueOf(Instant.now().getEpochSecond());
|
|
|
|
|
+ String sign = sha1Hex(user + xpCloudProperties.getUserKey() + timestamp);
|
|
|
|
|
+ request.setUser(user);
|
|
|
|
|
+ request.setTimestamp(timestamp);
|
|
|
|
|
+ request.setSign(sign);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 计算SHA1(小写16进制)
|
|
|
|
|
+ */
|
|
|
|
|
+ private String sha1Hex(String source) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ MessageDigest messageDigest = MessageDigest.getInstance("SHA-1");
|
|
|
|
|
+ byte[] digestBytes = messageDigest.digest(source.getBytes(StandardCharsets.UTF_8));
|
|
|
|
|
+ StringBuilder hex = new StringBuilder(digestBytes.length * 2);
|
|
|
|
|
+ for (byte digestByte : digestBytes) {
|
|
|
|
|
+ hex.append(String.format("%02x", digestByte));
|
|
|
|
|
+ }
|
|
|
|
|
+ return hex.toString();
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ throw new IotException("SHA1计算失败:" + e.getMessage());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|