- left-f-tools
- callbacToPromiseTask
代码语言:javascript
复制import { CallbackToPromiseTask } from './callbacToPromiseTask'
import asyncFormat from 'left-f-tools/lib/asyncFormat'
import Enum from 'left-f-tools/lib/Enum'
// API 名称及代码
const functionIDEnum = new Enum([
[0, 'RequestTypeACardNo', { label: '查询A卡卡号' }],
[1, 'RequestTypeBCardNo', { label: '查询B卡卡号' }],
[2, 'Request15693CardUID', { label: '查询15693卡卡号' }],
[3, 'RequestChinaIDCardNo', { label: '查询身份证卡号, 非证件号' }],
[4, 'RequestCardNo', { label: '查询卡号' }],
[5, 'M1ReadBlock', { label: 'M1读卡' }],
[6, 'M1WriteBlock', { label: 'M1写卡' }],
[7, 'M1ReadSector', { label: 'M1读取扇区' }],
[8, 'M1WriteSector', { label: 'M1写入扇区' }],
[9, 'M1IntialValue', { label: 'M1初始化钱包' }],
[10, 'M1GetValue', { label: 'M1获取金额' }],
[11, 'M1IncreaseValue', { label: 'M1充值' }],
[12, 'M1DecreaseValue', { label: 'M1消费' }],
[13, 'Beep', { label: '蜂鸣次数' }],
[14, 'Ver', { label: '版本' }],
[15, 'Tick', { label: '' }],
[16, 'LED', { label: '闪烁次数' }],
[17, 'typeacpureset', { label: '' }],
// [18, '', { label: '' }],
[19, 'CPUCos', { label: 'cpu 执行cos' }],
[20, 'SAMReset', { label: 'SAM 重置' }],
[21, 'SAMCos', { label: 'SAM 执行cos' }],
[22, 'DES', { label: 'DES 加密' }],
[23, 'G2_Inventory', { label: 'G2 存储' }],
[24, 'G2_Read', { label: 'G2 读卡' }],
[25, 'G2_Write', { label: 'G2 写卡' }],
[26, 'G2_WriteEPC', { label: 'G2 写 EPC' }],
[27, 'G2_KillTag', { label: 'G2 删除标签' }],
[28, 'G2_SetProtected', { label: 'G2 上锁' }],
[29, 'G2_Earse', { label: '' }],
[30, 'G2_SetReadProtected', { label: 'G2 读取上锁' }],
[31, 'G2_SetUnlockReadProtected', { label: 'G2 读取解锁' }],
[32, 'G2_SetEASAlert', { label: '' }],
[33, 'G2_LockUser', { label: 'G2 用户上锁' }],
[34, 'SinoPecCard_GetInfo', { label: '加油卡 获取信息' }],
[35, 'SinoPecCard_GetBalance', { label: '加油卡 获取余额' }],
[36, 'SinoPecCard_GetRecord', { label: '加油卡 获取纪律' }],
[37, 'ISO15693ReadBlock', { label: 'ISO15693 读块' }],
[38, 'ISO15693WriteBlock', { label: 'ISO15693 写块' }],
[39, 'ISO15693LockBlock', { label: 'ISO15693 锁块' }],
[40, 'ISO15693WriteAFI', { label: 'ISO15693 设置领域标识' }],
[41, 'ISO15693LockAFI', { label: 'ISO15693 锁定领域标识' }],
[42, 'ISO15693WriteDSFID', { label: 'ISO15693 写入 DSFID' }],
[43, 'ISO15693LockDSFID', { label: 'ISO15693 锁定 DSFID' }],
[44, 'ISO15693GetInformation', { label: 'ISO15693 获取卡信息' }],
[45, 'DownKey', { label: '下载密钥' }],
[46, 'NTAG_Auth', { label: 'NTAG 获取权限' }],
[47, 'NTAG_Read', { label: 'NTAG 读卡' }],
[48, 'NTAG_Write', { label: 'NTAG 写卡' }],
[49, 'NTAG_Counter', { label: '' }],
[50, 'NDEF_AddRecord_Sign', { label: 'NDEF 添加记录' }],
[51, 'NDEF_AddRecord', { label: 'NDEF 添加记录' }],
[52, 'NDEF_ClearAllRecords', { label: 'NDEF 清除记录' }],
[53, 'NDEF_Write', { label: 'NDEF 读卡' }],
[54, 'NDEF_Read', { label: 'NDEF 写卡' }],
[55, 'EY5K_RquestCardNo', { label: 'EY5K 读取卡号' }],
[56, 'EY5K_GetPublicInfo', { label: 'EY5K 获取公开信息' }],
[57, 'EY5K_SetPublicInfo', { label: 'EY5K 设置公开信息' }],
[58, 'EY5K_GetHolderInfo', { label: 'EY5K 获取用户信息' }],
[59, 'EY5K_SetHolderInfo', { label: 'EY5K 设置用户信息' }],
[60, 'EY5K_ReadUserFile', { label: 'EY5K 读取用户文件' }],
[61, 'EY5K_WriteUserFile', { label: 'EY5K 写入用户文件' }],
[62, 'EY5K_GetValue', { label: '' }],
[63, 'EY5K_IncreaseValue', { label: '' }],
[64, 'EY5K_DecreaseValue', { label: '' }],
[65, 'EY5K_GetRecords', { label: '' }],
[66, 'EY5K_ChangeKey', { label: '' }],
[67, 'GetTeminateCode', { label: '获取终止码' }],
[68, 'ShowImage', { label: '设置展示图片' }],
[69, 'ShowText', { label: '设置展示文本' }],
])
// 错误代码
const errCodeEnum = new Enum([
[ -1, "没有找到IC卡读卡器,支持型号:YW-605HA, YW-607,YW-627" ],
[ -3, "寻卡失败" ],
[ -4, "寻卡失败" ],
[ -5, "卡休眠失败" ],
[ -6, "密钥认证失败" ],
[ -7, "读取失败" ],
[ -8, "写入失败" ],
[ -9, "钱包初始化失败" ],
[ -10, "钱包读余额失败" ],
[ -11, "钱包充值失败" ],
[ -12, "钱包减值失败" ],
[ -13, "复位错误" ],
[ -14, "COS执行错误" ],
[ -101, "参数错误" ],
[ -102, "DES校验错误" ],
[ -103, "读卡器不支持" ],
[ -600, "没找到YW-602系列UHF读卡器" ],
[ -601, "寻G2标签失败" ],
[ -602, "读G2标签失败" ],
[ -603, "写G2标签失败" ],
[ -603, "执行失败" ],
])
// 错误类型
const errTypeEnum = new Enum([
[ 'socket', 'socket错误' ],
[ 'server', '服务错误' ],
])
/**
* 对用友 M1卡读卡器js的重构
* 提供两种监听模式,callback | promise
*
*
* -------------------------------------
* @callback_模式
*
* - 监听设置函数与websorct API 对应关系
*
* setonOpen --> websorct.onopen
* setonClose --> websorct.onclose
* setonError --> websorct.onerror
* setonMessage --> websorct.onmessage
*
* - 例子
* const c = new CardReader
* c.setonOpen(() => console.log('连接成功'))
* c.setonError(() => console.log('报错提示'))
* c.connect()
*
*
* -------------------------------------
* @promise_模式
*
* - 例子
* 通过追加 then 或 catch 可获取连接是否成功
* const c = new CardReader
* c.connect().then(() => console.log('连接成功')).catch(err => console.log('连接失败'))
*
*
* -------------------------------------
* @method
*
* - setProps 设置参数
* - connect 连接插件服务
* - disconnect 关闭连接
* - send 发送消息
*
*
* -------------------------------------
* @example
*
* (
async function(){
const c = new CardReaderAPI()
let [ res, err ] = await asyncFormat(c.connect())
if(err){ console.log('fail', data); return }
console.log(res)
// 获取A卡号
const [ resNo1, errNo1 ] = await asyncFormat(c.send(0,1,0))
console.log('>>>>', resNo1, errNo1)
}()
)
*
*/
export class CardReader{
constructor(){
this.taskState = CallbackToPromiseTask.create()
this.taskState.clear()
this._onMessage = () => {},
this._onError = () => {}
this._onOpen = () =>{}
this._onClose = () => {}
this.state = {
// 插件服务地址
serverURL: "ws://127.0.0.1:8009/YOWORFIDReader",
// 版本
version: '',
// 读卡器ID
readerID: 1,
// 自定义标识
UID: 0,
// 寻卡模式 0: 所有卡 1: 已激活
requestActive: 1,
// 密钥类型 0: A秘钥 1: B秘钥
keyMode: 0,
// 密钥字符串
keyString: 'FFFFFFFFFFFF',
// 密钥字符串的格式 0: 16进制 1: 字符串 2: 使用下载的密钥
keyStringMode: 0,
// 重复执行标志 0: 只执行一次 1: 重复执行
repeat: 0,
// 调用成功 蜂鸣器Beep次数
beepOnSuccess: 1,
// 调用失败 蜂鸣器Beep次数
beepOnFail: 0,
// 否将卡休眠 0: 不休眠 1: 休眠
haltAfterSuccess: 0,
// 加解密原数据处理方式 0: 原数据 1: 对原数据取反 2: 原数据 原数据取反
desMode: 0,
// 数据加密方向 0: 不加密 1: 加密 2: 解密
desDir: 0,
// DES密钥
desKey: '',
// DesKey密钥的格式 0: 16进制字符串 1: 普通字符串
desKeyMode: 0,
// websocet 对象
_wx: null,
// 是否已连接
_socketOpen: false,
// 参数拼接符
_splitChar: String.fromCharCode(65530),
}
}
setonMessage(callback){
if( typeof callback !== 'function'){ throw '监听方法非可执行函数' }
this._onMessage = callback
}
setonError(callback){
if( typeof callback !== 'function'){ throw '监听方法非可执行函数' }
this._onError = callback
}
setonOpen(callback){
if( typeof callback !== 'function'){ throw '监听方法非可执行函数' }
this._onOpen = callback
}
setonClose(callback){
if( typeof callback !== 'function'){ throw '监听方法非可执行函数' }
this._onClose = callback
}
setProps(data={}){
this.state = Object.assign({}, this.state, data)
}
_WSonOpen(){
this._onOpen()
this.setProps({ _socketOpen:true })
const task = this.taskState.shift()
task.resolve({ message: '连接成功' })
}
_WSonError(err){
const taks = this.taskState.shift()
const errorMsg = { message: err, type: errTypeEnum.get('socket') }
taks.reject(errorMsg)
this._onError(errorMsg)
}
_WSonClose(err){
this._onClose()
this.setProps({ _socketOpen:false })
const taks = this.taskState.shift()
taks.reject({message: '关闭服务'})
}
_WSonMessage(e){
const [ functionID, result, UID, readerID, cardNo, strData, valData ] = e.data.split(this.state._splitChar)
const resultData = {
functionID: parseInt(functionID),
result: parseInt(result),
UID: parseInt(UID),
readerID: parseInt(readerID),
cardNo,
strData,
valData: parseInt(valData)
}
// 设置版本
if(functionID === functionIDEnum.get('Ver')){
_this.setProps({ version: strData })
}
// promise task 分发
if(this.taskState.hasByKey(resultData.UID)){
const task = this.taskState.shift(resultData.UID)
if(resultData.result < 0){
const errorMsg = { message: errCodeEnum.get(resultData.result), type: errTypeEnum.get('server') }
task.reject(errorMsg)
}else{
task.resolve(errorMsg)
}
}
// 回调 task
if(resultData.result < 0){
const errorMsg = { message: errCodeEnum.get(resultData.result), type: errTypeEnum.get('server') }
this._onError(errorMsg)
}else{
this._onMessage(resultData)
}
}
_joinBySplitChar(strList){
return strList.join(this.state._splitChar)
}
_paramsToStr(FunctionID, paramsStr=[]){
const {
readerID,
UID,
requestActive,
keyMode,
keyString,
keyStringMode,
repeat,
beepOnSuccess,
beepOnFail,
haltAfterSuccess,
desDir,
desMode,
desKey,
desKeyMode,
} = this.state
const dataStr = this._joinBySplitChar([
readerID,
UID,
requestActive,
keyMode,
keyString,
keyStringMode,
repeat,
beepOnSuccess,
beepOnFail,
haltAfterSuccess,
desDir,
desMode,
desKey,
desKeyMode,
FunctionID,
...paramsStr
])
const funcName = functionIDEnum.get(FunctionID)
return `${funcName}:${dataStr}`
}
async connect(){
const [ promiseWait ] = this.taskState.push('CONNECT')
try {
let socket
if("WebSocket" in window){
socket = WebSocket
}
if("MozWebSocket" in window){
socket = MozWebSocket
}
if(!socket){
throw 'not supert websocket !!'
}
this._wx = new WebSocket(this.state.serverURL)
// _wx.callback this 指向 _wx
this._wx.onopen = this._WSonOpen.bind(this)
this._wx.onmessage = this._WSonMessage.bind(this)
this._wx.onclose = this._WSonClose.bind(this)
this._wx.onerror = this._WSonError.bind(this)
return promiseWait
} catch (error) {
return Promise.reject(error)
}
}
send(functionID, ...args){
const [ promiseWait, _key ] = this.taskState.push()
this.setProps({ UID: _key })
this._wx.send(this._paramsToStr(functionID, [...args]))
return promiseWait
}
disconnect(){
wx&&wx.close()
}
}
/**
* 针对用友通信方法的封装
* 方法的具体参数参看 http://www.youwokeji.com.cn/CloudReader
* -------------------------------------
* @example
*
*
(
async function(){
const c = new CardReaderAPI()
let [ res, err ] = await asyncFormat(c.connect())
if(err){ console.log('fail', data); return }
console.log(res)
const [ resNo1, errNo1 ] = await asyncFormat(c.M1ReadBlock(24,1))
console.log('>>>>', resNo1, errNo1)
const [ resNo2, errNo2 ] = await asyncFormat(c.M1ReadBlock(24,1))
console.log('>>>>', resNo2, errNo2)
}()
)
*
*
*/
export class CardReaderAPI extends CardReader {
constructor(...args){
super(...args)
}
RequestTypeACardNo(FormatID, OrderID){ return this.send(0,FormatID, OrderID) }
RequestTypeBCardNo(){ return this.send(1) }
Request15693CardUID(){ return this.send(2) }
RequestChinaIDCardNo(){ return this.send(3) }
RequestCardNo(){ return this.send(4) }
M1ReadBlock(blockIndex, FormatID){ return this.send(5, blockIndex, FormatID) }
M1WriteBlock(blockindex, blockdata, FormatID){ return this.send(6,blockindex, blockdata, FormatID) }
M1ReadSector(sectorindex, FormatID){ return this.send(7, sectorindex, FormatID) }
M1WriteSector(blockindex, blockdata, FormatID){ return this.send(8, blockindex, blockdata, FormatID) }
M1IntialValue(blockIndex, value){ return this.send(9, blockIndex, value) }
M1GetValue(blockIndex){ return this.send(10, blockIndex) }
M1IncreaseValue(blockIndex, value){ return this.send(11, blockIndex, value) }
M1DecreaseValue(blockIndex, value){ return this.send(12, blockIndex, value) }
Beep(blockIndex, value){ return this.send(13, blockIndex, value) }
Ver(){ return this.send(14) }
Tick(){ return this.send(15) }
LED(LedIndx, TimeOn, TimeOff, Times, LEDOnIndex){ return this.send(16, LedIndx, TimeOn, TimeOff, Times, LEDOnIndex) }
ACPUReset(){ return this.send(17) }
// (){ return this.send(18) }
CPUCOS(value){ return this.send(19, value) }
SAMReset(Index){ return this.send(20, Index) }
SAMCOS(Index, value){ return this.send(21, Index, value) }
Des(Data, DataForamt){ return this.send(22, Data, DataForamt) }
G2_Inventory(isEPC){ return this.send(23, isEPC) }
G2_Read(memType, StartPos, ReadLength, FormatID){ return this.send(24, memType, StartPos, ReadLength, FormatID) }
G2_Write(memType, StartPos, DataForamtID, Data){ return this.send(25, memType, StartPos, DataForamtID, Data) }
G2_WriteEPC(EPCData){ return this.send(26,EPCData) }
G2_KillTag(G2_KillTag){ return this.send(27, G2_KillTag) }
G2_SetProtected(ProtectByte, ProtectMode){ return this.send(28, ProtectByte, ProtectMode) }
G2_Earse(memType, StartPos, EarseLength){ return this.send(29, memType, StartPos, EarseLength) }
G2_SetReadProtected(){ return this.send(30) }
G2_SetUnlockReadProtected(){ return this.send(31) }
G2_SetEASAlert(EAS){ return this.send(32, EAS) }
G2_LockUser(UserAddr){ return this.send(33, UserAddr) }
SinoPecCard_GetInfo(){ return this.send(34) }
SinoPecCard_GetBalance(PIN){ return this.send(35, PIN) }
SinoPecCard_GetRecord(PIN, RecordID){ return this.send(36, PIN, RecordID) }
ISO15693ReadBlock(StartBlock, BlockNums, DataFormat){ return this.send(37, StartBlock, BlockNums, DataFormat) }
ISO15693WriteBlock(Block, Data, DataFormat){ return this.send(38, Block, Data, DataFormat) }
ISO15693LockBlock(Block){ return this.send(39, Block) }
ISO15693WriteAFI(AFI){ return this.send(40, AFI) }
ISO15693LockAFI(){ return this.send(41) }
RequestChinaIDCardNo(DSFID){ return this.send(42, DSFID) }
ISO15693LockDSFID(){ return this.send(43) }
ISO15693GetInformation(){ return this.send(44) }
DownKey(KeyIndex, KeyString){ return this.send(45, KeyIndex, KeyString) }
NTAG_Auth(){ return this.send(46) }
NTAG_Read(StartBlock, BlockNums, FormatID){ return this.send(47, StartBlock, BlockNums, FormatID) }
NTAG_Write(StartBlock, BlockNums, Data, FormatID){ return this.send(48, StartBlock, BlockNums, Data, FormatID) }
NTAG_Counter(){ return this.send(49) }
NTAG_Sign(){ return this.send(50) }
NDEF_AddRecord(Uri, Payload){ return this.send(51, Uri, Payload) }
NDEF_ClearAllRecords(){ return this.send(52) }
NDEF_Write(){ return this.send(53) }
NDEF_Read(){ return this.send(54) }
EY5K_RquestCardNo(){ return this.send(55) }
EY5K_GetPublicInfo(){ return this.send(56) }
EY5K_SetPublicInfo(SamIndex, PubStr){ return this.send(57, SamIndex, PubStr) }
EY5K_GetHolderInfo(SamIndex){ return this.send(58, SamIndex) }
EY5K_SetHolderInfo(SamIndex, HolderStr){ return this.send(59,SamIndex, HolderStr) }
EY5K_ReadUserFile(SamIndex, Addr, Count, Format){ return this.send(60, SamIndex, Addr, Count, Format) }
EY5K_WriteUserFile(SamIndex, Addr, DataStr, Format){ return this.send(61, SamIndex, Addr, DataStr, Format) }
EY5K_GetValue(){ return this.send(62) }
EY5K_IncreaseValue(SamIndex, Value){ return this.send(63,SamIndex, Value) }
EY5K_DecreaseValue(SamIndex, Value){ return this.send(64,SamIndex, Value) }
EY5K_GetRecords(){ return this.send(65) }
EY5K_ChangeKey(OldKey, NewKey){ return this.send(66,OldKey, NewKey) }
GetTeminateCode(SamIndex){ return this.send(67,SamIndex) }
ShowImage(Script){ return this.send(68,Script) }
ShowText(Txt){ return this.send(69, Txt) }
}
(
async function(){
const c = new CardReaderAPI()
let [ res, err ] = await asyncFormat(c.connect())
if(err){ console.log('fail', data); return }
console.log(res)
const [ resNo1, errNo1 ] = await asyncFormat(c.M1ReadBlock(24,1))
console.log('>>>>', resNo1, errNo1)
const [ resNo2, errNo2 ] = await asyncFormat(c.M1ReadBlock(24,1))
console.log('>>>>', resNo2, errNo2)
}()
)