PrintDialog.vue 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. <script setup lang="ts">
  2. import * as ProcessInstanceApi from '@/api/bpm/processInstance'
  3. import { useUserStore } from '@/store/modules/user'
  4. import { formatDate } from '@/utils/formatTime'
  5. import { DICT_TYPE, getDictLabel } from '@/utils/dict'
  6. import { decodeFields } from '@/utils/formCreate'
  7. const userStore = useUserStore()
  8. const visible = ref(false)
  9. const loading = ref(false)
  10. const printData = ref()
  11. const userName = computed(() => userStore.user.nickname ?? '')
  12. const printTime = ref(formatDate(new Date(), 'YYYY-MM-DD HH:mm'))
  13. const formFields = ref()
  14. const printDataMap = ref({})
  15. const open = async (id: string) => {
  16. loading.value = true
  17. try {
  18. printData.value = await ProcessInstanceApi.getProcessInstancePrintData(id)
  19. initPrintDataMap()
  20. parseFormFields()
  21. console.log(printData.value)
  22. } finally {
  23. loading.value = false
  24. }
  25. visible.value = true
  26. }
  27. defineExpose({ open })
  28. const parseFormFields = () => {
  29. const formFieldsObj = decodeFields(printData.value.formFields)
  30. const processVariables = printData.value.processVariables
  31. let res: any = []
  32. for (const item of formFieldsObj) {
  33. const id = item['field']
  34. const name = item['title']
  35. let html = '暂不支持此类型的表单展示'
  36. // TODO 完善各类型表单的展示
  37. if (item['type'] === 'input') {
  38. html = processVariables[item['field']]
  39. }
  40. if (item['type'] === 'UploadImg') {
  41. html = `<img src="${processVariables[item['field']]}" style="max-width: 600px" />`
  42. }
  43. printDataMap.value[item['field']] = html
  44. res.push({ id, name, html })
  45. }
  46. formFields.value = res
  47. }
  48. const initPrintDataMap = () => {
  49. printDataMap.value['startUser'] = printData.value.startUser.nickname
  50. printDataMap.value['startUserDept'] = printData.value.startUser.deptName
  51. printDataMap.value['processName'] = printData.value.processName
  52. printDataMap.value['processNum'] = printData.value.processInstanceId
  53. printDataMap.value['startTime'] = printData.value.startTime
  54. printDataMap.value['endTime'] = printData.value.endTime
  55. printDataMap.value['processStatus'] = getDictLabel(
  56. DICT_TYPE.BPM_PROCESS_INSTANCE_STATUS,
  57. printData.value.processStatus
  58. )
  59. printDataMap.value['printUsername'] = userName.value
  60. printDataMap.value['printTime'] = printTime.value
  61. }
  62. const getPrintTemplateHTML = () => {
  63. const parser = new DOMParser()
  64. let doc = parser.parseFromString(printData.value.printTemplateHtml, 'text/html')
  65. // table 添加border
  66. let tables = doc.querySelectorAll('table')
  67. tables.forEach((item) => {
  68. item.setAttribute('border', '1')
  69. item.setAttribute('style', (item.getAttribute('style') || '') + 'border-collapse:collapse;')
  70. })
  71. // 替换mentions
  72. let mentions = doc.querySelectorAll('[data-w-e-type="mention"]')
  73. mentions.forEach((item) => {
  74. const mentionId = JSON.parse(decodeURIComponent(item.getAttribute('data-info') ?? ''))['id']
  75. item.innerHTML = printDataMap.value[mentionId] ?? ''
  76. })
  77. // 替换流程记录
  78. let processRecords = doc.querySelectorAll('[data-w-e-type="process-record"]')
  79. let processRecordTable : Element = document.createElement('table')
  80. if (processRecords.length > 0) {
  81. // 构建流程记录html
  82. processRecordTable.setAttribute('border', '1')
  83. processRecordTable.setAttribute('style', 'width:100%;border-collapse:collapse;')
  84. const headTr = document.createElement('tr')
  85. const headTd = document.createElement('td')
  86. headTd.setAttribute('colspan', '2')
  87. headTd.setAttribute('width', 'auto')
  88. headTd.setAttribute('style', 'text-align: center;')
  89. headTd.innerHTML = '流程节点'
  90. headTr.appendChild(headTd)
  91. processRecordTable.appendChild(headTr)
  92. printData.value.approveNodes.forEach(item => {
  93. const tr = document.createElement('tr')
  94. const td1 = document.createElement('td')
  95. td1.innerHTML = item.nodeName
  96. const td2 = document.createElement('td')
  97. td2.innerHTML = item.nodeDesc
  98. tr.appendChild(td1)
  99. tr.appendChild(td2)
  100. processRecordTable.appendChild(tr)
  101. })
  102. }
  103. processRecords.forEach(item => {
  104. item.innerHTML = processRecordTable.outerHTML
  105. })
  106. // 返回html
  107. return doc.body.innerHTML
  108. }
  109. const printObj = ref({
  110. id: 'printDivTag',
  111. popTitle: '&nbsp',
  112. extraCss: '/print.css',
  113. extraHead: '',
  114. zIndex: 20003
  115. })
  116. </script>
  117. <template>
  118. <el-dialog v-loading="loading" v-model="visible" :show-close="false">
  119. <div id="printDivTag">
  120. <div v-if="printData.printTemplateEnable" v-html="getPrintTemplateHTML()"></div>
  121. <div v-else>
  122. <h2 class="text-center">{{ printData.processName }}</h2>
  123. <div class="text-right text-15px">{{ '打印人员: ' + userName }}</div>
  124. <div class="flex justify-between">
  125. <div class="text-15px">{{ '流程编号: ' + printData.processInstanceId }}</div>
  126. <div class="text-15px">{{ '打印时间: ' + printTime }}</div>
  127. </div>
  128. <table class="mt-20px w-100%" border="1" style="border-collapse: collapse">
  129. <tbody>
  130. <tr>
  131. <td class="p-5px w-25%">发起人</td>
  132. <td class="p-5px w-25%">{{ printData.startUser.nickname }}</td>
  133. <td class="p-5px w-25%">发起时间</td>
  134. <td class="p-5px w-25%">{{ printData.startTime }}</td>
  135. </tr>
  136. <tr>
  137. <td class="p-5px w-25%">所属部门</td>
  138. <td class="p-5px w-25%">{{ printData.startUser.deptName }}</td>
  139. <td class="p-5px w-25%">流程状态</td>
  140. <td class="p-5px w-25%">
  141. {{ getDictLabel(DICT_TYPE.BPM_PROCESS_INSTANCE_STATUS, printData.processStatus) }}
  142. </td>
  143. </tr>
  144. <tr>
  145. <td class="p-5px w-100% text-center" colspan="4">
  146. <h4>表单内容</h4>
  147. </td>
  148. </tr>
  149. <tr v-for="item in formFields" :key="item.id">
  150. <td class="p-5px w-20%">
  151. {{ item.name }}
  152. </td>
  153. <td class="p-5px w-80%" colspan="3">
  154. <div v-html="item.html"></div>
  155. </td>
  156. </tr>
  157. <tr>
  158. <td class="p-5px w-100% text-center" colspan="4">
  159. <h4>流程节点</h4>
  160. </td>
  161. </tr>
  162. <tr v-for="item in printData.approveNodes" :key="item.nodeId">
  163. <td class="p-5px w-20%">
  164. {{ item.nodeName }}
  165. </td>
  166. <td class="p-5px w-80%" colspan="3">
  167. {{ item.nodeDesc }}
  168. <div v-if="item.signUrl !== ''">
  169. <img class="w-90px h-40px" :src="item.signUrl" alt="" />
  170. </div>
  171. </td>
  172. </tr>
  173. </tbody>
  174. </table>
  175. </div>
  176. </div>
  177. <template #footer>
  178. <div class="dialog-footer">
  179. <el-button @click="visible = false">取 消</el-button>
  180. <el-button type="primary" v-print="printObj"> 打 印</el-button>
  181. </div>
  182. </template>
  183. </el-dialog>
  184. </template>