LsYzPrint.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562
  1. <template>
  2. <el-container>
  3. <el-aside width="210px">
  4. <PatientBaseList
  5. :yzType="yzType"
  6. @selectPatientInfo="selectPatientInfo"
  7. ></PatientBaseList>
  8. </el-aside>
  9. <el-container>
  10. <el-header style="height: 150px">
  11. <PatientInfo :patientInfo="patientInfo"></PatientInfo>
  12. </el-header>
  13. <div>
  14. <el-row>
  15. <el-col :span="8">
  16. <el-button icon="Search" type="primary" @click="queryInfo"
  17. >查询</el-button
  18. >
  19. <el-button icon="Printer" type="success" @click="handlePrint(false)"
  20. >打印预览</el-button
  21. >
  22. <el-button icon="Printer" type="success" @click="handlePrint(true)"
  23. >打印</el-button
  24. >
  25. </el-col>
  26. <el-col :span="8">
  27. <el-radio-group
  28. @change="initPageNumList"
  29. v-model="yzOrderParam.printType"
  30. >
  31. <el-radio :label="1">打印新增</el-radio>
  32. <el-radio :label="2">打印单页</el-radio>
  33. <el-radio :label="3">打印某页后</el-radio>
  34. </el-radio-group>
  35. </el-col>
  36. <el-col :span="4">
  37. 医嘱页号:
  38. <el-select
  39. v-model="yzOrderParam.pageNum"
  40. placeholder="请选择"
  41. style="width: 60px"
  42. >
  43. <el-option
  44. v-for="item in pageNumList"
  45. :key="item.code"
  46. :label="item.name"
  47. :value="item.code"
  48. ></el-option>
  49. </el-select>
  50. </el-col>
  51. <el-col :span="4">
  52. <el-button type="primary" @click="clearPrintPageClick"
  53. >清空打印页号</el-button
  54. >
  55. </el-col>
  56. </el-row>
  57. </div>
  58. <el-main>
  59. <el-scrollbar height="100%">
  60. <div id="cqYz">
  61. <table id="pageTable">
  62. <thead>
  63. <tr>
  64. <td
  65. colspan="7"
  66. style="
  67. width: 100%;
  68. text-align: center;
  69. padding: 16px 0;
  70. border: none;
  71. font-size: 23px;
  72. font-weight: bold;
  73. "
  74. >
  75. {{ env.VITE_HOSPITAL_NAME }}<br />临时医嘱单
  76. </td>
  77. </tr>
  78. <tr>
  79. <td colspan="7" style="border: none">
  80. <div>
  81. <div style="width: 15%;float: left;">姓名:{{ patientInfo.name }}</div>
  82. <div style="width: 15%;float: left;">
  83. 性别:{{ patientInfo.sexName }}
  84. </div>
  85. <div style="width: 15%;float: left;">
  86. 年龄:{{ companyFunc(patientInfo.age, "岁") }}
  87. </div>
  88. <div style="width: 15%;float: left;">
  89. 科别:{{ patientInfo.admissWardName }}
  90. </div>
  91. <div style="width: 18%;float: left;">
  92. 床号:{{ patientInfo.bedNo }}
  93. </div>
  94. <div>住院号:{{ patientInfo.inpatientNo }}</div>
  95. </div>
  96. </td>
  97. </tr>
  98. <tr>
  99. <th style="width: 60px; height: 40px">日期</th>
  100. <th style="width: 60px">时间</th>
  101. <th>临时医嘱</th>
  102. <th style="width: 85px">医师签名</th>
  103. <th style="width: 85px">核对护士签名</th>
  104. <th style="width: 120px">执行时间</th>
  105. <th style="width: 85px">执行护士签名</th>
  106. </tr>
  107. </thead>
  108. <tbody>
  109. <tr v-for="(item, index) in yzPrintVOList" :key="index">
  110. <td
  111. v-if="item.pageFlag == '1'"
  112. style="border: none"
  113. colspan="7"
  114. >
  115. 第{{ item.printPageOnce }}页
  116. </td>
  117. <td v-if="item.pageFlag != '1'" style="height: 41px">
  118. {{ item.date }}
  119. </td>
  120. <td v-if="item.pageFlag != '1'">{{ item.time }}</td>
  121. <td v-if="item.pageFlag != '1'" style="text-align: left">
  122. {{ item.orderGroupNo }} {{ item.newOrderName }}
  123. {{ item.newOrderNameCode }} {{ item.frequCode }}
  124. </td>
  125. <td v-if="item.pageFlag != '1'" style="text-align: left">
  126. <img v-if="item.doctorCode" style="width: 60px;" :src="getSign(item.doctorCode)"/>
  127. </td>
  128. <td v-if="item.pageFlag != '1'" style="text-align: left">
  129. <img v-if="item.nurseCode" style="width: 60px;" :src="getSign(item.nurseCode)"/>
  130. </td>
  131. <td v-if="item.pageFlag != '1'">{{ item.execTimeStr }}</td>
  132. <td v-if="item.pageFlag != '1'" style="text-align: left">
  133. <img v-if="item.execId" style="width: 60px;" :src="getSign(item.execId)"/>
  134. </td>
  135. </tr>
  136. </tbody>
  137. </table>
  138. </div>
  139. </el-scrollbar>
  140. </el-main>
  141. </el-container>
  142. </el-container>
  143. </template>
  144. <script setup name="lsYzPrint">
  145. import PatientInfo from "@/components/medical-advice/PatientInfo.vue";
  146. import PatientBaseList from "@/components/medical-advice/PatientBaseList.vue";
  147. import {
  148. lsYzPrint,
  149. getTotalPageNUm,
  150. recPrint,
  151. clearPrintPageNo,
  152. } from "@/api/medical-advice/medical-advice-management";
  153. import { getLodop, initLodop } from "@/utils/c-lodop";
  154. import { onMounted } from "vue";
  155. import { stringNotBlank } from "@/utils/blank-utils";
  156. import { ElMessage, ElMessageBox } from "element-plus";
  157. import env from "../../../utils/setting";
  158. // 基本信息
  159. const patientInfo = ref({});
  160. const yzType = ref("cq");
  161. const yzPrintVOList = ref([]);
  162. const companyFunc = (val, company) => {
  163. if (stringNotBlank(val)) {
  164. return val + company;
  165. } else {
  166. return "";
  167. }
  168. };
  169. const yzOrderParam = ref({
  170. patNo: "",
  171. times: null,
  172. inOutStatusFlag: "",
  173. type: 2,
  174. printType: 1,
  175. pageNum: "",
  176. });
  177. const pageNumList = ref([]);
  178. const getSign = (code) => {
  179. // return env.RESOURCE_BASE_URL + "/doctorSignatureImage/" + code + ".png";
  180. return "http://130.150.161.72:8080" + "/doctorSignatureImage/" + code + ".png";
  181. }
  182. //
  183. const initPageNumList = () => {
  184. yzOrderParam.value.pageNum = "";
  185. yzPrintVOList.value = [];
  186. if (yzOrderParam.value.printType === 1) {
  187. pageNumList.value = [];
  188. return;
  189. }
  190. getTotalPageNUm(yzOrderParam.value).then(res => {
  191. if (res.total) {
  192. pageNumList.value = [];
  193. for (let i = 0; i < res.total; i++) {
  194. let param = { code: i + 1 + "", name: i + 1 + "" };
  195. pageNumList.value.push(param);
  196. }
  197. } else {
  198. pageNumList.value = [];
  199. }
  200. });
  201. };
  202. const yzPrintCss = `
  203. #pageTable tr td, #pageTable tr th {
  204. border: 1px solid black;
  205. text-align: center;
  206. font-size: 12px;
  207. padding: 0 0;
  208. }
  209. #pageTable tr td{
  210. height: 27px;
  211. }
  212. #pageTable {
  213. border-collapse: collapse;
  214. }
  215. `;
  216. //清空
  217. const clearPrintPageClick = () => {
  218. clearPrintPageNo(yzOrderParam.value).then(res => {
  219. yzPrintVOList.value = [];
  220. pageNumList.value = [];
  221. });
  222. };
  223. const selectPatientInfo = val => {
  224. if (!stringNotBlank(val.patientInfo.inpatientNo)) {
  225. return ElMessage.error("请选中一个病人");
  226. }
  227. yzOrderParam.value.patNo = val.patientInfo.inpatientNo;
  228. yzOrderParam.value.times = val.patientInfo.admissTimes;
  229. yzOrderParam.value.inOutStatusFlag = val.inOutStatusFlag;
  230. clearInfo();
  231. };
  232. const queryInfo = () => {
  233. lsYzPrint(yzOrderParam.value).then(res => {
  234. patientInfo.value = res.patientInfo;
  235. yzPrintVOList.value = res.yzPrintVOList;
  236. });
  237. };
  238. const clearInfo = () => {
  239. yzPrintVOList.value = [];
  240. yzOrderParam.value.pageNum = "";
  241. yzOrderParam.value.printType = 1;
  242. pageNumList.value = [];
  243. };
  244. onMounted(() => {
  245. initLodop();
  246. });
  247. const daYingClick = () => {
  248. let LODOP = getLodop();
  249. LODOP.PRINT_INIT("长期医嘱单"); // 初始化打印机 名字
  250. LODOP.SET_PRINT_PAGESIZE(1, "210mm", "297mm", ""); // 设置纸张大小 A4
  251. LODOP.SET_PRINT_MODE("FULL_WIDTH_FOR_OVERFLOW", true); // 整宽不变形
  252. LODOP.ADD_PRINT_TABLE(
  253. "2mm",
  254. "5mm",
  255. "205mm",
  256. "220mm",
  257. "<style>" +
  258. yzPrintCss +
  259. "</style>" +
  260. "<body>" +
  261. document.getElementById("cqYz").innerHTML +
  262. "</body>"
  263. ); //要打印的内容
  264. LODOP.PREVIEW(); // 关闭
  265. };
  266. const printClick = () => {
  267. if (yzPrintVOList.value.length <= 0) {
  268. return ElMessage.error("没有打印数据");
  269. }
  270. if (yzOrderParam.value.printType === 1) {
  271. recPrint(yzOrderParam.value).then(res => {});
  272. }
  273. let LODOP = getLodop();
  274. LODOP.PRINT_INIT("长期医嘱单"); // 初始化打印机 名字
  275. LODOP.SET_PRINT_PAGESIZE(1, "210mm", "297mm", ""); // 设置纸张大小 A4
  276. LODOP.SET_PRINT_MODE("FULL_WIDTH_FOR_OVERFLOW", true); // 整宽不变形
  277. LODOP.ADD_PRINT_TABLE(
  278. "2mm",
  279. "5mm",
  280. "205mm",
  281. "220mm",
  282. "<style>" +
  283. yzPrintCss +
  284. "</style>" +
  285. "<body>" +
  286. document.getElementById("cqYz").innerHTML +
  287. "</body>"
  288. ); //要打印的内容
  289. LODOP.PRINT(); // 关闭
  290. queryInfo();
  291. };
  292. const print = (type) => {
  293. // 获取要打印的元素
  294. const printContent = document.getElementById('cqYz');
  295. if (!printContent) {
  296. console.error('未找到id为cqYz的元素');
  297. return;
  298. }
  299. // 创建打印窗口
  300. const printWindow = window.open('', '_blank');
  301. // 复制文档头部信息(确保样式生效)
  302. printWindow.document.head.innerHTML = document.head.innerHTML;
  303. // 创建打印区域
  304. printWindow.document.body.innerHTML = `
  305. <div class="print-container">
  306. ${printContent.outerHTML}
  307. </div>
  308. `;
  309. // 等待内容加载完成后执行打印
  310. if(type) {
  311. setTimeout(() => {
  312. printWindow.print();
  313. // 打印后关闭窗口
  314. printWindow.close();
  315. }, 100);
  316. }
  317. };
  318. const handlePrint = async (type) => {
  319. await nextTick();
  320. const printContent = document.getElementById('cqYz');
  321. if (!printContent) {
  322. console.error('未找到打印容器');
  323. return;
  324. }
  325. // 克隆原始内容
  326. const clonedContent = printContent.cloneNode(true);
  327. // 精确控制边框显示
  328. adjustBorders(clonedContent);
  329. // 等待图片加载
  330. await waitForImages(clonedContent);
  331. const printWindow = window.open('', '_blank');
  332. if (!printWindow) {
  333. alert('请允许弹出窗口以完成打印');
  334. return;
  335. }
  336. // 复制原页面样式
  337. const stylesheets = Array.from(document.styleSheets)
  338. .map(style => {
  339. try {
  340. if (style.href) return `<link rel="stylesheet" href="${style.href}">`;
  341. const rules = Array.from(style.cssRules).map(rule => rule.cssText).join('\n');
  342. return `<style>${rules}</style>`;
  343. } catch (e) {
  344. return '';
  345. }
  346. })
  347. .join('\n');
  348. // 打印专用样式
  349. const printSpecificCss = `
  350. @page {
  351. size: auto;
  352. margin: 10mm;
  353. }
  354. /* 根元素背景色设置 */
  355. html, body {
  356. background-color: #fff !important;
  357. -webkit-print-color-adjust: exact !important;
  358. print-color-adjust: exact !important;
  359. margin: 0 !important;
  360. padding: 0 !important;
  361. }
  362. @media print {
  363. .print-btn {
  364. display: none !important;
  365. }
  366. #pageTable {
  367. border-collapse: collapse !important;
  368. width: 100% !important;
  369. }
  370. /* 强制打印所有背景色 */
  371. * {
  372. -webkit-print-color-adjust: exact !important;
  373. print-color-adjust: exact !important;
  374. }
  375. /* 确保表格背景为白色 */
  376. #pageTable {
  377. background-color: #fff !important;
  378. }
  379. }
  380. `;
  381. // 构建打印页面
  382. printWindow.document.write(`
  383. <!DOCTYPE html>
  384. <html>
  385. <head>
  386. <meta charset="UTF-8">
  387. ${stylesheets}
  388. <style>${printSpecificCss}</style>
  389. </head>
  390. <body style="margin: 0; padding: 0;">
  391. ${clonedContent.outerHTML}
  392. </body>
  393. </html>
  394. `);
  395. printWindow.document.close();
  396. // 执行打印
  397. if(type) {
  398. printWindow.onload = () => {
  399. setTimeout(() => {
  400. printWindow.print();
  401. printWindow.onafterprint = () => printWindow.close();
  402. }, 300);
  403. };
  404. }
  405. };
  406. // 精确调整边框显示
  407. const adjustBorders = (element) => {
  408. // 1. 表头处理
  409. const thead = element.querySelector('thead');
  410. if (thead) {
  411. // 获取表头所有行
  412. const theadRows = thead.querySelectorAll('tr');
  413. // 第一个tr(标题行):强制无边框
  414. if (theadRows[0]) {
  415. const firstRowCells = theadRows[0].querySelectorAll('td');
  416. firstRowCells.forEach(cell => {
  417. cell.style.border = 'none !important';
  418. // 确保没有继承其他边框样式
  419. cell.style.borderTop = 'none !important';
  420. cell.style.borderBottom = 'none !important';
  421. });
  422. }
  423. // 第二个tr(患者信息行):保持无边框
  424. if (theadRows[1]) {
  425. const infoRowCells = theadRows[1].querySelectorAll('td');
  426. infoRowCells.forEach(cell => {
  427. cell.style.border = 'none !important';
  428. });
  429. }
  430. // 第三个tr(列标题行):添加边框
  431. if (theadRows[2]) {
  432. const columnHeaders = theadRows[2].querySelectorAll('th');
  433. columnHeaders.forEach(header => {
  434. header.style.border = '1px solid #000 !important';
  435. // 保留原有高度设置
  436. header.style.height = header.style.height || '40px';
  437. });
  438. }
  439. }
  440. // 2. 表体处理
  441. const tbody = element.querySelector('tbody');
  442. if (tbody) {
  443. const tbodyCells = tbody.querySelectorAll('td');
  444. tbodyCells.forEach(cell => {
  445. // 页码行:无边框
  446. if (cell.hasAttribute('colspan') && cell.colSpan >= 7) {
  447. cell.style.border = 'none !important';
  448. }
  449. // 数据行:有边框
  450. else {
  451. cell.style.border = '1px solid #000 !important';
  452. }
  453. });
  454. }
  455. };
  456. // 等待图片加载
  457. const waitForImages = (element) => {
  458. const images = element.querySelectorAll('img');
  459. if (images.length === 0) return Promise.resolve();
  460. const promises = Array.from(images).map(img => {
  461. return new Promise(resolve => {
  462. if (img.complete) resolve();
  463. img.onload = resolve;
  464. img.onerror = resolve;
  465. });
  466. });
  467. return Promise.all(promises);
  468. };
  469. </script>
  470. <style scoped>
  471. .nav {
  472. margin: 0 auto;
  473. width: 100%;
  474. }
  475. ul {
  476. list-style: none;
  477. width: 100%;
  478. }
  479. .nav li {
  480. float: left;
  481. margin-left: 10px;
  482. }
  483. #cqYz {
  484. width: 753px;
  485. height: 100%;
  486. padding: 0 0px;
  487. background: #fff;
  488. }
  489. #pageTable tr td,
  490. #pageTable tr th {
  491. border: 1px solid black;
  492. text-align: center;
  493. font-size: 12px;
  494. }
  495. #pageTable {
  496. border-collapse: collapse;
  497. }
  498. #pageTable tr td {
  499. height: 27px;
  500. }
  501. .print-btn {
  502. margin: 20px;
  503. padding: 8px 16px;
  504. background-color: #42b983;
  505. color: white;
  506. border: none;
  507. border-radius: 4px;
  508. cursor: pointer;
  509. }
  510. </style>