跳转到内容

JavaScript SDK

JavaScript SDK 适用于微信小程序、UniApp、Taro 等前端框架开发,通过 BLE(低功耗蓝牙)连接打印机设备。

所有包均发布至 npm,以 @psdk/ 为前缀。

Terminal window
npm install @psdk/frame-father @psdk/cpcl @psdk/device-ble-uniapp
包名说明
@psdk/frame-father核心框架
包名说明
@psdk/cpclCPCL 指令
@psdk/escESC 指令
@psdk/tsplTSPL 指令
包名说明
@psdk/device-ble-uniappUniApp BLE
@psdk/device-ble-wechat微信小程序 BLE
@psdk/device-ble-taroTaro BLE
import { UniappBleBluetooth } from "@psdk/device-ble-uniapp";
import { ConnectedDevice, Lifecycle, Raw } from '@psdk/frame-father';
const bluetooth = new UniappBleBluetooth({
allowNoName: false, // 是否允许无名称设备
});
// 监听发现的设备
bluetooth.discovered(async (devices) => {
if (!devices.length) return;
console.log('发现设备:', devices);
// 找到目标设备后连接
const targetDevice = devices.find(d => d.name.includes('Printer'));
if (targetDevice) {
await connectDevice(targetDevice);
}
});
// 开始搜索
await bluetooth.startDiscovery();
let connectedDevice;
async function connectDevice(device) {
try {
connectedDevice = await bluetooth.connect(device);
console.log('连接成功:', connectedDevice.name);
} catch (error) {
console.error('连接失败:', error);
}
}
await bluetooth.disconnect();

CPCL 指令用于便携式标签打印机。详细指令说明请参考 CPCL 指令文档

import { CPCL } from '@psdk/cpcl';
import { Lifecycle } from '@psdk/frame-father';
const lifecycle = new Lifecycle(connectedDevice);
const cpcl = CPCL.generic(lifecycle);
const reporter = await cpcl
.page({ width: 576, height: 400 })
.text({ x: 50, y: 50, content: '商品标签' })
.barcode({ x: 50, y: 150, content: '1234567890' })
.print()
.write({ chunkSize: 512 });
console.log('打印结果:', reporter);
import { CPCL } from '@psdk/cpcl';
import { Lifecycle } from '@psdk/frame-father';
const lifecycle = new Lifecycle(connectedDevice);
const cpcl = CPCL.generic(lifecycle);
await cpcl
.page({ width: 576, height: 400 })
// 标题
.center()
.text({
x: 0, y: 30,
font: 4, size: 2,
content: '商品标签',
})
// 商品信息
.left()
.text({ x: 30, y: 100, content: '名称: 有机苹果' })
.text({ x: 30, y: 140, content: '规格: 500g/袋' })
.text({ x: 30, y: 180, content: '价格: ¥25.90' })
// 条码
.barcode({
x: 100, y: 230,
type: '128',
height: 60,
content: '6901234567890',
})
// 二维码
.qrcode({
x: 400, y: 100,
content: 'https://example.com',
})
.print()
.write({ chunkSize: 512 });

ESC 指令广泛用于热敏小票打印机。详细指令说明请参考 ESC 指令文档

import { ESC } from '@psdk/esc';
import { Lifecycle } from '@psdk/frame-father';
const lifecycle = new Lifecycle(connectedDevice);
const esc = ESC.generic(lifecycle);
await esc
.initialize()
.align('center')
.text('收银小票')
.align('left')
.text('商品A x1 ¥29.90')
.cut()
.write({ chunkSize: 512 });
import { ESC } from '@psdk/esc';
import { Lifecycle } from '@psdk/frame-father';
const lifecycle = new Lifecycle(connectedDevice);
const esc = ESC.generic(lifecycle);
await esc
.initialize()
// 标题
.align('center')
.textSize({ width: 2, height: 2 })
.bold(true)
.text('XX 便利店')
.bold(false)
.textSize({ width: 1, height: 1 })
.text('订单号: 20240115001')
.text('================================')
// 商品列表
.align('left')
.text('可乐 500ml x2 ¥6.00')
.text('薯片 大包 x1 ¥8.50')
.text('--------------------------------')
// 合计
.textSize({ width: 1, height: 2 })
.text('合计: ¥14.50')
.textSize({ width: 1, height: 1 })
// 二维码
.align('center')
.qrcode({ content: 'https://shop.example.com', size: 5 })
.text('扫码关注店铺')
.feed(3)
.cut()
.write({ chunkSize: 512 });

