uu
This commit is contained in:
parent
114c73fc71
commit
7546192eee
@ -3,6 +3,9 @@
|
|||||||
<view class="lgn-page">
|
<view class="lgn-page">
|
||||||
<view class="pos-abt-all" style="z-index: 0;overflow: hidden;">
|
<view class="pos-abt-all" style="z-index: 0;overflow: hidden;">
|
||||||
<tpx-image width="750" mode="widthFix" :src="getCdnUrl('login/bg.png')"></tpx-image>
|
<tpx-image width="750" mode="widthFix" :src="getCdnUrl('login/bg.png')"></tpx-image>
|
||||||
|
<view class="yunduo">
|
||||||
|
<tpx-image width="750" mode="widthFix" :src="getCdnUrl('login/bg-yun.png')"></tpx-image>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="pos-rlt" style="z-index: 1;">
|
<view class="pos-rlt" style="z-index: 1;">
|
||||||
<view>
|
<view>
|
||||||
@ -93,4 +96,10 @@
|
|||||||
background-size: 100% auto;
|
background-size: 100% auto;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
}
|
}
|
||||||
|
.yunduo{
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0rpx;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -1,232 +1,356 @@
|
|||||||
<template>
|
<template>
|
||||||
<view>
|
<view>
|
||||||
<button @click="searchBle">搜索蓝牙</button>
|
<button @click="discoveryPrinter">搜索打印机</button>
|
||||||
<view style="margin-top: 30upx;" :key="index" v-for="(item,index) in devices">
|
<button @click="stopDiscoveryPrinter">停止搜索打印机</button>
|
||||||
<button style="width: 400upx; color: #0081FF;" @click="onConn(item)">{{item.name}}</button>
|
<view>选中的设备:{{deviceId}}</view>
|
||||||
|
<view class="text-red">设备列表</view>
|
||||||
|
<radio-group @change="radioChange">
|
||||||
|
<label class="uni-list-cell uni-list-cell-pd" v-for="(item, index) in devices" :key="index"
|
||||||
|
v-if="item.name && item.deviceId"
|
||||||
|
>
|
||||||
|
<view>
|
||||||
|
<radio :value="item.deviceId" />{{item.name}}({{item.deviceId}})
|
||||||
</view>
|
</view>
|
||||||
<button style="margin-top: 100upx;" @click="senBleLabel()">标签打印</button>
|
</label>
|
||||||
|
</radio-group>
|
||||||
|
|
||||||
<!-- <textarea auto-height placeholder-style="color:#F76260" placeholder="请输入票据信息" v-model="piaojuText" />
|
<view class="text-red">设备服务列表</view>
|
||||||
<button style="margin-top: 100upx;" @click="senBleLabel2()">票据打印</button> -->
|
<radio-group @change="radioChange2">
|
||||||
<canvas :style="{width: `${canvasWidth}rpx`, height: `${canvasHeight}rpx`}" canvas-id="firstCanvas" id="firstCanvas" class="firstCanvas" />
|
<label class="uni-list-cell uni-list-cell-pd" v-for="(item, index) in serverList" :key="index">
|
||||||
|
<view>
|
||||||
|
<radio :value="item.uuid" />{{item.uuid}}
|
||||||
</view>
|
</view>
|
||||||
|
</label>
|
||||||
|
</radio-group>
|
||||||
|
|
||||||
|
<view class="text-red">特征值</view>
|
||||||
|
<radio-group @change="radioChange3">
|
||||||
|
<label class="uni-list-cell uni-list-cell-pd" v-for="(item, index) in characteristics" :key="index">
|
||||||
|
<view>
|
||||||
|
<radio :value="item.uuid" />{{item.uuid}}(write:{{item.properties.write}} notify:{{item.properties.notify}} indicate:{{item.properties.indicate}})
|
||||||
|
</view>
|
||||||
|
</label>
|
||||||
|
</radio-group>
|
||||||
|
|
||||||
|
<button @click="writeBLECharacteristicValue">打印</button>
|
||||||
|
<canvas canvas-id="shareCanvas" :style="{width:canvas_width+'px', height: canvas_height+'px'}"></canvas>
|
||||||
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import * as tsc from '@/common/libs/tsc.js'
|
import PrinterJobs from './print/printerjobs.js'
|
||||||
import * as esc from '@/common/libs/esc.js'
|
import * as printerUtil from './print/printerutil.js'
|
||||||
import bluetoothTool from '@/common/libs/BluetoothTool.js'
|
import * as util from './print/util.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
name: 'xun_bluetoothPrint',
|
||||||
|
data () {
|
||||||
return {
|
return {
|
||||||
|
canvasId: 'shareCanvas',
|
||||||
|
canvas_width: 240,
|
||||||
|
canvas_height: 240,
|
||||||
devices: [],
|
devices: [],
|
||||||
currDev: null,
|
deviceId: '',
|
||||||
connId: '',
|
serverList: [],
|
||||||
piaojuText:'',
|
serviceId: '',
|
||||||
|
characteristics: [],
|
||||||
tableDomId: '',
|
characteristicId: ''
|
||||||
tableImgPath: '',
|
|
||||||
canvasWidth: 600,
|
|
||||||
canvasHeight: 600,
|
|
||||||
msg: ''
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch:{
|
mounted () {
|
||||||
msg(){
|
// 初始化蓝牙模块
|
||||||
uni.showToast({
|
this.openBluetoothAdapter()
|
||||||
title: this.msg
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onReady() {
|
|
||||||
this.renderCanvas()
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
//#ifdef APP-PLUS
|
|
||||||
// 蓝牙
|
|
||||||
bluetoothTool.init({
|
|
||||||
listenBTStatusCallback: (state)=> {
|
|
||||||
if(state == 'STATE_ON') {
|
|
||||||
let lastBleAddress = uni.getStorageSync('lastBleAddress')
|
|
||||||
if(lastBleAddress) {
|
|
||||||
uni.showLoading({
|
|
||||||
title: '正在连接...'
|
|
||||||
})
|
|
||||||
console.log(lastBleAddress)
|
|
||||||
bluetoothTool.connDevice(lastBleAddress,(result)=>{
|
|
||||||
uni.hideLoading()
|
|
||||||
uni.showToast({
|
|
||||||
title: result?'连接成功!':'连接失败...'
|
|
||||||
});
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
discoveryDeviceCallback: this.onDevice,
|
|
||||||
discoveryFinishedCallback: function() {
|
|
||||||
that.msg = "搜索完成";
|
|
||||||
},
|
|
||||||
readDataCallback: function(dataByteArr) {
|
|
||||||
// 读取蓝牙返回的数据
|
|
||||||
/* if(that.receiveDataArr.length >= 200) {
|
|
||||||
that.receiveDataArr = [];
|
|
||||||
}
|
|
||||||
that.receiveDataArr.push.apply(that.receiveDataArr, dataByteArr); */
|
|
||||||
},
|
|
||||||
connExceptionCallback: function(e) {
|
|
||||||
console.log(e);
|
|
||||||
that.msg = "设备连接失败";
|
|
||||||
}
|
|
||||||
});
|
|
||||||
//#endif
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
destroyed: function() {
|
openBluetoothAdapter () {
|
||||||
console.log("destroyed----------")
|
var _this = this
|
||||||
if (this.connId != '') {
|
|
||||||
uni.closeBLEConnection({
|
|
||||||
deviceId: this.connId,
|
|
||||||
success(res) {
|
|
||||||
console.log(res)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
},
|
|
||||||
searchBle() {
|
|
||||||
var that = this
|
|
||||||
console.log("initBule")
|
|
||||||
// 使用openBluetoothAdapter 接口,免去主动申请权限的麻烦
|
|
||||||
uni.openBluetoothAdapter({
|
uni.openBluetoothAdapter({
|
||||||
success(res) {
|
complete (e) {
|
||||||
this.devices = []
|
console.log(e);
|
||||||
console.log("打开 蓝牙模块,开始搜索模式...")
|
if (!e.errCode) {
|
||||||
console.log("openBluetoothAdapter res==", res)
|
console.log('初始化完成')
|
||||||
// that.getBuleState()
|
} else if (e.errCode == 10001) {
|
||||||
bluetoothTool.discoveryNewDevice();
|
uni.showToast({
|
||||||
}
|
icon: 'none',
|
||||||
|
title: '请打开手机蓝牙'
|
||||||
})
|
})
|
||||||
},
|
|
||||||
getBuleState(){
|
|
||||||
uni.getBluetoothAdapterState({
|
|
||||||
success: function(res) {
|
|
||||||
console.log("====getBluetoothAdapterState===", res)
|
|
||||||
if (res.available) {
|
|
||||||
if (res.discovering) {
|
|
||||||
that.stopFindBule()
|
|
||||||
}
|
|
||||||
//搜索蓝牙
|
|
||||||
//开始搜寻附近的蓝牙外围设备
|
|
||||||
console.log("开始搜寻附近的蓝牙外围设备")
|
|
||||||
uni.startBluetoothDevicesDiscovery({
|
|
||||||
success(res) {
|
|
||||||
console.log(res)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
console.log('本机蓝牙不可用')
|
uni.showToast({
|
||||||
}
|
icon: 'none',
|
||||||
},
|
title: e.errMsg
|
||||||
})
|
|
||||||
},
|
|
||||||
onDevice(newDevice){
|
|
||||||
console.log("监听寻找到新设备的事件---------------")
|
|
||||||
console.log(newDevice)
|
|
||||||
if(newDevice.name && newDevice.name != 'null') {
|
|
||||||
this.devices.push({
|
|
||||||
name: newDevice.name,
|
|
||||||
address: newDevice.address
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
},
|
},
|
||||||
stopFindBule() {
|
// 开始搜寻附近的蓝牙外围设备
|
||||||
console.log("停止搜寻附近的蓝牙外围设备---------------")
|
discoveryPrinter () {
|
||||||
uni.stopBluetoothDevicesDiscovery({
|
var _this = this
|
||||||
success(res) {
|
_this.devices = []
|
||||||
|
uni.startBluetoothDevicesDiscovery({
|
||||||
|
complete (e) {
|
||||||
|
console.log(e)
|
||||||
|
if (e.errMsg == "startBluetoothDevicesDiscovery:ok") {
|
||||||
|
// ArrayBuffer转16进度字符串示例
|
||||||
|
uni.onBluetoothDeviceFound(devices => {
|
||||||
|
console.log(devices)
|
||||||
|
_this.devices.push(devices.devices[0])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 停止搜寻附近的蓝牙外围设备
|
||||||
|
async stopDiscoveryPrinter () {
|
||||||
|
uni.stopBluetoothDevicesDiscovery()
|
||||||
|
},
|
||||||
|
radioChange (e) {
|
||||||
|
console.log(e)
|
||||||
|
this.deviceId = e.target.value
|
||||||
|
this.serviceId = ''
|
||||||
|
this.serverList = []
|
||||||
|
this.characteristics = []
|
||||||
|
this.characteristicId = ''
|
||||||
|
//连接蓝牙
|
||||||
|
this.connect()
|
||||||
|
},
|
||||||
|
radioChange2 (e) {
|
||||||
|
console.log(e)
|
||||||
|
this.serviceId = e.target.value
|
||||||
|
this.characteristics = []
|
||||||
|
this.characteristicId = ''
|
||||||
|
// 获取蓝牙特征值
|
||||||
|
setTimeout(() =>{
|
||||||
|
this.getBLEDeviceCharacteristics()
|
||||||
|
}, 500);
|
||||||
|
},
|
||||||
|
radioChange3 (e) {
|
||||||
|
console.log(e)
|
||||||
|
this.characteristicId = e.target.value
|
||||||
|
},
|
||||||
|
connect () {
|
||||||
|
var _this = this
|
||||||
|
uni.createBLEConnection({
|
||||||
|
deviceId: _this.deviceId,
|
||||||
|
complete (e) {
|
||||||
|
console.log("蓝牙连接回调=====", e)
|
||||||
|
if (!e.errCode) {
|
||||||
|
uni.showToast({
|
||||||
|
icon: 'none',
|
||||||
|
title: `蓝牙连接成功`
|
||||||
|
})
|
||||||
|
//获取蓝牙设备所有服务(service)。
|
||||||
|
setTimeout(()=> {
|
||||||
|
_this.getBLEDeviceServices()
|
||||||
|
}, 2000)
|
||||||
|
} else {
|
||||||
|
uni.showToast({
|
||||||
|
icon: 'none',
|
||||||
|
title: `连接设备失败:${e.errMsg}`
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
getBLEDeviceServices(){
|
||||||
|
var _this = this
|
||||||
|
uni.getBLEDeviceServices({
|
||||||
|
// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
|
||||||
|
deviceId: _this.deviceId,
|
||||||
|
success:(res)=>{
|
||||||
|
console.log('device services:', res)
|
||||||
|
_this.serverList = res.services
|
||||||
|
// _this.serviceId = res.services[0].uuid;
|
||||||
|
console.log('serverId:', _this.serviceId)
|
||||||
|
},
|
||||||
|
fail:(e) =>{
|
||||||
|
uni.showToast({
|
||||||
|
icon: 'none',
|
||||||
|
title: `设备服务获取失败:${e.errMsg}`
|
||||||
|
})
|
||||||
|
console.log("getBLEDeviceServices - fail==============", e)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
getBLEDeviceCharacteristics () {
|
||||||
|
var _this = this
|
||||||
|
uni.getBLEDeviceCharacteristics({
|
||||||
|
// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
|
||||||
|
deviceId: _this.deviceId,
|
||||||
|
// 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取
|
||||||
|
serviceId:_this.serviceId,
|
||||||
|
success:(res)=>{
|
||||||
|
console.log('getBLEDeviceCharacteristics', res)
|
||||||
|
_this.characteristics = res.characteristics
|
||||||
|
// _this.characteristicId = res.characteristics[0].uuid
|
||||||
|
},
|
||||||
|
fail:(res)=>{
|
||||||
console.log(res)
|
console.log(res)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
onConn(item) {
|
// 发送二进制数据
|
||||||
console.log("连接蓝牙---------------" + item.address)
|
async writeBLECharacteristicValue(){
|
||||||
|
if (!this.deviceId) {
|
||||||
bluetoothTool.connDevice(item.address,(result)=>{
|
uni.showToast({
|
||||||
if(result) {
|
icon: 'none',
|
||||||
uni.setStorageSync('lastBleAddress', item.address)
|
title: '请选择设备'
|
||||||
|
})
|
||||||
|
return
|
||||||
}
|
}
|
||||||
console.log('连接结果:',result)
|
if (!this.serviceId) {
|
||||||
});
|
uni.showToast({
|
||||||
|
icon: 'none',
|
||||||
|
title: '请选择设备服务'
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!this.characteristicId) {
|
||||||
|
uni.showToast({
|
||||||
|
icon: 'none',
|
||||||
|
title: '请选择特征值'
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let pic_res = await this.renderPic();
|
||||||
|
uni.showToast({
|
||||||
|
icon: 'none',
|
||||||
|
title: '图片获取成功'
|
||||||
|
})
|
||||||
|
|
||||||
|
let printerJobs = new PrinterJobs()
|
||||||
|
var arr = [{
|
||||||
|
title: '阿根廷车厘子',
|
||||||
|
number: 20,
|
||||||
|
price: '¥188.00'
|
||||||
|
}, {
|
||||||
|
title: '新鲜山竹',
|
||||||
|
number: 38,
|
||||||
|
price: '¥199.00'
|
||||||
|
}]
|
||||||
|
var arr2 = [{
|
||||||
|
title: '平台消暑费',
|
||||||
|
price: '9.99'
|
||||||
|
},{
|
||||||
|
title: '打包费',
|
||||||
|
price: '2.00',
|
||||||
|
}]
|
||||||
|
printerJobs
|
||||||
|
.print(`下单时间:2021-07-25 15:30:23`)
|
||||||
|
.print(printerUtil.fillLine())
|
||||||
|
.print('备注')
|
||||||
|
.setSize(2, 2)
|
||||||
|
.setBold(true)
|
||||||
|
.print(`叫那位非常漂亮的小姐姐送来,其他人送来拒收`)
|
||||||
|
.print(printerUtil.fillLine())
|
||||||
|
.printQrcode(pic_res)
|
||||||
|
// .setSize(1, 1)
|
||||||
|
// .setBold(false)
|
||||||
|
// .print(printerUtil.fillLine('*'))
|
||||||
|
// .setAlign('lt')
|
||||||
|
// .printArray(arr)
|
||||||
|
// .print(printerUtil.fillAround('其它'))
|
||||||
|
// .print(printerUtil.inline('平台随机立减', `-2.10`))
|
||||||
|
// .print(printerUtil.inline('平台服务费', `-10.99`))
|
||||||
|
// .printArray(arr2)
|
||||||
|
// .print(printerUtil.fillLine())
|
||||||
|
// .setAlign('rt')
|
||||||
|
// .setSize(1, 2)
|
||||||
|
// .setBold(true)
|
||||||
|
// .print(`用户支付:¥99.99`)
|
||||||
|
.print(printerUtil.fillLine())
|
||||||
|
|
||||||
|
let buffer = printerJobs.buffer();
|
||||||
|
console.log('buffer>>>',buffer)
|
||||||
|
this.printbuffs(buffer)
|
||||||
},
|
},
|
||||||
senBleLabel() {
|
printbuffs(buffer) {
|
||||||
//标签模式
|
// 1.并行调用多次会存在写失败的可能性
|
||||||
|
// 2.建议每次写入不超过20字节
|
||||||
|
// 分包处理,延时调用
|
||||||
|
const maxChunk = 20;
|
||||||
|
const delay = 20;
|
||||||
|
for (let i = 0, j = 0, length = buffer.byteLength; i < length; i += maxChunk, j++) {
|
||||||
|
let subPackage = buffer.slice(i, i + maxChunk <= length ? (i + maxChunk) : length);
|
||||||
|
setTimeout(this.printbuff, j * delay, subPackage);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getImageInfo(params = {}) {
|
||||||
|
return new Promise((resolve)=> {
|
||||||
uni.canvasGetImageData({
|
uni.canvasGetImageData({
|
||||||
canvasId: 'firstCanvas',
|
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0,
|
y: 0,
|
||||||
width: this.canvasWidth,
|
...params,
|
||||||
height: this.canvasHeight,
|
success(res) {
|
||||||
success: (res)=> {
|
console.log("img====",res);
|
||||||
uni.hideLoading()
|
let data = util.zip_image(res)
|
||||||
|
console.log("zip====", data);
|
||||||
var command = tsc.jpPrinter.createNew()
|
resolve(data);
|
||||||
command.init()
|
|
||||||
command.setSize(80, 60) // 纸张大小
|
|
||||||
command.setGap(2)
|
|
||||||
command.setCls()
|
|
||||||
command.setText(50, 10, "TSS24.BF2", 1, 1, "打印测试")
|
|
||||||
command.setQR(50, 50, "L", 5, "A", "https://www.baidu.com")
|
|
||||||
command.setBitmap(200, 0, 0, res)
|
|
||||||
command.setBox(100, 100, 700, 500, 1)
|
|
||||||
command.setPagePrint()
|
|
||||||
let data = command.getData()
|
|
||||||
bluetoothTool.sendByteData(data)
|
|
||||||
console.log('发送完毕')
|
|
||||||
},
|
|
||||||
fail: function(res) {
|
|
||||||
console.log(res)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
})
|
||||||
|
|
||||||
},
|
},
|
||||||
senBleLabel2(){
|
renderPic() {
|
||||||
//票据模式
|
|
||||||
var command = esc.jpPrinter.createNew()
|
|
||||||
command.init()
|
|
||||||
command.setText(this.piaojuText);
|
|
||||||
command.setPrintAndFeedRow(1)
|
|
||||||
bluetoothTool.sendData(command.getRawData())
|
|
||||||
},
|
|
||||||
renderCanvas() {
|
|
||||||
let filePath = 'http://oss-emis.tanex56.com/sapp/sdg/hdbg.png'
|
let filePath = 'http://oss-emis.tanex56.com/sapp/sdg/hdbg.png'
|
||||||
let that = this
|
let that = this
|
||||||
const firstCanvas = uni.createCanvasContext('firstCanvas', this);
|
return new Promise((resolve, reject)=> {
|
||||||
|
const cxt = uni.createCanvasContext(that.canvasId, that);
|
||||||
let scla = 1
|
let scla = 1
|
||||||
uni.getImageInfo({
|
uni.getImageInfo({
|
||||||
src: filePath,
|
src: filePath,
|
||||||
success(res) {
|
success(res) {
|
||||||
console.log(res.width + "--" + res.height)
|
// that.canvasWidth = res.width * scla
|
||||||
that.canvasWidth = res.width * scla
|
// that.canvasHeight = res.height * scla
|
||||||
that.canvasHeight = res.height * scla
|
// console.log(res, that.canvasWidth, that.canvasHeight)
|
||||||
console.log(res, that.canvasWidth, that.canvasHeight)
|
cxt.drawImage(filePath, 0, 0, that.canvas_width, that.canvas_height);
|
||||||
firstCanvas.drawImage(filePath, 0, 0, that.canvasWidth, that.canvasHeight);
|
cxt.draw();
|
||||||
firstCanvas.draw();
|
that.$nextTick(async () => { //获取画布像素数据
|
||||||
that.$nextTick(() => { //获取画布像素数据
|
let data = await that.getImageInfo({ canvasId: that.canvasId, width: that.canvas_width, height: that.canvas_height, })
|
||||||
|
resolve(data)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
fail(res) {
|
fail(e) {
|
||||||
console.log(res)
|
reject(e)
|
||||||
|
console.log(e)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
printbuff(buffer) {
|
||||||
|
var _this = this
|
||||||
|
uni.writeBLECharacteristicValue({
|
||||||
|
// 这里的 deviceId 需要在 getBluetoothDevices 或 onBluetoothDeviceFound 接口中获取
|
||||||
|
deviceId: _this.deviceId,
|
||||||
|
// 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取
|
||||||
|
serviceId: _this.serviceId,
|
||||||
|
// 这里的 characteristicId 需要在 getBLEDeviceCharacteristics 接口中获取
|
||||||
|
characteristicId: _this.characteristicId,
|
||||||
|
// 这里的value是ArrayBuffer类型
|
||||||
|
value: buffer,
|
||||||
|
success:(res)=> {
|
||||||
|
console.log('writeBLECharacteristicValue success', res.errMsg)
|
||||||
|
},
|
||||||
|
fail:(res)=> {
|
||||||
|
console.log('writeBLECharacteristicValue fail', res.errMsg)
|
||||||
|
},
|
||||||
|
complete (e) {
|
||||||
|
console.log('writeBLECharacteristicValue complete', e)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style scoped>
|
||||||
|
* { font-size: 24rpx;}
|
||||||
|
button { font-size: 28rpx;}
|
||||||
|
.text-red { color: red; font-size: 28rpx;}
|
||||||
|
|
||||||
|
/*二维码隐藏到窗口外*/
|
||||||
|
canvas {
|
||||||
|
position: absolute;
|
||||||
|
top: -999rpx
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
@ -158,7 +158,8 @@
|
|||||||
// val && ()
|
// val && ()
|
||||||
}),
|
}),
|
||||||
handleSubmit() {
|
handleSubmit() {
|
||||||
this.getRealGetWaybillPrintData()
|
// this.getRealGetWaybillPrintData()
|
||||||
|
this.goto("print/bluetoothPrinter")
|
||||||
// this.goto("print/bluetooth-mini-printer")
|
// this.goto("print/bluetooth-mini-printer")
|
||||||
},
|
},
|
||||||
handleSelAll() {
|
handleSelAll() {
|
||||||
|
|||||||
265
pages/print/print/bluetooth.js
Normal file
265
pages/print/print/bluetooth.js
Normal file
@ -0,0 +1,265 @@
|
|||||||
|
class Bluetooth {
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.isOpenBle = false;
|
||||||
|
this.deviceId = "";
|
||||||
|
this.serviceId = "";
|
||||||
|
this.writeId = "";
|
||||||
|
this.notifyId = "";
|
||||||
|
this.openBluetoothAdapter();
|
||||||
|
}
|
||||||
|
|
||||||
|
showToast(title) {
|
||||||
|
uni.showToast({
|
||||||
|
title: title,
|
||||||
|
icon: 'none',
|
||||||
|
'duration': 2000
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
openBluetoothAdapter() {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
uni.openBluetoothAdapter({
|
||||||
|
success: res => {
|
||||||
|
this.isOpenBle = true;
|
||||||
|
this.showToast("初始化蓝牙模块成功");
|
||||||
|
resolve(res);
|
||||||
|
},
|
||||||
|
fail: err => {
|
||||||
|
this.showToast(`初始化蓝牙模块失败` + JSON.stringify(err));
|
||||||
|
reject(err);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
startBluetoothDevicesDiscovery() {
|
||||||
|
if (!this.isOpenBle) {
|
||||||
|
this.showToast(`初始化蓝牙模块失败`)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let self = this;
|
||||||
|
uni.showLoading({
|
||||||
|
title: '蓝牙搜索中'
|
||||||
|
})
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
uni.startBluetoothDevicesDiscovery({
|
||||||
|
success: res => {
|
||||||
|
resolve(res)
|
||||||
|
},
|
||||||
|
fail: res => {
|
||||||
|
self.showToast(`搜索设备失败` + JSON.stringify(err));
|
||||||
|
reject(err);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, 300);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
stopBluetoothDevicesDiscovery() {
|
||||||
|
let self = this;
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
uni.stopBluetoothDevicesDiscovery({
|
||||||
|
success: e => {
|
||||||
|
uni.hideLoading();
|
||||||
|
},
|
||||||
|
fail: e => {
|
||||||
|
uni.hideLoading();
|
||||||
|
self.showToast(`停止搜索蓝牙设备失败` + JSON.stringify(err));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
createBLEConnection() {
|
||||||
|
//设备deviceId
|
||||||
|
let deviceId = this.deviceId;
|
||||||
|
let self = this;
|
||||||
|
|
||||||
|
uni.showLoading({
|
||||||
|
mask: true,
|
||||||
|
title: '设别连接中,请稍候...'
|
||||||
|
})
|
||||||
|
console.log(this.deviceId);
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
uni.createBLEConnection({
|
||||||
|
deviceId,
|
||||||
|
success: (res) => {
|
||||||
|
console.log("res:createBLEConnection " + JSON.stringify(res));
|
||||||
|
resolve(res)
|
||||||
|
},
|
||||||
|
fail: err => {
|
||||||
|
uni.hideLoading();
|
||||||
|
self.showToast(`停止搜索蓝牙设备失败` + JSON.stringify(err));
|
||||||
|
reject(err);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取蓝牙设备所有服务(service)
|
||||||
|
getBLEDeviceServices() {
|
||||||
|
let _serviceList = [];
|
||||||
|
let deviceId = this.deviceId;
|
||||||
|
let self = this;
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
uni.getBLEDeviceServices({
|
||||||
|
deviceId,
|
||||||
|
success: res => {
|
||||||
|
for (let service of res.services) {
|
||||||
|
if (service.isPrimary) {
|
||||||
|
_serviceList.push(service);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uni.hideLoading();
|
||||||
|
console.log("_serviceList: " + JSON.stringify(_serviceList));
|
||||||
|
resolve(_serviceList)
|
||||||
|
},
|
||||||
|
fail: err => {
|
||||||
|
uni.hideLoading();
|
||||||
|
self.showToast(`获取设备Services` + JSON.stringify(err));
|
||||||
|
reject(err);
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}, 500);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取蓝牙设备某个服务中所有特征值(characteristic)
|
||||||
|
getBLEDeviceCharacteristics() {
|
||||||
|
let deviceId = this.deviceId;
|
||||||
|
let serviceId = this.serviceId;
|
||||||
|
|
||||||
|
let self = this;
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
uni.getBLEDeviceCharacteristics({
|
||||||
|
deviceId,
|
||||||
|
serviceId,
|
||||||
|
success: res => {
|
||||||
|
for (let _obj of res.characteristics) {
|
||||||
|
//获取notify
|
||||||
|
if (_obj.properties.notify) {
|
||||||
|
self.notifyId = _obj.uuid;
|
||||||
|
uni.setStorageSync('notifyId', self.notifyId);
|
||||||
|
}
|
||||||
|
//获取writeId
|
||||||
|
if (_obj.properties.write) {
|
||||||
|
self.writeId = _obj.uuid;
|
||||||
|
uni.setStorageSync('writeId', self.writeId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//console.log("res:getBLEDeviceCharacteristics " + JSON.stringify(res));
|
||||||
|
let result = {
|
||||||
|
'notifyId': self.notifyId,
|
||||||
|
'writeId': self.writeId
|
||||||
|
};
|
||||||
|
self.showToast(`获取服务中所有特征值OK,${JSON.stringify(result)}`);
|
||||||
|
resolve(result)
|
||||||
|
},
|
||||||
|
fail: err => {
|
||||||
|
self.showToast(`getBLEDeviceCharacteristics` + JSON.stringify(err));
|
||||||
|
reject(err);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//断开联链接
|
||||||
|
closeBLEConnection() {
|
||||||
|
let deviceId = this.deviceId;
|
||||||
|
uni.closeBLEConnection({
|
||||||
|
deviceId,
|
||||||
|
success(res) {
|
||||||
|
console.log(res)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
notifyBLECharacteristicValue() {
|
||||||
|
let deviceId = this.deviceId;
|
||||||
|
let serviceId = this.serviceId;
|
||||||
|
let characteristicId = this.notifyId;
|
||||||
|
|
||||||
|
uni.notifyBLECharacteristicValueChange({
|
||||||
|
state: true, // 启用 notify 功能
|
||||||
|
deviceId,
|
||||||
|
serviceId,
|
||||||
|
characteristicId,
|
||||||
|
success(res) {
|
||||||
|
uni.onBLECharacteristicValueChange(function(res) {
|
||||||
|
|
||||||
|
});
|
||||||
|
},
|
||||||
|
fail(res) {
|
||||||
|
console.log('notifyBLECharacteristicValueChange failed:' + res.errMsg);
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
writeBLECharacteristicValue(buffer) {
|
||||||
|
let deviceId = this.deviceId;
|
||||||
|
let serviceId = this.serviceId;
|
||||||
|
let characteristicId = this.writeId;
|
||||||
|
|
||||||
|
console.log("this: " + JSON.stringify(this));
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
uni.writeBLECharacteristicValue({
|
||||||
|
deviceId,
|
||||||
|
serviceId,
|
||||||
|
characteristicId,
|
||||||
|
value: buffer,
|
||||||
|
success(res) {
|
||||||
|
console.log('message发送成功', JSON.stringify(res));
|
||||||
|
resolve(res);
|
||||||
|
},
|
||||||
|
fail(err) {
|
||||||
|
console.log('message发送失败', JSON.stringify(err));
|
||||||
|
reject(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
closeBluetoothAdapter() {
|
||||||
|
uni.closeBluetoothAdapter({
|
||||||
|
success: res => {
|
||||||
|
console.log(res)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//若APP在之前已有搜索过某个蓝牙设备,并成功建立连接,可直接传入之前搜索获取的 deviceId 直接尝试连接该设备,无需进行搜索操作。
|
||||||
|
reconnect() {
|
||||||
|
(async () => {
|
||||||
|
try {
|
||||||
|
this.deviceId = this.deviceId || uni.getStorageSync("deviceId");
|
||||||
|
this.serviceId = this.serviceId || uni.getStorageSync("serviceId");
|
||||||
|
|
||||||
|
let result1 = await this.createBLEConnection();
|
||||||
|
console.log("createBLEConnection: " + JSON.stringify(result1));
|
||||||
|
|
||||||
|
let result2 = await this.getBLEDeviceServices();
|
||||||
|
console.log("getBLEDeviceServices: " + JSON.stringify(result2));
|
||||||
|
|
||||||
|
let result3 = await this.getBLEDeviceCharacteristics();
|
||||||
|
console.log("getBLEDeviceCharacteristics: " + JSON.stringify(result3));
|
||||||
|
|
||||||
|
// this.writeId = uni.getStorageSync("writeId");
|
||||||
|
// this.notifyId = uni.getStorageSync("notifyId");
|
||||||
|
} catch (err) {
|
||||||
|
console.log("err: " + JSON.stringify(err));
|
||||||
|
}
|
||||||
|
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Bluetooth;
|
||||||
193
pages/print/print/commands.js
Normal file
193
pages/print/print/commands.js
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
/**
|
||||||
|
* 修改自https://github.com/song940/node-escpos/blob/master/commands.js
|
||||||
|
* ESC/POS _ (Constants)
|
||||||
|
*/
|
||||||
|
var _ = {
|
||||||
|
LF: [0x0a],
|
||||||
|
FS: [0x1c],
|
||||||
|
FF: [0x0c],
|
||||||
|
GS: [0x1d],
|
||||||
|
DLE: [0x10],
|
||||||
|
EOT: [0x04],
|
||||||
|
NUL: [0x00],
|
||||||
|
ESC: [0x1b],
|
||||||
|
EOL: '\n',
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [FEED_CONTROL_SEQUENCES Feed control sequences]
|
||||||
|
* @type {Object}
|
||||||
|
*/
|
||||||
|
_.FEED_CONTROL_SEQUENCES = {
|
||||||
|
CTL_LF: [0x0a], // Print and line feed
|
||||||
|
CTL_GLF: [0x4a, 0x00], // Print and feed paper (without spaces between lines)
|
||||||
|
CTL_FF: [0x0c], // Form feed
|
||||||
|
CTL_CR: [0x0d], // Carriage return
|
||||||
|
CTL_HT: [0x09], // Horizontal tab
|
||||||
|
CTL_VT: [0x0b], // Vertical tab
|
||||||
|
};
|
||||||
|
|
||||||
|
_.CHARACTER_SPACING = {
|
||||||
|
CS_DEFAULT: [0x1b, 0x20, 0x00],
|
||||||
|
CS_SET: [0x1b, 0x20]
|
||||||
|
};
|
||||||
|
|
||||||
|
_.LINE_SPACING = {
|
||||||
|
LS_DEFAULT: [0x1b, 0x32],
|
||||||
|
LS_SET: [0x1b, 0x33]
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [HARDWARE Printer hardware]
|
||||||
|
* @type {Object}
|
||||||
|
*/
|
||||||
|
_.HARDWARE = {
|
||||||
|
HW_INIT: [0x1b, 0x40], // Clear data in buffer and reset modes
|
||||||
|
HW_SELECT: [0x1b, 0x3d, 0x01], // Printer select
|
||||||
|
HW_RESET: [0x1b, 0x3f, 0x0a, 0x00], // Reset printer hardware
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [CASH_DRAWER Cash Drawer]
|
||||||
|
* @type {Object}
|
||||||
|
*/
|
||||||
|
_.CASH_DRAWER = {
|
||||||
|
CD_KICK_2: [0x1b, 0x70, 0x00], // Sends a pulse to pin 2 []
|
||||||
|
CD_KICK_5: [0x1b, 0x70, 0x01], // Sends a pulse to pin 5 []
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [MARGINS Margins sizes]
|
||||||
|
* @type {Object}
|
||||||
|
*/
|
||||||
|
_.MARGINS = {
|
||||||
|
BOTTOM: [0x1b, 0x4f], // Fix bottom size
|
||||||
|
LEFT: [0x1b, 0x6c], // Fix left size
|
||||||
|
RIGHT: [0x1b, 0x51], // Fix right size
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [PAPER Paper]
|
||||||
|
* @type {Object}
|
||||||
|
*/
|
||||||
|
_.PAPER = {
|
||||||
|
PAPER_FULL_CUT: [0x1d, 0x56, 0x00], // Full cut paper
|
||||||
|
PAPER_PART_CUT: [0x1d, 0x56, 0x01], // Partial cut paper
|
||||||
|
PAPER_CUT_A: [0x1d, 0x56, 0x41], // Partial cut paper
|
||||||
|
PAPER_CUT_B: [0x1d, 0x56, 0x42], // Partial cut paper
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [TEXT_FORMAT Text format]
|
||||||
|
* @type {Object}
|
||||||
|
*/
|
||||||
|
_.TEXT_FORMAT = {
|
||||||
|
TXT_NORMAL: [0x1b, 0x21, 0x00], // Normal text
|
||||||
|
TXT_2HEIGHT: [0x1b, 0x21, 0x10], // Double height text
|
||||||
|
TXT_2WIDTH: [0x1b, 0x21, 0x20], // Double width text
|
||||||
|
TXT_4SQUARE: [0x1b, 0x21, 0x30], // Double width & height text
|
||||||
|
|
||||||
|
TXT_UNDERL_OFF: [0x1b, 0x2d, 0x00], // Underline font OFF
|
||||||
|
TXT_UNDERL_ON: [0x1b, 0x2d, 0x01], // Underline font 1-dot ON
|
||||||
|
TXT_UNDERL2_ON: [0x1b, 0x2d, 0x02], // Underline font 2-dot ON
|
||||||
|
TXT_BOLD_OFF: [0x1b, 0x45, 0x00], // Bold font OFF
|
||||||
|
TXT_BOLD_ON: [0x1b, 0x45, 0x01], // Bold font ON
|
||||||
|
TXT_ITALIC_OFF: [0x1b, 0x35], // Italic font ON
|
||||||
|
TXT_ITALIC_ON: [0x1b, 0x34], // Italic font ON
|
||||||
|
|
||||||
|
TXT_FONT_A: [0x1b, 0x4d, 0x00], // Font type A
|
||||||
|
TXT_FONT_B: [0x1b, 0x4d, 0x01], // Font type B
|
||||||
|
TXT_FONT_C: [0x1b, 0x4d, 0x02], // Font type C
|
||||||
|
|
||||||
|
TXT_ALIGN_LT: [0x1b, 0x61, 0x00], // Left justification
|
||||||
|
TXT_ALIGN_CT: [0x1b, 0x61, 0x01], // Centering
|
||||||
|
TXT_ALIGN_RT: [0x1b, 0x61, 0x02], // Right justification
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [BARCODE_FORMAT Barcode format]
|
||||||
|
* @type {Object}
|
||||||
|
*/
|
||||||
|
_.BARCODE_FORMAT = {
|
||||||
|
BARCODE_TXT_OFF: [0x1d, 0x48, 0x00], // HRI barcode chars OFF
|
||||||
|
BARCODE_TXT_ABV: [0x1d, 0x48, 0x01], // HRI barcode chars above
|
||||||
|
BARCODE_TXT_BLW: [0x1d, 0x48, 0x02], // HRI barcode chars below
|
||||||
|
BARCODE_TXT_BTH: [0x1d, 0x48, 0x03], // HRI barcode chars both above and below
|
||||||
|
|
||||||
|
BARCODE_FONT_A: [0x1d, 0x66, 0x00], // Font type A for HRI barcode chars
|
||||||
|
BARCODE_FONT_B: [0x1d, 0x66, 0x01], // Font type B for HRI barcode chars
|
||||||
|
|
||||||
|
BARCODE_HEIGHT: function (height) { // Barcode Height [1-255]
|
||||||
|
return [0x1d, 0x68, height];
|
||||||
|
},
|
||||||
|
BARCODE_WIDTH: function (width) { // Barcode Width [2-6]
|
||||||
|
return [0x1d, 0x77, width];
|
||||||
|
},
|
||||||
|
BARCODE_HEIGHT_DEFAULT: [0x1d, 0x68, 0x64], // Barcode height default:100
|
||||||
|
BARCODE_WIDTH_DEFAULT: [0x1d, 0x77, 0x01], // Barcode width default:1
|
||||||
|
|
||||||
|
BARCODE_UPC_A: [0x1d, 0x6b, 0x00], // Barcode type UPC-A
|
||||||
|
BARCODE_UPC_E: [0x1d, 0x6b, 0x01], // Barcode type UPC-E
|
||||||
|
BARCODE_EAN13: [0x1d, 0x6b, 0x02], // Barcode type EAN13
|
||||||
|
BARCODE_EAN8: [0x1d, 0x6b, 0x03], // Barcode type EAN8
|
||||||
|
BARCODE_CODE39: [0x1d, 0x6b, 0x04], // Barcode type CODE39
|
||||||
|
BARCODE_ITF: [0x1d, 0x6b, 0x05], // Barcode type ITF
|
||||||
|
BARCODE_NW7: [0x1d, 0x6b, 0x06], // Barcode type NW7
|
||||||
|
BARCODE_CODE93: [0x1d, 0x6b, 0x48], // Barcode type CODE93
|
||||||
|
BARCODE_CODE128: [0x1d, 0x6b, 0x49], // Barcode type CODE128
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [IMAGE_FORMAT Image format]
|
||||||
|
* @type {Object}
|
||||||
|
*/
|
||||||
|
_.IMAGE_FORMAT = {
|
||||||
|
S_RASTER_N: [0x1d, 0x76, 0x30, 0x00], // Set raster image normal size
|
||||||
|
S_RASTER_2W: [0x1d, 0x76, 0x30, 0x01], // Set raster image double width
|
||||||
|
S_RASTER_2H: [0x1d, 0x76, 0x30, 0x02], // Set raster image double height
|
||||||
|
S_RASTER_Q: [0x1d, 0x76, 0x30, 0x03], // Set raster image quadruple
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [BITMAP_FORMAT description]
|
||||||
|
* @type {Object}
|
||||||
|
*/
|
||||||
|
_.BITMAP_FORMAT = {
|
||||||
|
BITMAP_S8: [0x1b, 0x2a, 0x00],
|
||||||
|
BITMAP_D8: [0x1b, 0x2a, 0x01],
|
||||||
|
BITMAP_S24: [0x1b, 0x2a, 0x20],
|
||||||
|
BITMAP_D24: [0x1b, 0x2a, 0x21]
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [GSV0_FORMAT description]
|
||||||
|
* @type {Object}
|
||||||
|
*/
|
||||||
|
_.GSV0_FORMAT = {
|
||||||
|
GSV0_NORMAL: [0x1d, 0x76, 0x30, 0x00],
|
||||||
|
GSV0_DW: [0x1d, 0x76, 0x30, 0x01],
|
||||||
|
GSV0_DH: [0x1d, 0x76, 0x30, 0x02],
|
||||||
|
GSV0_DWDH: [0x1d, 0x76, 0x30, 0x03]
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [BEEP description]
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
_.BEEP = [0x1b, 0x42]; // Printer Buzzer pre hex
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [COLOR description]
|
||||||
|
* @type {Object}
|
||||||
|
*/
|
||||||
|
|
||||||
|
_.COLOR = {
|
||||||
|
0: [0x1b, 0x72, 0x00], // black
|
||||||
|
1: [0x1b, 0x72, 0x01] // red
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [exports description]
|
||||||
|
* @type {[type]}
|
||||||
|
*/
|
||||||
|
export default _
|
||||||
191
pages/print/print/gbk.js
Normal file
191
pages/print/print/gbk.js
Normal file
File diff suppressed because one or more lines are too long
221
pages/print/print/printerjobs.js
Normal file
221
pages/print/print/printerjobs.js
Normal file
@ -0,0 +1,221 @@
|
|||||||
|
import commands from'./commands'
|
||||||
|
import gbk from'./gbk'
|
||||||
|
import * as printerUtil from'./printerutil'
|
||||||
|
|
||||||
|
const printerJobs = function() {
|
||||||
|
this._queue = Array.from(commands.HARDWARE.HW_INIT);
|
||||||
|
this._enqueue = function(cmd) {
|
||||||
|
this._queue.push.apply(this._queue, cmd);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 增加打印内容
|
||||||
|
* @param {string} content 文字内容
|
||||||
|
*/
|
||||||
|
printerJobs.prototype.text = function(content) {
|
||||||
|
if (content) {
|
||||||
|
let uint8Array = gbk.encode(content);
|
||||||
|
let encoded = Array.from(uint8Array);
|
||||||
|
this._enqueue(encoded);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打印文字
|
||||||
|
* @param {string} content 文字内容
|
||||||
|
*/
|
||||||
|
printerJobs.prototype.print = function(content) {
|
||||||
|
this.text(content);
|
||||||
|
this._enqueue(commands.LF);
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
printerJobs.prototype.printArray = function(array) {
|
||||||
|
array.forEach(v => {
|
||||||
|
if (v.number) {
|
||||||
|
this.text(printerUtil.inline(v.title + '*' + v.number, `${v.price}`))
|
||||||
|
} else {
|
||||||
|
this.text(printerUtil.inline(v.title, `${v.price}`))
|
||||||
|
}
|
||||||
|
this._enqueue(commands.LF);
|
||||||
|
})
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
printerJobs.prototype.printQrcode = function(content) {
|
||||||
|
|
||||||
|
if (content) {
|
||||||
|
const cmds = [].concat([27, 97, 1], [29, 118, 48, 0, 30, 0, 240, 0], content, [27, 74, 3], [27, 64]);
|
||||||
|
this._enqueue(cmds);
|
||||||
|
this._enqueue(commands.LF);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
printerJobs.prototype.printQrcodeByESC = function(content) {
|
||||||
|
let arrPrint = [];
|
||||||
|
|
||||||
|
let uint8Array = gbk.encode(content);
|
||||||
|
let encoded = Array.from(uint8Array);
|
||||||
|
|
||||||
|
//初始化打印机
|
||||||
|
arrPrint= arrPrint.concat([0x1B, 0x40]); //16进制
|
||||||
|
//居中对齐
|
||||||
|
arrPrint=arrPrint.concat([0x1B, 0x61, 0x01]); //16进制
|
||||||
|
//正文
|
||||||
|
/*
|
||||||
|
* QR Code 设置单元大小 【格式】 ASCII GS ( k pL pH 1 C n 十六进制 1D 28 6B 03
|
||||||
|
* 00 31 43 n 十进制 29 40 107 03 0 49 67 n 功能:设置QR CODE 单元大小。
|
||||||
|
* 说明:·n 对应QR版本号, 决定QR CODE的高度与宽度。 · 1≤n ≤16。(十六进制为0x01≤n ≤0x0f)
|
||||||
|
*/
|
||||||
|
//设置设置 QR Code 的单元大小为 n 点
|
||||||
|
arrPrint=arrPrint.concat([0x1d, 0x28, 0x6b, 0x03, 0x00, 0x31, 0x43, 0x05]);
|
||||||
|
//设置错误纠正等级
|
||||||
|
arrPrint=arrPrint.concat([0x1d, 0x28, 0x6b, 0x03, 0x00, 0x31, 0x45, 0x05]);
|
||||||
|
//传入数据的长度+3
|
||||||
|
arrPrint=arrPrint.concat([0x1d, 0x28, 0x6b, encoded.length+3, 0x00, 0x31, 0x50, 0x30]);
|
||||||
|
//二维码内容
|
||||||
|
arrPrint=arrPrint.concat(encoded);
|
||||||
|
//开始打印二维码
|
||||||
|
arrPrint=arrPrint.concat([0x1d, 0x28, 0x6b, 0x03, 0x00, 0x31, 0x51, 0x30]);
|
||||||
|
//恢复居左对齐
|
||||||
|
arrPrint=arrPrint.concat([0x1B, 0x61, 0x00]); //16进制
|
||||||
|
this._enqueue(arrPrint);
|
||||||
|
this._enqueue(commands.LF);
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打印文字并换行
|
||||||
|
* @param {string} content 文字内容
|
||||||
|
*/
|
||||||
|
printerJobs.prototype.println = function(content = '') {
|
||||||
|
return this.print(content + commands.EOL);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置对齐方式
|
||||||
|
* @param {string} align 对齐方式 LT/CT/RT
|
||||||
|
*/
|
||||||
|
printerJobs.prototype.setAlign = function(align) {
|
||||||
|
this._enqueue(commands.TEXT_FORMAT['TXT_ALIGN_' + align.toUpperCase()]);
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置字体
|
||||||
|
* @param {string} family A/B/C
|
||||||
|
*/
|
||||||
|
printerJobs.prototype.setFont = function(family) {
|
||||||
|
this._enqueue(commands.TEXT_FORMAT['TXT_FONT_' + family.toUpperCase()]);
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设定字体尺寸
|
||||||
|
* @param {number} width 字体宽度 1~2
|
||||||
|
* @param {number} height 字体高度 1~2
|
||||||
|
*/
|
||||||
|
printerJobs.prototype.setSize = function(width, height) {
|
||||||
|
if (2 >= width && 2 >= height) {
|
||||||
|
this._enqueue(commands.TEXT_FORMAT.TXT_NORMAL);
|
||||||
|
if (2 === width && 2 === height) {
|
||||||
|
this._enqueue(commands.TEXT_FORMAT.TXT_4SQUARE);
|
||||||
|
} else if (1 === width && 2 === height) {
|
||||||
|
this._enqueue(commands.TEXT_FORMAT.TXT_2HEIGHT);
|
||||||
|
} else if (2 === width && 1 === height) {
|
||||||
|
this._enqueue(commands.TEXT_FORMAT.TXT_2WIDTH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设定字体是否加粗
|
||||||
|
* @param {boolean} bold
|
||||||
|
*/
|
||||||
|
printerJobs.prototype.setBold = function(bold) {
|
||||||
|
if (typeof bold !== 'boolean') {
|
||||||
|
bold = true;
|
||||||
|
}
|
||||||
|
this._enqueue(bold ? commands.TEXT_FORMAT.TXT_BOLD_ON : commands.TEXT_FORMAT.TXT_BOLD_OFF);
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设定是否开启下划线
|
||||||
|
* @param {boolean} underline
|
||||||
|
*/
|
||||||
|
printerJobs.prototype.setUnderline = function(underline) {
|
||||||
|
if (typeof underline !== 'boolean') {
|
||||||
|
underline = true;
|
||||||
|
}
|
||||||
|
this._enqueue(underline ? commands.TEXT_FORMAT.TXT_UNDERL_ON : commands.TEXT_FORMAT.TXT_UNDERL_OFF);
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置行间距为 n 点行,默认值行间距是 30 点
|
||||||
|
* @param {number} n 0≤n≤255
|
||||||
|
*/
|
||||||
|
printerJobs.prototype.setLineSpacing = function(n) {
|
||||||
|
if (n === undefined || n === null) {
|
||||||
|
this._enqueue(commands.LINE_SPACING.LS_DEFAULT);
|
||||||
|
} else {
|
||||||
|
this._enqueue(commands.LINE_SPACING.LS_SET);
|
||||||
|
this._enqueue([n]);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打印空行
|
||||||
|
* @param {number} n
|
||||||
|
*/
|
||||||
|
printerJobs.prototype.lineFeed = function(n = 1) {
|
||||||
|
return this.print(new Array(n).fill(commands.EOL).join(''));
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置字体颜色,需要打印机支持
|
||||||
|
* @param {number} color - 0 默认颜色黑色 1 红色
|
||||||
|
*/
|
||||||
|
printerJobs.prototype.setColor = function(color) {
|
||||||
|
this._enqueue(commands.COLOR[color === 1 ? 1 : 0]);
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://support.loyverse.com/hardware/printers/use-the-beeper-in-a-escpos-printers
|
||||||
|
* 蜂鸣警报,需要打印机支持
|
||||||
|
* @param {number} n 蜂鸣次数,1-9
|
||||||
|
* @param {number} t 蜂鸣长短,1-9
|
||||||
|
*/
|
||||||
|
printerJobs.prototype.beep = function(n, t) {
|
||||||
|
this._enqueue(commands.BEEP);
|
||||||
|
this._enqueue([n, t]);
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清空任务
|
||||||
|
*/
|
||||||
|
printerJobs.prototype.clear = function() {
|
||||||
|
this._queue = Array.from(commands.HARDWARE.HW_INIT);
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回ArrayBuffer
|
||||||
|
*/
|
||||||
|
printerJobs.prototype.buffer = function() {
|
||||||
|
return new Uint8Array(this._queue).buffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default printerJobs
|
||||||
91
pages/print/print/printerutil.js
Normal file
91
pages/print/print/printerutil.js
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
// 打印机纸宽58mm,页的宽度384,字符宽度为1,每行最多盛放32个字符
|
||||||
|
const PAGE_WIDTH = 384;
|
||||||
|
const MAX_CHAR_COUNT_EACH_LINE = 32;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param str
|
||||||
|
* @returns {boolean} str是否全是中文
|
||||||
|
*/
|
||||||
|
function isChinese(str) {
|
||||||
|
return /^[\u4e00-\u9fa5]$/.test(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回字符串宽度(1个中文=2个英文字符)
|
||||||
|
* @param str
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
function getStringWidth(str) {
|
||||||
|
let width = 0;
|
||||||
|
for (let i = 0, len = str.length; i < len; i++) {
|
||||||
|
width += isChinese(str.charAt(i)) ? 2 : 1;
|
||||||
|
}
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 同一行输出str1, str2,str1居左, str2居右
|
||||||
|
* @param {string} str1 内容1
|
||||||
|
* @param {string} str2 内容2
|
||||||
|
* @param {number} fontWidth 字符宽度 1/2
|
||||||
|
* @param {string} fillWith str1 str2之间的填充字符
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function inline(str1, str2, fillWith = ' ', fontWidth = 1) {
|
||||||
|
const lineWidth = MAX_CHAR_COUNT_EACH_LINE / fontWidth;
|
||||||
|
// 需要填充的字符数量
|
||||||
|
let fillCount = lineWidth - (getStringWidth(str1) + getStringWidth(str2) + 2) % lineWidth;
|
||||||
|
let fillStr = new Array(fillCount).fill(fillWith.charAt(0)).join('');
|
||||||
|
return str1 + fillStr + str2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用字符填充一整行
|
||||||
|
* @param {string} fillWith 填充字符
|
||||||
|
* @param {number} fontWidth 字符宽度 1/2
|
||||||
|
*/
|
||||||
|
function fillLine(fillWith = '-', fontWidth = 1) {
|
||||||
|
const lineWidth = MAX_CHAR_COUNT_EACH_LINE / fontWidth;
|
||||||
|
return new Array(lineWidth).fill(fillWith.charAt(0)).join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文字内容居中,左右用字符填充
|
||||||
|
* @param {string} str 文字内容
|
||||||
|
* @param {number} fontWidth 字符宽度 1/2
|
||||||
|
* @param {string} fillWith str1 str2之间的填充字符
|
||||||
|
*/
|
||||||
|
function fillAround(str, fillWith = '-', fontWidth = 1) {
|
||||||
|
const lineWidth = MAX_CHAR_COUNT_EACH_LINE / fontWidth;
|
||||||
|
let strWidth = getStringWidth(str);
|
||||||
|
// 内容已经超过一行了,没必要填充
|
||||||
|
if (strWidth >= lineWidth) {
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
// 需要填充的字符数量
|
||||||
|
let fillCount = lineWidth - strWidth;
|
||||||
|
// 左侧填充的字符数量
|
||||||
|
let leftCount = Math.round(fillCount / 2);
|
||||||
|
// 两侧的填充字符,需要考虑左边需要填充,右边不需要填充的情况
|
||||||
|
let fillStr = new Array(leftCount).fill(fillWith.charAt(0)).join('');
|
||||||
|
return fillStr + str + fillStr.substr(0, fillCount - leftCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ArrayBuffer转16进度字符串示例
|
||||||
|
function ab2hex(buffer) {
|
||||||
|
const hexArr = Array.prototype.map.call(
|
||||||
|
new Uint8Array(buffer),
|
||||||
|
function(bit) {
|
||||||
|
return ('00' + bit.toString(16)).slice(-2)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return hexArr.join(',')
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export {
|
||||||
|
inline,
|
||||||
|
fillLine,
|
||||||
|
fillAround,
|
||||||
|
ab2hex,
|
||||||
|
};
|
||||||
66
pages/print/print/util.js
Normal file
66
pages/print/print/util.js
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
const formatTime = date => {
|
||||||
|
const year = date.getFullYear()
|
||||||
|
const month = date.getMonth() + 1
|
||||||
|
const day = date.getDate()
|
||||||
|
const hour = date.getHours()
|
||||||
|
const minute = date.getMinutes()
|
||||||
|
const second = date.getSeconds()
|
||||||
|
|
||||||
|
return [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute, second].map(formatNumber).join(':')
|
||||||
|
}
|
||||||
|
|
||||||
|
const formatNumber = n => {
|
||||||
|
n = n.toString()
|
||||||
|
return n[1] ? n : '0' + n
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//4合1
|
||||||
|
function convert4to1(res) {
|
||||||
|
let arr = [];
|
||||||
|
for (let i = 0; i < res.length; i++) {
|
||||||
|
if (i % 4 == 0) {
|
||||||
|
let rule = 0.29900 * res[i] + 0.58700 * res[i + 1] + 0.11400 * res[i + 2];
|
||||||
|
if (rule > 200) {
|
||||||
|
res[i] = 0;
|
||||||
|
} else {
|
||||||
|
res[i] = 1;
|
||||||
|
}
|
||||||
|
arr.push(res[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
//8合1
|
||||||
|
function convert8to1(arr) {
|
||||||
|
let data = [];
|
||||||
|
for (let k = 0; k < arr.length; k += 8) {
|
||||||
|
let temp = arr[k] * 128 + arr[k + 1] * 64 + arr[k + 2] * 32 + arr[k + 3] * 16 + arr[k + 4] * 8 + arr[k + 5] * 4 +
|
||||||
|
arr[k + 6] * 2 + arr[k + 7] * 1
|
||||||
|
data.push(temp);
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
//我的图片宽度是240,那么拼接的指令就是[29, 118, 48, 0, 30, 0, 240, 0]
|
||||||
|
//我的图片宽度是160,那么拼接的指令就是[29, 118, 48, 0, 20, 0, 160, 0]
|
||||||
|
//补充一点,打印非二维码的图片,宽度一定要是24的倍数,不然打印也会出现乱码
|
||||||
|
function toArrayBuffer(res) {
|
||||||
|
let arr = convert4to1(res.data);
|
||||||
|
let data = convert8to1(arr);
|
||||||
|
let cmds = [].concat([27, 97, 1], [29, 118, 48, 0, 30, 0, 240, 0], data, [27, 74, 3], [27, 64]);
|
||||||
|
return new Uint8Array(cmds).buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
function zip_image(res) {
|
||||||
|
let arr = convert4to1(res.data);
|
||||||
|
let data = convert8to1(arr);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
formatTime,
|
||||||
|
toArrayBuffer,
|
||||||
|
zip_image,
|
||||||
|
}
|
||||||
5
pages/print/print/weapp.qrcode.esm.js
Normal file
5
pages/print/print/weapp.qrcode.esm.js
Normal file
File diff suppressed because one or more lines are too long
BIN
static/images/login/bg-yun.png
Normal file
BIN
static/images/login/bg-yun.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 250 KiB After Width: | Height: | Size: 78 KiB |
Loading…
Reference in New Issue
Block a user