前端开发如何一天时间,将一个OA系统的100多个流程的表单打印做出来

249 阅读9分钟

背景

前端干了6年,迷迷糊糊的,突然想写写博客,把自己这六年来,攻克的技术难点,功能点记录一下,写的不好,大家体谅一下。

方法

下面是,我在OA系统做的一个功能点,做了一个前端统一打印功能,主要是OA系统: 先说一下目前主流的实现打印的实现方式吧:

  1. 后端实现:提前写好word模板,后台把数据塞进去,然后前端再调用接口,下载文件,下载后再打印。(或者是浏览器机制。是PDF的话,下载后直接有预览,预览里面有下载。)
  2. 前端实现一:将将页面截图,塞进word里面。直接下载,或者转pdf下载。
  3. 前端实现二:前端请接口,准备word模版里面,把数据塞进去。

弊端

先说上面实现的几个弊端吧:

  1. 我不是不想用1方法,采用1没有去前端什么事,调个下载接口就行了,可是太多流程了打印,后端都要发癫了,不给我干这活哦,少量打印还好。
  2. 2方法简单了,做一个统一的方法,将页面截图,塞进word里面,但是经不住他丑呀……截图系统的图,塞进word里会变形…表单一长,就显示不全。
  3. 3方法也是如此,要对接太多接口了,准备太多太多模版了,前端我自己也干不来。

也许有更好的,我技术有限,没有想到。我用的是都不是这三种,我先上截图吧,不然你们不信,我那还真有这场景,100多个表单打印。

效果图

流程界面图

微信图片_20241216092518.png

微信图片_20241216100753.png

点击打印按钮,进行打印预览

微信截图_20241216102918.png

微信截图_20241216103012.png

微信图片_2024121609251000.png

其他流程打印图

微信图片_20241216103346.png

一百多个流程表单

真的有很多打印……………………………… 微信图片_20241216103654.png

上代码(哈哈,上菜)

所用插件

canvas-editor

基于canvas/svg的富文本编辑器 文档地址

canvas-editor, 它底层基于 canvas 实现, 我们使用它可以实现类似于 word文档编辑器类似的效果, 同时还支持很多灵活可配置的 API, 可以帮助我们定制属于自己的文档编辑平台。

我为什么要用这个插件呢,因为这个插件是现成的,而且样式好看,开源的。(感恩canvas-editor);很符合是目前的项目要求,用这个插件,我只需要封装一个方法,把我界面的元素和数据,解析成canvas-editor构成word,所需要的数据格式就可以进行预览,且打印就可以了。

实现思路

由于业务需要,打印一共分两个,一个是表单模块,一个是意见模块。由于表单是动态的,数据字段及属性格式是不固定的,而意见模块的数据格式是固定。

1、封装vue组件弹框

<template>
  <el-dialog v-model="dialogVisible" title="表单打印" :width="980" :close-on-click-modal="false"
    :close-on-press-escape="false" :destroy-on-close="true" draggable>
    <!-- 预览容器--->
    <div
      style="max-height: calc(100vh - 200px);background: #fafafa;text-align: center;overflow: auto;display: flex;justify-content: center;">
      <div class="canvas-editor"></div>
    </div>
    <template #footer>
      <span class="dialog-footer">
        <el-button @click="dialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="printfFormFn()">打印</el-button>
      </span>
    </template>
  </el-dialog>
</template>
<script lang="ts" setup name="printfForm">
const dialogVisible=ref(false)
// 打开弹框
const openDialog = (domHtml: HTMLElement,commentList: any[],) => {
   // domHtmlm 是表单的所有元素节点
   // commentList 是意见列表数据格式的[{node:'流程节点',state:'状态',userName:'审批人',time:'审批 时间',comment:'审批意见'}]
   // 初始化canvas-editor
  initCanvasEditor(domHtml,commentList)
  dialogVisible.value = true;

}
defineExpose({
  openDialog
})
</script>

