0602
This commit is contained in:
@@ -0,0 +1,564 @@
|
||||
<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`
|
||||
const placeholders = {
|
||||
'TSPL': `输入TSPL指令,如:\n${sizeCmd}\nGAP 2 mm\nCLS\nTEXT 50 50 "4" 0 1 1 "Hello"\nPRINT`,
|
||||
'CPCL': `输入CPCL指令,如:\n! 0 200 200 240 1\n${sizeCmd}\nGAP 2mm\nTEXT 4 0 10 10 EN Hello\nPRINT`
|
||||
}
|
||||
return placeholders[this.commandType] || '输入打印指令...'
|
||||
}
|
||||
},
|
||||
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>
|
||||
Reference in New Issue
Block a user