import QRCode from 'qrcode'; // 二维码生成库 import { ElDialog, ElButton, ElMessage ,ElImage,ElMessageBox } from 'element-plus';// 引入ElMessage,解决提示无反应 import { h,createVNode, render } from 'vue'; //此js文件是用来自定义扩展业务代码,可以扩展一些自定义页面或者重新配置生成的代码 let extension = { components: { //查询界面扩展组件 gridHeader: '', gridBody: '', gridFooter: '', //新建、编辑弹出框扩展组件 modelHeader: '', modelBody: '', modelFooter: '' }, tableAction: '', //指定某张表的权限(这里填写表名,默认不用填写) buttons: { view: [{ name: '生成二维码', type: 'success', value: '生成二维码', onClick: async function () { // 1. 校验选中行 const selectedRows = this.$refs.table.getSelected(); if (selectedRows.length === 0) { ElMessage.warning('请先选择一行数据'); return; } if (selectedRows.length > 1) { ElMessage.warning('仅支持选择一行数据生成二维码'); return; } // 2. 获取单据编号 const newMaterialBarCode = selectedRows[0].newMaterialBarCode; if (!newMaterialBarCode) { ElMessage.error('选中的数据中未找到单据编号'); return; } // 3. 获取单据明细数据(新增:通过单据编号获取QtyTrans、MaterialCode、MaterialName) // let detailList = []; // const loading = ElLoading.service({ text: '获取单据明细中...' }); // try { // const res = await http.post('/api/DocumentDetail/details', { transNo: transNo }); // // 校验返回格式(必须是数组且至少有一条数据) // if (!res.status || !Array.isArray(res.data) || res.data.length === 0) { // throw new Error('未查询到单据明细数据'); // } // detailList = res.data; // // 校验每条明细的必填字段 // detailList.forEach((item, index) => { // if (!item.qtyTrans || !item.materialCode || !item.materialName) { // throw new Error(`第${index + 1}条明细数据不完整`); // } // }); // } catch (err) { // ElMessage.error(err.message || '获取单据明细失败'); // loading.close(); // return; // } finally { // loading.close(); // } // 4. 生成二维码 let qrCodeUrl = ''; try { qrCodeUrl = await QRCode.toDataURL(newMaterialBarCode, { width: 200, // 二维码大小适配布局 margin: 1 }); } catch (err) { ElMessage.error('二维码生成失败,请重试'); console.error('二维码生成错误:', err); return; } // 5. 创建弹窗 const mountNode = document.createElement('div'); document.body.appendChild(mountNode); // 添加打印专用样式 const addPrintStyle = () => { const style = document.createElement('style'); style.id = 'qr-print-style'; style.textContent = ` @media print { body > *:not(.print-container) { display: none !important; } .print-container { position: fixed !important; top: 50px !important; left: 50px !important; width: 90% !important; height: auto !important; } /* 打印内容布局 */ .print-content { display: flex !important; flex-direction: column !important; gap: 20px !important; } .qr-wrapper { align-self: flex-start !important; /* 二维码靠左 */ } .detail-fields { display: flex !important; justify-content: space-around !important; /* 字段均匀分布 */ width: 100% !important; margin-top: 20px !important; font-size: 16px !important; } .field-item { text-align: center !important; padding: 10px !important; border: 1px solid #eee !important; border-radius: 4px !important; width: 30% !important; /* 每个字段占1/3宽度 */ } .field-label { font-weight: bold !important; margin-bottom: 5px !important; display: block !important; } } `; document.head.appendChild(style); return style; }; // 打印函数 const printQrCode = () => { // 创建打印容器 const printContainer = document.createElement('div'); printContainer.className = 'print-container'; printContainer.style = 'position:fixed; top:-9999px; left:-9999px;'; document.body.appendChild(printContainer); // 填充打印内容(布局:二维码左上角 + 三个字段均匀分布) printContainer.innerHTML = ` `; // 添加打印样式 const printStyle = addPrintStyle(); // 清理函数(防止重复移除) const cleanUp = () => { if (printContainer.parentNode === document.body) { document.body.removeChild(printContainer); } if (printStyle && printStyle.parentNode === document.head) { document.head.removeChild(printStyle); } window.removeEventListener('afterprint', cleanUp); }; // 监听打印完成 window.addEventListener('afterprint', cleanUp, { once: true }); // 触发打印 window.print(); }; // 弹窗组件(预览布局) const vnode = createVNode(ElDialog, { title: '单据二维码及明细', width: '600px', modelValue: true, appendToBody: true, 'onUpdate:modelValue': (isVisible) => { if (!isVisible) { const printStyle = document.getElementById('qr-print-style'); if (printStyle && printStyle.parentNode === document.head) { document.head.removeChild(printStyle); } render(null, mountNode); if (mountNode.parentNode === document.body) { document.body.removeChild(mountNode); } } } }, { default: () => [ // 预览区布局(和打印布局一致) h('div', { style: { padding: '20px' } }, [ // 二维码预览(左上角) h('div', { style: { marginBottom: '20px' } }, [ h(ElImage, { src: qrCodeUrl, alt: '单据二维码', style: { width: '200px', height: '200px' } }), h('p', { style: { marginTop: '10px', fontSize: '16px' } }, `单据编号:${newMaterialBarCode}`) ]), // 明细字段预览(均匀分布) // h('div', { style: { display: 'flex', justifyContent: 'space-around', gap: '10px' } }, [ // h('div', { style: { textAlign: 'center', padding: '10px', border: '1px solid #eee', width: '30%' } }, [ // h('div', { style: { fontWeight: 'bold', marginBottom: '5px' } }, '交易数量'), // h('div', null, detailList[0].qtyTrans) // ]), // h('div', { style: { textAlign: 'center', padding: '10px', border: '1px solid #eee', width: '30%' } }, [ // h('div', { style: { fontWeight: 'bold', marginBottom: '5px' } }, '物料编码'), // h('div', null, detailList[0].materialCode) // ]), // h('div', { style: { textAlign: 'center', padding: '10px', border: '1px solid #eee', width: '30%' } }, [ // h('div', { style: { fontWeight: 'bold', marginBottom: '5px' } }, '物料名称'), // h('div', null, detailList[0].materialName) // ]) // ]) ]) ], footer: () => h('div', null, [ h(ElButton, { type: 'default', onClick: () => { const printStyle = document.getElementById('qr-print-style'); if (printStyle) document.head.removeChild(printStyle); render(null, mountNode); if (mountNode.parentNode === document.body) { document.body.removeChild(mountNode); } } }, '关闭'), h(ElButton, { type: 'primary', onClick: () => { ElMessageBox.confirm( '是否打印该内容?', '打印确认', { confirmButtonText: '确认打印', cancelButtonText: '取消', type: 'info' } ).then(async () => { try { // 执行打印并等待完成,捕获可能的错误 await printQrCode(); setTimeout(() => { render(null, mountNode); if (mountNode.parentNode === document.body) { document.body.removeChild(mountNode); } }, 500); } catch (printErr) { // 显示真实错误(而非“已取消”) ElMessage.error(`打印失败:${printErr.message || '未知错误'}`); console.error('打印错误:', printErr); } }).catch((err) => { // 仅用户主动取消时才显示“已取消” if (err === 'cancel' || err.name === 'CanceledError') { ElMessage.info('已取消打印'); } }); } }, '打印') ]) }); vnode.appContext = this.$.appContext; render(vnode, mountNode); } }], box: [], detail: [] }, //扩展的按钮 methods: { //下面这些方法可以保留也可以删除 onInit() { }, onInited() { //框架初始化配置后 //如果要配置明细表,在此方法操作 //this.detailOptions.columns.forEach(column=>{ }); }, searchBefore(param) { //界面查询前,可以给param.wheres添加查询参数 //返回false,则不会执行查询 return true; }, searchAfter(result) { //查询后,result返回的查询数据,可以在显示到表格前处理表格的值 return true; }, addBefore(formData) { //新建保存前formData为对象,包括明细表,可以给给表单设置值,自己输出看formData的值 return true; }, updateBefore(formData) { //编辑保存前formData为对象,包括明细表、删除行的Id return true; }, rowClick({ row, column, event }) { //查询界面点击行事件 this.$refs.table.$refs.table.toggleRowSelection(row); //单击行时选中当前行; }, modelOpenAfter(row) { //点击编辑、新建按钮弹出框后,可以在此处写逻辑,如,从后台获取数据 //(1)判断是编辑还是新建操作: this.currentAction=='Add'; //(2)给弹出框设置默认值 //(3)this.editFormFields.字段='xxx'; //如果需要给下拉框设置默认值,请遍历this.editFormOptions找到字段配置对应data属性的key值 //看不懂就把输出看:console.log(this.editFormOptions) } } }; export default extension;