printStockEnterHt.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. <template>
  2. <ele-modal
  3. title="入库单"
  4. :visible.sync="QRvisible"
  5. v-if="QRvisible"
  6. width="1100px"
  7. @close="close"
  8. >
  9. <div id="printSectionHt">
  10. <div
  11. v-for="(rowItem, idx) in formData"
  12. :key="rowItem.id || idx"
  13. style="
  14. font-family: SimSun, serif;
  15. padding: 20px;
  16. width: 24cm;
  17. min-height: 14cm;
  18. margin: 0 auto;
  19. box-sizing: border-box;
  20. page-break-after: always;
  21. "
  22. >
  23. <!-- 入库单标题 -->
  24. <div style="text-align: center; margin-bottom: 20px;">
  25. <h2 style="margin: 0; font-size: 24px; font-weight: bold;">{{ groupName }}入库单</h2>
  26. </div>
  27. <!-- 供应商/客户信息 -->
  28. <div style="margin-bottom: 20px; width: 100%;">
  29. <div style="width: 100%; display: flex;">
  30. <div style="width: 40%;">
  31. 供应商名称:{{ rowItem.supplierNames || '' }}
  32. </div>
  33. <div style="width: 30%;">
  34. 日期:{{ rowItem.storageTime || '' }}
  35. </div>
  36. <div style="width: 30%;">
  37. 编号:{{ rowItem.bizNo || '' }}
  38. </div>
  39. </div>
  40. </div>
  41. <!-- 入库物品表格 -->
  42. <table
  43. border="1"
  44. cellspacing="0"
  45. style="
  46. width: 100%;
  47. border-collapse: collapse;
  48. font-size: 14px;
  49. "
  50. >
  51. <thead>
  52. <tr>
  53. <th style="border: 1px solid #000; padding: 4px; text-align: center; width: 5%;">编号</th>
  54. <th style="border: 1px solid #000; padding: 4px; text-align: center; width: 20%;">型号规格</th>
  55. <th v-if="rowItem.bizType == 6" style="border: 1px solid #000; padding: 4px; text-align: center; width: 12%;">客户</th>
  56. <th style="border: 1px solid #000; padding: 4px; text-align: center; width: 8%;">颜色</th>
  57. <th style="border: 1px solid #000; padding: 4px; text-align: center; width: 8%;">单位</th>
  58. <th style="border: 1px solid #000; padding: 4px; text-align: center; width: 8%;">入库数量</th>
  59. <th style="border: 1px solid #000; padding: 4px; text-align: center; width: 10%;">批次号</th>
  60. <th style="border: 1px solid #000; padding: 4px; text-align: center; width: 8%;">单价</th>
  61. <th style="border: 1px solid #000; padding: 4px; text-align: center; width: 10%;">金额</th>
  62. </tr>
  63. </thead>
  64. <tbody>
  65. <tr v-for="(row, index) in rowItem.outInDetailList" :key="index">
  66. <td style="border: 1px solid #000; padding: 4px; text-align: center;">{{ index + 1 }}</td>
  67. <td style="border: 1px solid #000; padding: 4px; text-align: center;">{{row.categoryModel || '' }}{{ row.categoryModel && row?.specification ? '/' : '' }}{{ row?.specification || '' }}</td>
  68. <td v-if="rowItem.bizType == 6" style="border: 1px solid #000; padding: 4px; text-align: center;">{{ rowItem?.clientName || '' }}</td>
  69. <td style="border: 1px solid #000; padding: 4px; text-align: center;">{{ row?.colorKey || '' }}</td>
  70. <td style="border: 1px solid #000; padding: 4px; text-align: center;">{{ row?.measureUnit || '' }}</td>
  71. <td style="border: 1px solid #000; padding: 4px; text-align: center;">{{ row?.measureQuantity || '' }}</td>
  72. <td style="border: 1px solid #000; padding: 4px; text-align: center;">{{ row?.batchNo || '' }}</td>
  73. <td style="border: 1px solid #000; padding: 4px; text-align: center;"></td>
  74. <td style="border: 1px solid #000; padding: 4px; text-align: center;"></td>
  75. </tr>
  76. <!-- 合计行 -->
  77. <tr>
  78. <td style="border: 1px solid #000; padding: 4px; text-align: center;" colspan="2">合计:</td>
  79. <td v-if="rowItem.bizType == 6" style="border: 1px solid #000; padding: 4px; text-align: center;"></td>
  80. <td style="border: 1px solid #000; padding: 4px; text-align: center;"></td>
  81. <td style="border: 1px solid #000; padding: 4px; text-align: center;"></td>
  82. <td style="border: 1px solid #000; padding: 4px; text-align: center;">{{ getTotalAmount(rowItem) }}</td>
  83. <td style="border: 1px solid #000; padding: 4px; text-align: center;"></td>
  84. <td style="border: 1px solid #000; padding: 4px; text-align: center;"></td>
  85. <td style="border: 1px solid #000; padding: 4px; text-align: center;"></td>
  86. </tr>
  87. </tbody>
  88. </table>
  89. <!-- 签字区域 -->
  90. <div style="margin-top: 20px; display: flex; width: 100%;">
  91. <div style="width: 25%;">
  92. <strong>主管:</strong>{{ rowItem.verifyName || '' }}
  93. </div>
  94. <div style="width: 25%;">
  95. <strong>仓库:</strong>{{ warehouseMap[rowItem.id] || '' }}
  96. </div>
  97. <div style="width: 25%;">
  98. <strong>记账:</strong>{{ rowItem.extInfo?.createUserName || '' }}
  99. </div>
  100. <div style="width: 25%;">
  101. <strong>经手人:</strong>{{ rowItem?.fromUser || '' }}
  102. </div>
  103. </div>
  104. </div>
  105. </div>
  106. <div slot="footer">
  107. <el-button type="primary" @click="exportExcel">导出</el-button>
  108. <el-button @click="print">打印预览</el-button>
  109. <el-button @click="close">关闭</el-button>
  110. </div>
  111. </ele-modal>
  112. </template>
  113. <script>
  114. import storageApi from '@/api/warehouseManagement';
  115. import { saveAs } from 'file-saver';
  116. export default {
  117. name: 'print',
  118. components: {},
  119. props: {
  120. groupName: {
  121. type: String,
  122. default: ''
  123. }
  124. },
  125. data() {
  126. return {
  127. QRvisible: false,
  128. formData: [],
  129. warehouseMap: {}
  130. };
  131. },
  132. methods: {
  133. // 计算单个入库单的总数量
  134. getTotalAmount(rowItem) {
  135. if (!rowItem?.outInDetailList || !Array.isArray(rowItem.outInDetailList)) {
  136. return 0;
  137. }
  138. return rowItem.outInDetailList.reduce((sum, row) => {
  139. const amount = parseFloat(row.measureQuantity || 0);
  140. return sum + (isNaN(amount) ? 0 : amount);
  141. }, 0);
  142. },
  143. async init(ids, rows) {
  144. console.log('ids~~', ids, rows);
  145. // 批量获取每个入库单的详情
  146. const res = await storageApi.getInboundDetailsByIds(ids);
  147. res.map(item => {
  148. item.supplierNames = [...new Set(item.outInDetailList.map(row => row.supplierName || ''))].join(',');
  149. return item
  150. })
  151. this.formData = res;
  152. // 构建仓库映射
  153. this.warehouseMap = {};
  154. rows.forEach((row) => {
  155. this.warehouseMap[row.id] = row.warehouseName || '';
  156. });
  157. console.log('formData', this.formData, this.warehouseMap);
  158. this.QRvisible = true;
  159. },
  160. close() {
  161. this.formData = [];
  162. this.warehouseMap = {};
  163. this.QRvisible = false;
  164. },
  165. print() {
  166. const printSection = document.getElementById('printSectionHt');
  167. // 创建打印任务
  168. const printWindow = window.open('', '_blank');
  169. printWindow.document.open();
  170. printWindow.document.write('<html><head><title>打印预览</title>');
  171. printWindow.document.write(
  172. '<style type="text/css">' +
  173. '@page { size: 24cm 14cm; margin: 0; }' +
  174. 'body { margin: 0; padding: 0; }' +
  175. 'div[style*="page-break-after"] { page-break-after: always; }' +
  176. '</style>'
  177. );
  178. printWindow.document.write('</head><body>');
  179. printWindow.document.write(printSection.innerHTML);
  180. printWindow.document.write('</body></html>');
  181. printWindow.document.close();
  182. printWindow.onload = function () {
  183. printWindow.print();
  184. };
  185. },
  186. exportExcel() {
  187. const border =
  188. 'border-top:1px solid #000;border-right:1px solid #000;border-bottom:1px solid #000;border-left:1px solid #000;';
  189. const cellBase = `${border}padding:4px;mso-number-format:"\\@";vertical-align:middle;text-align:center;mso-horizontal-align:center;`;
  190. const th = `${cellBase}font-weight:bold;font-family:'宋体';font-size:12pt;`;
  191. const td = `${cellBase}font-family:'宋体';font-size:11pt;`;
  192. const labelLeft = `${border}padding:4px;mso-number-format:"\\@";vertical-align:middle;text-align:left;mso-horizontal-align:left;font-family:'宋体';font-size:11pt;`;
  193. const title = `${this.groupName || ''}入库单`;
  194. // 遍历多个单据生成多个表格
  195. let tables = '';
  196. this.formData.forEach((rowItem) => {
  197. const list = rowItem.outInDetailList || [];
  198. const totalAmount = this.getTotalAmount(rowItem);
  199. const warehouseName = this.warehouseMap[rowItem.id] || '';
  200. const isBizType6 = rowItem.bizType == 6;
  201. const supplierValue = rowItem.supplierNames || '';
  202. const totalCols = isBizType6 ? 9 : 8;
  203. const colWidths = isBizType6
  204. ? [55, 200, 100, 70, 70, 70, 80, 70, 80]
  205. : [55, 200, 70, 70, 70, 80, 70, 80];
  206. const colGroup = colWidths
  207. .map((w) => `<col width="${w}" style="width:${w}pt;" />`)
  208. .join('');
  209. const customerTh = isBizType6
  210. ? `<td align="center" valign="middle" style="${th}">客户</td>`
  211. : '';
  212. const rows = list
  213. .map(
  214. (item, index) => `
  215. <tr height="24" style="height:24pt;">
  216. <td align="center" valign="middle" style="${td}">${index + 1}</td>
  217. <td align="center" valign="middle" style="${td}">${item.categoryModel || ''}${item.categoryModel && item.specification ? '/' : ''}${item.specification || ''}</td>
  218. ${isBizType6 ? `<td align="center" valign="middle" style="${td}">${rowItem?.clientName || ''}</td>` : ''}
  219. <td align="center" valign="middle" style="${td}">${item.colorKey || ''}</td>
  220. <td align="center" valign="middle" style="${td}">${item.measureUnit || ''}</td>
  221. <td align="center" valign="middle" style="${td}">${item.measureQuantity || ''}</td>
  222. <td align="center" valign="middle" style="${td}">${item.batchNo || ''}</td>
  223. <td align="center" valign="middle" style="${td}"></td>
  224. <td align="center" valign="middle" style="${td}"></td>
  225. </tr>`
  226. )
  227. .join('');
  228. const customerEmpty = isBizType6
  229. ? '<td align="center" valign="middle" style="${td}"></td>'
  230. : '';
  231. tables += `
  232. <table border="1" cellspacing="0" cellpadding="0" align="center"
  233. style="border-collapse:collapse;border:1px solid #000;mso-border-alt:solid #000 0.5pt;font-family:'宋体';font-size:11pt;text-align:center;">
  234. <colgroup>${colGroup}</colgroup>
  235. <tr height="40" style="height:40pt;">
  236. <td colspan="${totalCols}" align="center" valign="middle" style="${border}padding:6px;text-align:center;font-family:'宋体';font-size:22pt;font-weight:bold;">${title}</td>
  237. </tr>
  238. <tr height="26" style="height:26pt;">
  239. <td colspan="${isBizType6 ? 3 : 3}" align="left" valign="middle" style="${labelLeft}">供应商名称:${supplierValue}</td>
  240. <td align="left" valign="middle" style="${labelLeft}">日期:${rowItem.storageTime || ''}</td>
  241. <td colspan="${isBizType6 ? 3 : 2}" align="left" valign="middle" style="${labelLeft}">编号:${rowItem.bizNo || ''}</td>
  242. </tr>
  243. <tr height="28" style="height:28pt;">
  244. <td align="center" valign="middle" style="${th}">编号</td>
  245. <td align="center" valign="middle" style="${th}">型号规格</td>
  246. ${customerTh}
  247. <td align="center" valign="middle" style="${th}">颜色</td>
  248. <td align="center" valign="middle" style="${th}">单位</td>
  249. <td align="center" valign="middle" style="${th}">入库数量</td>
  250. <td align="center" valign="middle" style="${th}">批次号</td>
  251. <td align="center" valign="middle" style="${th}">单价</td>
  252. <td align="center" valign="middle" style="${th}">金额</td>
  253. </tr>
  254. ${rows}
  255. <tr height="26" style="height:26pt;">
  256. <td colspan="2" align="center" valign="middle" style="${td};font-weight:bold;">合计:</td>
  257. ${customerEmpty}
  258. <td align="center" valign="middle" style="${td}"></td>
  259. <td align="center" valign="middle" style="${td}"></td>
  260. <td align="center" valign="middle" style="${td};font-weight:bold;">${totalAmount}</td>
  261. <td align="center" valign="middle" style="${td}"></td>
  262. <td align="center" valign="middle" style="${td}"></td>
  263. <td align="center" valign="middle" style="${td}"></td>
  264. </tr>
  265. <tr height="28" style="height:28pt;">
  266. <td align="left" valign="middle" style="${labelLeft}">主管:${rowItem.verifyName || ''}</td>
  267. <td align="left" valign="middle" style="${labelLeft}">仓库:${warehouseName}</td>
  268. <td align="left" valign="middle" style="${labelLeft}">记账:${rowItem.extInfo?.createUserName || ''}</td>
  269. <td colspan="${isBizType6 ? 6 : 5}" align="left" valign="middle" style="${labelLeft}">经手人:${rowItem.fromUser || ''}</td>
  270. </tr>
  271. </table>
  272. <br style="mso-special-character:line-break;page-break-before:always" />`;
  273. });
  274. const html = `<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40">
  275. <head>
  276. <meta charset="UTF-8" />
  277. <style>
  278. br { mso-data-placement: same-cell; }
  279. table { mso-displayed-decimal-separator:"."; mso-displayed-thousand-separator:","; }
  280. td { mso-ignore:padding; }
  281. </style>
  282. <!--[if gte mso 9]><xml>
  283. <x:ExcelWorkbook><x:ExcelWorksheets><x:ExcelWorksheet>
  284. <x:Name>${title}</x:Name>
  285. <x:WorksheetOptions>
  286. <x:DefaultRowHeight>260</x:DefaultRowHeight>
  287. <x:Print><x:ValidPrinterInfo/><x:HorizontalResolution>600</x:HorizontalResolution><x:VerticalResolution>600</x:VerticalResolution></x:Print>
  288. <x:Selected/>
  289. <x:DoNotDisplayGridlines/>
  290. </x:WorksheetOptions>
  291. </x:ExcelWorksheet></x:ExcelWorksheets></x:ExcelWorkbook>
  292. </xml><![endif]-->
  293. </head>
  294. <body>${tables}</body></html>`;
  295. const blob = new Blob(['\uFEFF' + html], {
  296. type: 'application/vnd.ms-excel;charset=utf-8'
  297. });
  298. const firstBizNo = this.formData[0]?.bizNo || '';
  299. const suffix = this.formData.length > 1 ? `等${this.formData.length}条` : firstBizNo;
  300. saveAs(blob, `${title}_${suffix}.xls`);
  301. }
  302. }
  303. };
  304. </script>
  305. <style scoped lang="scss">
  306. table {
  307. border-collapse: collapse;
  308. }
  309. th, td {
  310. border: 1px solid #000;
  311. text-align: center;
  312. padding: 8px;
  313. }
  314. @media print {
  315. .no-print {
  316. display: none;
  317. }
  318. }
  319. </style>