feat(export): 添加导出标签图片ZIP功能并优化标签样式

- 在库存物料条码打印接口中新增导出物料标签图片ZIP接口,支持批量生成PNG图片压缩包
- 新增HtmlToImageUtil工具类,使用wkhtmltoimage将HTML转换为PNG图片
- 在储位管理中新增导出标签ZIP接口,实现储位二维码批量导出功能
- 普通物料订单及生产订单相关控制器新增导出物料标签图片ZIP接口,支持订单物料标签图片批量下载
- 生产订单副产品管理新增导出物料标签图片ZIP接口,支持副产品标签导出为ZIP
- 优化二维码标签HTML模板(dp-1.html、qitao.html、spitem.html),调整尺寸和样式以适配打印需求
- 公共DTO类DeliverNormalOrderItemDTO添加打印名称字段printLabel,标签中显示以改善展示信息
- 相关接口返回Content-Type设为application/zip,支持ZIP文件响应UI下载体验
This commit is contained in:
曹鹏飞 2025-12-15 11:50:44 +08:00
parent 81b9f5c7bb
commit 2c9c0db974
15 changed files with 667 additions and 120 deletions

View File

@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.nflg.wms.admin.util.HtmlToImageUtil;
import com.nflg.wms.admin.util.PdfGeneratorUtil;
import com.nflg.wms.admin.util.QRCodeUtil;
import com.nflg.wms.admin.util.ThymeleafUtil;
@ -34,7 +35,9 @@ import jakarta.validation.constraints.NotNull;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
@ -52,6 +55,8 @@ import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
* 库存物料条码打印
@ -202,7 +207,7 @@ public class BarcodePrintingController extends BaseController {
@PostMapping("exportMaterialsPdf")
public void exportMaterials(HttpServletResponse response, @Valid @RequestBody @NotNull BarcodePrintingIdsQO request) throws Exception {
List<WmsInventoryBarcodePrinting> codelist = printingService.listByIds(request.getIds());
VUtil.trueThrowBusinessError(Objects.isNull(codelist)).throwMessage("订单不存在");
VUtil.trueThrowBusinessError(Objects.isNull(codelist)).throwMessage("物料不存在");
List<DeliverNormalOrderItemDTO> datas = new ArrayList<>();
// Integer i = 1;
for (WmsInventoryBarcodePrinting item : codelist) {
@ -223,7 +228,7 @@ public class BarcodePrintingController extends BaseController {
dto.setRowNo("");
dto.setPrintNo(IdUtil.getSnowflakeNextIdStr());
dto.setPrintNum("1");
String qCode = QRCodeUtil.generateQRCodeBase64(generateQRContent(dto, serialNumber), 100, 100);
String qCode = QRCodeUtil.generateQRCodeBase64(generateQRContent(dto, serialNumber), 100, 100);
dto.setQrCode(qCode);
datas.add(dto);
//i += 1;
@ -254,13 +259,89 @@ public class BarcodePrintingController extends BaseController {
Map<String, Object> variables = new HashMap<>();
variables.put("list", datas);
if (Objects.equals(request.getType(), 1)) {
String html = ThymeleafUtil.generator("/template/qrcode/", "Inv-1", ".html", variables);
String html = ThymeleafUtil.generator("/template/qrcode/", "dp-1", ".html", variables);
URL baseUrl = new ClassPathResource("template/qrcode/").getURL();
PdfGeneratorUtil.generatePdf("库存物料条码(逐个)", html, baseUrl.toString(), response);
} else {
String html = ThymeleafUtil.generator("/template/qrcode/", "Inv-2", ".html", variables);
String html = ThymeleafUtil.generator("/template/qrcode/", "dp-2", ".html", variables);
URL baseUrl = new ClassPathResource("template/qrcode/").getURL();
PdfGeneratorUtil.generatePdf("库存物料条码(整张)", html, baseUrl.toString(), response);
}
}
/**
* 导出物料标签图片ZIP
* @param ids id列表
*/
@PostMapping(value = "exportItemImageZip", produces = "application/zip")
public ResponseEntity<byte[]> exportItemImageZip(@RequestBody @NotEmpty List<Long> ids) throws Exception {
List<WmsInventoryBarcodePrinting> codelist = printingService.listByIds(ids);
VUtil.trueThrowBusinessError(Objects.isNull(codelist)).throwMessage("物料不存在");
List<DeliverNormalOrderItemDTO> datas = new ArrayList<>();
// Integer i = 1;
for (WmsInventoryBarcodePrinting item : codelist) {
if (StrUtil.isNotBlank(item.getSerialNumbers())) {
List<String> serialNumbers = StrUtil.split(item.getSerialNumbers(), ",");
for (String serialNumber : serialNumbers) {
DeliverNormalOrderItemDTO dto = new DeliverNormalOrderItemDTO();
dto.setMaterialNo(item.getMaterialNo());
dto.setMaterialDesc(item.getMaterialDes());
dto.setBatchNo(StrUtil.isBlank(item.getBatchNumber()) ? "" : item.getBatchNumber());
dto.setExternalOrderNo("");
dto.setRowNo("");
dto = new DeliverNormalOrderItemDTO();
dto.setMaterialNo(item.getMaterialNo());
dto.setMaterialDesc(item.getMaterialDes());
dto.setBatchNo(StrUtil.isBlank(item.getBatchNumber()) ? "" : item.getBatchNumber());
dto.setExternalOrderNo("");
dto.setRowNo("");
dto.setPrintNo(IdUtil.getSnowflakeNextIdStr());
dto.setPrintNum("1");
String qCode = QRCodeUtil.generateQRCodeBase64(generateQRContent(dto, serialNumber), 100, 100);
dto.setQrCode(qCode);
datas.add(dto);
//i += 1;
}
} else {
int codeNum = item.getQty().divide(item.getPackingNum(), 0, RoundingMode.UP).intValue();
for (int j = 0; j < codeNum; j++) {
DeliverNormalOrderItemDTO dto = new DeliverNormalOrderItemDTO();
dto.setMaterialNo(item.getMaterialNo());
dto.setMaterialDesc(item.getMaterialDes());
dto.setBatchNo(StrUtil.isBlank(item.getBatchNumber()) ? "" : item.getBatchNumber());
dto.setExternalOrderNo("");
dto.setRowNo("");
dto = new DeliverNormalOrderItemDTO();
dto.setMaterialNo(item.getMaterialNo());
dto.setMaterialDesc(item.getMaterialDes());
dto.setBatchNo(StrUtil.isBlank(item.getBatchNumber()) ? "" : item.getBatchNumber());
dto.setExternalOrderNo("");
dto.setRowNo("");
dto.setPrintNo(IdUtil.getSnowflakeNextIdStr());
dto.setPrintNum(item.getPackingNum().toString());
String qCode = QRCodeUtil.generateQRCodeBase64(generateQRContent(dto, ""), 100, 100);
dto.setQrCode(qCode);
datas.add(dto);
}
}
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (ZipOutputStream zos = new ZipOutputStream(baos)) {
for (DeliverNormalOrderItemDTO it : datas) {
Map<String, Object> variables = new HashMap<>();
variables.put("list", datas);
String html = ThymeleafUtil.generator("/template/qrcode/", "dp-1", ".html", variables);
ZipEntry entry = new ZipEntry(it.getPrintNo() + ".png");
zos.putNextEntry(entry);
byte[] imageBytes = HtmlToImageUtil.convertToPng(html, 60);
zos.write(imageBytes, 0, imageBytes.length);
zos.closeEntry();
}
}
byte[] zipBytes = baos.toByteArray();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.valueOf("application/zip"));
headers.setContentLength(zipBytes.length);
return new ResponseEntity<>(zipBytes, headers, HttpStatus.OK);
}
}

View File

@ -15,6 +15,7 @@ import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
@ -115,6 +116,15 @@ public class BinController extends BaseController {
binControllerService.exportPdf(response, ids);
}
/**
* 导出标签ZIP
* @param ids 储位id列表
*/
@PostMapping("exportZip")
public ResponseEntity<byte[]> exportZip(@Valid @RequestBody @NotEmpty List<Long> ids) throws Exception {
return binControllerService.exportZip(ids);
}
/**
* 获取库存信息
* @param warehouseId 仓库id

View File

@ -10,10 +10,7 @@ import com.nflg.wms.admin.repository.InMaterialScanRecordRespository;
import com.nflg.wms.admin.service.BasdeSerialNumberControllerService;
import com.nflg.wms.admin.service.BinService;
import com.nflg.wms.admin.service.SapService;
import com.nflg.wms.admin.util.NoUtil;
import com.nflg.wms.admin.util.PdfGeneratorUtil;
import com.nflg.wms.admin.util.QRCodeUtil;
import com.nflg.wms.admin.util.ThymeleafUtil;
import com.nflg.wms.admin.util.*;
import com.nflg.wms.common.constant.Constant;
import com.nflg.wms.common.pojo.ApiResult;
import com.nflg.wms.common.pojo.PageData;
@ -35,15 +32,22 @@ import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import java.io.ByteArrayOutputStream;
import java.math.BigDecimal;
import java.net.URL;
import java.time.Instant;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
* 生产订单入库管理
@ -242,6 +246,65 @@ public class InProduceOrderController extends BaseController {
}
}
/**
* 导出物料标签图片ZIP
* @param id 订单ID
*/
@GetMapping(value = "exportItemImageZip", produces = "application/zip")
public ResponseEntity<byte[]> exportItemImageZip(@Valid @RequestParam @NotNull Long id) throws Exception {
WmsInProduceOrder order = produceOrderService.getById(id);
VUtil.trueThrowBusinessError(Objects.isNull(order)).throwMessage("订单不存在");
List<WmsInProduceOrderItem> list = produceOrderItemService.getByOrderId(id);
if (order.getList()) {
list.removeIf(item -> Objects.equals(item.getParentId(), 0L));
}
List<DeliverNormalOrderItemDTO> datas = new ArrayList<>();
for (WmsInProduceOrderItem item : list) {
BigDecimal[] result = item.getNum().divideAndRemainder(BigDecimal.ONE);
for (int i = 0, count = result[0].intValue(); i < count; i++) {
DeliverNormalOrderItemDTO dto = new DeliverNormalOrderItemDTO();
dto.setMaterialNo(item.getMaterialNo());
dto.setMaterialDesc(item.getMaterialDesc());
dto.setExternalOrderNo(order.getOrderNo());
dto.setRowNo("");
dto.setIndex(i);
dto.setPrintNo(IdUtil.getSnowflakeNextIdStr());
dto.setPrintLabel("自制件");
if (i == count - 1 && result[1].compareTo(BigDecimal.ZERO) > 0) {
dto.setPrintNum(DF.format(result[1]));
} else {
dto.setPrintNum(DF.format(BigDecimal.ONE));
}
dto.setSupplierCode("");
dto.setBatchNo(item.getBatchNo());
dto.setQrCode(QRCodeUtil.generateQRCodeBase64(generateQRContent(dto, ""), 100, 100));
datas.add(dto);
}
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (ZipOutputStream zos = new ZipOutputStream(baos)) {
for (DeliverNormalOrderItemDTO it : datas) {
Map<String, Object> variables = new HashMap<>();
variables.put("list", datas);
String html = ThymeleafUtil.generator("/template/qrcode/", "dp-1", ".html", variables);
// HtmlToImageUtil.convertToPng(html, 800);
// response.setContentType("image/png");
// response.getOutputStream().write(HtmlToImageUtil.convertToPng(html, 60));
// break;
ZipEntry entry = new ZipEntry(it.getPrintNo() + ".png");
zos.putNextEntry(entry);
byte[] imageBytes = HtmlToImageUtil.convertToPng(html, 60);
zos.write(imageBytes, 0, imageBytes.length);
zos.closeEntry();
}
}
byte[] zipBytes = baos.toByteArray();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.valueOf("application/zip"));
headers.setContentLength(zipBytes.length);
return new ResponseEntity<>(zipBytes, headers, HttpStatus.OK);
}
/**
* 导出报工单PDF单个
* @param id 订单id

View File

@ -10,10 +10,7 @@ import com.nflg.wms.admin.pojo.dto.PdfPageDTO;
import com.nflg.wms.admin.repository.InMaterialScanRecordRespository;
import com.nflg.wms.admin.service.BasdeSerialNumberControllerService;
import com.nflg.wms.admin.service.SapService;
import com.nflg.wms.admin.util.NoUtil;
import com.nflg.wms.admin.util.PdfGeneratorUtil;
import com.nflg.wms.admin.util.QRCodeUtil;
import com.nflg.wms.admin.util.ThymeleafUtil;
import com.nflg.wms.admin.util.*;
import com.nflg.wms.common.pojo.ApiResult;
import com.nflg.wms.common.pojo.PageData;
import com.nflg.wms.common.pojo.document.InMaterialScanRecord;
@ -37,15 +34,22 @@ import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import java.io.ByteArrayOutputStream;
import java.math.BigDecimal;
import java.net.URL;
import java.time.Instant;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
* 生产订单副产品(拆解)管理
@ -371,6 +375,62 @@ public class InProduceOrderSurplusController extends BaseController {
}
}
/**
* 导出物料标签图片ZIP
* @param id 订单ID
*/
@GetMapping(value = "exportItemImageZip", produces = "application/zip")
public ResponseEntity<byte[]> exportItemImageZip(@Valid @RequestParam @NotNull Long id) throws Exception {
WmsInProduceOrderSurplus order = inProduceOrderSurplusService.getById(id);
VUtil.trueThrowBusinessError(Objects.isNull(order)).throwMessage("订单不存在");
List<WmsInProduceOrderSurplusItem> list = inProduceOrderSurplusItemService.getList(id);
List<DeliverNormalOrderItemDTO> datas = new ArrayList<>();
for (WmsInProduceOrderSurplusItem item : list) {
BigDecimal[] result = item.getNum().divideAndRemainder(BigDecimal.ONE);
for (int i = 0, count = result[0].intValue(); i < count; i++) {
DeliverNormalOrderItemDTO dto = new DeliverNormalOrderItemDTO();
dto.setMaterialNo(item.getMatnr());
dto.setMaterialDesc(item.getMaktx2());
dto.setExternalOrderNo(order.getAufnr());
dto.setRowNo("");
dto.setIndex(i);
dto.setPrintNo(IdUtil.getSnowflakeNextIdStr());
dto.setPrintLabel("自制件");
if (i == count - 1 && result[1].compareTo(BigDecimal.ZERO) > 0) {
dto.setPrintNum(DF.format(result[1]));
} else {
dto.setPrintNum(DF.format(BigDecimal.ONE));
}
dto.setSupplierCode("");
dto.setBatchNo("");
dto.setQrCode(QRCodeUtil.generateQRCodeBase64(generateQRContent(dto, ""), 100, 100));
datas.add(dto);
}
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (ZipOutputStream zos = new ZipOutputStream(baos)) {
for (DeliverNormalOrderItemDTO it : datas) {
Map<String, Object> variables = new HashMap<>();
variables.put("list", datas);
String html = ThymeleafUtil.generator("/template/qrcode/", "dp-1", ".html", variables);
// HtmlToImageUtil.convertToPng(html, 800);
// response.setContentType("image/png");
// response.getOutputStream().write(HtmlToImageUtil.convertToPng(html, 60));
// break;
ZipEntry entry = new ZipEntry(it.getPrintNo() + ".png");
zos.putNextEntry(entry);
byte[] imageBytes = HtmlToImageUtil.convertToPng(html, 60);
zos.write(imageBytes, 0, imageBytes.length);
zos.closeEntry();
}
}
byte[] zipBytes = baos.toByteArray();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.valueOf("application/zip"));
headers.setContentLength(zipBytes.length);
return new ResponseEntity<>(zipBytes, headers, HttpStatus.OK);
}
/**
* 导出拆解单
*/

View File

@ -6,10 +6,7 @@ import cn.hutool.core.util.StrUtil;
import com.nflg.wms.admin.pojo.dto.SAPMaterialInfoInOrderDTO;
import com.nflg.wms.admin.service.BasdeSerialNumberControllerService;
import com.nflg.wms.admin.service.SapService;
import com.nflg.wms.admin.util.NoUtil;
import com.nflg.wms.admin.util.PdfGeneratorUtil;
import com.nflg.wms.admin.util.QRCodeUtil;
import com.nflg.wms.admin.util.ThymeleafUtil;
import com.nflg.wms.admin.util.*;
import com.nflg.wms.common.pojo.ApiResult;
import com.nflg.wms.common.pojo.PageData;
import com.nflg.wms.common.pojo.dto.DeliverNormalOrderItemDTO;
@ -36,14 +33,21 @@ import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import java.io.ByteArrayOutputStream;
import java.math.BigDecimal;
import java.net.URL;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
* 普通物料订单管理
@ -181,6 +185,7 @@ public class NormalOrderController extends BaseController {
DeliverNormalOrderItemDTO dto = Convert.convert(DeliverNormalOrderItemDTO.class, order);
dto.setIndex(i);
dto.setPrintNo(order.getId() + "-" + i);
dto.setPrintLabel(dto.getPrintNo());
if (i == order.getLableNum() - 1) {
BigDecimal n = order.getBatchNum().divideAndRemainder(order.getMinPackageNum())[1];
if (n.compareTo(BigDecimal.ZERO) == 0) {
@ -270,6 +275,7 @@ public class NormalOrderController extends BaseController {
dto.setBatchNo(NoUtil.getBatchNo(supplierNo));
dto.setIndex(i);
dto.setPrintNo(order.getId() + "-" + i);
dto.setPrintLabel(dto.getPrintNo());
if (i == order.getLableNum() - 1) {
BigDecimal n = order.getBatchNum().divideAndRemainder(order.getMinPackageNum())[1];
if (n.compareTo(BigDecimal.ZERO) == 0) {
@ -303,4 +309,48 @@ public class NormalOrderController extends BaseController {
URL baseUrl = new ClassPathResource("template/qrcode/").getURL();
PdfGeneratorUtil.generatePdf("普通物料条码(整张)", html, baseUrl.toString(), response);
}
/**
* 导出采购单物料图片ZIP
* @param ids 要打印的id列表
*/
@PostMapping(value = "exportOrderItemImageZip", produces = "application/zip")
public ResponseEntity<byte[]> exportOrderItemImageZip(@Valid @RequestBody @NotNull List<Long> ids) throws Exception {
List<DeliverNormalOrderVO> orders = deliverNormalOrderService.getList(ids);
VUtil.trueThrowBusinessError(CollectionUtil.isEmpty(orders)).throwMessage("没有需要打印的数据");
return exportItemImageZip(convert(orders));
}
/**
* 导出打印送货单物料图片ZIP
* @param datas 要打印的数据
*/
@PostMapping(value = "deliver/exportOrderItemImageZip", produces = "application/zip")
public void exportDeliverOrderPdfPerPage(@Valid @RequestBody @NotEmpty List<DeliverNormalOrderSaveItemQO> datas) throws Exception {
exportItemImageZip(convert1(datas.get(0).getSupplierNo(), datas));
}
/**
* 导出标签图片ZIP
*/
private ResponseEntity<byte[]> exportItemImageZip(List<DeliverNormalOrderItemDTO> list) throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (ZipOutputStream zos = new ZipOutputStream(baos)) {
for (DeliverNormalOrderItemDTO it : list) {
Map<String, Object> variables = new HashMap<>();
variables.put("list", List.of(it));
String html = ThymeleafUtil.generator("/template/qrcode/", "dp-1", ".html", variables);
ZipEntry entry = new ZipEntry(it.getPrintNo() + ".png");
zos.putNextEntry(entry);
byte[] imageBytes = HtmlToImageUtil.convertToPng(html, 60);
zos.write(imageBytes, 0, imageBytes.length);
zos.closeEntry();
}
}
byte[] zipBytes = baos.toByteArray();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.valueOf("application/zip"));
headers.setContentLength(zipBytes.length);
return new ResponseEntity<>(zipBytes, headers, HttpStatus.OK);
}
}

View File

@ -22,10 +22,7 @@ import com.nflg.wms.admin.service.BasdeSerialNumberControllerService;
import com.nflg.wms.admin.service.BinService;
import com.nflg.wms.admin.service.SapService;
import com.nflg.wms.admin.service.StructuralPackageControllerService;
import com.nflg.wms.admin.util.NoUtil;
import com.nflg.wms.admin.util.PdfGeneratorUtil;
import com.nflg.wms.admin.util.QRCodeUtil;
import com.nflg.wms.admin.util.ThymeleafUtil;
import com.nflg.wms.admin.util.*;
import com.nflg.wms.common.constant.OrderState;
import com.nflg.wms.common.constant.STATE;
import com.nflg.wms.common.exception.NflgException;
@ -51,7 +48,9 @@ import jakarta.validation.constraints.NotNull;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
@ -71,6 +70,8 @@ import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
* 钢构件订单管理
@ -456,13 +457,14 @@ public class StructuralPackageOrderController extends BaseController {
for (DeliverStructuralPackageOrderTrayItemVO it : list) {
for (int i = 0, count = it.getShipmentNum().intValue(); i < count; i++) {
DeliverStructuralPackageOrderTrayItemVO vo = BeanUtil.copy(it, DeliverStructuralPackageOrderTrayItemVO.class);
vo.setQrCodeId(it.getId() + "-" + (i + 1));
vo.setQrCode(it.getId() + "-" + (i + 1) + "^" + it.getMaterialNo() + "_" + it.getTrayNo() + "_1");
vo.setQrCodeImage(QRCodeUtil.generateQRCodeBase64(vo.getQrCode(), 200, 200));
datas.add(vo);
}
if (it.getShipmentNum().remainder(BigDecimal.ONE).compareTo(BigDecimal.ZERO) > 0) {
DeliverStructuralPackageOrderTrayItemVO vo = BeanUtil.copy(it, DeliverStructuralPackageOrderTrayItemVO.class);
vo.setQrCodeId(it.getId() + "-" + (it.getShipmentNum().intValue() + 1));
vo.setQrCode(it.getId() + "-" + (it.getShipmentNum().intValue() + 1) + "^" + it.getMaterialNo() + "_" + it.getTrayNo() + "_" + it.getShipmentNum().remainder(BigDecimal.ONE));
vo.setQrCodeImage(QRCodeUtil.generateQRCodeBase64(vo.getQrCode(), 200, 200));
datas.add(vo);
@ -476,6 +478,59 @@ public class StructuralPackageOrderController extends BaseController {
PdfGeneratorUtil.generatePdf(trayVO.getExternalOrderNo() + "-" + trayVO.getWorkbenchCode() + "标签", html, baseUrl.toString(), response);
}
/**
* 导出零件标签图片ZIP
* @param id 托盘id
*/
@GetMapping(value = "exportItemImageZip", produces = "application/zip")
public ResponseEntity<byte[]> exportItemImageZip(HttpServletResponse response, @Valid @RequestParam @NotNull Long id) throws Exception {
DeliverStructuralPackageOrderExtendVO trayVO = deliverStructuralPackageOrderTrayService.getInfo(id);
VUtil.trueThrowBusinessError(Objects.isNull(trayVO)).throwMessage("数据不存在");
List<DeliverStructuralPackageOrderTrayItemVO> list = deliverStructuralPackageOrderTrayItemService.getListVOByTrayId(id);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (ZipOutputStream zos = new ZipOutputStream(baos)) {
List<DeliverStructuralPackageOrderTrayItemVO> datas = new ArrayList<>();
int index = 0;
for (DeliverStructuralPackageOrderTrayItemVO it : list) {
datas.clear();
index++;
for (int i = 0, count = it.getShipmentNum().intValue(); i < count; i++) {
DeliverStructuralPackageOrderTrayItemVO vo = BeanUtil.copy(it, DeliverStructuralPackageOrderTrayItemVO.class);
vo.setQrCodeId(it.getId() + "-" + (i + 1));
vo.setQrCode(it.getId() + "-" + (i + 1) + "^" + it.getMaterialNo() + "_" + it.getTrayNo() + "_1");
vo.setQrCodeImage(QRCodeUtil.generateQRCodeBase64(vo.getQrCode(), 200, 200));
datas.add(vo);
}
if (it.getShipmentNum().remainder(BigDecimal.ONE).compareTo(BigDecimal.ZERO) > 0) {
DeliverStructuralPackageOrderTrayItemVO vo = BeanUtil.copy(it, DeliverStructuralPackageOrderTrayItemVO.class);
vo.setQrCodeId(it.getId() + "-" + (it.getShipmentNum().intValue() + 1));
vo.setQrCode(it.getId() + "-" + (it.getShipmentNum().intValue() + 1) + "^" + it.getMaterialNo() + "_" + it.getTrayNo() + "_" + it.getShipmentNum().remainder(BigDecimal.ONE));
vo.setQrCodeImage(QRCodeUtil.generateQRCodeBase64(vo.getQrCode(), 200, 200));
datas.add(vo);
}
Map<String, Object> variables = new HashMap<>();
variables.put("list", datas);
variables.put("info", trayVO);
variables.put("index", index);
String html = ThymeleafUtil.generator("/template/qrcode/", "spitem", ".html", variables);
// HtmlToImageUtil.convertToPng(html, 800);
// response.setContentType("image/png");
// response.getOutputStream().write(HtmlToImageUtil.convertToPng(html, 60));
// break;
ZipEntry entry = new ZipEntry(it.getId() + ".png");
zos.putNextEntry(entry);
byte[] imageBytes = HtmlToImageUtil.convertToPng(html, 60);
zos.write(imageBytes, 0, imageBytes.length);
zos.closeEntry();
}
}
byte[] zipBytes = baos.toByteArray();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.valueOf("application/zip"));
headers.setContentLength(zipBytes.length);
return new ResponseEntity<>(zipBytes, headers, HttpStatus.OK);
}
/**
* 导出托盘标签PDF
* @param id 托盘id
@ -492,6 +547,25 @@ public class StructuralPackageOrderController extends BaseController {
PdfGeneratorUtil.generatePdf("托盘标签" + trayVO.getTrayNo(), html, baseUrl.toString(), response);
}
/**
* 导出托盘标签图片
* @param id 托盘id
*/
@GetMapping(value = "exportTrayImage", produces = MediaType.IMAGE_PNG_VALUE)
public ResponseEntity<byte[]> exportTrayImage(@Valid @RequestParam @NotNull Long id) throws Exception {
DeliverStructuralPackageOrderExtendVO trayVO = deliverStructuralPackageOrderTrayService.getInfo(id);
VUtil.trueThrowBusinessError(Objects.isNull(trayVO)).throwMessage("数据不存在");
trayVO.setQrCode(QRCodeUtil.generateQRCodeBase64(trayVO.getTrayNo(), 100, 100));
Map<String, Object> variables = new HashMap<>();
variables.put("info", trayVO);
String html = ThymeleafUtil.generator("/template/qrcode/", "tray", ".html", variables);
byte[] imageBytes = HtmlToImageUtil.convertToPng(html, 60);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.IMAGE_PNG);
headers.setContentLength(imageBytes.length);
return new ResponseEntity<>(imageBytes, headers, HttpStatus.OK);
}
/**
* 导出齐套标签PDF
* @param id 托盘id
@ -510,6 +584,27 @@ public class StructuralPackageOrderController extends BaseController {
PdfGeneratorUtil.generatePdf("齐套标签" + trayVO.getTrayNo(), html, baseUrl.toString(), response);
}
/**
* 导出齐套标签图片
* @param id 托盘id
*/
@GetMapping(value = "exportQiTaoImage", produces = MediaType.IMAGE_PNG_VALUE)
public ResponseEntity<byte[]> exportQiTaoImage(@Valid @RequestParam @NotNull Long id) throws Exception {
DeliverStructuralPackageOrderExtendVO trayVO = deliverStructuralPackageOrderTrayService.getInfo(id);
VUtil.trueThrowBusinessError(Objects.isNull(trayVO)).throwMessage("数据不存在");
String temp = trayVO.getExternalOrderNo() + "$" + trayVO.getRowNo() + "$" + trayVO.getPackageNo();
String uniqueCode = DigestUtil.md5Hex(temp);
trayVO.setQrCode(QRCodeUtil.generateQRCodeBase64(uniqueCode + "$" + temp, 100, 100));
Map<String, Object> variables = new HashMap<>();
variables.put("info", trayVO);
String html = ThymeleafUtil.generator("/template/qrcode/", "qitao", ".html", variables);
byte[] imageBytes = HtmlToImageUtil.convertToPng(html, 60);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.IMAGE_PNG);
headers.setContentLength(imageBytes.length);
return new ResponseEntity<>(imageBytes, headers, HttpStatus.OK);
}
/**
* 根据托盘号获取托盘信息PDA使用
*/
@ -1054,10 +1149,6 @@ public class StructuralPackageOrderController extends BaseController {
} else if (!DateTimeUtil.isValidDate(expectDeliveryDate)) {
sb.append("期望交期无效;");
}
String rowNo = StrUtil.trim(data.get("行项目*").toString());
if (StrUtil.isBlank(rowNo)) {
sb.append("行项目不能为空;");
}
String snum = StrUtil.trim(data.get("数量*").toString());
BigDecimal num = null;
if (StrUtil.isBlank(snum)) {
@ -1071,6 +1162,7 @@ public class StructuralPackageOrderController extends BaseController {
}
}
String poNum = StrUtil.trim(data.get("采购订单号*").toString());
String rowNo = StrUtil.trim(data.get("行项目*").toString());
BigDecimal transportNum = num;
if (StrUtil.isBlank(poNum)) {
sb.append("采购订单号不能为空;");
@ -1081,6 +1173,9 @@ public class StructuralPackageOrderController extends BaseController {
if (CollectionUtil.isEmpty(orders)) {
sb.append("采购订单号无效;");
} else {
if (StrUtil.isBlank(rowNo)) {
sb.append("行项目不能为空;");
}
SAPMaterialInfoInOrderDTO order = orders.stream()
.filter(it -> StrUtil.equals(it.getEbelp(), rowNo))
.findFirst()

View File

@ -5,6 +5,7 @@ import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.nflg.wms.admin.util.HtmlToImageUtil;
import com.nflg.wms.admin.util.PdfGeneratorUtil;
import com.nflg.wms.admin.util.QRCodeUtil;
import com.nflg.wms.admin.util.ThymeleafUtil;
@ -36,8 +37,11 @@ import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
@ -53,7 +57,10 @@ import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
@Slf4j
@Component
public class BinControllerService {
@ -102,14 +109,14 @@ public class BinControllerService {
if (updateCheckAndImport(data)) {
return ApiResult.success();
} else {
try(ByteArrayOutputStream osOut = new ByteArrayOutputStream()) {
try (ByteArrayOutputStream osOut = new ByteArrayOutputStream()) {
new Workbook()
.addSheet(new ListSheet<>(data))
.writeTo(osOut);
try(ByteArrayInputStream isIn = new ByteArrayInputStream(osOut.toByteArray())) {
try (ByteArrayInputStream isIn = new ByteArrayInputStream(osOut.toByteArray())) {
return ApiResult.error(STATE.DataNoCheckPass, "导入文件失败", fileUploadService.upload("temp/" + DateTimeUtil.format(LocalDate.now(), "yyyyMMdd") + "/" + IdUtil.fastUUID() + ".xlsx", isIn, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"));
}
}catch (Exception e){
} catch (Exception e) {
return ApiResult.error(STATE.BusinessError, "保存文件出错");
}
}
@ -155,9 +162,9 @@ public class BinControllerService {
bin.setUpdateTime(LocalDateTime.now());
}
}
if (StrUtil.isBlank(dto.getName())){
if (StrUtil.isBlank(dto.getName())) {
sb.append("仓库名称不能为空;");
}else {
} else {
bin.setName(dto.getName());
}
bin.setRemark(dto.getRemark());
@ -206,8 +213,10 @@ public class BinControllerService {
List<WmsBin> bins = wmsBinService.listByIds(ids);
Map<String, Object> variables = new HashMap<>();
variables.put("datas", bins.stream().map(bin -> new QRCodeDTO()
.setNo(bin.getNo())
.setQrCode(QRCodeUtil.generateQRCodeBase64(bin.getNo(), 100, 100))));
.setNo(bin.getNo())
.setQrCode(QRCodeUtil.generateQRCodeBase64(bin.getNo(), 100, 100))
).toList()
);
String html = ThymeleafUtil.generator("/template/", "储位二维码", ".html", variables);
PdfGeneratorUtil.generatePdf("储位二维码", html, response);
}
@ -215,4 +224,30 @@ public class BinControllerService {
public List<BinInventoryVO> getInventory(Long warehouseId) {
return wmsBinService.getInventory(warehouseId);
}
public ResponseEntity<byte[]> exportZip(@Valid @NotEmpty List<Long> ids) throws Exception {
List<WmsBin> bins = wmsBinService.listByIds(ids);
List<QRCodeDTO> datas = bins.stream().map(bin -> new QRCodeDTO()
.setNo(bin.getNo())
.setQrCode(QRCodeUtil.generateQRCodeBase64(bin.getNo(), 100, 100)))
.toList();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (ZipOutputStream zos = new ZipOutputStream(baos)) {
for (QRCodeDTO it : datas) {
Map<String, Object> variables = new HashMap<>();
variables.put("datas", List.of(it));
String html = ThymeleafUtil.generator("/template/", "储位二维码", ".html", variables);
ZipEntry entry = new ZipEntry(it.getNo() + ".png");
zos.putNextEntry(entry);
byte[] imageBytes = HtmlToImageUtil.convertToPng(html, 40);
zos.write(imageBytes, 0, imageBytes.length);
zos.closeEntry();
}
}
byte[] zipBytes = baos.toByteArray();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.valueOf("application/zip"));
headers.setContentLength(zipBytes.length);
return new ResponseEntity<>(zipBytes, headers, HttpStatus.OK);
}
}

View File

@ -0,0 +1,68 @@
package com.nflg.wms.admin.util;
import cn.hutool.core.io.FileUtil;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@Slf4j
public class HtmlToImageUtil {
/**
* 将HTML内容转换为PNG图片
* @param htmlContent HTML内容
* @param width 图片宽度单位mm
* @return PNG图片字节数组
* @throws Exception 转换异常
*/
public static byte[] convertToPng(String htmlContent, int width) throws Exception {
Path inputHtmlPath = null, outputImgPath = null;
try {
Path tempDir = Paths.get(System.getProperty("java.io.tmpdir"), "wkhtml");
if (!Files.exists(tempDir)) {
Files.createDirectories(tempDir);
}
long t = System.currentTimeMillis();
inputHtmlPath = tempDir.resolve("input_" + t + ".html");
outputImgPath = tempDir.resolve("output_" + t + ".png");
Files.write(inputHtmlPath, htmlContent.getBytes());
List<String> command = new ArrayList<>();
command.add("wkhtmltoimage");
// 可选参数设置宽度 (例如 1200px)
command.add("--width");
command.add(String.valueOf((int) (width * 3.78)));
// 可选参数指定图片类型 (例如 PNG)
command.add("--format");
command.add("png");
//质量
command.add("--quality");
command.add("100");
// 输入文件路径
command.add(inputHtmlPath.toAbsolutePath().toString());
// 输出文件路径
command.add(outputImgPath.toAbsolutePath().toString());
ProcessBuilder builder = new ProcessBuilder(command);
Process process = builder.start();
int exitCode = process.waitFor();
if (exitCode != 0) {
// 读取错误流帮助调试
String error = new String(process.getErrorStream().readAllBytes());
throw new IOException("html转换图片失败退出码: " + exitCode + ", 错误信息: " + error);
}
return FileUtil.readBytes(outputImgPath);
} finally {
if (Objects.nonNull(inputHtmlPath)) {
Files.deleteIfExists(inputHtmlPath);
}
if (Objects.nonNull(outputImgPath)) {
Files.deleteIfExists(outputImgPath);
}
}
}
}

View File

@ -6,22 +6,19 @@
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
<style>
@page {
size: A4;
margin: 5mm; /* 关键!清除默认页边距 */
}
@media print {
body {
font-size: 9pt;
}
size: 60mm 40mm;
margin: 0;
}
body {
width: 58mm;
height: 38mm;
font-size: 8pt;
font-family: SimSun, Arial, sans-serif;
font-size: 9pt;
margin: 0;
padding: 0;
}
table {
margin: 3px;
border: 1px solid #000;
border-collapse: collapse;
}
table, th, td {
@ -35,25 +32,32 @@
}
.div-with-border {
border-bottom: 1px solid #000;
padding: 5px;
width: 200px;
padding: 1mm;
width: 37mm;
text-align: left;
}
.qrcode {
width: 18mm;
height: 18mm;
margin-top: 2mm;
margin-bottom: 2mm;
}
</style>
</head>
<body>
<table th:each="item, iterStat : ${list}" th:style="${iterStat.index == 0} ? 'page-break-before: auto;' : 'page-break-before: always;'">
<tr>
<td style="width: 150px;text-align: center;padding: 5px;">
<img height="120" th:src="${item.qrCode}" width="120"/>
<div th:text="${item.printNo}">20250227100950-0</div>
<td style="width: 20mm;text-align: center;">
<img alt="" class="qrcode" th:src="${item.qrCode}"/>
<div th:text="${item.printLabel}">20250227100950-0</div>
</td>
<td style="width: 200px;text-align: left;vertical-align: top">
<div class="title div-with-border"><img alt="logo" height="20" src="../../img/logo2.png" style="margin-right: 5px;" /></div>
<td style="text-align: left;vertical-align: top">
<div class="title div-with-border"><img alt="logo" style="height: 5mm" src="../../img/logo2.png"/></div>
<div class="div-with-border">SAP编码: <span th:text="${item.materialNo}"></span></div>
<div class="div-with-border">名称: <span th:text="${item.materialDesc}"></span></div>
<div class="div-with-border" style="height: 8mm">名称: <span th:text="${item.materialDesc}"></span></div>
<div class="div-with-border">数量: <span th:text="${item.printNum}"></span></div>
<div style="padding: 5px;">批次号: <span th:text="${item.batchNo}"></span></div>
<div style="padding: 1mm;">批次号: <span th:text="${item.batchNo}"></span></div>
</td>
</tr>
</table>

View File

@ -5,44 +5,58 @@
<title>齐套标签</title>
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
<style>
@media print {
body {
font-size: 10pt;
}
@page {
size: 60mm 40mm;
margin: 0;
}
body {
width: 58mm;
height: 38mm;
font-size: 8pt;
font-family: SimSun, Arial, sans-serif;
margin: 0;
padding: 0;
font-size: 10pt;
padding-left: 1mm;
padding-top: 1mm;
line-height: 1.1;
font-weight: normal;
font-style: normal;
-webkit-print-color-adjust: exact;
print-color-adjust: exact;
}
table {
margin: 3px;
border-collapse: collapse;
border: 1px solid #000;
}
th, td {
border: 1px solid #000;
padding: 5px;
}
.qrcode {
width: 18mm;
height: 18mm;
margin-top: 2mm;
margin-bottom: 2mm;
}
</style>
</head>
<body>
<table>
<tr style="height: 50px;">
<tr style="height: 12mm;">
<td colspan="3" th:text="${info.packageDesc}">
左踏板连接架
</td>
</tr>
<tr>
<td rowspan="4" style="text-align: center;width: 100px;">
<img alt="" height="100" th:src="${info.qrCode}"/>
<td rowspan="4" style="text-align: center;">
<img class="qrcode" alt="" th:src="${info.qrCode}"/>
</td>
<td style="width: 70px;">
<td style="width: 13mm;">
采购单号:
</td>
<td style="width: 100px;" th:text="${info.externalOrderNo}">
<td style="width: 23mm;" th:text="${info.externalOrderNo}">
S2507090053
</td>
</tr>

View File

@ -4,44 +4,93 @@
<meta charset="UTF-8"/>
<title>钢构件物料标签</title>
<style>
@page {
size: 60mm 40mm;
margin: 0;
}
body {
font-size: 9pt;
width: 58mm;
height: 38mm;
font-size: 8pt;
font-family: SimSun, Arial, sans-serif;
margin: 0;
padding-left: 1mm;
padding-top: 1mm;
line-height: 1.1;
font-weight: normal;
font-style: normal;
-webkit-print-color-adjust: exact;
print-color-adjust: exact;
}
table, th, td {
border: 1px solid black;
table {
border-collapse: collapse;
padding: 5px;
text-align: left;
border: 1px solid #000;
}
tr td {
border: 1px solid #000;
}
.img {
width: 34mm;
}
.qrcode {
width: 18mm;
height: 18mm;
margin-top: 2mm;
margin-bottom: 2mm;
}
.name {
height: 8mm;
display: table-cell;
vertical-align: middle;
text-overflow: ellipsis;
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
</style>
</head>
<body>
<table th:each="item , iterStat: ${list}" th:style="${iterStat.index == 0} ? 'page-break-before: auto;' : 'page-break-before: always;'">
<tr>
<td colspan="4" th:text="|${item.materialDesc}(${info.supplierCode})|">833-33-07-NF左踏板连接架(0000101627)</td>
</tr>
<tr>
<td colspan="2" rowspan="3">
<img alt="" height="130" th:src="${item.qrCodeImage}" width="130"/>
</td>
<td colspan="2" th:text="${item.drawingNo}">833-33-07-NF</td>
</tr>
<tr>
<td style="width: 70px;"><span style="font-weight: bold">SAP编码:</span></td>
<td th:text="${item.materialNo}">2100080450</td>
</tr>
<tr>
<td colspan="2" rowspan="3">
<img alt="" height="100" th:src="${item.image}"/>
</td>
</tr>
<tr></tr>
<tr>
<td colspan="2" style="height: 20px;font-size: 6pt;" th:text="${item.qrCode}">77777</td>
</tr>
</table>
<div th:each="item , iterStat: ${list}"
th:style="${iterStat.index == 0} ? 'page-break-before: auto;' : 'page-break-before: always;'">
<div th:text="${index}">1</div>
<table>
<tr>
<td colspan="4">
<div th:text="|${item.materialDesc}(${info.supplierCode})|" class="name">
833-33-07-NF左踏板连接架(0000101627)833-33-07-NF左踏板连接架NF左踏板连接架NF左踏板连接架(0000101627)
</div>
</td>
</tr>
<tr>
<td colspan="2" rowspan="3" style="text-align: center">
<img th:src="${item.qrCodeImage}" class="qrcode"
src="https://img-s.msn.cn/tenant/amp/entityid/AA1RXD8a.img" alt=""/>
</td>
<td colspan="2" th:text="${item.drawingNo}">833-33-07-NF</td>
</tr>
<tr>
<td style="font-weight: bold;text-align: center;font-size: 7pt;width: 10mm">SAP编码</td>
<td th:text="${item.materialNo}" style="width: 20mm">2100080450</td>
</tr>
<tr>
<td colspan="2" rowspan="2" class="center">
<img th:src="${item.image}" class="img" src="https://img-s.msn.cn/tenant/amp/entityid/AA1RVn7C.img"
alt=""/>
</td>
</tr>
<tr>
<td colspan="2" style="font-size: 6pt;text-align: center;height: 2mm" th:text="${item.qrCodeId}">
1244565616465_1
</td>
</tr>
</table>
</div>
</body>
</html>

View File

@ -5,16 +5,18 @@
<title>托盘标签</title>
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
<style>
@media print {
body {
font-size: 10pt;
}
@page {
size: 60mm 40mm;
margin: 0;
}
body {
width: 58mm;
height: 38mm;
font-size: 8pt;
font-family: SimSun, Arial, sans-serif;
margin: 3px;
margin: 0;
padding: 0;
font-size: 10pt;
}
table {
border-collapse: collapse;
@ -23,25 +25,31 @@
th, td {
border: 1px solid #000;
padding: 5px;
}
.qrcode {
width: 18mm;
height: 18mm;
margin-top: 2mm;
margin-bottom: 2mm;
}
</style>
</head>
<body>
<table>
<tr style="height: 50px;">
<tr style="height: 12mm;">
<td colspan="3" th:text="${info.packageDesc}">
左踏板连接架
</td>
</tr>
<tr>
<td rowspan="3" style="text-align: center;width: 100px;">
<img alt="" height="100" th:src="${info.qrCode}"/>
<td rowspan="3" style="text-align: center;">
<img class="qrcode" alt="" th:src="${info.qrCode}"/>
</td>
<td style="width: 60px;">
<td style="width: 13mm;">
托盘号:
</td>
<td style="width: 100px;" th:text="${info.trayNo}">
<td style="width: 23mm;" th:text="${info.trayNo}">
S2507090053
</td>
</tr>

View File

@ -6,26 +6,23 @@
<title>二维码</title>
<style>
@page {
size: A4 landscape; /* 横向 A4 */
margin: 0; /* 页边距 */
}
body {
font-family: SimSun, serif;
font-size: 12px;
margin: 10px;
size: 40mm 60mm;
margin: 0;
}
.qrcode {
width: 100px;
text-align: center;
}
.qrcode img {
width: 100%;
margin-top: 1mm;
width: 35mm;
height: 35mm;
}
.container {
width: 38mm;
height: 58mm;
font-size: 10pt;
font-family: SimSun, serif;
margin: 0;
padding: 0;
page-break-after: always;
}
@ -36,8 +33,11 @@
</head>
<body>
<div class="container" th:each="item : ${datas}">
<div class="qrcode"><img alt="" th:src="${item.qrCode}" src="../img/qrcode.png"/>
<span th:text="${item.no}">ICO2156115651</span>
<div style="text-align: center">
<div>
<img class="qrcode" alt="" th:src="${item.qrCode}" src="../img/qrcode.png"/>
</div>
<div th:text="${item.no}">ICO2156115651</div>
</div>
</div>
</body>

View File

@ -104,6 +104,11 @@ public class DeliverNormalOrderItemDTO {
*/
private String printNo;
/**
* 打印名称
*/
private String printLabel;
/**
* 二维码base64
*/

View File

@ -114,4 +114,9 @@ public class DeliverStructuralPackageOrderTrayItemVO implements Serializable {
* 二维码内容
*/
private String qrCode;
/**
* 二维码id
*/
private String qrCodeId;
}