SettlementDialog.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  1. <template>
  2. <el-dialog
  3. v-model="dialogVisible"
  4. title="领取设备结算单"
  5. width="75%"
  6. :close-on-click-modal="false"
  7. @close="handleClose"
  8. >
  9. <!-- <div class="title">
  10. <img src="../../../../../assets/u2855.svg" alt="">
  11. <span>已领取</span>
  12. </div> -->
  13. <div ref="printContent" class="print-container">
  14. <el-form :model="formData" label-width="110px" label-position="top" class="print-form">
  15. <el-row :gutter="16">
  16. <el-col :span="8">
  17. <el-form-item label="借用单编号">
  18. <div class="form-content">{{ formData.application_no }}</div>
  19. </el-form-item>
  20. </el-col>
  21. <el-col :span="8">
  22. <el-form-item label="借用人">
  23. <div class="form-content">{{ name }}</div>
  24. </el-form-item>
  25. </el-col>
  26. <el-col :span="8">
  27. <el-form-item label="学号/工号">
  28. <div class="form-content">{{ userCode }}</div>
  29. </el-form-item>
  30. </el-col>
  31. </el-row>
  32. <el-row :gutter="16">
  33. <el-col :span="8">
  34. <el-form-item label="借用性质">
  35. <div class="form-content">{{ borrowType }}</div>
  36. </el-form-item>
  37. </el-col>
  38. <el-col :span="8">
  39. <el-form-item label="借出时间">
  40. <div class="form-content">{{ formData.expected_start_time }}</div>
  41. </el-form-item>
  42. </el-col>
  43. <el-col :span="8">
  44. <el-form-item label="预计归还时间">
  45. <div class="form-content">{{ formData.expected_end_time }}</div>
  46. </el-form-item>
  47. </el-col>
  48. </el-row>
  49. <div class="detail-title">借用明细表</div>
  50. <div class="table-container">
  51. <table class="detail-table">
  52. <thead>
  53. <tr>
  54. <th width="60">序号</th>
  55. <th>设备编号</th>
  56. <th>设备分类</th>
  57. <th>设备名称</th>
  58. <th>借用数量</th>
  59. <th>规格型号</th>
  60. <th>存放位置</th>
  61. <th>备注</th>
  62. </tr>
  63. </thead>
  64. <tbody>
  65. <tr v-for="(item, index) in filteredItems" :key="index">
  66. <td>{{ index + 1 }}</td>
  67. <td>{{ item.device_code }}</td>
  68. <td>{{ item.device_category_name }}</td>
  69. <td>{{ item.device_name }}</td>
  70. <td>{{ item.quantity }}</td>
  71. <td>{{ item.device_specification }}</td>
  72. <td>{{ item.device_storage_location || '-' }}</td>
  73. <td>{{ item.remark || '-' }}</td>
  74. </tr>
  75. </tbody>
  76. </table>
  77. </div>
  78. <div class="accessories-info">
  79. <div class="detail-title">配件信息</div>
  80. <div class="form-content">{{ formData.accessories || '-' }}</div>
  81. </div>
  82. <div class="remark-info">
  83. <div class="detail-title">备注</div>
  84. <div class="form-content">{{ formData.remark || '-' }}</div>
  85. </div>
  86. </el-form>
  87. </div>
  88. <template #footer>
  89. <el-button @click="handleClose">关闭</el-button>
  90. <el-button type="primary" @click="handlePrint">打印</el-button>
  91. </template>
  92. </el-dialog>
  93. </template>
  94. <script setup lang="ts">
  95. import { ref, defineProps, defineEmits, watch, computed } from 'vue';
  96. import { ElMessage } from 'element-plus';
  97. const props = defineProps<{
  98. visible: boolean;
  99. settlementData: any;
  100. modelValue: any;
  101. }>();
  102. const emit = defineEmits(['update:visible', 'update:modelValue']);
  103. const dialogVisible = ref(false);
  104. const formData = ref<any>({});
  105. watch(
  106. () => props.visible,
  107. (val) => {
  108. dialogVisible.value = val;
  109. if (val) {
  110. // 优先使用 modelValue,如果没有则使用 settlementData
  111. formData.value = props.modelValue || props.settlementData || {};
  112. }
  113. }
  114. );
  115. watch(
  116. () => props.modelValue,
  117. (val) => {
  118. console.log("val:::",val);
  119. if (val) {
  120. /* formData.value.app_user_borrower = val.borrower_info.user_code; */
  121. formData.value = val;
  122. console.log("formData.value:::",formData.value);
  123. }
  124. },
  125. { immediate: true }
  126. );
  127. const name = computed(() => {
  128. return formData.value?.app_user_borrower?.name || formData.value?.borrower_info?.name || '';
  129. });
  130. const userCode = computed(() => {
  131. return formData.value?.app_user_borrower?.user_code || formData.value?.borrower_info?.user_code || '';
  132. });
  133. const borrowType=computed(() => {
  134. return formData.value?.borrow_type_label || formData.value?.borrow_type || '';
  135. });
  136. interface DeviceItem {
  137. device_code: string;
  138. device_category_name: string;
  139. device_name: string;
  140. quantity: number;
  141. device_specification: string;
  142. device_storage_location?: string;
  143. remark?: string;
  144. }
  145. const filteredItems = computed(() => {
  146. return formData.value?.items?.filter((item: DeviceItem | null) => item?.device !== null) || [];
  147. });
  148. const handleClose = () => {
  149. emit('update:visible', false);
  150. emit('update:modelValue', formData.value);
  151. };
  152. /* const handlePrint = () => {
  153. window.print();
  154. }; */
  155. // 定义打印区域的ref
  156. const printContent = ref<HTMLElement | null>(null);
  157. const handlePrint = () => {
  158. try {
  159. if (!printContent.value) {
  160. ElMessage.error('打印区域未找到');
  161. return;
  162. }
  163. // 1. 克隆打印区域内容
  164. const printElement = printContent.value.cloneNode(true);
  165. // 2. 创建打印专用iframe
  166. const iframe = document.createElement('iframe');
  167. iframe.style.position = 'absolute';
  168. iframe.style.width = '0px';
  169. iframe.style.height = '0px';
  170. iframe.style.left = '-9999px';
  171. document.body.appendChild(iframe);
  172. // 确保iframe和其document已经准备好
  173. if (!iframe.contentWindow || !iframe.contentWindow.document) {
  174. throw new Error('iframe初始化失败');
  175. }
  176. const printDocument = iframe.contentWindow.document;
  177. // 3. 添加打印样式
  178. printDocument.write(`
  179. <!DOCTYPE html>
  180. <html>
  181. <head>
  182. <meta charset="utf-8">
  183. <title>设备借用单打印</title>
  184. <style>
  185. /* 打印样式 */
  186. @media print {
  187. body {
  188. font-family: Arial, sans-serif;
  189. padding: 20px;
  190. margin: 0;
  191. }
  192. .no-print {
  193. display: none !important;
  194. }
  195. /* 表单布局优化 */
  196. .el-form {
  197. width: 100%;
  198. }
  199. .el-row {
  200. display: flex !important;
  201. flex-wrap: nowrap !important;
  202. margin: 0 -8px;
  203. }
  204. .el-col {
  205. padding: 0 8px;
  206. flex: 1;
  207. }
  208. /* 表单项样式 */
  209. .el-form-item {
  210. margin-bottom: 12px;
  211. page-break-inside: avoid;
  212. }
  213. .el-form-item__label {
  214. font-weight: bold;
  215. margin-bottom: 4px;
  216. display: block;
  217. }
  218. .el-form-item__content {
  219. line-height: 1.5;
  220. }
  221. /* 表格样式优化 */
  222. table {
  223. page-break-inside: auto;
  224. width: 100% !important;
  225. border-collapse: collapse;
  226. margin: 20px 0;
  227. table-layout: fixed;
  228. }
  229. tr {
  230. page-break-inside: avoid;
  231. page-break-after: auto;
  232. }
  233. th, td {
  234. border: 1px solid #000;
  235. padding: 8px;
  236. text-align: center;
  237. word-break: break-all;
  238. }
  239. /* 隐藏Element Plus的默认样式 */
  240. .el-input__inner {
  241. border: none !important;
  242. padding: 0 !important;
  243. }
  244. .el-form--label-top .el-form-item__label {
  245. padding: 0;
  246. }
  247. /* 标题样式 */
  248. h2 {
  249. text-align: center;
  250. margin-bottom: 30px;
  251. font-size: 24px;
  252. }
  253. /* 明细表标题 */
  254. .detail-title {
  255. font-weight: bold;
  256. margin: 20px 0 10px;
  257. font-size: 16px;
  258. }
  259. /* 配件信息和备注 */
  260. .accessories-info,
  261. .remark-info {
  262. margin-top: 20px;
  263. }
  264. .accessories-info .el-input,
  265. .remark-info .el-input {
  266. width: 100%;
  267. }
  268. }
  269. /* 屏幕预览样式 */
  270. @media screen {
  271. body {
  272. background-color: #fff;
  273. padding: 20px;
  274. }
  275. }
  276. </style>
  277. </head>
  278. <body>
  279. <h2 style="text-align: center; margin-bottom: 30px;">设备借用单</h2>
  280. </body>
  281. </html>
  282. `);
  283. // 4. 插入内容并添加打印类
  284. const body = printDocument.body;
  285. body.appendChild(printElement);
  286. // 5. 添加打印按钮(仅屏幕显示)
  287. const printBtn = printDocument.createElement('button');
  288. printBtn.className = 'no-print';
  289. printBtn.textContent = '打印';
  290. printBtn.style.cssText = `
  291. position: fixed;
  292. top: 20px;
  293. right: 20px;
  294. padding: 10px 20px;
  295. background: #409EFF;
  296. color: white;
  297. border: none;
  298. border-radius: 4px;
  299. cursor: pointer;
  300. z-index: 9999;
  301. `;
  302. printBtn.onclick = () => {
  303. try {
  304. if (iframe.contentWindow) {
  305. iframe.contentWindow.print();
  306. } else {
  307. throw new Error('打印窗口未准备好');
  308. }
  309. } catch (error) {
  310. console.error('打印过程出错:', error);
  311. ElMessage.error('打印失败,请重试');
  312. }
  313. };
  314. body.appendChild(printBtn);
  315. // 6. 自动触发打印
  316. if (iframe.contentWindow) {
  317. iframe.contentWindow.focus();
  318. setTimeout(() => {
  319. try {
  320. if (iframe.contentWindow) {
  321. iframe.contentWindow.print();
  322. } else {
  323. throw new Error('打印窗口未准备好');
  324. }
  325. } catch (error) {
  326. console.error('打印过程出错:', error);
  327. ElMessage.error('打印失败,请重试');
  328. } finally {
  329. // 确保iframe被移除
  330. document.body.removeChild(iframe);
  331. }
  332. }, 500);
  333. } else {
  334. throw new Error('打印窗口未准备好');
  335. }
  336. } catch (error) {
  337. console.error('打印准备过程出错:', error);
  338. ElMessage.error('打印准备失败,请重试');
  339. }
  340. };
  341. </script>
  342. <style scoped>
  343. @media print {
  344. .el-dialog__footer {
  345. display: none;
  346. }
  347. }
  348. .print-container {
  349. padding: 20px;
  350. }
  351. .print-form {
  352. width: 100%;
  353. }
  354. .form-content {
  355. min-height: 20px;
  356. line-height: 20px;
  357. padding: 4px 0;
  358. }
  359. .detail-title {
  360. font-weight: bold;
  361. margin: 20px 0 10px;
  362. font-size: 16px;
  363. }
  364. .table-container {
  365. margin: 20px 0;
  366. width: 100%;
  367. overflow-x: auto;
  368. }
  369. .detail-table {
  370. width: 100%;
  371. border-collapse: collapse;
  372. table-layout: fixed;
  373. }
  374. .detail-table th,
  375. .detail-table td {
  376. border: 1px solid #000;
  377. padding: 8px;
  378. text-align: center;
  379. word-break: break-all;
  380. }
  381. .detail-table th {
  382. background-color: #f5f7fa;
  383. font-weight: bold;
  384. }
  385. .accessories-info,
  386. .remark-info {
  387. margin-top: 20px;
  388. }
  389. .form-content {
  390. /* border: 1px solid #dcdfe6; */
  391. padding: 8px;
  392. min-height: 32px;
  393. line-height: 1.5;
  394. border-radius: 4px;
  395. }
  396. @media print {
  397. .print-container {
  398. padding: 0;
  399. }
  400. .form-content {
  401. border: none;
  402. padding: 4px 0;
  403. }
  404. .el-form-item {
  405. margin-bottom: 16px !important;
  406. }
  407. .el-form-item__label {
  408. color: #000 !important;
  409. line-height: 1.5 !important;
  410. }
  411. .detail-table th {
  412. background-color: #fff !important;
  413. }
  414. /* 确保分页时表头重复 */
  415. thead {
  416. display: table-header-group;
  417. }
  418. /* 避免元素被分页截断 */
  419. tr, .el-form-item, .accessories-info, .remark-info {
  420. page-break-inside: avoid;
  421. }
  422. }
  423. .title {
  424. display: flex;
  425. justify-content: flex-end;
  426. position: relative;
  427. }
  428. .title span {
  429. position: absolute;
  430. right: 10px;
  431. bottom: 30%;
  432. align-self: flex-start;
  433. padding: 0;
  434. box-sizing: border-box;
  435. transform: rotate(315deg);
  436. font-family: "Impact Bold", "Impact Normal", "Impact", sans-serif;
  437. font-weight: 700;
  438. font-style: normal;
  439. font-size: 17px;
  440. color: #F77105;
  441. }
  442. </style>