在我的项目中,我最初使用 Java 调用 TSC 打印机打印标签,但由于后端程序部署在阿里云的云服务器,无法与本地的 TSC 打印机建立连接,因此决定切换到使用前端 Vue 实现打印功能。以下是一个详细的步骤指南,帮助你在 Vue 项目中实现 TSC 打印机的调用。
要在 Vue 项目中实现与 TSC 打印机的联调,可以借助 TSC PrintServer 软件。TSC PrintServer 是一个中间件,可以将打印机连接到网络,通过 HTTP WebSocket 请求发送打印命令。
TSC 打印机 厂家官网软件下载地址:资料下载 | TSC Printers (chinatsc.cn)
直达下载地址:https://fs.chinatsc.cn/system/files/tsc-printserver_setup_v1006.zip
- 下载 TSC PrintServer:
- 下载并安装 TSC PrintServer 软件后,找到安装目录中的 Example 文件夹。
- 拷贝文件:
- 将 Example\assert\js 文件夹下的 base64.js 和 TSC.js 文件拷贝到 Vue 项目的 src/utils/print/ 文件夹中。
将TSC.js文件略微调整
import Base64 from "@/utils/print/base64";
var functions_inorder = [];
//======================================================================================================================
//@description 清空数据
function init() {
functions_inorder = [];
}
//======================================================================================================================
//@description 连接打印机USB
//@param {String} usbPrinter: usb路徑(USBPath),若参数为空字串{"openport_usb" :""}则自动连接找到的第一台打印机
function openport_usb(usbPrinter) {
functions_inorder.push({ openport_usb: usbPrinter });
}
//======================================================================================================================
//@description 连接打印机网络
//@param {String} ip: 打印机IP地址
//@param {String} port: 打印机网络端口
function openport_net(ip, port) {
functions_inorder.push({ openport_net: ip + "," + port });
}
//======================================================================================================================
//@description 中断打印机连线
function closeport() {
functions_inorder.push({ closeport: "" });
}
//======================================================================================================================
//@description 清除打印机Buffer
function clearbuffer() {
functions_inorder.push({ clearbuffer: "" });
}
//======================================================================================================================
//@description 设定标签资讯
//@param {String} width_mm: 标签宽度(单位mm)
//@param {String} height_mm: 标签高度(单位mm)
//@param {String} speed: 打印速度
//@param {String} density: 打印浓度
//@param {String} sensor: 標籤種類["0":GAP, "1":BLINE]
//@param {String} gap_height: 间隙高度(单位mm)
//@param {String} gap_offset: 间隙偏移(单位mm)
function setup(width_mm, height_mm, speed, density, sensor, gap_height, gap_offset) {
functions_inorder.push({
setup:
width_mm +
"," +
height_mm +
"," +
speed +
"," +
density +
"," +
sensor +
"," +
gap_height +
"," +
gap_offset,
});
}
//======================================================================================================================
//@description 打印条码
//@param {String} x: 条码x轴座标(单位dot)
//@param {String} y: 条码y轴座标(单位dot)
//@param {String} type: 条码类型["128", "128M", "EAN128", "25", "25C", "39", "39C", "93", "EAN13", "EAN13+2", "EAN13+5", "EAN8", "EAN8+2", "EAN8+5", "CODA", "POST", "UPCA", "UPCA+2", "UPCA+5", "UPCE", "UPCE+2", "UPCE+5", "CPOST", "MSI", "MSIC", "PLESSEY", "ITF14", "EAN14", "11", "TELEPEN", "TELEPENN", "PLANET", "CODE49", "DPI", "DPL"]
//@param {String} height: 条码高度
//@param {String} readable: 条码可读性["0":无, "1":置左, "2":置中, "3":置右]
//@param {String} rotation: 条码旋转["0":无, "90":90度, "180":180度, "270":270度]
//@param {String} narrow: 条码窄元件宽度[详见TSPL手册BARCODE条目]
//@param {String} wide: 条码宽元件宽度[详见TSPL手册BARCODE条目]
//@param {String} code: 条码内容
function barcode(x, y, type, height, readable, rotation, narrow, wide, code) {
if (code.charAt(0) == "@")
functions_inorder.push({
barcode:
x +
"," +
y +
',"' +
type +
'",' +
height +
"," +
readable +
"," +
rotation +
"," +
narrow +
"," +
wide +
"," +
code,
});
else
functions_inorder.push({
barcode:
x +
"," +
y +
',"' +
type +
'",' +
height +
"," +
readable +
"," +
rotation +
"," +
narrow +
"," +
wide +
',"' +
code +
'"',
});
}
//======================================================================================================================
//@description 打印文字
//@param {String} x: 文字x轴座标(单位dot)
//@param {String} y: 文字y轴座标(单位dot)
//@param {String} fonttype: 内建字型名称["0", "1", "2", "3", "4", "5", "6", "7", "8", "ROMAN.TTF"] 或 下载字型名称
//@param {String} rotation: 文字旋转["0":无, "90":90度, "180":180度, "270":270度]
//@param {String} xmul: 文字x轴放大率
//@param {String} ymul: 文字y轴放大率
//@param {String} text: 打印文字
function printerfont(x, y, fonttype, rotation, xmul, ymul, text) {
if (text.charAt(0) == "@")
functions_inorder.push({
printerfont:
x +
"," +
y +
',"' +
fonttype +
'",' +
rotation +
"," +
xmul +
"," +
ymul +
"," +
text,
});
else
functions_inorder.push({
printerfont:
x +
"," +
y +
',"' +
fonttype +
'",' +
rotation +
"," +
xmul +
"," +
ymul +
',"' +
text +
'"',
});
}
//======================================================================================================================
//@description 发送指令到打印机
//@param {String} cmd: 指令
function sendcommand(cmd) {
functions_inorder.push({ sendcommand: cmd });
}
//======================================================================================================================
//@description 发送指令到打印机,加上换行符号(\r\n)
//@param {String} cmd: 指令
function sendcommand_crlf(cmd) {
functions_inorder.push({ sendcommand_crlf: cmd });
}
//======================================================================================================================
//@description 打印标签
//@param {String} sets: 份数
//@param {String} copies: 张数
function printlabel(sets, copies) {
functions_inorder.push({ printlabel: sets + "," + copies });
return functions_inorder;
}
//======================================================================================================================
//@description 下载PCX
//@param {String} file_path: 档案路径
//@param {String} image_name: 保存名称
function downloadpcx(file_path, image_name) {
functions_inorder.push({ downloadpcx: file_path + "," + image_name });
}
//======================================================================================================================
//@description 跳过下一张标签
function formfeed() {
functions_inorder.push({ formfeed: "" });
}
//======================================================================================================================
//@description 关闭backfeed功能
function nobackfeed() {
functions_inorder.push({ nobackfeed: "" });
}
//======================================================================================================================
//@description 打印文字
//@param {String} x: 文字x轴座标(单位dot)
//@param {String} y: 文字y轴座标(单位dot)
//@param {String} fontheight: 文字大小
//@param {String} rotation: 文字旋转["0":无, "90":90度, "180":180度, "270":270度]
//@param {String} fontstyle: 文字样式["0":无, "1":斜体, "2":粗体, "3":斜体+粗体]
//@param {String} fontunderline: 文字底线["0":无, "1":底线]
//@param {String} szFaceName: 字型名称[例:"Arial"]
//@param {String} text: 打印文字
function windowsfont(x, y, fontheight, rotation, fontstyle, fontunderline, szFaceName, text){
functions_inorder.push({
windowsfont:
x +
"," +
y +
"," +
fontheight +
"," +
rotation +
"," +
fontstyle +
"," +
fontunderline +
"," +
szFaceName +
"," +
text,
});
}
//======================================================================================================================
//@description 发送位元组数据到打印机
//@param {String} cmd: 指令
function sendUint8Array(uint8_arr) {
functions_inorder.push({ sendUint8Array: Base64.fromUint8Array(uint8_arr) });
// console.log("uint8_arr", uint8_arr);
// console.log("functions_inorder", functions_inorder);
}
//======================================================================================================================
//@description 返回打印机状态
function printerstatus() {
functions_inorder.push({ printerstatus: "" });
}
//======================================================================================================================
//@description 返回打印机名称
function printername() {
functions_inorder.push({ printername: "" });
}
//======================================================================================================================
//@description 返回打印机序号
function printerserial() {
functions_inorder.push({ printerserial: "" });
}
export default {
printerserial,
printername,
printerstatus,
sendUint8Array,
windowsfont,
functions_inorder,
nobackfeed,
formfeed,
barcode,
downloadpcx,
printlabel,
sendcommand_crlf,
sendcommand,
printerfont,
setup,
clearbuffer,
closeport,
openport_net,
openport_usb,
init,
};
接下来在业务界面index.vue调用打印机代码,我是根据选中的id调用了后端的查询单据详情接口,单个或批量的查询选中的数据,在成功返回的方法里面循环遍历结果数据,并调用PrintCode(this.usbPath, x);方法实现标签打印。
<script>
import printApi from "@/utils/print/TSC";
var websocket;
export default {
data() {
return {
usbPath: {},
};
},
created() {
this.getList();
},
methods: {
/** 打印按钮操作 */
handlePrint(row) {
this.webSocketConnect()
.then((res) => {
this.usbPath.usb_printers = res;
const ids = row.id || this.ids;
getPrintInfo(ids).then((response) => {
response.rows.forEach((x, y) => {
this.PrintCode(this.usbPath, x);
});
});
this.$modal.msgSuccess("执行打印了");
})
.catch((err) => {
this.$modal.msgError("获取打印机失败");
});
},
PrintCode(usbPath, obj) {
const u8 = new Uint8Array(2);
u8[0] = 13;
u8[1] = 10;
printApi.init();
// 需要携带打印参数(打印机路径)
printApi.openport_usb(usbPath.usb_printers);
printApi.sendUint8Array(u8);
printApi.clearbuffer();
//--------------------------
//xxxxx这里就是标签内容书写区域
//--------------------------
printApi.setup("50", "30", "5", "15", "0", "22", "0");
printApi.sendcommand_crlf('QRCODE 345,35,Q,5,A,0,M2,S7,"https://shanghai.chinaxxxxxx.com/jishu_index.html?id=' + obj.id + '"');
printApi.printerfont("270","250","MSYH.TTF","180","7","7","" + obj.center + "");
printApi.printerfont("250", "210", "MSYH.TTF", "180", "7", "7", "待检");
printApi.printerfont("170", "210", "MSYH.TTF", "180", "7", "7", "在检");
printApi.printerfont("90", "210", "MSYH.TTF", "180", "7", "7", "已检");
printApi.sendcommand_crlf("BOX 250,170,190,130,2");
printApi.sendcommand_crlf("BOX 170,170,110,130,2");
printApi.sendcommand_crlf("BOX 90,170,30,130,2");
printApi.printerfont("230", "160", "MSYH.TTF", "180", "7", "7", "√");
printApi.barcode("330","50","128","50","0","90","1","1","" + obj.center + "");
printApi.sendcommand_crlf('PUTBMP 40,40,"LOGO.BMP"');
//@description 打印标签
//@param {String} sets: 份数
//@param {String} copies: 张数
// 抛出打印的参数
let printData = printApi.printlabel(1, 1);
// console.log("printData", printData);
let data = {};
data.functions_inorder = printData;
this.webSocketSend(data);
// return printData;
},
/**连接*/
webSocketConnect() {
return new Promise((resolve, reject) => {
websocket = new WebSocket("ws://127.0.0.1:8888");
websocket.onopen = function (e) {
//加载时获取 usb 列表
var obj = { usb_list: [] };
websocket.send(JSON.stringify(obj));
};
websocket.onmessage = (event) => {
if (event.data === "Finished") {
} else {
try {
const obj = JSON.parse(event.data);
if ("usb_list" in obj) {
if (obj.usb_list.length === 0) {
this.$modal.msgError("找不到打印机");
} else {
resolve(obj.usb_list[0].USBPath);
}
}
if ("Function_Failed" in obj) {
alert(`Failed: ${obj.Function_Failed}`);
}
if ("printerstatus" in obj) {
if (obj.printerstatus.length != 0) {
alert(`Printer Status:\r\n${obj.printerstatus.join("\r\n")}`);
}
}
if ("printername" in obj) {
alert(`Printer Name: ${obj.printername}\r\n`);
}
if ("printerserial" in obj) {
alert(`Printer Serial: ${obj.printerserial}\r\n`);
}
if ("about" in obj) {
alert(`TSC PrintServer\r\nVersion: ${obj.about}\r\n`);
}
} catch (e) {
reject(new Error(`Invalid return value--${e}`));
}
}
};
websocket.onclose = function (event) {
if (event.code != 1000) {
var reason = "";
if (event.code == 1001)
reason = "端点正在“消失”,例如服务器出现故障或浏览器已离开页面";
else if (event.code == 1002)
reason = "终结点由于协议错误而终止连接";
else if (event.code == 1003)
reason =
"端点正在终止连接,因为它收到了一种它无法接受的数据类型(例如,如果端点收到二进制消息,则仅理解文本数据可能会发送此数据)。";
else if (event.code == 1004)
reason = "保留。具体含义可能会在将来定义";
else if (event.code == 1005) reason = "实际上不存在状态代码";
else if (event.code == 1006)
reason = "连接异常,例如,没有发送或接收 Close 控制帧";
else if (event.code == 1007)
reason =
"终结点正在终止连接,因为它在消息中接收到的数据与消息类型不一致(例如,文本消息中的非 UTF-8 [https://www.rfc-editor.org/rfc/rfc3629] 数据)";
else if (event.code == 1008)
reason =
"终结点正在终止连接,因为它收到了“违反其策略”的消息。如果没有其他合理的理由,或者需要隐藏有关策略的具体细节,则会给出此原因";
else if (event.code == 1009)
reason = "终结点正在终止连接,因为它收到的消息太大而无法处理";
else if (event.code == 1010)
reason =
"客户端)正在终止连接,因为它期望服务器协商一个或多个扩展,但服务器未在 WebSocket 握手的响应消息中返回它们。<br /> 具体来说,需要的扩展是:" +
event.reason;
else if (event.code == 1011)
reason =
"服务器正在终止连接,因为它遇到了阻止其完成请求的意外情况。";
else if (event.code == 1015)
reason =
"由于无法执行 TLS 握手(例如,无法验证服务器证书),连接已关闭";
else reason = "未知原因";
reject(
new Error(`WebSocket closed with code ${event.code}: ${reason}`)
);
} else {
resolve();
}
};
websocket.onerror = function (error) {
reject(new Error(`WebSocket error: ${error}`));
};
});
},
/**websocket的close事件*/
webSocketClose() {
websocket.close();
},
/**websocket发送消息*/
webSocketSend(obj) {
websocket.send(JSON.stringify(obj));
},
},
};
</script>
最后双击启动TSC PrintServer.exe程序,本地打开WebSocket监听,在页面点击打印按钮,就可以打印标签了。
评论(0)