tianyi 6 days ago
parent
commit
2c26426eca
  1. 618
      components/print/index.js
  2. 6
      components/tab-bar/myCenter.vue

618
components/print/index.js

@ -1,317 +1,315 @@
import PrinterJobs from '@/components/print/printerjobs.js'
import PrinterJobs from '@/components/print/printerjobs.js' import printerUtil from '@/components/print/printerutil.js'
import printerUtil from '@/components/print/printerutil.js' import util from '@/components/print/util.js'
import util from '@/components/print/util.js' import drawQrcode from '@/components/print/weapp.qrcode.esm.js'
import drawQrcode from '@/components/print/weapp.qrcode.esm.js' import Bluetooth from '@/components/print/bluetooth.js'
import Bluetooth from '@/components/print/bluetooth.js' let bluetooth = new Bluetooth();
let bluetooth = new Bluetooth(); let isPrint = false
let isPrint= false let data1 = {}
let data1 = {} export default {
export default { getData(onDone) {
// onDone: 打印完成(或失败/跳过)后执行的回调,用于队列驱动 var that = this;
getData(onDone) { if (uni.getStorageSync('bluetoothDeviceId')) {
var that = this; let id = uni.getStorageSync('bluetoothDeviceId')
if(uni.getStorageSync('bluetoothDeviceId')){ const baseUrl = getApp().globalData.mainurl
let id = uni.getStorageSync('bluetoothDeviceId') uni.request({
const baseUrl = getApp().globalData.mainurl url: baseUrl + "/mall/order/detail/" + getApp().globalData.printData[0].order_id,
uni.request({ data: {},
url: baseUrl + "/mall/order/detail/"+ getApp().globalData.printData[0].order_id, method: 'GET',
data: {}, header: {
method:'GET', "content-type": 'application/x-www-form-urlencoded',
header: { 'accessToken': uni.getStorageSync('hiver_token')
"content-type": 'application/x-www-form-urlencoded', },
'accessToken':uni.getStorageSync('hiver_token') success: function(res) {
}, if (res.data.code == 200) {
success: function(res) { data1 = res.data.result
if (res.data.code == 200) { console.log('打印的数据----------',data1)
data1 = res.data.result that.bindViewTap(id, false, onDone)
that.bindViewTap(id, false, onDone) } else {
} else { uni.showToast({
uni.showToast({ title: res.data.message,
title: res.data.message, icon: 'none'
icon: 'none' });
}); if (typeof onDone === 'function') onDone();
// 请求失败也需要通知队列继续处理下一条 return;
if (typeof onDone === 'function') onDone(); }
return; uni.hideLoading();
} },
uni.hideLoading(); fail: function(err) {
}, uni.hideLoading();
fail: function(err) {
uni.hideLoading();
// 请求失败也需要通知队列继续处理下一条
if (typeof onDone === 'function') onDone();
}
})
}else{
uni.showModal({
title: '提示',
content: '您还没有连接打印机,将无法为您打印小票!',
confirmText:'连接蓝牙',
cancelText:'暂不连接',
success: function (res) {
if (res.confirm) {
uni.navigateTo({
url:'/pages/myCenter/setPrint'
})
}
// 未连接打印机也通知队列继续(跳过当前条)
if (typeof onDone === 'function') onDone();
}
});
}
},
async bindViewTap(deviceId, state, onDone) {
var _this = this;
try {
//1.链接设备
await bluetooth.createBLEConnection(deviceId).then((res) => {
bluetooth.deviceId = deviceId;
}).catch((e) => {
throw e;
});
let server = [];
//2.寻找服务
await bluetooth.getBLEDeviceServices().then((res) => {
bluetooth.notifyId = '';
bluetooth.writeId = '';
bluetooth.num = 0;
bluetooth.serviceList = res
}).catch((e) => {
throw e;
});
//3.获取蓝牙设备所有服务
let result3 = await bluetooth.getBLEDeviceCharacteristics().then(res => {
uni.setStorageSync('bluetoothDeviceId', deviceId);
this.pickUpOnce(onDone)
}).catch((e) => {
throw e;
});
} catch (e) {
// 蓝牙连接异常也需要通知队列继续
if (typeof onDone === 'function') onDone(); if (typeof onDone === 'function') onDone();
} }
}, })
//打印一次 } else {
pickUpOnce(onDone) { uni.showModal({
isPrint = true; title: '提示',
bluetooth.notifyBLECharacteristicValue(); content: '您还没有连接打印机,将无法为您打印小票!',
let self = this; confirmText: '连接蓝牙',
setTimeout(() => { cancelText: '暂不连接',
self.writeBLECharacteristicValue(onDone); success: function(res) {
}, 500); if (res.confirm) {
}, uni.navigateTo({
maskPhoneLastFour(phone) { url: '/pages/myCenter/setPrint'
if (!phone) return ''; })
const str = String(phone); }
if (str.length <= 4) return str; // 长度不足4位直接返回 if (typeof onDone === 'function') onDone();
return str.replace(/.(?=.{4})/g, '*');
},
//写入控制命令
async writeBLECharacteristicValue(onDone) {
let printerJobs = new PrinterJobs();
printerJobs.setAlign('ct').setSize(2, 2).setLineSpacing(60).print(
(data1.deliveryType == 1 && data1.orderType == 3 ? data1.deliveryInfo.numberCode :data1.numberCode) + (
(data1.status == 7 || data1.status == 11) ? '待退款' :
data1.deliveryType == 1 && data1.orderType == 3 ? '面对面配送' :
data1.deliveryType == 1 ? '配送' :
data1.isPack == 0 ? '到店-堂食' :
data1.isPack == 1 ? '到店-打包' : '到店'
)
);
printerJobs.setSize(1, 1).setLineSpacing(40);
printerJobs.setAlign('lt').print(
'预计时间:' + (data1.deliveryInfo == null ? '暂无' : this.formatTime(data1.deliveryInfo.mustFinishTime))
);
printerJobs.setAlign('lt').print(data1.shopName);
printerJobs.print(printerUtil.fillLine('-', 1, 32));
printerJobs.setAlign('lt').setSize(2, 2).setLineSpacing(60).print(
data1.receiverName == null ? '暂无' : data1.receiverName
);
printerJobs.setSize(1, 1).setLineSpacing(40);
printerJobs.setAlign('lt').print('联系电话: ' + this.maskPhoneLastFour(data1.receiverPhone));
printerJobs.setAlign('lt').setSize(2, 2).setLineSpacing(60).print(
'地址:' + (data1.receiverAddress == null ? '暂无' : data1.receiverAddress)
);
printerJobs.setSize(1, 1).setLineSpacing(40);
printerJobs.setAlign('lt').print('顾客电话已被隐藏,您可登录商家端或骑手端查看');
printerJobs.print(printerUtil.fillLine('-', 1, 32));
// 商品列表
for (var i = 0; i < data1.goodsList.length; i++) {
var productName = this.removeEmojis(data1.goodsList[i].productName)
printerJobs.setAlign('lt').setSize(2, 2).print(productName);
if (data1.goodsList[i].specs) {
printerJobs.setSize(1, 1).print(this.delNode(data1.goodsList[i].specs));
}
printerJobs.setSize(2, 2);
printerJobs.setAlign('lt').text('¥'+data1.goodsList[i].price);
printerJobs.text(" ");
printerJobs.print('X' + data1.goodsList[i].quantity);
printerJobs.setSize(1, 1);
}
printerJobs.print(printerUtil.fillLine('-', 1, 32));
printerJobs.setAlign('lt').print('配送费:' + data1.deliveryFee);
printerJobs.print('合计金额:' + data1.totalAmount);
printerJobs.setSize(2, 2).print('备注:' + data1.remark);
printerJobs.setSize(1, 1).print(printerUtil.fillLine('-', 1, 32));
printerJobs.setAlign('lt').print('商品取到后,如有任何商品问题,请及时联系商家和平台,客服将为您服务,谢谢您的惠顾');
printerJobs.lineFeed(3);
let buffer = printerJobs.buffer();
this.sendPrint(buffer, onDone);
},
// 去除字符串中的 Emoji 表情
removeEmojis(str) {
if (!str) return '';
// 兼容性极好的 Emoji 正则表达式(支持各种运行环境,包括小程序和旧版浏览器)
var emojiRegex = /(?:[\u2700-\u27bf]|(?:\ud83c[\udde6-\uddff]){2}|[\ud800-\udbff][\udc00-\udfff]|[\u0023-\u0039]\ufe0f?\u20e3|\u3299|\u3297|\u303d|\u3030|\u24c2|\ud83c[\udd70-\udd71]|\ud83c[\udd7e-\udd7f]|\ud83c\udd8e|\ud83c[\udd91-\udd9a]|\ud83c[\udde6-\uddff]|\ud83c[\ude01-\ude02]|\ud83c\ude1a|\ud83c\ude2f|\ud83c[\ude32-\ude3a]|\ud83c[\ude50-\ude51]|\u203c|\u2049|[\u25aa-\u25ab]|\u25b6|\u25c0|[\u25fb-\u25fe]|\u00a9|\u00ae|\u2122|\u2139|\ud83c\udc04|[\u2600-\u26FF]|\u2b05|\u2b06|\u2b07|\u2b1b|\u2b1c|\u2b50|\u2b55|\u231a|\u231b|\u2328|\u23cf|[\u23e9-\u23f3]|[\u23f8-\u23fa]|\ud83c\udccf|\u2934|\u2935|[\u2190-\u21ff])/g;
return str.replace(emojiRegex, '');
},
formatTime(value) {
if (!value) return '';
if (value == '尽快送达') return '尽快送达';
const date = new Date(value);
// 获取年份
const year = date.getFullYear();
// 获取月份 (getMonth 返回 0-11,所以需要 +1),并补齐0
const month = String(date.getMonth() + 1).padStart(2, '0');
// 获取日 (getDate),并补齐0
const day = String(date.getDate()).padStart(2, '0');
// 获取小时 (getHours),并补齐0
const hour = String(date.getHours()).padStart(2, '0');
// 获取分钟 (getMinutes),并补齐0
const minute = String(date.getMinutes()).padStart(2, '0');
// 获取秒 (getSeconds),并补齐0
const second = String(date.getSeconds()).padStart(2, '0');
// 拼接格式:年-月-日 时:分:秒
return `${year}-${month}-${day} ${hour}:${minute}:${second}`;
},
delNode(data) {
// 1. 统一转为字符串
let str;
if (typeof data === 'object' && data !== null) {
// 对象或数组 → JSON 字符串
str = JSON.stringify(data);
} else if (typeof data === 'string') {
str = data;
} else {
// 其他类型(数字、布尔等)先转字符串
str = String(data);
} }
});
}
},
async bindViewTap(deviceId, state, onDone) {
var _this = this;
try {
await bluetooth.createBLEConnection(deviceId).then((res) => {
bluetooth.deviceId = deviceId;
}).catch((e) => {
throw e;
});
let server = [];
await bluetooth.getBLEDeviceServices().then((res) => {
bluetooth.notifyId = '';
bluetooth.writeId = '';
bluetooth.num = 0;
bluetooth.serviceList = res
}).catch((e) => {
throw e;
});
let result3 = await bluetooth.getBLEDeviceCharacteristics().then(res => {
uni.setStorageSync('bluetoothDeviceId', deviceId);
this.pickUpOnce(onDone)
}).catch((e) => {
throw e;
});
} catch (e) {
if (typeof onDone === 'function') onDone();
}
},
//打印一次
pickUpOnce(onDone) {
isPrint = true;
bluetooth.notifyBLECharacteristicValue();
let self = this;
setTimeout(() => {
self.writeBLECharacteristicValue(onDone);
}, 500);
},
maskPhoneLastFour(phone) {
if (!phone) return '';
const str = String(phone);
if (str.length <= 4) return str;
return str.replace(/.(?=.{4})/g, '*');
},
//写入控制命令
async writeBLECharacteristicValue(onDone) {
let printerJobs = new PrinterJobs();
printerJobs.setAlign('ct').setSize(2, 2).setLineSpacing(60).print(
data1.deliveryType == 1 && data1.orderType == 3 ? data1.deliveryInfo.numberCode : data1.numberCode
);
printerJobs.setAlign('ct').setSize(2, 2).setLineSpacing(60).print(
(data1.deliveryInfo && data1.deliveryInfo.appointmentDelivery == 1 && data1.status != 7 && data1.status == 11)? '预约单':
(data1.status == 7 || data1.status == 11)? '申请退款':
(data1.deliveryType == 1 && data1.orderType == 3) ? '面对面配送':
(data1.status == 3 && data1.deliveryType == 2)? '待消费':
data1.status == 5? '已完成':
data1.status == 6? '已取消':
data1.status == 8? '已退款':
data1.status == 12? '已售后':
data1.isPack == 0 ? '到店-堂食':
data1.isPack == 1 ? '到店-打包':
data1.deliveryType == 1 ? '配送': ''
);
if(data1.deliveryInfo && data1.deliveryInfo.appointmentDelivery == 1){
printerJobs.setAlign('lt').print(
'要求送达时间:' + (data1.deliveryInfo == null ? ' ' : this.formatTime(data1.deliveryInfo.mustFinishTime))
);
}
printerJobs.setSize(1, 1).setLineSpacing(40);
printerJobs.setAlign('lt').print(data1.shopName);
printerJobs.setAlign('lt').print(
'下单时间:' + this.formatTime(data1.createTime)
);
if(data1.mallRefundRecord == null){
if(data1.deliveryType == 1){
printerJobs.setAlign('lt').print(
'预计送达时间:' + (data1.deliveryInfo == null ? ' ' : this.formatTime(data1.deliveryInfo.mustFinishTime))
);
}else if(data1.userRequireMake == 1){
printerJobs.setAlign('lt').print(
'核销时间:' + this.formatTime(data1.createTime)
);
}
}
if(data1.mallRefundRecord != null){
if(data1.userRequireMake == 1 && data1.deliveryType == 2){
printerJobs.setAlign('lt').print(
'核销时间:' + this.formatTime(data1.createTime)
);
}
printerJobs.setAlign('lt').print(
'申请退款时间:' + (data1.mallRefundRecord == null ? ' ' : this.formatTime(data1.mallRefundRecord[0].createTime))
);
// 2. 删除所有大括号 { } 和双引号 " }
const result = str.replace(/[{}"]/g, ''); printerJobs.print(printerUtil.fillLine('-', 1, 32));
return result; if(data1.deliveryType == 1 && data1.status != 7 && data1.status != 11 && data1.status != 5 && data1.status != 6 && data1.status != 8 && data1.status != 12){
}, printerJobs.setAlign('lt').setSize(2, 2).setLineSpacing(60).print(
sendPrint(buffer, onDone) { data1.receiverName == null ? ' ' : data1.receiverName
const maxChunk = 20; // 每次20字节 );
const delay = 50; // 间隔50ms }
isPrint = true; printerJobs.setSize(1, 1).setLineSpacing(40);
printerJobs.setAlign('lt').print('联系电话: ' + this.maskPhoneLastFour(data1.receiverPhone));
const totalLength = buffer.byteLength; if(data1.deliveryType == 1 && data1.status != 7 && data1.status != 11 && data1.status != 5 && data1.status != 6 && data1.status != 8 && data1.status != 12){
let currentIndex = 0; printerJobs.setAlign('lt').setSize(2, 2).setLineSpacing(60).print(
'地址:' + (data1.receiverAddress == null ? ' ' : data1.receiverAddress)
// 创建源数据的视图,方便读取 );
const srcView = new Uint8Array(buffer); }
printerJobs.setSize(1, 1).setLineSpacing(40);
const sendNextChunk = () => { printerJobs.setAlign('lt').print('顾客电话已被隐藏,您可登录商家端或骑手端查看');
if (currentIndex >= totalLength) { printerJobs.print(printerUtil.fillLine('-', 1, 32));
// 发送完毕 for (var i = 0; i < data1.goodsList.length; i++) {
isPrint = false; var productName = this.removeEmojis(data1.goodsList[i].productName)
if (typeof onDone === 'function') onDone(); printerJobs.setAlign('lt').setSize(2, 2).print(productName);
return; if (data1.goodsList[i].specs) {
} printerJobs.setSize(1, 1).print(this.delNode(data1.goodsList[i].specs));
}
const end = Math.min(currentIndex + maxChunk, totalLength); printerJobs.setSize(2, 2);
const chunkLength = end - currentIndex; printerJobs.setAlign('lt').text('¥' + data1.goodsList[i].price);
const valueToSend = new ArrayBuffer(chunkLength); printerJobs.text(" ");
const dstView = new Uint8Array(valueToSend); printerJobs.print('X' + data1.goodsList[i].quantity);
dstView.set(srcView.subarray(currentIndex, end)); printerJobs.setSize(1, 1);
bluetooth.writeBLECharacteristicValue(valueToSend).then(() => { }
currentIndex = end; printerJobs.print(printerUtil.fillLine('-', 1, 32));
setTimeout(sendNextChunk, delay); printerJobs.setAlign('lt').print('配送费:' + data1.deliveryFee);
}).catch((err) => { if(data1.packageFee > 0){
printerJobs.print('打包费:' + data1.packageFee);
isPrint = false; }
if (typeof onDone === 'function') onDone(err); if(data1.userCoupon && data1.userCoupon.length >0){
}); printerJobs.print('优惠券:-' + data1.userCoupon[0].discountAmount);
}; }
if(data1.freeAmount > 0){
// 开始发送第一个包 printerJobs.print('锦鲤免单:-' + data1.freeAmount);
sendNextChunk(); }
}, printerJobs.print('商品金额:' + data1.goodsAmount);
sendPrintData(buffer) { printerJobs.print('合计金额:' + (data1.goodsAmount + data1.deliveryFee + data1.packageFee));
bluetooth.writeBLECharacteristicValue(buffer).then(res => {}); if(data1.mallRefundRecord != null){
}, printerJobs.print('应退金额:' + data1.totalAmount);
startSearch(state) { }else{
let that = this printerJobs.print('实付金额:' + data1.totalAmount);
bluetooth.openBluetoothAdapter().then(e => { }
printerJobs.setSize(2, 2).print('备注:' + data1.remark);
uni.startBluetoothDevicesDiscovery({ if(data1.mallRefundRecord != null){
success: res => { printerJobs.setAlign('lt').print(
uni.onBluetoothDeviceFound(result => { '退款原因:' + (data1.mallRefundRecord == null ? ' ' : data1.mallRefundRecord[0].reason)
let arr = that.list; );
let devices = []; }
let list = result.devices; printerJobs.setSize(1, 1).print(printerUtil.fillLine('-', 1, 32));
for (let i = 0; i < list.length; ++i) { printerJobs.setAlign('lt').print('商品取到后,如有任何商品问题,请及时联系商家和平台,客服将为您服务,谢谢您的惠顾');
if (list[i].name && list[i].name != "未知设备") { printerJobs.lineFeed(3);
let arrNew = arr.filter((item) => { let buffer = printerJobs.buffer();
return item.deviceId == list[i].deviceId; this.sendPrint(buffer, onDone);
}); },
if (arrNew.length == 0) { // 去除字符串中的 Emoji 表情
devices.push(list[i]); removeEmojis(str) {
} if (!str) return '';
if (uni.getStorageSync('bluetoothDeviceId') == list[i] var emojiRegex =
.deviceId) { /(?:[\u2700-\u27bf]|(?:\ud83c[\udde6-\uddff]){2}|[\ud800-\udbff][\udc00-\udfff]|[\u0023-\u0039]\ufe0f?\u20e3|\u3299|\u3297|\u303d|\u3030|\u24c2|\ud83c[\udd70-\udd71]|\ud83c[\udd7e-\udd7f]|\ud83c\udd8e|\ud83c[\udd91-\udd9a]|\ud83c[\udde6-\uddff]|\ud83c[\ude01-\ude02]|\ud83c\ude1a|\ud83c\ude2f|\ud83c[\ude32-\ude3a]|\ud83c[\ude50-\ude51]|\u203c|\u2049|[\u25aa-\u25ab]|\u25b6|\u25c0|[\u25fb-\u25fe]|\u00a9|\u00ae|\u2122|\u2139|\ud83c\udc04|[\u2600-\u26FF]|\u2b05|\u2b06|\u2b07|\u2b1b|\u2b1c|\u2b50|\u2b55|\u231a|\u231b|\u2328|\u23cf|[\u23e9-\u23f3]|[\u23f8-\u23fa]|\ud83c\udccf|\u2934|\u2935|[\u2190-\u21ff])/g;
// that.bindViewTap(list[i].deviceId, state) return str.replace(emojiRegex, '');
} },
} formatTime(value) {
if (!value) return '';
if (value == '尽快送达') return '尽快送达';
const date = new Date(value);
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const hour = String(date.getHours()).padStart(2, '0');
const minute = String(date.getMinutes()).padStart(2, '0');
const second = String(date.getSeconds()).padStart(2, '0');
return `${year}-${month}-${day} ${hour}:${minute}:${second}`;
},
delNode(data) {
let str;
if (typeof data === 'object' && data !== null) {
str = JSON.stringify(data);
} else if (typeof data === 'string') {
str = data;
} else {
str = String(data);
}
const result = str.replace(/[{}"]/g, '');
return result;
},
sendPrint(buffer, onDone) {
const maxChunk = 20;
const delay = 50;
isPrint = true;
const totalLength = buffer.byteLength;
let currentIndex = 0;
const srcView = new Uint8Array(buffer);
const sendNextChunk = () => {
if (currentIndex >= totalLength) {
isPrint = false;
if (typeof onDone === 'function') onDone();
return;
}
const end = Math.min(currentIndex + maxChunk, totalLength);
const chunkLength = end - currentIndex;
const valueToSend = new ArrayBuffer(chunkLength);
const dstView = new Uint8Array(valueToSend);
dstView.set(srcView.subarray(currentIndex, end));
bluetooth.writeBLECharacteristicValue(valueToSend).then(() => {
currentIndex = end;
setTimeout(sendNextChunk, delay);
}).catch((err) => {
isPrint = false;
if (typeof onDone === 'function') onDone(err);
});
};
sendNextChunk();
},
sendPrintData(buffer) {
bluetooth.writeBLECharacteristicValue(buffer).then(res => {});
},
startSearch(state) {
let that = this
bluetooth.openBluetoothAdapter().then(e => {
uni.startBluetoothDevicesDiscovery({
success: res => {
uni.onBluetoothDeviceFound(result => {
let arr = that.list;
let devices = [];
let list = result.devices;
for (let i = 0; i < list.length; ++i) {
if (list[i].name && list[i].name != "未知设备") {
let arrNew = arr.filter((item) => {
return item.deviceId == list[i].deviceId;
});
if (arrNew.length == 0) {
devices.push(list[i]);
} }
that.list = arr.concat(devices); if (uni.getStorageSync('bluetoothDeviceId') == list[i]
}); .deviceId) {
}, // that.bindViewTap(list[i].deviceId, state)
fail: res => { }
uni.hideLoading(); }
uni.showToast({
title: `搜索设备失败` + JSON.stringify(err)
})
} }
that.list = arr.concat(devices);
});
},
fail: res => {
uni.hideLoading();
uni.showToast({
title: `搜索设备失败` + JSON.stringify(err)
}) })
}).catch(e => {}); }
}, })
// 停止搜索 }).catch(e => {});
stopSearch() { },
// 停止搜索
uni.hideLoading(); stopSearch() {
bluetooth.stopBluetoothDevicesDiscovery();
} uni.hideLoading();
} bluetooth.stopBluetoothDevicesDiscovery();
}
}

6
components/tab-bar/myCenter.vue

@ -109,9 +109,9 @@
}, },
methods: { methods: {
init(){ init(){
this.shopName = JSON.parse(uni.getStorageSync('area')).shop.shopName; this.shopName = JSON.parse(uni.getStorageSync('area')).shopName;
this.shopIcon = JSON.parse(uni.getStorageSync('area')).shop.shopIcon; this.shopIcon = JSON.parse(uni.getStorageSync('area')).shopIcon;
this.region = JSON.parse(uni.getStorageSync('area')).shop.region; this.region = JSON.parse(uni.getStorageSync('area')).region;
// key // key
const { keys } = uni.getStorageInfoSync(); const { keys } = uni.getStorageInfoSync();
const data = {}; const data = {};

Loading…
Cancel
Save