TSPL 指令用于标签条码打印机。详细指令说明请参考 TSPL 指令文档

import { TSPL } from '@psdk/tspl';
import { Lifecycle } from '@psdk/frame-father';
const lifecycle = new Lifecycle(connectedDevice);
const tspl = TSPL.generic(lifecycle);
await tspl
.page({ width: 60, height: 40 })
.cls()
.text({ x: 50, y: 50, content: '标签内容' })
.print(1)
.write({ chunkSize: 512 });
import { TSPL } from '@psdk/tspl';
import { Lifecycle } from '@psdk/frame-father';
const lifecycle = new Lifecycle(connectedDevice);
const tspl = TSPL.generic(lifecycle);
await tspl
.page({ width: 60, height: 40 })
.gap(3)
.direction('up')
.cls()
// 标题
.text({
x: 180, y: 30,
font: 'TSS24.BF2',
xMulti: 2, yMulti: 2,
content: '商品标签',
})
// 分隔线
.bar({ x: 30, y: 80, width: 420, height: 2 })
// 商品信息
.text({ x: 30, y: 100, content: '品名: 有机苹果' })
.text({ x: 30, y: 140, content: '规格: 500g/袋' })
.text({ x: 30, y: 180, content: '价格: ¥25.90' })
// 条码
.barcode({
x: 100, y: 220,
type: '128',
height: 60,
content: '6901234567890',
})
// 二维码
.qrcode({
x: 350, y: 100,
cellWidth: 4,
content: 'https://example.com',
})
.print(1)
.write({ chunkSize: 512 });
import { Raw } from '@psdk/frame-father';
// 发送原始二进制指令
const reporter = await cpcl
.raw(Raw.binary(new Uint8Array([0x10, 0xff, 0xbf])))
.write({ chunkSize: 512 });
import { WechatBleBluetooth } from "@psdk/device-ble-wechat";
import { CPCL } from '@psdk/cpcl';
import { Lifecycle } from '@psdk/frame-father';
Page({
data: {
deviceList: [],
connectedDevice: null,
},
onLoad() {
this.bluetooth = new WechatBleBluetooth();
// 监听设备
this.bluetooth.discovered((devices) => {
this.setData({ deviceList: devices });
});
},
// 开始搜索
async startScan() {
await this.bluetooth.startDiscovery();
},
// 连接设备
async connectDevice(e) {
const device = e.currentTarget.dataset.device;
try {
const connectedDevice = await this.bluetooth.connect(device);
this.setData({ connectedDevice });
wx.showToast({ title: '连接成功' });
} catch (error) {
wx.showToast({ title: '连接失败', icon: 'error' });
}
},
// 打印
async print() {
const { connectedDevice } = this.data;
if (!connectedDevice) return;
const lifecycle = new Lifecycle(connectedDevice);
const cpcl = CPCL.generic(lifecycle);
await cpcl
.page({ width: 576, height: 400 })
.text({ x: 50, y: 50, content: '小程序打印测试' })
.print()
.write({ chunkSize: 512 });
wx.showToast({ title: '打印完成' });
},
});
import { TaroBleBluetooth } from "@psdk/device-ble-taro";
import { CPCL } from '@psdk/cpcl';
import { Lifecycle } from '@psdk/frame-father';
// 初始化方式与 UniApp 相同
const bluetooth = new TaroBleBluetooth();
// 搜索设备
bluetooth.discovered((devices) => {
console.log('发现设备:', devices);
});
await bluetooth.startDiscovery();
// 连接设备
const connectedDevice = await bluetooth.connect(device);
// 打印
const lifecycle = new Lifecycle(connectedDevice);
const cpcl = CPCL.generic(lifecycle);
await cpcl
.page({ width: 576, height: 400 })
.text({ x: 50, y: 50, content: 'Taro 打印测试' })
.print()
.write({ chunkSize: 512 });
try {
await cpcl.write({ chunkSize: 512 });
console.log('打印成功');
} catch (error) {
if (error.code === 'BLE_DISCONNECTED') {
console.error('蓝牙断开连接');
} else if (error.code === 'BLE_TIMEOUT') {
console.error('蓝牙超时');
} else {
console.error('打印失败:', error.message);
}
}

完整示例请参考: