feat(): 改为vite

This commit is contained in:
2026-03-16 17:58:57 +08:00
parent cd734d8524
commit 1ccbd4e872
74 changed files with 46574 additions and 2145 deletions
+5
View File
@@ -0,0 +1,5 @@
export * from "./knock-test";
export * from "./permission";
export * from "./printer";
export * from "./time";
export * from "./timer";
+138
View File
@@ -0,0 +1,138 @@
import { debounce } from "lodash-es";
export class Operation {
duration = 1000;
delay = 1000;
times = 1;
}
export class Config {
maxWaitTime = 5000;
operations: Operation[] = [];
}
export class KnockTest {
config: Config;
index = 0;
times = 0;
/**
* 空闲状态:"idle"times从0开始计数,进入duration期
* duration期间:"knocking"times达到Operation的指定次数后进入delay期
* delay期间:"wait",此期间不能点击,如果点击则重置,否则进入下一个空闲状态
*/
status: "idle" | "knocking" | "wait" = "idle";
durationTimerId: number | null = null;
delayTimerId: number | null = null;
callbackList: (() => void)[] = [];
maxWaitFun: () => void;
constructor(config: Config) {
const c = new Config();
this.config = Object.assign(c, config);
this.maxWaitFun = debounce(() => {
console.log("maxWaitFun");
this.reset();
}, this.config.maxWaitTime);
}
addCallback(cb: () => void) {
this.callbackList.push(cb);
}
knock() {
console.log("knock");
this.maxWaitFun();
this.times++;
switch (this.status) {
case "idle":
this.handleIdle();
break;
case "knocking":
this.handleKnocking();
break;
case "wait":
this.handleWait();
break;
default:
break;
}
}
private reset() {
this.status = "idle";
this.times = 0;
this.index = 0;
if (this.durationTimerId != null) {
clearTimeout(this.durationTimerId);
this.durationTimerId = null;
}
if (this.delayTimerId != null) {
clearTimeout(this.delayTimerId);
}
}
private handleIdle() {
if (this.config.operations.length === 0) {
throw new Error("至少添加一个操作项");
}
const operation = this.config.operations[this.index];
this.status = "knocking";
this.durationTimerId = window.setTimeout(() => {
if (operation.times !== this.times) {
this.reset();
}
}, operation.duration);
this.checkKnock();
}
private handleKnocking() {
this.checkKnock();
}
private checkKnock() {
const operation = this.config.operations[this.index];
if (operation.times === this.times) {
if (this.durationTimerId != null) {
clearTimeout(this.durationTimerId);
this.durationTimerId = null;
}
this.status = "wait";
this.times = 0;
this.index++;
this.delayTimerId = window.setTimeout(() => {
this.status = "idle";
this.times = 0;
if (this.delayTimerId != null) {
clearTimeout(this.delayTimerId);
this.delayTimerId = null;
}
}, operation.delay);
if (this.index > this.config.operations.length - 1) {
console.log("成功");
this.reset();
this.callbackList.forEach((cb) => cb());
}
}
}
private handleWait() {
if (this.delayTimerId != null) {
clearTimeout(this.delayTimerId);
this.delayTimerId = null;
}
this.reset();
}
}
+1
View File
@@ -0,0 +1 @@
export * from "./KnockTest";
@@ -0,0 +1,21 @@
export class Permission {
/**
*
*/
list: string[];
separator: string;
level: number;
constructor(list: string[], level = 3, separator = ":") {
this.list = list;
this.level = level;
this.separator = separator;
}
isValid(str: string) {
const p = new Array(this.level).fill("\\w+?").join(this.separator);
// ^\w+?:\w+?:\w+?$
const r = new RegExp(`^${p}$`);
return r.test(str);
}
}
+1
View File
@@ -0,0 +1 @@
export * from "./Permission";
+49
View File
@@ -0,0 +1,49 @@
import { JpPrinter } from "./esc.js";
export class PrintUtil extends JpPrinter {
/**
* 添加标题
* @param title
*/
addTitle(title: string) {
return this.storeLayout()
.setAlign("m")
.setLineSpacing(7.5 * 8 * 2)
.setFontSize(0x10 + 0x1)
.addText(title)
.addLF()
.restoreLayout();
}
/**
* 添加文本
* @param text
* @param align
* @returns
*/
addTextLine(text: string, align = "l") {
return this.storeLayout()
.setAlign(align)
.setFontSize(0x00 + 0x00)
.addText(text)
.addLF()
.restoreLayout();
}
/**
* 添加条目
* @param label
* @param value
* @returns
*/
addItem(label: string, value: string) {
return this.storeLayout()
.setAlign("l")
.setFontSize(0x00 + 0x00)
.addText(label)
.addText("")
.addText(value)
.addLF()
.restoreLayout();
}
}
File diff suppressed because it is too large Load Diff
+4
View File
@@ -0,0 +1,4 @@
export * from "./esc";
export * from "./esc-plus";
export * from "./tsc-plus";
export * from "./tsc";
+307
View File
@@ -0,0 +1,307 @@
import { TSC } from "./tsc.js";
const fontInfoList = [
{
name: "1",
width: 8,
height: 12,
},
{
name: "2",
width: 12,
height: 20,
},
{
name: "3",
width: 16,
height: 24,
},
{
name: "4",
width: 24,
height: 32,
},
{
name: "5",
width: 32,
height: 48,
},
{
name: "6",
width: 14,
height: 19,
},
{
name: "7",
width: 21,
height: 27,
},
{
name: "8",
width: 14,
height: 25,
},
{
name: "9",
width: 9,
height: 17,
},
{
name: "10",
width: 12,
height: 24,
},
{
name: "TSS16.BF2",
width: 16,
height: 16,
},
{
name: "TSS20.BF2",
width: 20,
height: 20,
},
{
name: "TST24.BF2",
width: 24,
height: 24,
},
{
name: "TSS24.BF2",
width: 24,
height: 24,
},
{
name: "K",
width: 24,
height: 24,
},
{
name: "TSS32.BF2",
width: 32,
height: 32,
},
];
export class TSCPlus extends TSC {
static MILLIMETERS_PER_INCH = 25.4;
constructor(data = []) {
super(data);
this.font = "TSS24.BF2";
this.lineHeight = "1.2";
this.dpi = 200;
this.nextX = 0;
this.nextY = 0;
this.widthDot = this.mmToDot(40);
this.heightDot = this.mmToDot(30);
this.paddingTopDot = 0;
this.paddingLeftDot = 0;
this.paddingRightDot = 0;
this.paddingBottomDot = 0;
this.setSizeDot(this.widthDot, this.heightDot);
}
/**
* 设置内边距
* @param {number} paddingTopDot
* @param {number} paddingRightDot
* @param {number} paddingBottomDot
* @param {number} paddingLeftDot
*/
setPadding(paddingTopDot, paddingRightDot, paddingBottomDot, paddingLeftDot) {
this.paddingTopDot = paddingTopDot;
this.paddingRightDot = paddingRightDot;
this.paddingBottomDot = paddingBottomDot;
this.paddingLeftDot = paddingLeftDot;
this.nextX = this.paddingLeftDot;
this.nextY = this.paddingTopDot;
}
mmToDot(mm) {
mm = Number(mm);
return Math.round(this.dpi / TSCPlus.MILLIMETERS_PER_INCH) * mm;
}
setDpi(dpi) {
this.dpi = dpi;
}
setSize(w, h) {
if (/^\d+(\.\d+)? mm$/.test(w)) {
this.widthDot = this.mmToDot(parseInt(w));
this.heightDot = this.mmToDot(parseInt(h));
} else {
this.widthDot = parseInt(w) * this.dpi;
this.heightDot = parseInt(h) * this.dpi;
}
return super.setSize(w, h);
}
setSizeMM(w, h) {
this.widthDot = w * 8;
this.heightDot = h * 8;
return super.setSizeMM(w, h);
}
setSizeDot(w, h) {
return this.setSizeMM(w / 8, h / 8);
}
/**
* 设置字体
* @param {string} font
*/
setFont(font) {
this.font = String(font);
}
/**
* 设置行高
* @param {string|number} lineHeight
*/
setLineHeight(lineHeight) {
this.lineHeight = String(lineHeight);
}
static getLetterWidthDot(font) {
const fontInfo = fontInfoList.find((v) => v.name === font);
return fontInfo.width;
}
static getFontLineHeightDot(font, lineHeight) {
const fontInfo = fontInfoList.find((v) => v.name === font);
if (/^\d+(\.\d+)?dot$/.test(lineHeight)) {
const [, lineHeightDot] = /^(\d+(\.\d+))?dot$/.exec(lineHeight);
return lineHeightDot;
} else if (/^\d+(\.\d+)?$/.test(lineHeight)) {
const [, lineHeightNum] = /^(\d+(\.\d+))?$/.exec(lineHeight);
const lineHeightDot = fontInfo.height * lineHeightNum;
return lineHeightDot;
} else {
throw new Error("无效行高:" + lineHeight);
}
}
/**
* 获取文本宽度点数
* @param {string} text
* @returns {number}
*/
static getTextDots(text, letterDots = 12) {
text = String(text);
let ch = 0;
text.split("").forEach((c) => {
// 是否是汉字,汉字两倍宽
const isChinese = /[^\x00-\xff]/.test(c);
if (isChinese) {
ch += 2;
} else {
ch++;
}
});
return ch * letterDots;
}
/**
* 根据最大点数获取文本
* @param {string} text
* @param {number} maxDots
* @return {string}
*/
static getMaxText(text = "", maxDots = 0) {
let subStr = "";
for (let i = 0; i < text.length; i++) {
subStr = text.substring(0, text.length - i);
if (TSCPlus.getTextDots(subStr) <= maxDots) {
break;
}
}
return subStr;
}
/**
* 分割字符串
* "123456789" => ["1234", "5678", "9"]
* @param {string} str
* @param {number} maxDots
* @return {string[]}
*/
static splitString(str, maxDots) {
let itemDots = TSCPlus.getTextDots(str);
const arr = [];
while (itemDots > 0) {
const maxStr = TSCPlus.getMaxText(str, maxDots);
arr.push(maxStr);
str = str.slice(maxStr.length);
itemDots = TSCPlus.getTextDots(str);
}
if (str.length > 0) {
arr.push(str);
}
return arr;
}
addTextLn(text, options = {}) {
text = String(text);
const font = String(options.font ?? this.font);
let x = parseInt(options.x ?? this.nextX);
this.nextY = parseInt(options.y ?? this.nextY);
const rotation = parseInt(options.rotation ?? 0);
const sx = parseInt(options.sx ?? 1);
const sy = parseInt(options.sy ?? 1);
const align = options.align ?? "left";
const contentWidth =
this.widthDot - this.paddingLeftDot - this.paddingRightDot;
const textList = TSCPlus.splitString(text, contentWidth);
textList.forEach((t) => {
const textDots = parseInt(TSCPlus.getTextDots(t) * sx);
console.log(align, textDots, contentWidth);
if (textDots < contentWidth) {
if (align == "center") {
x += parseInt((contentWidth - textDots) / 2);
} else if (align == "right") {
x += parseInt(contentWidth - textDots);
}
}
console.log("x", x);
this.setText(x, this.nextY, font, rotation, sx, sy, t);
const lineHeightDot =
TSCPlus.getFontLineHeightDot(font, this.lineHeight) * sy;
this.nextY = parseInt(this.nextY + lineHeightDot);
console.log("this.nextY", this.nextY);
});
return this;
}
addAddBarCode(content, options = {}) {
const x = parseInt(options.x ?? this.nextX);
this.nextY = parseInt(options.y ?? this.nextY);
const height = parseInt(options.height ?? 80);
const rotation = parseInt(options.rotation ?? 0);
this.setBarCode(
x,
this.nextY,
options.codeType,
height,
options.readable,
rotation,
options.narrow,
options.wide,
content,
);
this.nextY += height + 24;
return this;
}
}
+616
View File
@@ -0,0 +1,616 @@
import * as encode from "text-encoding";
export class TSC {
static LINE_BREAK = "\r\n";
constructor(data = []) {
// 打印数据
this.data = data;
}
addData(...data) {
this.data.push(...data);
}
addDataArray(dataArray) {
this.data.push(...dataArray);
}
addCode(code) {
const textEncoder = new encode.TextEncoder("gb18030", {
NONSTANDARD_allowLegacyEncoding: true,
});
const data = textEncoder.encode(code);
this.data.push(...data);
return this;
}
getData = function () {
return this.data;
};
// 系统设定指令====================
/**
* 该指令用于设定卷标纸的宽度和长度
* @param {number|string} w 标签宽度 单位英寸inch
* @param {number|string} h 标签高度 单位英寸inch
* @returns {TSC}
*/
setSize(w, h) {
const code = `SIZE ${w},${h}${TSC.LINE_BREAK}`;
return this.addCode(code);
}
/**
* 该指令用于设定卷标纸的宽度和长度
* @param {number|string} w 标签宽度 单位毫米mm
* @param {number|string} h 标签高度 单位毫米mm
* @returns {TSC}
*/
setSizeMM(w, h) {
return this.setSize(`${w} mm`, `${h} mm`);
}
/**
* 该指令用于定义两张卷标纸间的垂直间距距离
* @param {number|string} m 两标签纸中间的垂直距离 单位英寸inch
* @param {number|string} n 垂直间距偏移 单位英寸inch
* @returns {TSC}
*/
setGap(m = 0, n = 0) {
const code = `GAP ${m},${n}${TSC.LINE_BREAK}`;
return this.addCode(code);
}
/**
* 该指令用于定义两张卷标纸间的垂直间距距离
* @param {number|string} m 两标签纸中间的垂直距离 单位毫米mm
* @param {number|string} n 垂直间距偏移 单位毫米mm
* @returns {TSC}
*/
setGapMM(m = 0, n = 0) {
const code = `GAP ${m} mm,${n} mm${TSC.LINE_BREAK}`;
return this.addCode(code);
}
/**
* 该指令用于设定黑标高度及定义标签印完后标签额外送出的长度
* @param {number|string} m 黑标高度 单位英寸inch
* @param {number|string} n 额外送出纸张长度 单位英寸inch
* @returns {TSC}
*/
setBLine(m = 0, n = 0) {
const code = `BLINE ${m},${n}${TSC.LINE_BREAK}`;
return this.addCode(code);
}
/**
* 该指令用于控制在剥离模式时(peel-off mode)每张卷标停止的位置,
* 在打印下一张时打印机会将原先多推出或少推出的部分以回拉方式补偿回来。
* 该指令仅适用于剥离模式。
* @param {number|string} m 纸张停止的距离 单位英寸inch
* @returns {TSC}
*/
setOffset(offset = 0) {
const code = `OFFSET ${offset}${TSC.LINE_BREAK}`;
return this.addCode(code);
}
/**
* 该指令用于控制打印速度
* @param {number|string} speed 打印速度
* @returns {TSC}
*/
setSpeed(speed = 1.5) {
const code = `SPEED ${speed}${TSC.LINE_BREAK}`;
return this.addCode(code);
}
/**
* 该指令用于控制打印时的浓度
* @param {number|string} density 打印浓度
* @returns {TSC}
*/
setDensity(density = 10) {
const code = `DENSITY ${density}${TSC.LINE_BREAK}`;
return this.addCode(code);
}
/**
* 该指令用于定义打印时出纸和打印字体的方向
* @param {number|string} direction
* @returns {TSC}
*/
setDirection(direction = 0) {
const code = `DIRECTION ${direction}${TSC.LINE_BREAK}`;
return this.addCode(code);
}
/**
* 该指令用于定义卷标的参考坐标原点。坐标原点位置和打印方向有关
* @param {number|string} x 水平方向的坐标位置,单位dot
* @param {number|string} y 垂直方向的坐标位置,单位dot
* @returns {TSC}
*/
setReference(x = 0, y = 0) {
const code = `REFERENCE ${x},${y}${TSC.LINE_BREAK}`;
return this.addCode(code);
}
/**
* 该指令表示标签打印偏移量多少设置
* @param {number|string} n 打印偏移量
* @returns {TSC}
*/
setShift(n = 0) {
const code = `SHIFT ${n}${TSC.LINE_BREAK}`;
return this.addCode(code);
}
/**
* 该指令用于选择对应的国际字符集
* 001:USA
* 002:French
* 003:Latin America
* 034:Spanish
* 039:Italian
* 044:United Kingdom
* 046:Swedish
* 047:Norwegian
* 049:German
* @param {number|string} country 字符集
* @returns {TSC}
*/
setCountry(country = 0) {
const code = `COUNTRY ${country}${TSC.LINE_BREAK}`;
return this.addCode(code);
}
/**
* 该指令用于选择对应的国际代码页
* 8-bit codepage 字符集代表
* 437:United States
* 850:Multilingual
* 852:Slavic
* 860:Portuguese
* 863:Canadian/French
* 865:Nordic
*
* Windows code page
* 1250:Central Europe
* 1252:Latin I
* 1253:Greek
* 1254:Turkish
*
* 以下代码页仅限于12×24 dot 英数字体
* WestEurope:WestEurope
* Greek:Greek
* Hebrew:Hebrew
* EastEurope:EastEurope
* Iran:Iran
* IranII:IranII
* Latvian:Latvian
* Arabic:Arabic
* Vietnam:Vietnam
* Uygur:Uygur
* Thai:Thai
* 1252:Latin I
* 1257:WPC1257
* 1251:WPC1251
* 866:Cyrillic
* 858:PC858
* 747:PC747
* 864:PC864
* 1001:PC1001
* @param {number|string} n 代码页
* @returns {TSC}
*/
setCodepage(n = 0) {
const code = `CODEPAGE ${n}${TSC.LINE_BREAK}`;
return this.addCode(code);
}
/**
* 该指令用于清除图像缓冲区(image buffer)的数据
* 注:此项指令必须置于 SIZE 指令之后
* @param {number|string} n 代码页
* @returns {TSC}
*/
setCls() {
const code = `CLS${TSC.LINE_BREAK}`;
return this.addCode(code);
}
/**
* 该指令用于将标签纸向前推送指定的长度
* 打印机分辨率200 DPI:1 mm = 8 dots
* 打印机分辨率300 DPI:1 mm = 12 dots
* @param {number|string} n 1≤n≤9999,单位dot
* @returns {TSC}
*/
setFeed(n) {
const code = `FEED ${n}${TSC.LINE_BREAK}`;
return this.addCode(code);
}
/**
* 该指令用于将标签纸向前推送指定的长度
* 打印机分辨率200 DPI:1 mm = 8 dots
* 打印机分辨率300 DPI:1 mm = 12 dots
* @param {number|string} n 1≤n≤9999,单位dot
* @returns {TSC}
*/
setBackFeed(n) {
const code = `BACKFEED ${n}${TSC.LINE_BREAK}`;
return this.addCode(code);
}
/**
* 该指令用于将标签纸向前推送指定的长度
* 打印机分辨率200 DPI:1 mm = 8 dots
* 打印机分辨率300 DPI:1 mm = 12 dots
* @param {number|string} n 1≤n≤9999,单位dot
* @returns {TSC}
*/
setBackUp(n) {
const code = `BACKUP ${n}${TSC.LINE_BREAK}`;
return this.addCode(code);
}
/**
* 该指令用于控制打印机进一张标签纸
* @returns {TSC}
*/
setFromFeed() {
const code = `FORMFEED${TSC.LINE_BREAK}`;
return this.addCode(code);
}
/**
* 在使用含有间隙或黑标的标签纸时,
* 若不能确定第一张标签纸是否在正确打印位置时,
* 此指令可将标签纸向前推送至下一张标签纸的起点开始打印。
* 标签尺寸和间隙需要在本条指令前设置
* 注:使用该指令时,纸张高度大于或等于30 mm
* @returns {TSC}
*/
setHome() {
const code = `HOME${TSC.LINE_BREAK}`;
return this.addCode(code);
}
/**
* 该指令用于打印出存储于影像缓冲区内的数据
* @param {number|string} m 指定打印的份数(set
* @param {number|string} n 每张标签需重复打印的张数
* @returns {TSC}
*/
setPrint(m = 1, n = 1) {
const code = `PRINT ${m},${n}${TSC.LINE_BREAK}`;
return this.addCode(code);
}
/**
* 该指令用于控制蜂鸣器的频率,可设定10阶的声音,
* 频率,可设定10阶的声音,每阶声音的长短由第二个参数控制
* @param {number|string} m 指定打印的份数(set
* @param {number|string} n 每张标签需重复打印的张数
* @returns {TSC}
*/
setSound(level = 1, interval = 300) {
const code = `SOUND ${level},${interval}${TSC.LINE_BREAK}`;
return this.addCode(code);
}
/**
* 该指令用于设定打印机进纸时,若经过所设定的长度仍无法侦测到垂直间距,
* 则打印机在连续纸模式工作。
* @param {number|string} limit 英制系统(inch
* @returns {TSC}
*/
setLimitFeed(limit = 1) {
const code = `LIMITFEED ${limit}${TSC.LINE_BREAK}`;
return this.addCode(code);
}
/**
* 不经自测动作,直接打印自检页信息。
* @returns {TSC}
*/
setSelfTest() {
const code = `SELFTEST${TSC.LINE_BREAK}`;
return this.addCode(code);
}
// 卷标内容设计指令==============================
/**
* 该指令用于在标签上画线
* @param {number|string} x 线条左上角X坐标,单位dot
* @param {number|string} y 线条左上角Y坐标,单位dot
* @param {number|string} width 线宽,单位dot
* @param {number|string} height 线高,单位dot
* @returns {TSC}
*/
setBar(x, y, width, height) {
const code = `BAR ${x},${y},${width},${height}${TSC.LINE_BREAK}`;
return this.addCode(code);
}
/**
* 该指令用于在标签上画线
* @param {number|string} x 线条左上角X坐标,单位dot
* @param {number|string} y 线条左上角Y坐标,单位dot
* @param {number|string} codeType 线宽,单位dot
* @param {number|string} height 条形码高度,以点(dot)表示
* @param {number|string} readable 0 表示人眼不可识,1表示人眼可识
* @param {number|string} rotation 条形码旋转角度,顺时针方向
* @param {number|string} narrow 窄bar宽度,以点(dot)表示
* @param {number|string} wide 宽bar宽度,以点(dot)表示
* @param {number|string} content 内容
* @returns {TSC}
*/
setBarCode(
x,
y,
codeType = "128",
height = 80,
readable = 1,
rotation = 0,
narrow = 2,
wide = 2,
content,
) {
x = parseInt(x);
y = parseInt(y);
height = parseInt(height);
readable = parseInt(readable);
rotation = parseInt(rotation);
narrow = parseInt(narrow);
wide = parseInt(wide);
content = String(content);
const code = `BARCODE ${x},${y},"${codeType}",${height},${readable},${rotation},${narrow},${wide},"${content}"${TSC.LINE_BREAK}`;
return this.addCode(code);
}
/**
* 该指令用于在卷标上绘制矩形方框
* @param {number|string} x1 线条左上角X坐标,单位dot
* @param {number|string} y1 线条左上角Y坐标,单位dot
* @param {number|string} x2 方框右下角X坐标,单位dot
* @param {number|string} y2 方框右下角Y坐标,单位dot
* @param {number|string} thickness 方框线宽,单位dot
* @returns {TSC}
*/
setBox(x1, y1, x2, y2, thickness) {
const code = `BOX ${x1},${y1},${x2},${y2},${thickness}${TSC.LINE_BREAK}`;
return this.addCode(code);
}
/**
* 该指令用于在卷标上绘制位图(非BMP格式图档)
* @param {number|string} x 线条左上角X坐标,单位dot
* @param {number|string} y 线条左上角Y坐标,单位dot
* @param {number|string} width 方框右下角X坐标,单位dot
* @param {number|string} height 方框右下角Y坐标,单位dot
* @param {number|string} mode 方框线宽,单位dot
* @param {number|string} bitmapData 方框线宽,单位dot
* @returns {TSC}
*/
setBitmap(x, y, width, height, mode, bitmapData) {
const w = width;
const h = height;
const bitw = parseInt((w + 7) / 8) * 8;
// var bitw = (parseInt(w) % 8) == 0 ? (parseInt(w) / 8) :( parseInt(w) / 8+1);
const pitch = parseInt(bitw / 8);
const bits = new Uint8Array(h * pitch);
const code = `BITMAP "${x},${y},${bitw},${pitch},${h},${mode},`;
this.addCode(code);
// for (var i=0; i<bits.length; i++) {
// bits[i] = 0;
// }
for (y = 0; y < h; y++) {
for (x = 0; x < w; x++) {
var color = bitmapData[(y * w + x) * 4 + 1];
if (color <= 128) {
bits[parseInt(y * pitch + x / 8)] |= 0x80 >> x % 8;
}
}
}
for (var i = 0; i < bits.length; i++) {
this.addData(~bits[i] & 0xff);
}
return this;
}
/**
* 该指令用于清除影像缓冲区部分区域的数据
* @param {number|string} x 清除区域的左上角X座标,单位dot
* @param {number|string} y 清除区域的左上角Y座标,单位dot
* @param {number|string} width 清除区域宽度,单位dot
* @param {number|string} height 清除区域高度,单位dot
* @returns {TSC}
*/
setErase(x, y, width, height) {
const code = `ERASE ${x},${y},${width},${height}${TSC.LINE_BREAK}`;
return this.addCode(code);
}
/**
* 将指定的区域反相打印
* @param {number|string} x 反相区域的左上角X座标,单位dot
* @param {number|string} y 反相区域的左上角Y座标,单位dot
* @param {number|string} width 反相区域宽度,单位dot
* @param {number|string} height 反相区域高度,单位dot
* @returns {TSC}
*/
setReverse(x, y, width, height) {
const code = `REVERSE ${x},${y},${width},${height}${TSC.LINE_BREAK}`;
return this.addCode(code);
}
/**
* 该指令用于打印字符串
* @param {number|string} x 文字X方向起始点坐标
* @param {number|string} y 文字Y方向起始点坐标
* @param {number|string} font 字体名称
* @param {number|string} sx X 方向放大倍率1-10
* @param {number|string} sy Y 方向放大倍率1-10
* @param {number|string} content 内容
* @returns {TSC}
*/
setText(x, y, font, rotation, sx, sy, content) {
x = parseInt(x);
y = parseInt(y);
rotation = parseInt(rotation);
sx = parseInt(sx);
sy = parseInt(sy);
content = String(content);
const code = `TEXT ${x},${y},"${font}",${rotation},${sx},${sy},"${content}"${TSC.LINE_BREAK}`;
return this.addCode(code);
}
/**
* 该指令用来打印二维码
* @param {number|string} x 二维码水平方向起始点坐标
* @param {number|string} y 反相区域的左上角Y座标,单位dot
* @param {number|string} level 选择QRCODE纠错等级
* @param {number|string} width 二维码宽度1-10
* @param {number|string} mode 手动/自动编码
* @param {number|string} rotation 旋转角度(顺时针方向)
* @param {number|string} content 内容
* @returns {TSC}
*/
setQrcode(x, y, level, width, mode, rotation, content) {
const code = `QRCODE ${x},${y},${level},${width},${mode},${rotation},"${content}"${TSC.LINE_BREAK}`;
return this.addCode(code);
}
// 询问打印机状态指令=========================
// 打印机外围功能设定指令=========================
/**
* 该指令用来起动Key1 的预设功能
* 预设为进纸功能
* @param {"ON"|"OFF"} k 开启按键/关闭按键
* @returns {TSC}
*/
setKey1(k) {
const code = `SET KYE1 ${k}${TSC.LINE_BREAK}`;
return this.addCode(code);
}
/**
* 该指令用来起动Key2 的预设功能
* 预设为暂停功能
* @param {"ON"|"OFF"} k 开启按键/关闭按键
* @returns {TSC}
*/
setKey2(k) {
const code = `SET KYE2 ${k}${TSC.LINE_BREAK}`;
return this.addCode(code);
}
/**
* 该指令用来启动/关闭剥离模式,默认值为关闭
* @param {"ON"|"OFF"} k 开启按键/关闭按键
* @returns {TSC}
*/
setPeel(k) {
const code = `SET PEEL ${k}${TSC.LINE_BREAK}`;
return this.addCode(code);
}
/**
* 此命令是用来启用/禁用撕纸位置走到撕纸处,此设置关掉电源后将保存在打印机内
* @param {"ON"|"OFF"} k 开启按键/关闭按键
* @returns {TSC}
*/
setTear(k) {
const code = `SET TEAR ${k}${TSC.LINE_BREAK}`;
return this.addCode(code);
}
/**
* 此命令是用来启用/禁用撕纸位置走到撕纸处,此设置关掉电源后将保存在打印机内
* @param {"ON"|"OFF"} k 开启按键/关闭按键
* @returns {TSC}
*/
setStripper(k) {
const code = `SET STRIPPER ${k}${TSC.LINE_BREAK}`;
return this.addCode(code);
}
/**
* 此设置用于启用/禁用打印头合盖传感器。如果禁用合盖传感器,打印机头被打开时,将不会传回错误信息。
* 此设置将保存在打印机内存。
* @param {"ON"|"OFF"} k 开启按键/关闭按键
* @returns {TSC}
*/
setHead(k) {
const code = `SET HEAD ${k}${TSC.LINE_BREAK}`;
return this.addCode(code);
}
/**
* 此设置用于启用/禁用打印头合盖传感器。如果禁用合盖传感器,打印机头被打开时,将不会传回错误信息。
* 此设置将保存在打印机内存。
* @param {"ON"|"OFF"|"AUTO"|string|number} k 开启按键/关闭按键
* @returns {TSC}
*/
setHead2(k) {
const code = `SET PRINTKEY ${k}${TSC.LINE_BREAK}`;
return this.addCode(code);
}
/**
* 此命令将禁用/启用标签机在无纸或开盖错误发生后,
* 上纸或合盖后重新打印一次标签内容
* @param {"ON"|"OFF"} k 开启按键/关闭按键
* @returns {TSC}
*/
setReprint(k) {
const code = `SET REPRINT ${k}${TSC.LINE_BREAK}`;
return this.addCode(code);
}
/**
* 设定开启/关闭碳带感应器,即切换热转式/热感印式打印。通常打印机于开启电源时,
* 碳带感应器即会自动检测打印机是否已装上碳带,并藉此决定使用热感式或热转式打印。
* 此项设定并不会存于打印机中。此方法仅适用于热转式机器。
* @param {"ON"|"OFF"} k 开启按键/关闭按键
* @returns {TSC}
*/
setRibbon(k) {
const code = `SET RIBBON ${k}${TSC.LINE_BREAK}`;
return this.addCode(code);
}
/**
* 此命令用于设置切刀状态,关闭打印机电源后,该设置将会被存储在打印机内存中。
* @param {"OFF"|"BATCH"|string|number} k 开启按键/关闭按键
* @returns {TSC}
*/
setCutter(k) {
const code = `SET CUTTER ${k}${TSC.LINE_BREAK}`;
return this.addCode(code);
}
/**
* 此指令用于设置打印机自动返回状态
* @param {"ON"|"OFF"|"BATCH"} k 开启按键/关闭按键
* @param {string} content
* @returns {TSC}
*/
setResponse(k, content) {
const code = `SET RESPONSE "${content}",${k}${TSC.LINE_BREAK}`;
return this.addCode(code);
}
}
+16
View File
@@ -0,0 +1,16 @@
/**
* 等待
* @param timeout 等待时间,ms
*/
export function wait(timeout: number): Promise<void> {
return new Promise((resolve, reject) => {
try {
const id = setTimeout(() => {
resolve();
clearTimeout(id);
}, timeout);
} catch (error) {
reject(error);
}
});
}
+86
View File
@@ -0,0 +1,86 @@
import dayjs from "dayjs";
import { Duration } from "dayjs/plugin/duration";
type TimerCallback = (time: string) => void;
export default class Countdown {
id = -1;
duration: Duration;
format = "HH:mm:ss";
/**
* 倒计时步骤监听器
*/
stepEventListenerList = <TimerCallback[]>[];
/**
* 倒计时完成时间监听器
*/
countdownEventListenerList = <TimerCallback[]>[];
initialTime = 0;
constructor(time: number) {
this.initialTime = time;
this.duration = dayjs.duration(time);
}
/**
* 添加倒计时步骤监听器
* @param cb
* @returns
*/
addStepEventListener(cb: TimerCallback) {
if (!(cb instanceof Function)) {
return new TypeError("回调函数类型错误: cb: " + cb);
}
this.stepEventListenerList.push(cb);
}
/**
* 添加倒计时完成时间监听器
* @param cb
* @returns
*/
addCountdownEventListener(cb: TimerCallback) {
if (!(cb instanceof Function)) {
return new TypeError("回调函数类型错误: cb: " + cb);
}
this.countdownEventListenerList.push(cb);
}
/**
* 开始倒计时
*/
start() {
this.id = window.setInterval(() => {
this.duration = this.duration.subtract(1000);
const str = this.duration.format(this.format);
this.stepEventListenerList.forEach((cb) => cb(str));
if (this.duration.asMilliseconds() <= 0) {
this.stop();
}
}, 1000);
}
/**
* 结束倒计时
*/
stop() {
console.log("stop", this.id);
const str = this.duration.format(this.format);
clearInterval(this.id);
this.id = -1;
this.countdownEventListenerList.forEach((cb) => cb(str));
}
/**
* 重新开始计时
*/
restart() {
clearInterval(this.id);
this.id = -1;
this.duration = dayjs.duration(this.initialTime);
this.start();
}
}
+101
View File
@@ -0,0 +1,101 @@
type TimerCallback = (time: number) => void;
export default class TimeoutTimer {
startTime = 0;
endTime = 0;
interval = 0;
time = 0;
id = -1;
stepEventListenerList = <TimerCallback[]>[];
countdownEventListenerList = <TimerCallback[]>[];
/**
*
* @param startTime 起始时间
* @param endTime 结束时间
* @param interval 间隔(ms)
*/
constructor(startTime = 5, endTime = 0, interval = 1000) {
this.startTime = startTime;
this.endTime = endTime;
this.interval = interval;
}
/**
* 倒计时步骤监听器
* @param cb
* @returns
*/
addStepEventListener(cb: TimerCallback) {
if (!(cb instanceof Function)) {
return new TypeError("回调函数类型错误: cb: " + cb);
}
this.stepEventListenerList.push(cb);
}
/**
* 倒计时完成时间监听器
* @param cb
* @returns
*/
addCountdownEventListener(cb: TimerCallback) {
if (!(cb instanceof Function)) {
return new TypeError("回调函数类型错误: cb: " + cb);
}
this.countdownEventListenerList.push(cb);
}
/**
* 开始倒计时
* @param startTime
* @param endTime
* @param interval
* @param stepEventListener
* @param countdownEventListener
* @returns
*/
static start(
startTime: number,
endTime: number = 0,
interval = 1000,
stepEventListener?: TimerCallback,
countdownEventListener?: TimerCallback,
) {
const timer = new TimeoutTimer(startTime, endTime, interval);
if (stepEventListener != null) {
timer.addStepEventListener(stepEventListener);
}
if (countdownEventListener != null) {
timer.addCountdownEventListener(countdownEventListener);
}
return timer;
}
/**
* 开始倒计时
*/
start() {
this.time = this.startTime;
this.id = window.setInterval(() => {
this.time -= this.interval;
console.log(this.time);
this.stepEventListenerList.forEach((cb) => cb(this.time));
if (this.time <= this.endTime && this.id !== -1) {
this.stop();
}
}, this.interval);
}
/**
* 结束倒计时
*/
stop() {
console.log("stop", this.id);
clearInterval(this.id);
this.id = -1;
this.time = this.endTime;
this.countdownEventListenerList.forEach((cb) => cb(this.time));
}
}
+2
View File
@@ -0,0 +1,2 @@
export { default as Countdown } from "./Countdown";
export { default as TimeoutTimer } from "./TimeoutTimer";