对外抛出打开预览组件方法

2、初始化canvas-editor

进入插件canvas-editor

import docxPlugin from "@hufe921/canvas-editor-plugin-docx";

封装初始化方法

import docxPlugin from "@hufe921/canvas-editor-plugin-docx";

// 将表格行分未24格子,每格长28像素
const colgroupList: { width: number }[] = []
for (let i = 0; i < 24; i++) {
  colgroupList.push({ width: 28 })
}
// 容器对象
let instance=null
const initWord = (domHtml: HTMLElement, commentList: any[]) => {
  // 获取标题
  const title = initTittle(domHtml)
  //处理好的意见数据,对应canvas-editor是行数据
  const commentListWord: ITr[] = initCommentList(JSON.parse(JSON.stringify(commentList)))
    //处理好的格式数据,对应canvas-editor是行数据
  const formListWord: ITr[] = initFormList(domHtml)
  // 获取容器
  let dom = document.querySelector('.canvas-editor') as HTMLDivElement
  // 初始化容器
   if (dom) {
      instance = new Editor(
        dom,
        [
          {// 标题设置
            value: title + '\n',
            size: 24,
            rowFlex: RowFlex.CENTER,
            bold: true,
            rowMargin: 0,
          },
          {// 意见设置
            value: '',
            colgroup: colgroupList,
            type: ElementType.TABLE,
            trList: formList,

          },
          { //表单设置
            value: '',
            colgroup: colgroupList,
            type: ElementType.TABLE,
            trList: commentList,
          }
        ],
        {
          mode: EditorMode.READONLY,
          watermark: {// 水印设置
            data: 'XXX公司 [' + userName + ' ' + formatDate(new Date()) + ' 打印]',
            data: '',
            size: 14,
            opacity: 0.2,
            repeat: true
          },
          margins: [50, 60, 50, 60] as unknown as IMargin,// 纸张设置
        }
      )
    }
}

3、初始化标题

const initTittle = (domHtml: HTMLElement) => {
  let title = ''
  let dom: HTMLElement = domHtml.querySelector('.title') as HTMLElement
  if (dom) {
    title = dom.innerText
  } 
  if(!title){
   title = '未知标题'
   }
  return title
}

4、初始化意见行列表

