效果(這里金額為或者字段為空不顯示)
顯示
打印,不會有表格是分兩頁打印的,根據自己需要設置一頁打印多少個表格
根據后端數據生成多個表格
html部分
<div id="bodyPrintGz"> <div id="gzDiv"></div> </div>
js部分,雖然innerHTML也可以完成顯示,我一開始也是用innerHTML來做的,但是后面打印的時候,innerHTML沒有內容,所以改用了appendChild來生成表格
selectGz() { if ( this.ztId != "" && this.company != "" && this.gzlb != "" && this.yearAndMonth != "" ) { httpGet( `/xxxxx/gzdr/gzdy/?ztId=${this.ztId}&bmName=${this.company}&gzlb=${this.gzlb}&qj=${this.yearAndMonth}` ) .then(rst => { this.items = rst; var div = document.getElementById("gzDiv"); //先把舊數據刪除 while (div.hasChildNodes()) { //當div下還存在子節點時 循環繼續 div.removeChild(div.firstChild); } //新數據遍歷生成多個表格,每行最多16列 this.items.forEach(x => { //創建table元素 var table = document.createElement("table"); for (let i = 0; i < this.ceil(x.headers.length); i++) { //創建表頭tr元素 var tr1 = document.createElement("tr"); for ( let j = i * 16; j < (x.headers.length > 16 ? (i + 1) * 16 : x.headers.length); j++ ) { //創建td元素 var td1 = document.createElement("td"); if (x.headers[j]) { //創建內容 var textnode1 = document.createTextNode(x.headers[j].value); //把內容添加進單元格 td1.appendChild(textnode1); //設置單元格樣式 td1.setAttribute("style", "width:100px;font-size:12px;"); } //把單元格添加進tr元素里面 tr1.appendChild(td1); } //把表頭添加進table里面 table.appendChild(tr1); //創建數據tr元素 var tr2 = document.createElement("tr"); for ( let k = i * 16; k < (x.bodys.length > 16 ? (i + 1) * 16 : x.bodys.length); k++ ) { var td2 = document.createElement("td"); if (x.bodys[k]) { var textnode2 = document.createTextNode(x.bodys[k].value); td2.appendChild(textnode2); td2.setAttribute("style", "width:100px;font-size:12px;"); } tr2.appendChild(td2); } table.appendChild(tr2); } var trs = Array.from(table.getElementsByTagName("tr")); table.setAttribute("border", "1"); table.setAttribute("cellspacing", "0"); table.setAttribute("style", "margin-bottom:20px;"); div.appendChild(table); }); }) .catch(e => this.$message.error(e.message)); } }, ceil(data) { //向上取整 return Math.ceil(data / 16); }
打印
import printJS from "print-js";
onPrint() { var par = document.getElementById("gzDiv"); var tables = Array.from(par.getElementsByTagName("table")); var div1 = document.createElement("div"); var div2 = document.createElement("div"); var ht = 0; tables.forEach((tb, index) => { //獲取表格的高度,用一個變量來保存,而不是tb.offsetHeight直接運算,要不然最后的表格有問題,我就試過 var tbh = tb.offsetHeight; ht = ht + tbh; //橫向打印,限制一張A4紙,最多打印600高度,當超過時換頁 if (ht <= 600) { div2.appendChild(tb); if (index == tables.length - 1) { div1.appendChild(div2); } else { //設置每個表格之間的間距為20 ht = ht + 20; } } else { //當超過600時,div加上換頁樣式,強制換頁 div2.setAttribute("style", "page-break-after:always;"); div1.appendChild(div2); div2 = document.createElement("div"); div2.appendChild(tb); if (index == tables.length - 1) { //div2.setAttribute("style", "page-break-after:always;"); div1.appendChild(div2); } else { ht = tbh + 20; } } }); //上面已經拿了之前的child了,所以此時的par的子節點為空的 // var childs = Array.from(par.children); // childs.forEach(ch => { // par.removeChild(ch); // }); //直接把新的div子節點append到par里 par.appendChild(div1); //放大到原來的1.2倍 par.style.zoom = 1.2; printJS({ printable: "gzDiv", type: "html", targetStyles: ["*"] }); //還原 par.style.zoom = 1; },
前端是主要的,提供思路
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
后端的封裝是根據前端想要怎么樣來封裝的
后端封裝視圖層,關鍵的是:表頭和內容是一一對應的
(1)model類,其中有5個字段是固定的,還有一個字段是擴展列kzl(表頭不固定,存放多個表格內容),數據庫中第1行存的是表頭,之后才是內容
@Entity(name = "xxxxx.Gzdr") @Table(name = "xxxxx_gzdr") public class Gzdr implements Serializable { @Id @GeneratedValue(strategy = GenerationType.AUTO) private int id; @Column(name = "zt_id", nullable = false) private int ztId; @Nationalized @Column(length = 50, nullable = false) private String qj; @Nationalized @Column(name = "gzlb_id", length = 50, nullable = false) private String gzlbId; @Nationalized @Column(name = "bm_name", length = 50, nullable = false) private String bmName; @Nationalized @Column(name = "gz_num", length = 50, nullable = false) private String gzNum; @Nationalized @Column(length = 50, nullable = false) private String name; @Column(name = "field_id", length = 255, nullable = false) private String fieldId; @Column(name = "row_num", nullable = false) private int rowNum; @Column(columnDefinition = "CLOB", nullable = false) private String kzl;
(2)view類
public class GzView { private List<GzlrValue> headers; private List<GzlrValue> bodys; public List<GzlrValue> getHeaders() { return headers; } public void setHeaders(List<GzlrValue> headers) { this.headers = headers; } public List<GzlrValue> getBodys() { return bodys; } public void setBodys(List<GzlrValue> bodys) { this.bodys = bodys; } }
public class GzlrValue { private int id; private String value; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } @Override public String toString() { return "GzlrValue{" + "id=" + id + ", value='" + value + '\'' + '}'; } }
controller
@GetMapping("/gzdy") public List<GzView> gzdy(@RequestParam(value = "ztId") int ztId, @RequestParam(value = "bmName") String bmName, @RequestParam(value = "gzlb") int gzlb, @RequestParam(value = "qj") String qj) throws JsonProcessingException { List<GzView> items = new ArrayList<>(); logger.info("這是期間" + qj); List<Gzdr> gzdrLisr = gzdrRepository.findAllByZtIdAndBmNameAndGzlbIdAndQj(ztId, bmName, String.valueOf(gzlb), qj); int count = gzdrLisr.size(); logger.info("這是部門有多少個人" + count); //拿到唯一的表頭 List<String> collect = gzdrLisr.stream().map(Gzdr::getFieldId).distinct().collect(Collectors.toList()); Gzdr headerGzdr = gzdrRepository.findAllByFieldIdAndRowNum(collect.get(0), 0); logger.info("這是唯一的表頭" + headerGzdr); for (var gzdr : gzdrLisr) { items.add(getView(headerGzdr,gzdr)); } logger.info("這是最終集合" + items.toString()); return items; } private GzView getView(Gzdr headerGzdr, Gzdr gzdr) throws JsonProcessingException { GzView gzView = new GzView(); List<GzlrValue> headers = new ArrayList<>(); ObjectMapper objectMapper = new ObjectMapper(); List<GzlrValue> bodys = new ArrayList<>(); GzlrValue it = new GzlrValue(); it.setId(1); it.setValue(gzdr.getQj()); bodys.add(it); it = new GzlrValue(); it.setId(2); it.setValue(gzdr.getBmName()); bodys.add(it); it = new GzlrValue(); it.setId(3); it.setValue(gzdr.getGzNum()); bodys.add(it); it = new GzlrValue(); it.setId(4); it.setValue(gzdr.getName()); bodys.add(it); List<GzlrValue> cells1 = objectMapper.readValue(gzdr.getKzl(), new TypeReference<>() { }); List<GzlrValue> collect = cells1.stream().filter(x -> !x.getValue().equals("0.0")).collect(Collectors.toList()); bodys.addAll(collect); gzView.setBodys(bodys); List<Header> headers1 = objectMapper.readValue(headerGzdr.getKzl(), new TypeReference<>() { }); for (var bd : bodys) { if (bd.getId() <= 4) { it = new GzlrValue(); it.setId(bd.getId()); switch (bd.getId()) { case 1: it.setValue("期間"); break; case 2: it.setValue("部門名稱"); break; case 3: it.setValue("工資號"); break; case 4: it.setValue("姓名"); break; default: break; } headers.add(it); } else { it = new GzlrValue(); it.setId(bd.getId()); List<Header> collect1 = headers1.stream().filter(x -> x.getId() == bd.getId()).collect(Collectors.toList()); it.setValue(collect1.get(0).getValue()); headers.add(it); } } gzView.setHeaders(headers); return gzView; }