Files
uni-pda/pages/settings/devices/printTest.vue
T
2026-07-23 14:49:31 +08:00

572 lines
14 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="container">
<!-- 状态栏 -->
<view class="status-section">
<view class="status-item">
<text class="status-label">打印机</text>
<text class="status-value" :class="{ connected: connected }">
{{ connected ? '已连接' : '未连接' }}
</text>
</view>
<view class="status-item" v-if="connected">
<text class="status-label">设备名称</text>
<text class="status-value device-name">{{ printerConfig.deviceName }}</text>
</view>
</view>
<!-- 操作按钮 -->
<view class="section action-section" v-if="!connected">
<button class="btn btn-primary" :loading="isConnecting" @click="handleConnect">
{{ isConnecting ? '连接中...' : '重新连接' }}
</button>
</view>
<!-- 打印控制区 -->
<view class="section print-section" v-if="connected">
<view class="section-header">
<text class="section-title">打印测试</text>
</view>
<!-- 指令类型选择 -->
<view class="command-type">
<text class="type-label">指令类型:</text>
<view class="type-switch">
<view
class="type-btn"
:class="{ active: commandType === 'CPCL' }"
@click="selectCommandType('CPCL')">
CPCL
</view>
<view
class="type-btn"
:class="{ active: commandType === 'TSPL' }"
@click="selectCommandType('TSPL')">
TSPL
</view>
</view>
</view>
<!-- 纸尺寸选择 -->
<view class="paper-size-section">
<text class="paper-size-label">打印纸尺寸</text>
<view class="paper-size-grid">
<view
class="paper-size-item"
:class="{ selected: paperWidth === 100 && paperHeight === 100 }"
@click="selectPaperSize(100, 100)">
<text class="paper-size-name">100mm x 100mm</text>
</view>
<view
class="paper-size-item"
:class="{ selected: paperWidth === 150 && paperHeight === 150 }"
@click="selectPaperSize(150, 150)">
<text class="paper-size-name">150mm x 150mm</text>
</view>
<view
class="paper-size-item"
:class="{ selected: paperWidth === 200 && paperHeight === 200 }"
@click="selectPaperSize(200, 200)">
<text class="paper-size-name">200mm x 200mm</text>
</view>
</view>
</view>
<!-- 打印内容 -->
<view class="print-content">
<view class="content-header">
<text class="content-title">打印内容</text>
<view class="content-actions">
<button size="mini" @click="clearContent">清空</button>
<button size="mini" type="primary" :loading="isPrinting" @click="doPrint">打印</button>
</view>
</view>
<textarea
class="content-textarea"
v-model="printContent"
:placeholder="contentPlaceholder">
</textarea>
</view>
<!-- 快捷模板 -->
<view class="template-section">
<text class="template-title">快捷模板</text>
<scroll-view class="template-list" scroll-x>
<view class="template-tags">
<view class="template-tag" @click="useTemplate('qrcode')">二维码</view>
<view class="template-tag" @click="useTemplate('barcode')">条码</view>
<view class="template-tag" @click="useTemplate('label')">废料标签</view>
</view>
</scroll-view>
</view>
</view>
<!-- 断开连接 -->
<view class="section" v-if="connected">
<button class="btn btn-outline" @click="handleDisconnect">断开连接</button>
</view>
</view>
</template>
<script>
import printerService from '@/utils/BluetoothPrinterService.new.js';
export default {
data() {
return {
isConnecting: false,
isPrinting: false,
connected: false,
connectingText: '正在检查配置...',
printerConfig: {},
commandType: 'CPCL',
paperWidth: 100,
paperHeight: 100,
printContent: ''
}
},
computed: {
contentPlaceholder() {
const sizeCmd = this.commandType === 'CPCL'
? `SIZE ${this.paperWidth}mm ${this.paperHeight}mm`
: `SIZE ${this.paperWidth} mm ${this.paperHeight} mm`
// TSPL 分支保持原样
if (this.commandType !== 'CPCL') {
return `输入TSPL指令,如:\n${sizeCmd}\nGAP 2 mm\nCLS\nTEXT 50 50 "4" 0 1 1 "Hello"\nPRINT`
}
// CPCL200x200 用大标签配置,其余尺寸用默认小标签配置
const isLargeLabel = this.paperWidth === 200 && this.paperHeight === 200
const cpclHeader = isLargeLabel ? '! 0 200 200 1600 1' : '! 0 200 200 240 1'
const cpclGap = isLargeLabel ? 'GAP-SENSE' : 'GAP 2mm'
return `输入CPCL指令,如:\n${cpclHeader}\n${sizeCmd}\n${cpclGap}\nTEXT 4 0 10 10 EN Hello\nPRINT`
}
},
onLoad() {
this.loadPrinterConfig()
this.syncConfigFromService()
this.checkAndConnect()
},
onShow() {
if (!this.connected && !this.isConnecting) {
this.checkAndConnect()
}
},
onUnload() {
this.handleDisconnect()
},
mounted() {
printerService.onConnectionChange(this.handleConnectionChange)
},
beforeDestroy() {
printerService.offConnectionChange(this.handleConnectionChange)
},
methods: {
handleConnectionChange(connected) {
this.connected = connected
if (connected) {
this.loadPrinterConfig()
this.syncConfigFromService()
}
},
/**
* 从 printerService 同步配置
*/
syncConfigFromService() {
const serviceConfig = printerService.getConfig()
if (serviceConfig.commandType) {
this.commandType = serviceConfig.commandType
}
if (serviceConfig.paperWidth && serviceConfig.paperHeight) {
this.paperWidth = serviceConfig.paperWidth
this.paperHeight = serviceConfig.paperHeight
}
},
loadPrinterConfig() {
const storeState = uni.getStorageSync('printerConfig') || {}
const serviceConfig = printerService.getConfig()
this.printerConfig = {
deviceId: serviceConfig.deviceId || storeState.deviceId || '',
serviceId: serviceConfig.serviceId || storeState.serviceId || '',
writeCharId: serviceConfig.writeCharId || storeState.writeCharId || '',
deviceName: serviceConfig.deviceName || storeState.deviceName || ''
}
},
/**
* 检查配置并自动连接
*/
async checkAndConnect() {
this.loadPrinterConfig()
if (!this.printerConfig.deviceId) {
this.connectingText = '未配置打印机,请先配置设备'
return
}
if (!this.printerConfig.serviceId || !this.printerConfig.writeCharId) {
this.connectingText = '配置不完整,请重新配置设备'
return
}
if (printerService.isConnected()) {
this.connected = true
return
}
this.isConnecting = true
this.connectingText = '正在连接...'
try {
const success = await printerService.autoConnect()
this.connected = success
if (success) {
this.connectingText = '连接成功'
this.syncConfigFromService()
} else {
this.connectingText = '连接失败,请检查设备是否开启'
}
} catch (err) {
this.connectingText = '连接异常: ' + (err.message || '未知错误')
} finally {
this.isConnecting = false
}
},
/**
* 手动连接
*/
async handleConnect() {
if (this.isConnecting) return
this.isConnecting = true
this.connectingText = '正在连接...'
this.loadPrinterConfig()
if (!this.printerConfig.deviceId) {
uni.showToast({ title: '请先配置打印机设备', icon: 'none' })
this.connectingText = '未配置打印机'
this.isConnecting = false
return
}
try {
const success = await printerService.autoConnect()
this.connected = success
if (success) {
uni.showToast({ title: '连接成功', icon: 'none' })
this.syncConfigFromService()
} else {
if (!this.printerConfig.serviceId || !this.printerConfig.writeCharId) {
uni.showToast({ title: '配置不完整,请重新配置', icon: 'none' })
this.connectingText = '配置不完整'
} else {
uni.showToast({ title: '连接失败,请检查设备', icon: 'none' })
this.connectingText = '连接失败'
}
}
} catch (err) {
uni.showToast({ title: '连接异常', icon: 'none' })
this.connectingText = '连接异常'
} finally {
this.isConnecting = false
}
},
/**
* 断开连接
*/
async handleDisconnect() {
if (!this.connected && !this.deviceId) return
try {
await printerService.disconnect()
this.connected = false
this.connectingText = '已断开连接'
} catch (err) {
this.connected = false
}
},
/**
* 选择指令类型
*/
selectCommandType(type) {
this.commandType = type
printerService.setCommandType(type)
// 切换指令类型时同步更新纸张尺寸
printerService.setPaperSize(this.paperWidth, this.paperHeight)
},
/**
* 选择打印纸尺寸
*/
selectPaperSize(width, height) {
this.paperWidth = width
this.paperHeight = height
printerService.setPaperSize(width, height)
},
/**
* 快捷模板
*/
useTemplate(type) {
if (type === 'label') {
const testData = {
mingcheng: '测试废物',
leibie: '危险废物',
daima: 'HW49',
xingtai: '液态',
zhuyaochengfen: '测试成分',
youhaichengfen: '无',
zhuyi: '防潮',
shibiema: 'TEST' + Date.now(),
danwei: '测试单位',
lianxi: '13800138000',
riqi: new Date().toISOString().split('T')[0],
zhongliang: '10kg',
beizhu: '测试备注',
biaoshi: '',
qrcode: 'https://www.cswm.org.cn/qr/?code=7G6MOYELnFHZfF1Y0F8e6gjxR2K2pALNJJNhJSuOg17LV6IZfuDWUnF2qC3Rsdejs&type=WFBQ'
}
// 确保 service 使用当前的 commandType 和 paperSize
printerService.setCommandType(this.commandType)
printerService.setPaperSize(this.paperWidth, this.paperHeight)
this.printContent = printerService.generateWasteLabel(testData)
return
}
if (type === 'qrcode') {
printerService.setCommandType(this.commandType)
printerService.setPaperSize(this.paperWidth, this.paperHeight)
this.printContent = printerService.generateQRCodeTemplate('https://www.example.com')
return
}
if (type === 'barcode') {
printerService.setCommandType(this.commandType)
printerService.setPaperSize(this.paperWidth, this.paperHeight)
this.printContent = printerService.generateBarcodeTemplate('1234567890')
return
}
},
/**
* 清空打印内容
*/
clearContent() {
this.printContent = ''
},
/**
* 执行打印
*/
async doPrint() {
if (this.isPrinting) return
if (!this.printContent.trim()) {
uni.showToast({ title: '请输入打印内容', icon: 'none' })
return
}
this.isPrinting = true
try {
// 确保打印前同步配置
printerService.setCommandType(this.commandType)
printerService.setPaperSize(this.paperWidth, this.paperHeight)
await printerService.printText(this.printContent)
uni.showToast({ title: '打印成功', icon: 'success' })
} catch (err) {
uni.showToast({ title: '打印失败: ' + (err.message || err || '未知错误'), icon: 'none' })
} finally {
this.isPrinting = false
}
}
}
}
</script>
<style scoped>
.container {
padding: 20rpx;
background: #f5f5f5;
min-height: 100vh;
}
.status-section {
display: flex;
background: #fff;
padding: 30rpx;
border-radius: 12rpx;
margin-bottom: 20rpx;
}
.status-item {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
}
.status-label {
font-size: 26rpx;
color: #999;
margin-bottom: 12rpx;
}
.status-value {
font-size: 32rpx;
font-weight: bold;
color: #666;
}
.status-value.connected {
color: #34c759;
}
.device-name {
font-size: 26rpx;
color: #34c759;
max-width: 300rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.section {
background: #fff;
border-radius: 12rpx;
padding: 24rpx;
margin-bottom: 20rpx;
}
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16rpx;
}
.section-title {
font-size: 30rpx;
font-weight: bold;
color: #333;
}
.action-section button {
width: 100%;
margin-bottom: 20rpx;
}
.action-section button:last-child {
margin-bottom: 0;
}
/* 指令类型 */
.command-type {
display: flex;
align-items: center;
margin-bottom: 16rpx;
}
.type-label {
font-size: 26rpx;
color: #666;
margin-right: 16rpx;
}
.type-switch {
display: flex;
border: 1rpx solid #007aff;
border-radius: 8rpx;
overflow: hidden;
}
.type-btn {
padding: 12rpx 24rpx;
font-size: 24rpx;
color: #007aff;
background: #fff;
}
.type-btn.active {
background: #007aff;
color: #fff;
}
/* 纸尺寸 */
.paper-size-section {
margin-bottom: 20rpx;
}
.paper-size-label {
font-size: 26rpx;
color: #666;
margin-bottom: 12rpx;
display: block;
}
.paper-size-grid {
display: flex;
flex-wrap: wrap;
gap: 16rpx;
}
.paper-size-item {
flex: 1;
min-width: 200rpx;
padding: 20rpx;
background: #f0f0f0;
border-radius: 8rpx;
border: 2rpx solid transparent;
text-align: center;
}
.paper-size-item.selected {
background: #e8f4ff;
border-color: #007aff;
}
.paper-size-name {
font-size: 24rpx;
color: #333;
}
.paper-size-item.selected .paper-size-name {
color: #007aff;
font-weight: bold;
}
/* 打印内容 */
.print-section {
min-height: 400rpx;
}
.print-content {
margin-bottom: 20rpx;
}
.content-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12rpx;
}
.content-title {
font-size: 26rpx;
color: #666;
}
.content-actions {
display: flex;
gap: 12rpx;
}
.content-textarea {
width: 100%;
height: 280rpx;
border: 1rpx solid #ddd;
border-radius: 8rpx;
padding: 16rpx;
font-size: 24rpx;
font-family: 'Courier New', monospace;
box-sizing: border-box;
}
/* 快捷模板 */
.template-section {
margin-bottom: 20rpx;
}
.template-title {
font-size: 26rpx;
color: #666;
margin-bottom: 12rpx;
display: block;
}
.template-list {
width: 100%;
}
.template-tags {
display: flex;
gap: 12rpx;
padding: 4rpx;
}
.template-tag {
padding: 12rpx 24rpx;
background: #f0f0f0;
border-radius: 8rpx;
font-size: 24rpx;
color: #333;
}
.template-tag:active {
background: #e0e0e0;
}
</style>