// 初始化意见行列
const initCommentList = (commentList:any[]) => {
  // 处理审核意见
  const list: ITr[] = []
  // 初始化表头
  list.push({
    height: 30,
    tdList: [
      {
        colspan: 4,// 占四列
        rowspan: 1,//占一行
        backgroundColor: '#fafafa',
        value: [
          { value: `环节`, size: 16, rowFlex: RowFlex.CENTER },
        ]
      },
      {
        colspan: 3,
        rowspan: 1,
        backgroundColor: '#fafafa',
        value: [
          { value: `状态`, size: 16, rowFlex: RowFlex.CENTER },
        ]
      },
      {
        colspan: 8,
        rowspan: 1,
        backgroundColor: '#fafafa',
        value: [
          { value: `审批意见`, size: 16, rowFlex: RowFlex.CENTER },
        ]
      },
      {
        colspan: 3,
        rowspan: 1,
        backgroundColor: '#fafafa',
        value: [
          { value: `审批人`, size: 16, rowFlex: RowFlex.CENTER },
        ]
      },
      {
        colspan: 6,
        rowspan: 1,
        backgroundColor: '#fafafa',
        value: [
          { value: `审批时间`, size: 16, rowFlex: RowFlex.CENTER },
        ]
      },
    ]
  })
  commentList.forEach(((item: any) => {
    let row =  {
    height: 30,
    tdList: [
      {
        colspan: 4,// 占四列
        rowspan: 1,//占一行
        backgroundColor: '#fafafa',
        value: [
          { value: item.node, size: 16, rowFlex: RowFlex.CENTER },
        ]
      },
      {
        colspan: 3,
        rowspan: 1,
        value: [
          { value: item.state, size: 16, rowFlex: RowFlex.CENTER },
        ]
      },
      {
        colspan: 8,
        rowspan: 1,
        value: [
          { value: item.comments, size: 16, rowFlex: RowFlex.CENTER },
        ]
      },
      {
        colspan: 3,
        rowspan: 1,
        value: [
          { value: item.userName, size: 16, rowFlex: RowFlex.CENTER },
        ]
      },
      {
        colspan: 6,
        rowspan: 1,
        value: [
          { value: item.time, size: 16, rowFlex: RowFlex.CENTER },
        ]
      },
    ]
  }
     list.push(row)
  })
  return list
}

5、处理表单节点,获取到对应的行数据

const initFormList=(domHtml: HTMLElement)=>{
  //定义返回结果行
  const resultList: ITr[] = []
  // 定义标题对象
  const titleRow: ITr = {
    height: 30,
    tdList: [
      {
        colspan: 24,
        rowspan: 1,
        verticalAlign: VerticalAlign.MIDDLE,
        value: [
          { value: '基本信息', size: 15, rowFlex: RowFlex.LEFT, bold: true },
        ]
      },
    ]
  }
 // 定义标签对象
  const labelTd: ITd = {
    colspan: 4,
    rowspan: 1,
    verticalAlign: VerticalAlign.MIDDLE,
    backgroundColor: '#fafafa',
    value: [
      { value: '标题', size: 14, rowFlex: RowFlex.CENTER },
    ]
  }
  // 定义值对象
  const valueTd: ITd = {
    colspan: 8,
    rowspan: 1,
    verticalAlign: VerticalAlign.MIDDLE,
    value: [
      { value: '值', size: 14, rowFlex: RowFlex.LEFT },
    ]
  }
  // 定义行对象
  const valRow: ITr = {
    height: 30,
    tdList: []
  }
   //表单设置
  let pageFormList = domHtml.querySelectorAll('.el-form') as unknown as HTMLElement[]
  if (pageFormList.length > 0) {
    pageFormList.forEach(pageForm => {
      let childNodes = pageForm.childNodes as NodeListOf<HTMLElement>; // 获取所有的子节点
      childNodes.forEach((node: HTMLElement) => {
        // 处理二级标题
        if (node.className && node.className == 'subTitle') {
          if (valRow && valRow.tdList.length == 2) {
            valRow.tdList[1].colspan = 20;
            resultList.push(JSON.parse(JSON.stringify(valRow)))
            valRow.tdList = [];
          } else if (valRow && valRow.tdList.length == 4) {
            resultList.push(JSON.parse(JSON.stringify(valRow)))
            valRow.tdList = [];
          }
          titleRow.tdList[0].value[0].value = node.innerText
          resultList.push(JSON.parse(JSON.stringify(titleRow)))
        }
        else if (node.classList && node.classList.contains('el-form-item')) {
          const dom1 = node.querySelector('.el-form-item__label') as HTMLElement
          if (dom1) {
            const dom2 = node.querySelector('.el-form-item__content') as HTMLElement
            let value = dom2.innerText || ''
            // 处理输入框的值
            const inputDom = dom2.querySelector('input')
            if (inputDom) {
              value = inputDom.value
            }
            //处理文本输入框的值
            const textareaDom = dom2.querySelector('textarea')
            if (textareaDom) {
              value = textareaDom.value
            }
            // 获取单选款选中值
            const radioDom = dom2.querySelector('.el-radio-group') as HTMLElement
            if (radioDom) {
              const valDom = radioDom.querySelector('.is-checked') as HTMLElement
              if (valDom) {
                value = valDom.innerText || ''
              } else {
                value = ''
              }
            }
            //处理多选框的值
            const selectDom = dom2.querySelector('.el-select') as HTMLElement
            if (selectDom) {
              const valDom = selectDom.querySelector('.el-select__tags') as HTMLElement
              if (valDom) {
                value = valDom.innerText || ''
              }
            }

            const listValueTd: string[] = []
            // 处理附件样式
            const documentDomList = dom2.querySelectorAll('.el-icon-document') as unknown as HTMLElement[]
            if (documentDomList.length > 0) {
              let listValue: string[] = []
              documentDomList.forEach((fileDom: any) => {
                listValueTd.push(fileDom.innerText)
                listValue.push(fileDom.innerText)
              })
              value = listValue.join('\n')
            }
            let titleVal = dom1.innerText
            labelTd.value[0].value = titleVal || ''
            valueTd.value[0].value = value || ''
            //处理每行的逻辑
            if (valRow.tdList.length <= 2) {
                // 单独占一行的情况1
              if (node.classList.contains('lineRow') && valRow.tdList.length == 2) {
                valRow.tdList[1].colspan = 20
                resultList.push(JSON.parse(JSON.stringify(valRow)))
                valRow.tdList = []
                valRow.tdList.push(JSON.parse(JSON.stringify(labelTd)))
                valRow.tdList.push(JSON.parse(JSON.stringify(valueTd)))
                valRow.tdList[1].colspan = 20
                resultList.push(JSON.parse(JSON.stringify(valRow)))
                valRow.tdList = []
              } 
              //单独占一行的情况2
              else if (node.classList.contains("lineRow") && valRow.tdList.length == 0) {
                valRow.tdList.push(JSON.parse(JSON.stringify(labelTd)))
                valRow.tdList.push(JSON.parse(JSON.stringify(valueTd)))
                valRow.tdList[1].colspan = 20
                resultList.push(JSON.parse(JSON.stringify(valRow)))
                valRow.tdList = []
              } else {
                valRow.tdList.push(JSON.parse(JSON.stringify(labelTd)))
                valRow.tdList.push(JSON.parse(JSON.stringify(valueTd)))
              }
            } else {
              resultList.push(JSON.parse(JSON.stringify(valRow)))
              valRow.tdList = [];
              valRow.tdList.push(JSON.parse(JSON.stringify(labelTd)))
              valRow.tdList.push(JSON.parse(JSON.stringify(valueTd)))
            }
          }
        }
      })
    })
  }
  //处理行行数据
  if (valRow && valRow.tdList.length == 2) {
    valRow.tdList[1].colspan = 20;
    resultList.push(JSON.parse(JSON.stringify(valRow)))
    valRow.tdList = [];
  } else if (valRow && valRow.tdList.length == 4) {
    resultList.push(JSON.parse(JSON.stringify(valRow)))
    valRow.tdList = [];
  }
  titleRow.tdList[0].value[0].value = '审批意见'
  resultList.push(JSON.parse(JSON.stringify(titleRow)))
  return resultList
}

调用打印方法

const printfFormFn = () => {
  instance.command.executePrint()
}

完整代码

<template>
  <el-dialog v-model="dialogVisible" title="表单打印" :width="980" :close-on-click-modal="false"
    :close-on-press-escape="false" :destroy-on-close="true" draggable>
    <!-- 预览容器--->
    <div
      style="max-height: calc(100vh - 200px);background: #fafafa;text-align: center;overflow: auto;display: flex;justify-content: center;">
      <div class="canvas-editor"></div>
    </div>
    <template #footer>
      <span class="dialog-footer">
        <el-button @click="dialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="printfFormFn()">打印</el-button>
      </span>
    </template>
  </el-dialog>
</template>
<script lang="ts" setup name="printfForm">
import docxPlugin from "@hufe921/canvas-editor-plugin-docx";
const dialogVisible=ref(false)
// 打开弹框
const openDialog = (domHtml: HTMLElement,commentList: any[],) => {
   // domHtmlm 是表单的所有元素节点
   // commentList 是意见列表数据格式的[{node:'流程节点',state:'状态',userName:'审批人',time:'审批 时间',comment:'审批意见'}]
   // 初始化canvas-editor
  initCanvasEditor(domHtml,commentList)
  dialogVisible.value = true;
}
// 将表格行分未24格子,每格长28像素
const colgroupList: { width: number }[] = []
for (let i = 0; i < 24; i++) {
  colgroupList.push({ width: 28 })
}
// 容器对象
let instance=null
const initWord = (domHtml: HTMLElement, commentList: any[]) => {
  // 获取标题
  const title = initTittle(domHtml)
  //处理好的意见数据,对应canvas-editor是行数据
  const commentListWord: ITr[] = initCommentList(JSON.parse(JSON.stringify(commentList)))
    //处理好的格式数据,对应canvas-editor是行数据
  const formListWord: ITr[] = initFormList(domHtml)
  // 获取容器
  let dom = document.querySelector('.canvas-editor') as HTMLDivElement
  // 初始化容器
   if (dom) {
      instance = new Editor(
        dom,
        [
          {// 标题设置
            value: title + '\n',
            size: 24,
            rowFlex: RowFlex.CENTER,
            bold: true,
            rowMargin: 0,
          },
          {// 意见设置
            value: '',
            colgroup: colgroupList,
            type: ElementType.TABLE,
            trList: formList,

          },
          { //表单设置
            value: '',
            colgroup: colgroupList,
            type: ElementType.TABLE,
            trList: commentList,
          }
        ],
        {
          mode: EditorMode.READONLY,
          watermark: {// 水印设置
            data: 'XXX公司 [' + userName + ' ' + formatDate(new Date()) + ' 打印]',
            data: '',
            size: 14,
            opacity: 0.2,
            repeat: true
          },
          margins: [50, 60, 50, 60] as unknown as IMargin,// 纸张设置
        }
      )
    }
}
const initTittle = (domHtml: HTMLElement) => {
  let title = ''
  let dom: HTMLElement = domHtml.querySelector('.title') as HTMLElement
  if (dom) {
    title = dom.innerText
  } 
  if(!title){
   title = '未知标题'
   }
  return title
}
// 初始化意见行列
const initCommentList = (commentList:any[]) => {
  // 处理审核意见
  const list: ITr[] = []
  // 初始化表头
  list.push({
    height: 30,
    tdList: [
      {
        colspan: 4,// 占四列
        rowspan: 1,//占一行
        backgroundColor: '#fafafa',
        value: [
          { value: `环节`, size: 16, rowFlex: RowFlex.CENTER },
        ]
      },
      {
        colspan: 3,
        rowspan: 1,
        backgroundColor: '#fafafa',
        value: [
          { value: `状态`, size: 16, rowFlex: RowFlex.CENTER },
        ]
      },
      {
        colspan: 8,
        rowspan: 1,
        backgroundColor: '#fafafa',
        value: [
          { value: `审批意见`, size: 16, rowFlex: RowFlex.CENTER },
        ]
      },
      {
        colspan: 3,
        rowspan: 1,
        backgroundColor: '#fafafa',
        value: [
          { value: `审批人`, size: 16, rowFlex: RowFlex.CENTER },
        ]
      },
      {
        colspan: 6,
        rowspan: 1,
        backgroundColor: '#fafafa',
        value: [
          { value: `审批时间`, size: 16, rowFlex: RowFlex.CENTER },
        ]
      },
    ]
  })
  commentList.forEach(((item: any) => {
    let row =  {
    height: 30,
    tdList: [
      {
        colspan: 4,// 占四列
        rowspan: 1,//占一行
        backgroundColor: '#fafafa',
        value: [
          { value: item.node, size: 16, rowFlex: RowFlex.CENTER },
        ]
      },
      {
        colspan: 3,
        rowspan: 1,
        value: [
          { value: item.state, size: 16, rowFlex: RowFlex.CENTER },
        ]
      },
      {
        colspan: 8,
        rowspan: 1,
        value: [
          { value: item.comments, size: 16, rowFlex: RowFlex.CENTER },
        ]
      },
      {
        colspan: 3,
        rowspan: 1,
        value: [
          { value: item.userName, size: 16, rowFlex: RowFlex.CENTER },
        ]
      },
      {
        colspan: 6,
        rowspan: 1,
        value: [
          { value: item.time, size: 16, rowFlex: RowFlex.CENTER },
        ]
      },
    ]
  }
     list.push(row)
  })
  return list
}
const initFormList=(domHtml: HTMLElement)=>{
  //定义返回结果行
  const resultList: ITr[] = []
  // 定义标题对象
  const titleRow: ITr = {
    height: 30,
    tdList: [
      {
        colspan: 24,
        rowspan: 1,
        verticalAlign: VerticalAlign.MIDDLE,
        value: [
          { value: '基本信息', size: 15, rowFlex: RowFlex.LEFT, bold: true },
        ]
      },
    ]
  }
 // 定义标签对象
  const labelTd: ITd = {
    colspan: 4,
    rowspan: 1,
    verticalAlign: VerticalAlign.MIDDLE,
    backgroundColor: '#fafafa',
    value: [
      { value: '标题', size: 14, rowFlex: RowFlex.CENTER },
    ]
  }
  // 定义值对象
  const valueTd: ITd = {
    colspan: 8,
    rowspan: 1,
    verticalAlign: VerticalAlign.MIDDLE,
    value: [
      { value: '值', size: 14, rowFlex: RowFlex.LEFT },
    ]
  }
  // 定义行对象
  const valRow: ITr = {
    height: 30,
    tdList: []
  }
   //表单设置
  let pageFormList = domHtml.querySelectorAll('.el-form') as unknown as HTMLElement[]
  if (pageFormList.length > 0) {
    pageFormList.forEach(pageForm => {
      let childNodes = pageForm.childNodes as NodeListOf<HTMLElement>; // 获取所有的子节点
      childNodes.forEach((node: HTMLElement) => {
        // 处理二级标题
        if (node.className && node.className == 'subTitle') {
          if (valRow && valRow.tdList.length == 2) {
            valRow.tdList[1].colspan = 20;
            resultList.push(JSON.parse(JSON.stringify(valRow)))
            valRow.tdList = [];
          } else if (valRow && valRow.tdList.length == 4) {
            resultList.push(JSON.parse(JSON.stringify(valRow)))
            valRow.tdList = [];
          }
          titleRow.tdList[0].value[0].value = node.innerText
          resultList.push(JSON.parse(JSON.stringify(titleRow)))
        }
        else if (node.classList && node.classList.contains('el-form-item')) {
          const dom1 = node.querySelector('.el-form-item__label') as HTMLElement
          if (dom1) {
            const dom2 = node.querySelector('.el-form-item__content') as HTMLElement
            let value = dom2.innerText || ''
            // 处理输入框的值
            const inputDom = dom2.querySelector('input')
            if (inputDom) {
              value = inputDom.value
            }
            //处理文本输入框的值
            const textareaDom = dom2.querySelector('textarea')
            if (textareaDom) {
              value = textareaDom.value
            }
            // 获取单选款选中值
            const radioDom = dom2.querySelector('.el-radio-group') as HTMLElement
            if (radioDom) {
              const valDom = radioDom.querySelector('.is-checked') as HTMLElement
              if (valDom) {
                value = valDom.innerText || ''
              } else {
                value = ''
              }
            }
            //处理多选框的值
            const selectDom = dom2.querySelector('.el-select') as HTMLElement
            if (selectDom) {
              const valDom = selectDom.querySelector('.el-select__tags') as HTMLElement
              if (valDom) {
                value = valDom.innerText || ''
              }
            }

            const listValueTd: string[] = []
            // 处理附件样式
            const documentDomList = dom2.querySelectorAll('.el-icon-document') as unknown as HTMLElement[]
            if (documentDomList.length > 0) {
              let listValue: string[] = []
              documentDomList.forEach((fileDom: any) => {
                listValueTd.push(fileDom.innerText)
                listValue.push(fileDom.innerText)
              })
              value = listValue.join('\n')
            }
            let titleVal = dom1.innerText
            labelTd.value[0].value = titleVal || ''
            valueTd.value[0].value = value || ''
            //处理每行的逻辑
            if (valRow.tdList.length <= 2) {
                // 单独占一行的情况1
              if (node.classList.contains('lineRow') && valRow.tdList.length == 2) {
                valRow.tdList[1].colspan = 20
                resultList.push(JSON.parse(JSON.stringify(valRow)))
                valRow.tdList = []
                valRow.tdList.push(JSON.parse(JSON.stringify(labelTd)))
                valRow.tdList.push(JSON.parse(JSON.stringify(valueTd)))
                valRow.tdList[1].colspan = 20
                resultList.push(JSON.parse(JSON.stringify(valRow)))
                valRow.tdList = []
              } 
              //单独占一行的情况2
              else if (node.classList.contains("lineRow") && valRow.tdList.length == 0) {
                valRow.tdList.push(JSON.parse(JSON.stringify(labelTd)))
                valRow.tdList.push(JSON.parse(JSON.stringify(valueTd)))
                valRow.tdList[1].colspan = 20
                resultList.push(JSON.parse(JSON.stringify(valRow)))
                valRow.tdList = []
              } else {
                valRow.tdList.push(JSON.parse(JSON.stringify(labelTd)))
                valRow.tdList.push(JSON.parse(JSON.stringify(valueTd)))
              }
            } else {
              resultList.push(JSON.parse(JSON.stringify(valRow)))
              valRow.tdList = [];
              valRow.tdList.push(JSON.parse(JSON.stringify(labelTd)))
              valRow.tdList.push(JSON.parse(JSON.stringify(valueTd)))
            }
          }
        }
      })
    })
  }
  //处理行行数据
  if (valRow && valRow.tdList.length == 2) {
    valRow.tdList[1].colspan = 20;
    resultList.push(JSON.parse(JSON.stringify(valRow)))
    valRow.tdList = [];
  } else if (valRow && valRow.tdList.length == 4) {
    resultList.push(JSON.parse(JSON.stringify(valRow)))
    valRow.tdList = [];
  }
  titleRow.tdList[0].value[0].value = '审批意见'
  resultList.push(JSON.parse(JSON.stringify(titleRow)))
  return resultList
}
const printfFormFn = () => {
  instance.command.executePrint()
}
defineExpose({
  openDialog
})
</script>

页面调用方法

<template>
<div>
    <el-button size="small" :icon="Printer" @click="PrintShowFn()">打印</el-button>
    <div id="formDataDom">
     <el-form ref="formRef" :model="form" label-width="150px" :inline="true" :rules="rules">
      <div class="title">请假申请表</div>
      <div class="pm-title">基本信息</div>
      <!--   这里写表单对应的相(有类lineRow的,占一行)-->
      <el-form-item label="请假人" prop="stateName" class="borderRight">
         <el-input v-model="form.userName" placeholder="请输入" />
      </el-form-item>
      <el-form-item label="请假原因" prop="stateName" class="borderRight">
         <el-input v-model="form.userName" :rows="2" type="textarea" placeholder="请输入" />
      </el-form-item>
     </el-form>
    </div>
    <printf-form ref="printfFormRef"></printf-form>
  </div>
</template>
<script lang="ts" setup name="printfForm">

const commentList=ref([])//审核意见数据
const form=ref<any>({})
const printfFormRef=ref()
const PrintShowFn = () => {
  const domHtml = document.getElementById('formDataDom')
  printfFormRef.value.openDialog(commentList.value, domHtml)
}
</script>

再次感谢canvas-editor

纯手打,转载标明出处,作者:iceBin