|
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 = `
|
<div class="print-content">
|
<!-- 二维码(左上角) -->
|
<div class="qr-wrapper">
|
<img src="${qrCodeUrl}" style="width: 200px; height: 200px;" />
|
<p style="margin-top: 10px; font-size: 16px;">单据编号:${newMaterialBarCode}</p>
|
</div>
|
|
<!-- 明细字段(均匀分布) -->
|
<div class="detail-fields">
|
<div class="field-item">
|
<span class="field-label">交易数量</span>
|
<span>${detailList[0].qtyTrans}</span>
|
</div>
|
<div class="field-item">
|
<span class="field-label">物料编码</span>
|
<span>${detailList[0].materialCode}</span>
|
</div>
|
<div class="field-item">
|
<span class="field-label">物料名称</span>
|
<span>${detailList[0].materialName}</span>
|
</div>
|
</div>
|
</div>
|
`;
|
|
// 添加打印样式
|
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;
|