微信小店打印组件前端web端对接
1. 打印组件准备
插件下载地址:
Windows 64位下载链接
Windows 32位下载链接
Mac下载链接
注:如使用的是ISV打单或其他软件也需下载。
运营端使用指南:[https://store.weixin.qq.com/chengzhang/webdoc/wiki/544/6c826cffaccc0396/growth_center_manual_for_store?source=7&sourceType=4]
2. WebSocket对接
- 创建WebSocket, 建立web端和插件链接
let waitingList = [], // 等待列表
socket = null,// socket实例
socketReady = false, // 是否开启监听了
event = Event.getInstance() // 发布订阅模式封装的eventBus
function start() {
if (location.protocol.indexOf('https') >= 0) {
socket = new WebSocket('ws://127.0.0.1:12705')
} else if (location.protocol.indexOf('http') >= 0) {
socket = new WebSocket('ws://127.0.0.1:12705')
}
// 打开Socket
socket.onopen = e => {
// 监听消息
socketReady = true
for (let index = 0, len = this.waitingList.length; index < len; index++) {
const element = waitingList[index]
socket.send(JSON.stringify(element))
}
waitingList = []
}
// 接收到Socket传输的消息
socket.onmessage = e => {
const response = JSON.parse(e.data)
const cmd = response.command
event.trigger(cmd, response)
}
// 监听Socket的关闭
socket.onclose = e => {
this.socketReady = false
// event.trigger('spSokcetClose', e) // 触发关闭监听, 需要注册监听 event.on('spSokcetClose', closeHandler)
socket = null
}
// 监听Socket的报错
socket.onerror = e => {
this.socketReady = false
// event.trigger('spSokcetError', e) // 触发错误监听, 需要注册监听 event.on('spSokcetError', errorHandler)
socket = null
}
}
/**
* 发送方法封装
*/
function send(request) {
if (socketReady) {
socket.send(JSON.stringify(request))
} else {
// 等待下次执行
waitingList.push(request)
}
if (!socket) {
// 没有初始化socket,初始化
this.start()
}
}
获取打印机列表
getPrinters() {
const request = {
requestID: '1234', // 自己生成请求的UUID
command: 'getPrinterList'
}
return new Promise((resolve, reject) => {
event.once('getPrinterList', function (res) {
if (res.ret === 0) {
resolve(res)
} else {
reject(res)
}
})
send(request)
})
}
打印、预览面单
function doPrintOrPreview(data, printer, preview = false){
let request = {
requestID: '1234', // 自己生成请求的UUID
command: 'print'
}
const { preview, printer } = params
if (preview) {
request.command = 'preview'
}else {
request.version = '2.0' // 打印必传
request.printType = 2 // Number 打印类型,默认为 1,打印固定高度的面单;如果为2,则打印任意自定义内容,需要传递 size 参数指定纸张尺寸,printInfo 改为传递 base64 格式的 html
request.size = {
width: 76, // 纸张尺寸,单位毫米,printType 为 2 时必传,若是出现面单裁切或面单大小非130*76,则必须传入size
height: 130,
}
request.printer = printer // 选中的打印机,printer.name
}
request.taskList = [] // 面单数据数组
request.taskList.push({
taskID: this._getUUID(8, 10), //String, 调用方保证唯一
printInfo: '', // String, [获取打印报文]接口返回的print_info
printNum: {
curNum: 1, // 打印计数-当前张数
sumNum: 1, // 打印计数-总张数
},
// 自定义模板信息,没有自定义模板需求可不传
// 参考模板url:https://res.wx.qq.com/shop/public/2023-09-12/c39e49ba-9c0e-4912-91c1-5386fdd08f80.xml
customInfo: {
templateUrl, // 自定义模板url
// 模板里面定义的数据字段
data: {},
},
// 面单补充信息,用来覆盖寄件人信息,没有这种需求可以不传
extendData: {},
})
return new Promise((resolve, reject) => {
const handler = function (res) {
if (res.requestID !== request.requestID) return
if (res.command === 'preview') {
// 预览
if (res.previewUrl || res.previewImage) {
let url
if (res.previewUrl) {
url = res.previewUrl
} else if (res && res.previewImage) {
url = res.previewImage
}
window.open(url)
resolve(res)
} else {
reject(res)
}
} else {
//打印
// 失败结果
const errResult = res.results.filter(item => !item.success)
if (errResult.length === 0) {
// 全部成功
resolve(res)
return
}
if (errResult.length === res.results.length && errResult.length > 0) {
// 全部打印失败
const err = new Error()
err.message = '打印失败,失败原因:' + errResult[0].failureReason
reject(err)
return
}
// 部分失败
const err = new Error()
err.message =
'部分运单打印失败,失败原因:' + errResult[0].failureReason
reject(err)
}
event.off(cmd, handler)
}
event.on(cmd, handler)
send(request)
})
}
event 发布订阅模式
export default class Event {
/**
* 构造函数,对象中新增eventHandlers对象存储事件处理器
*/
constructor() {
this.eventHandlers = {}
return this
}
/**
* 返回Event单例对象
* @static
* @returns Event Object
* @memberof Event
*/
static getInstance() {
if (!this.Instance) {
this.Instance = new Event()
}
return this.Instance
}
/**
* 绑定事件监听器(订阅者)
* @param {String} cmd 监听事件名称
* @param {Function} handler 事件处理器
* @memberof Event
*/
on(cmd, handler) {
if (typeof handler === 'function') {
if (!this.eventHandlers[cmd]) {
this.eventHandlers[cmd] = []
}
this.eventHandlers[cmd].push(handler)
}
}
/**
* 移除事件监听器(订阅者)
* @param {String} cmd 监听事件名称
* @param {Function} handler 事件处理器
* @memberof Event
*/
off(cmd, handler) {
if (typeof handler === 'function') {
if (this.eventHandlers[cmd].length > 0) {
const handlerList = this.eventHandlers[cmd]
const len = handlerList.length
for (let index = 0; index < len; index++) {
if (handlerList[index] === handler) {
handlerList.splice(index, 1)
if (handlerList.length === 0) {
delete this.eventHandlers[cmd]
}
break
}
}
}
}
}
/**
* 单词事件监听器
* 执行完毕后移除对应事件监听器
* @param {String} cmd 监听事件名称
* @param {Function} handler 事件处理器
* @memberof Event
*/
once(cmd, handler) {
if (typeof handler === 'function') {
const cbfun = (...params) => {
handler.apply(this, params)
this.off(cmd, cbfun)
}
this.on(cmd, cbfun)
}
}
/**
* 事件触发器
* 触发事件,顺序执行监听器
* @param {*} cmd 监听事件名称
* @param {*} params 传递给事件处理器的传参
* @memberof Event
*/
trigger(cmd, ...params) {
if (!this.eventHandlers[cmd] || !this.eventHandlers[cmd].length) return
const ctrl = this.eventHandlers[cmd]
ctrl.forEach(item => {
item.apply(this, params)
})
}
/**
* 清除一个事件上全部事件事件监听器
* @param {Srting} cmd 事件名称
*/
clear(cmd) {
if (!this.eventHandlers[cmd]) return
delete this.eventHandlers[cmd]
}
}
打印、预览等使用示例参照官方:微信小店API