<template>
|
<view class="container">
|
<!-- 打印按钮区域:仅在屏幕显示,打印时隐藏 -->
|
<view class="print-btn-container no-print">
|
<view @click="handlePrint" class="print-btn">
|
<image src="/static/icon_dayin.png" class="print-icon" alt="打印" />
|
<text class="print-text">打印</text>
|
</view>
|
<view @click="navigateBack" class="back-btn">
|
<text>返回</text>
|
</view>
|
</view>
|
|
<!-- 预览区域 -->
|
<view v-if="printData" class="preview-content">
|
<view class="preview-header">
|
<text class="title">移库单</text>
|
</view>
|
|
<view class="preview-body">
|
<!-- 顶部信息行 -->
|
<view class="top-info">
|
<image src="@/static/index_logo.png" class="logo" mode="aspectFit" />
|
<text class="doc-number">XHJ.QM.QMSOO9E</text>
|
</view>
|
|
<!-- 表格部分 -->
|
<table class="info-table">
|
<tr>
|
<td>生产订单号</td>
|
<td>{{ printData.orderNo }}</td>
|
<td>产品型号</td>
|
<td>G-639</td>
|
<td rowspan="4" class="qr-cell">
|
<view class="qr-container">
|
<uv-qrcode
|
:value="qrContent"
|
:size="180"
|
:margin="10"
|
ref="qrcode"
|
@click="saveQRCode"
|
></uv-qrcode>
|
<text class="qr-text">C2506080024</text>
|
</view>
|
</td>
|
</tr>
|
<tr>
|
<td>客户名称</td>
|
<td>东方日产</td>
|
<td>物料号</td>
|
<td>120047854</td>
|
</tr>
|
<tr>
|
<td>客户型号</td>
|
<td>4200-51354</td>
|
<td>生产批号</td>
|
<td>25159847</td>
|
</tr>
|
<tr>
|
<td>生产分厂</td>
|
<td>双林新火炬工厂</td>
|
<td>数量</td>
|
<td>73</td>
|
</tr>
|
<tr class="inspection-status">
|
<td>检验状态</td>
|
<td colspan="4"></td>
|
</tr>
|
</table>
|
</view>
|
</view>
|
|
<!-- 备用web-view -->
|
<web-view v-if="previewUrl" class="no-print" :src="previewUrl"></web-view>
|
</view>
|
</template>
|
|
<script>
|
import io from '@hyoga/uni-socket.io';
|
import { PrinterCommands } from '@/common/util/printer-commands.js';
|
import uvQrcode from '@/uni_modules/uv-qrcode/components/uv-qrcode/uv-qrcode.vue'
|
|
export default {
|
components: { uvQrcode },
|
data() {
|
return {
|
previewUrl: '',
|
printData: null,
|
printerConfig: null,
|
qrContent: 'C2506080024'
|
};
|
},
|
onLoad(options) {
|
try {
|
if (options.previewUrl) {
|
this.previewUrl = decodeURIComponent(options.previewUrl);
|
}
|
if (options.printData) {
|
this.printData = JSON.parse(decodeURIComponent(options.printData));
|
}
|
} catch (e) {
|
console.error('数据解析错误:', e);
|
uni.showToast({ title: '数据加载失败', icon: 'none' });
|
}
|
this.printerConfig = uni.getStorageSync('printerConfig') || null;
|
this.setLandscapeOrientation();
|
},
|
onUnload() {
|
if (uni.setScreenOrientation) {
|
uni.setScreenOrientation({ orientation: 'portrait' });
|
}
|
},
|
methods: {
|
setLandscapeOrientation() {
|
if (uni.setScreenOrientation) {
|
uni.setScreenOrientation({
|
orientation: 'landscape',
|
success: () => console.log('已横屏'),
|
fail: (err) => console.error('横屏设置失败:', err)
|
});
|
}
|
},
|
saveQRCode() {
|
this.$refs.qrcode.save();
|
},
|
navigateBack() {
|
uni.navigateBack();
|
},
|
async handlePrint() {
|
if (!this.printData) {
|
uni.showToast({ title: '打印数据为空', icon: 'none' });
|
return;
|
}
|
|
this.printerConfig = uni.getStorageSync('printerConfig') || null;
|
if (!this.printerConfig?.ip || !this.printerConfig?.port) {
|
uni.showModal({
|
title: '未配置打印机',
|
content: '是否前往设置?',
|
success: (res) => {
|
if (res.confirm) uni.navigateTo({ url: '/pages/user/location' });
|
}
|
});
|
return;
|
}
|
|
try {
|
uni.showLoading({ title: '打印中...', mask: true });
|
const qrBase64 = this.$refs.qrcode.toDataURL();
|
const qrBuffer = this.base64ToArrayBuffer(qrBase64);
|
const printDataWithQr = { ...this.printData, qrBuffer };
|
|
const commands = new PrinterCommands(this.printerConfig.model || 'generic');
|
const printCommand = commands.buildTransferOrder(printDataWithQr);
|
await this.sendPrintCommand(printCommand);
|
|
uni.hideLoading();
|
uni.showToast({ title: '打印成功', icon: 'success' });
|
} catch (error) {
|
uni.hideLoading();
|
uni.showToast({ title: error.message || '打印失败', icon: 'none' });
|
}
|
},
|
sendPrintCommand(command) {
|
return new Promise((resolve, reject) => {
|
if (!this.printerConfig) {
|
reject(new Error('未配置打印机'));
|
return;
|
}
|
|
const { ip, port, model } = this.printerConfig;
|
if (!ip || !port) {
|
reject(new Error('打印机配置不完整'));
|
return;
|
}
|
|
const protocol = model === 'zebra' ? 'tcp://' : 'ws://';
|
const socket = io(`${protocol}${ip}:${port}`, {
|
transports: ['websocket'],
|
timeout: 5000
|
});
|
|
let isResolved = false;
|
socket.on('connect', () => {
|
socket.emit('print', command, (response) => {
|
socket.disconnect();
|
if (!isResolved) {
|
isResolved = true;
|
response.success ? resolve() : reject(new Error(response.error || '打印失败'));
|
}
|
});
|
});
|
|
socket.on('connect_error', (err) => {
|
if (!isResolved) {
|
isResolved = true;
|
reject(new Error(`连接失败: ${err.message}`));
|
}
|
});
|
|
socket.on('disconnect', (reason) => {
|
if (!isResolved) {
|
isResolved = true;
|
reject(new Error(`连接断开: ${reason}`));
|
}
|
});
|
|
setTimeout(() => {
|
if (!isResolved) {
|
isResolved = true;
|
socket.disconnect();
|
reject(new Error('打印超时'));
|
}
|
}, 10000);
|
});
|
},
|
base64ToArrayBuffer(base64) {
|
const binaryString = uni.base64Decode(base64);
|
const len = binaryString.length;
|
const bytes = new Uint8Array(len);
|
for (let i = 0; i < len; i++) {
|
bytes[i] = binaryString.charCodeAt(i);
|
}
|
return bytes.buffer;
|
}
|
}
|
};
|
</script>
|
|
<style scoped>
|
.container {
|
position: relative;
|
height: 100vh;
|
padding-top: 60rpx; /* 预留打印按钮区域高度 */
|
}
|
|
/* 打印按钮区域样式 */
|
.print-btn-container {
|
position: fixed;
|
top: 0;
|
left: 0;
|
right: 0;
|
height: 60rpx;
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
padding: 0 30rpx;
|
background-color: #f5f5f5;
|
z-index: 999;
|
}
|
|
.print-btn {
|
display: flex;
|
align-items: center;
|
color: #007AFF;
|
}
|
|
.print-icon {
|
width: 25px;
|
height: 25px;
|
margin-right: 8rpx;
|
}
|
|
.back-btn {
|
color: #333;
|
}
|
|
/* 预览区域样式 */
|
.preview-header {
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
padding: 15rpx 20rpx;
|
background-color: #007AFF;
|
color: white;
|
}
|
|
.title {
|
font-size: 32rpx;
|
font-weight: bold;
|
}
|
|
.preview-body {
|
padding: 30rpx;
|
}
|
|
.top-info {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
margin-bottom: 20rpx;
|
padding: 10rpx 0;
|
border-bottom: 1px solid #ddd;
|
}
|
|
.logo {
|
width: 120rpx;
|
height: 60rpx;
|
}
|
|
.doc-number {
|
font-size: 28rpx;
|
font-weight: bold;
|
color: #000;
|
}
|
|
.info-table {
|
width: 100%;
|
border-collapse: collapse;
|
margin-top: 20rpx;
|
}
|
|
.info-table td {
|
border: 1px solid #ddd;
|
padding: 10rpx;
|
text-align: center;
|
vertical-align: middle;
|
}
|
|
.qr-cell {
|
width: 200rpx;
|
text-align: center;
|
}
|
|
.qr-container {
|
display: flex;
|
flex-direction: column;
|
align-items: center;
|
justify-content: center;
|
padding: 10rpx;
|
}
|
|
.qr-text {
|
font-size: 24rpx;
|
color: #000;
|
}
|
|
.inspection-status {
|
height: 320rpx;
|
line-height: 320rpx;
|
}
|
|
/* 打印样式控制:带no-print类的元素在打印时不显示 */
|
@media print {
|
@page {
|
size: auto;
|
margin: 10mm; /* 调整打印边距 */
|
}
|
.no-print {
|
display: none !important; /* 打印时隐藏操作按钮 */
|
}
|
.container {
|
padding-top: 0; /* 移除打印时的顶部留白 */
|
}
|
}
|
</style>
|