效果(这里金额为或者字段为空不显示)
显示
打印,不会有表格是分两页打印的,根据自己需要设置一页打印多少个表格
根据后端数据生成多个表格
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; }