@yoooloo42/beat 1.0.20 → 1.0.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yoooloo42/beat",
3
- "version": "1.0.20",
3
+ "version": "1.0.22",
4
4
  "description": "",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1"
@@ -0,0 +1,121 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import https from 'https';
4
+ import http from 'http'; // 也可能需要处理 http 链接
5
+
6
+ /**
7
+ * 从本地文件路径获取文件的 Base64 编码。
8
+ * @param {string} filePath - 本地文件的绝对或相对路径。
9
+ * @returns {Promise<string>} - 文件的 Base64 编码字符串。
10
+ */
11
+ function getBase64FromLocalFile(filePath) {
12
+ return new Promise((resolve, reject) => {
13
+ // 确保路径是绝对路径
14
+ const absolutePath = path.resolve(filePath);
15
+
16
+ // 使用 { encoding: 'base64' } 直接读取为 Base64 字符串
17
+ fs.readFile(absolutePath, { encoding: 'base64' }, (err, data) => {
18
+ if (err) {
19
+ console.error(`[本地文件错误] 读取本地文件失败: ${err.message}`);
20
+ return reject(err);
21
+ }
22
+ resolve(data);
23
+ });
24
+ });
25
+ }
26
+
27
+ /**
28
+ * 从远程文件 URL 获取文件的 Base64 编码,支持自动重定向跟随 (3xx 状态码)。
29
+ * @param {string} fileUrl - 远程文件的完整 URL。
30
+ * @param {number} [redirects=5] - 最大重定向次数限制。
31
+ * @returns {Promise<string>} - 文件的 Base64 编码字符串。
32
+ */
33
+ function getBase64FromURL(fileUrl, redirects = 5) {
34
+ if (redirects === 0) {
35
+ return Promise.reject(new Error(`[远程文件错误] 重定向次数过多 (${fileUrl})`));
36
+ }
37
+
38
+ // 根据 URL 协议选择合适的模块
39
+ const client = fileUrl.startsWith('https') ? https : http;
40
+
41
+ return new Promise((resolve, reject) => {
42
+ client.get(fileUrl, (res) => {
43
+ const statusCode = res.statusCode;
44
+
45
+ // --- 处理重定向 (3xx 状态码) ---
46
+ if (statusCode >= 300 && statusCode < 400 && res.headers.location) {
47
+ const newUrl = res.headers.location;
48
+ console.log(`[重定向] 遇到状态码 ${statusCode},重定向至: ${newUrl}`);
49
+ // 递归调用自身,跟随重定向
50
+ return getBase64FromURL(newUrl, redirects - 1)
51
+ .then(resolve)
52
+ .catch(reject);
53
+ }
54
+
55
+ // --- 处理请求失败 (4xx, 5xx) ---
56
+ if (statusCode < 200 || statusCode >= 400) {
57
+ return reject(new Error(`[远程文件错误] 请求失败,状态码: ${statusCode} (${fileUrl})`));
58
+ }
59
+
60
+ // --- 成功获取 (2xx) ---
61
+ const chunks = [];
62
+ res.on('data', (chunk) => {
63
+ chunks.push(chunk);
64
+ });
65
+
66
+ res.on('end', () => {
67
+ try {
68
+ // 合并所有 Buffer 块并转换为 Base64 字符串
69
+ const buffer = Buffer.concat(chunks);
70
+ const base64String = buffer.toString('base64');
71
+ resolve(base64String);
72
+ } catch (e) {
73
+ reject(new Error(`[远程文件错误] 处理远程文件数据失败: ${e.message}`));
74
+ }
75
+ });
76
+
77
+ }).on('error', (err) => {
78
+ console.error(`[远程文件错误] 远程请求连接错误: ${err.message}`);
79
+ reject(err);
80
+ });
81
+ });
82
+ }
83
+
84
+ /*
85
+ // ------------------------------------
86
+ // 示例执行
87
+ // ------------------------------------
88
+
89
+ // 1. 本地文件示例(请确保 'test.bmp' 存在于同一目录下)
90
+ // 注意:如果文件不存在,会捕获到错误。
91
+ getBase64FromLocalFile('Base64.js.test.png')
92
+ .then(base64String => {
93
+ console.log('\n--- 本地文件结果 ---');
94
+ console.log(`本地文件的 Base64 编码长度: ${base64String.length}`);
95
+ console.log(`本地文件的 Base64 编码 (前50字符): ${base64String.substring(0, 50)}...`);
96
+ })
97
+ .catch(error => {
98
+ // 捕获本地文件不存在或权限不足的错误
99
+ console.error('\n--- 本地文件错误 ---');
100
+ console.error('获取本地文件 Base64 失败:', error.message);
101
+ });
102
+
103
+ // 2. 远程 URL 示例(使用支持重定向的函数)
104
+ const remoteUrl = 'https://picsum.photos/200/300'; // 这个 URL 会导致 302 重定向
105
+ getBase64FromURL(remoteUrl)
106
+ .then(base64String => {
107
+ console.log('\n--- 远程文件结果 ---');
108
+ console.log(`远程文件的 Base64 编码长度: ${base64String.length}`);
109
+ console.log(`远程文件的 Base64 编码 (前50字符): ${base64String.substring(0, 50)}...`);
110
+ })
111
+ .catch(error => {
112
+ // 捕获请求失败或重定向超时的错误
113
+ console.error('\n--- 远程文件错误 ---');
114
+ console.error('获取远程文件 Base64 失败:', error.message);
115
+ });
116
+ */
117
+
118
+ export default {
119
+ getBase64FromLocalFile,
120
+ getBase64FromURL
121
+ }
Binary file
@@ -0,0 +1,166 @@
1
+ // 飞鹅票据打印机
2
+
3
+ import http from 'http'
4
+ import qs from 'querystring'
5
+ import Hash from './crypto/Hash.js'
6
+ const host = 'api.feieyun.cn',
7
+ port = '80',
8
+ path = '/Api/Open/'
9
+
10
+ // 添加打印机(支持批量)
11
+ function Open_printerAddlist (para) {
12
+ // para.user
13
+ // para.ukey
14
+ // para.snList 打印机列表
15
+
16
+ // ---------- 参数 snList 示例 ----------
17
+ // 格式说明:打印机编号(必填)#打印机识别码(必填)#备注名称(选填)#流量卡号码(选填),多台打印机请换行(\n),每次最多100行(台)
18
+ // var snList = "sn1#key1#note1#carnum1\nsn2#key2#note2#carnum2"
19
+ // addprinter ( snList ) ;
20
+
21
+ // ---------- 返回值示例 ----------
22
+ // 正确的例子:{"msg":"ok","ret":0,"data":{"ok":["sn#key#note#carnum","316500011#abcdefgh#快餐前台"],"no":["316500012#abcdefgh#快餐前台#13688889999
23
+ // (错误:识别码不正确)"]},"serverExecutedTime":3} 错误:{"msg":"参数错误 : 该帐号未注册.","ret":-2,"data":null,"serverExecutedTime":37}
24
+
25
+ return new Promise(function (resolve, reject) {
26
+ let stime = Math.floor(new Date().getTime() / 1000) //时间戳
27
+ let sig = Hash.sha1(para.user + para.ukey + stime) //签名
28
+
29
+ let post_data = {
30
+ user: para.user,
31
+ stime,
32
+ sig,
33
+ apiname: 'Open_printerAddlist',
34
+ printerContent: para.snList
35
+ }
36
+ let content = qs.stringify(post_data)
37
+ let options = {
38
+ hostname: host,
39
+ port,
40
+ path,
41
+ method: 'POST',
42
+ headers: {'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}
43
+ }
44
+
45
+ //发起请求
46
+ let req = http.request(options, function (res) {
47
+ res.setEncoding('utf-8')
48
+ res.on('data', function (response) {
49
+ let response0 = JSON.parse(response)
50
+
51
+ if (response0.msg === 'ok' || response0.ret === 0) {
52
+ resolve({code: 0, message: '增加打印机成功'})
53
+ } else {
54
+ resolve({code: 1, message: '增加打印机失败:' + response0.msg})
55
+ }
56
+ })
57
+ })
58
+ req.on('error', function (err) {
59
+ resolve({code: 1, message: '请求失败:' + err})
60
+ })
61
+ req.write(content)
62
+ req.end()
63
+ })
64
+ }
65
+
66
+ // 打印
67
+ function Open_printMsg(para){
68
+ // para.user
69
+ // para.ukey
70
+ // para.sn 打印机编号(9 位数字)
71
+ // para.note 打印机备注名称
72
+ // para.orderInfo 打印内容
73
+
74
+ // 提示:调用打印接口之前,必须登录后台在该账号下添加打印机,或者通过 API 接口,把打印机添加到该账号下面
75
+
76
+ // ---------- 返回值示例 ----------
77
+ // 正确的例子:{"msg":"ok","ret":0,"data":"xxxx_xxxx_xxxxxxxxx","serverExecutedTime":6}
78
+ // 错误:{"msg":"错误信息.","ret":非零错误码,"data":null,"serverExecutedTime":5}
79
+
80
+ /*
81
+ 标签说明:
82
+ 单标签:
83
+ "<BR>"为换行,"<CUT>"为切刀指令(主动切纸,仅限切刀打印机使用才有效果)
84
+ "<LOGO>"为打印LOGO指令(前提是预先在机器内置LOGO图片),"<PLUGIN>"为钱箱或者外置音响指令
85
+ 成对标签:
86
+ "<CB></CB>"为居中放大一倍,"<B></B>"为放大一倍,"<C></C>"为居中,<L></L>字体变高一倍
87
+ <W></W>字体变宽一倍,"<QR></QR>"为二维码,"<BOLD></BOLD>"为字体加粗,"<RIGHT></RIGHT>"为右对齐
88
+
89
+ 拼凑订单内容时,可参考下面的示例
90
+ 根据打印纸张的宽度,自行调整内容的格式,可参考下面的示例
91
+ var orderInfo ;
92
+ orderInfo = "<CB>测试打印</CB><BR>" ; //标题字体如需居中放大,就需要用标签套上
93
+ orderInfo += "名称      单价 数量 金额<BR>" ;
94
+ orderInfo += "--------------------------------<BR>" ;
95
+ orderInfo += "番       1.0 1 1.0<BR>" ;
96
+ orderInfo += "番茄      10.0 10 10.0<BR>" ;
97
+ orderInfo += "番茄炒     10.0 100 100.0<BR>" ;
98
+ orderInfo += "番茄炒粉    100.0 100 100.0<BR>" ;
99
+ orderInfo += "番茄炒粉粉   1000.0 1 100.0<BR>" ;
100
+ orderInfo += "番茄炒粉粉粉粉 100.0 100 100.0<BR>" ;
101
+ orderInfo += "番茄炒粉粉粉粉 15.0 1 15.0<BR>" ;
102
+ orderInfo += "备注:快点送到xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx<BR>" ;
103
+ orderInfo += "--------------------------------<BR>" ;
104
+ orderInfo += "合计:xx.0元<BR>" ;
105
+ orderInfo += "送货地点:xxxxxxxxxxxxxxxxx<BR>" ;
106
+ orderInfo += "联系电话:138000000000<BR>" ;
107
+ orderInfo += "订餐时间:2011-01-06 19:30:10<BR><BR>" ;
108
+ orderInfo += "----------请扫描二维码----------" ;
109
+ orderInfo += "<QR>http://www.dzist.com</QR>" ; //把二维码字符串用标签套上即可自动生成二维码
110
+ */
111
+
112
+ return new Promise(function (resolve, reject) {
113
+ let stime = Math.floor(new Date().getTime() / 1000) //时间戳
114
+ let sig = Hash.sha1(para.user + para.ukey + stime) //签名
115
+
116
+ let post_data = {
117
+ user: para.user,
118
+ stime,
119
+ sig,
120
+ apiname: 'Open_printMsg',
121
+ sn: para.sn,
122
+ content: para.orderInfo,
123
+ times: '1' //打印联数,默认为1
124
+ }
125
+ let content = qs.stringify(post_data)
126
+ let options = {
127
+ hostname: host,
128
+ port,
129
+ path,
130
+ method: 'POST',
131
+ headers: {'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}
132
+ }
133
+
134
+ let req = http.request(options, function (res) {
135
+ res.setEncoding('utf-8')
136
+ res.on('data', function (response) {
137
+ let response0 = JSON.parse(response)
138
+
139
+ if (response0.msg === 'ok' || response0.ret === 0) {
140
+ resolve({
141
+ code: 0,
142
+ message: para.sn + ' ' + para.note + ' 打印成功'
143
+ })
144
+ } else {
145
+ resolve({
146
+ code: 1,
147
+ message: para.sn + ' ' + para.note + ' 打印失败:' + response0.msg
148
+ })
149
+ }
150
+ })
151
+ })
152
+ req.on('error', function (err) {
153
+ resolve({
154
+ code: 1,
155
+ message: para.sn + ' ' + para.note + ' 请求失败:' + err
156
+ })
157
+ })
158
+ req.write(content)
159
+ req.end()
160
+ })
161
+ }
162
+
163
+ export default {
164
+ Open_printerAddlist,
165
+ Open_printMsg
166
+ }
@@ -0,0 +1,170 @@
1
+ // 驿町管家智能门锁
2
+ // http://www.yizoo.net/
3
+
4
+ import Request from 'request'
5
+
6
+ // 获取令牌
7
+ function openSmartLogin(para){
8
+ // para.url 接口请求地址
9
+ // para.accountName 登录账号
10
+ // para.password 密码
11
+
12
+ return new Promise((resolve, reject) => {
13
+ Request({
14
+ url: para.url,
15
+ method: 'POST',
16
+ json: true,
17
+ headers: {
18
+ 'Content-Type': 'text/json;charset=utf-8',
19
+ 'Content-Version': '1.0' // 接口版本,不填则默认获取1.0版本
20
+ },
21
+ body: {
22
+ method: 'openSmartLogin', // 接口方法
23
+ data: {
24
+ accountName: para.accountName,
25
+ password: para.password
26
+ }
27
+ }
28
+ }, function (error, response, body) {
29
+ if (error) throw error
30
+
31
+ let msgId = body.msgId,
32
+ resultCode = body.resultCode,
33
+ reason = body.reason,
34
+ method = body.method,
35
+ data = body.data
36
+
37
+ if (resultCode !== 0) {
38
+ return resolve({code: 1, message: '获取 tokenid 失败:' + reason})
39
+ }
40
+
41
+ resolve({code: 0, message: '获取 tokenid 成功',
42
+ data: {
43
+ tokenId: data.tokenId, // 令牌
44
+ expireTime: data.expireTime // 有效时长(单位:秒)
45
+ }
46
+ })
47
+ })
48
+ })
49
+ }
50
+
51
+ // 获取门锁信息
52
+ function openSmartRoomList(para){
53
+ // para.requestUrl 接口请求地址
54
+ // para.tokenId 访问令牌
55
+
56
+ return new Promise((resolve, reject) => {
57
+ let startNum = 0, // 开始下标,默认:0
58
+ pageSize = 10, // 分页大小,默认:10
59
+ pageSizeMax = 50 // 分页大小,最大:50
60
+
61
+ // 第一次请求
62
+ Request({
63
+ url: para.requestUrl,
64
+ method: 'POST',
65
+ json: true,
66
+ headers: {
67
+ 'Content-Type': 'text/json;charset=utf-8',
68
+ 'Content-Version': '1.0' // 接口版本,不填则默认获取1.0版本
69
+ },
70
+ body: {
71
+ method: 'openSmartRoomList', // 接口方法
72
+ tokenId: para.tokenId,
73
+ data: {
74
+ startNum,
75
+ pageSize: pageSizeMax
76
+ }
77
+ }
78
+ }, function (error, response, body) {
79
+ if (error) throw error
80
+
81
+ let resultCode = body.resultCode,
82
+ reason = body.reason,
83
+ roomList = body.data.roomList, // 门锁信息
84
+ listSum = body.listSum // 总记录数
85
+
86
+ if (resultCode !== 0) {
87
+ return resolve({code: 1, message: '获取门锁信息失败:' + reason})
88
+ }
89
+
90
+ let roomListAll = [], // 门锁信息转义、累加
91
+ arrPromiseReq = []
92
+
93
+ for (let i = 0; i < roomList.length; i++) {
94
+ roomListAll.push({
95
+ roomName: roomList [i].roomName, // 房号
96
+ buildingCode: roomList [i].buildingCode, // 楼栋编码
97
+ floorCode: roomList [i].floorCode, // 楼层
98
+ roomCode: roomList [i].roomCode, // 房间编码
99
+ lockCode: roomList [i].lockCode, // 门锁编码
100
+ lockMac: roomList [i].lockMac, // 门锁Mac
101
+ aesKey: roomList [i].aesKey // 门锁AES128密钥
102
+ })
103
+ }
104
+
105
+ //剩余请求次数
106
+ let reqCount = Math.floor(listSum / pageSizeMax)
107
+ reqCount = listSum % pageSizeMax > 0 ? reqCount + 1 : reqCount
108
+ reqCount = reqCount > 0 ? reqCount - 1 : 0
109
+
110
+ //继续发送请求
111
+ for (let iReq = 0; iReq < reqCount; iReq++) {
112
+ arrPromiseReq.push(new Promise((resolve0, reject0) => {
113
+ Request({
114
+ url: para.requestUrl,
115
+ method: 'POST',
116
+ json: true,
117
+ headers: {
118
+ 'Content-Type': 'text/json;charset=utf-8',
119
+ 'Content-Version': '1.0' // 接口版本,不填则默认获取1.0版本
120
+ },
121
+ body: {
122
+ method: 'openSmartRoomList', // 接口方法
123
+ tokenId: para.tokenId,
124
+ data: {
125
+ startNum: (iReq + 1) * pageSizeMax + 1,
126
+ pageSize: pageSizeMax
127
+ }
128
+ }
129
+ }, function (error, response, body) {
130
+ if (error) throw error
131
+
132
+ let resultCode = body.resultCode,
133
+ reason = body.reason,
134
+ roomList = body.data.roomList // 门锁信息
135
+
136
+ if (resultCode !== 0) {
137
+ return resolve({code: 1, message: '获取门锁信息失败:' + reason})
138
+ }
139
+
140
+ //门锁信息转义、累加
141
+ for (let i = 0; i < roomList.length; i++) {
142
+ roomListAll.push({
143
+ roomName: roomList [i].roomName, // 房号
144
+ buildingCode: roomList [i].buildingCode, // 楼栋编码
145
+ floorCode: roomList [i].floorCode, // 楼层
146
+ roomCode: roomList [i].roomCode, // 房间编码
147
+ lockCode: roomList [i].lockCode, // 门锁编码
148
+ lockMac: roomList [i].lockMac, // 门锁Mac
149
+ aesKey: roomList [i].aesKey // 门锁AES128密钥
150
+ })
151
+ }
152
+
153
+ resolve0()
154
+ })
155
+ }))
156
+ }
157
+
158
+ Promise.all(arrPromiseReq).then(() => {
159
+ resolve({code: 0, message: '获取门锁信息成功',
160
+ data: roomListAll
161
+ })
162
+ })
163
+ })
164
+ })
165
+ }
166
+
167
+ export default {
168
+ openSmartLogin,
169
+ openSmartRoomList
170
+ }