import {searchAndConnectDevice, writeBLECharacteristicValue} from "../uni/basic.js"; import {cmdIds, Result, subCmdIds} from '../constant' import {convertWeekdaysToNumber, createPackageEnd, md5Encrypt, parseTimeToList, timestampToArray} from "../format.js"; import {sm4} from "sm-crypto"; import { checkRepeatCardName, checkRepeatFaceName, checkRepeatFingerprintName, checkRepeatPalmVeinName, checkRepeatRemoteName, clearAllIcCard, deleteIcCardRequest, getFingerprintListRequest, getIcCardListRequest, updateIcCardRequest } from "../api.js"; /** * 检查并返回具体哪个参数为空 * @param {Object} params - 参数对象 * @param {Array} requiredFields - 必填字段列表 * @returns {string | null} - 如果有字段为空,则返回错误消息;否则返回null */ function _checkRequiredFields(params, requiredFields) { for (let field of requiredFields) { if (!params[field]) { return `${field} 不能为空`; } } return null; } /** * 注册扩展产品(卡片、指纹等) * * @param {Object} params - 所需参数 * @param {string} params.type - 产品类型,['card','fingerprint','face'] * @param {string} params.keyId - 钥匙 ID * @param {string} params.uid - 用户 ID * @param {number} params.userCountLimit - 使用次数限制,整型,0xFFFF 表示不限次数 * @param {number} params.operate - 操作类型,整型,0: 注册, 1: 修改, 2: 删除, 3: 删除全部 * @param {number} params.isAdmin - 是否管理员,整型,1 表示是,0 表示否 * @param {number} params.isForce - 是否胁迫,整型,1 表示是,0 表示否 * @param {number} params.isRound - 是否循环,整型,1 表示是,0 表示否 * @param {array} params.weekDays - 循环周期,数组,Bit0 -- 6 置位分别代表周日 -- 周六,例如:循环星期一、星期二、星期四,对应为:[1,2,4] * @param {number} params.startDate - 生效日期,时间戳,永久则填0 * @param {number} params.endDate - 失效日期,时间戳,永久则填0 * @param {string} params.startTime - 生效时间,字符串,例如:'00:00' * @param {string} params.endTime - 失效时间,字符串,例如:'00:00' * @param {number} params.cardId - 卡片Id,仅当 type 为 'card' 且operate=1 时需要 * @param {number} params.cardNo - 卡片序号,仅当 type 为 'card' 时需要 * @param {string} params.cardName - 卡片名称,仅当 type 为 'card' 时需要 * @param {number} params.cardType - 卡片类型,1:永久,2:期限,4:循环,仅当 type 为 'card' 时需要 * @param {number} params.cardUserNo - 卡UserNo,仅当 type 为 'card' 时需要 (选填) * @param {number} params.fingerprintName - 指纹名,仅当 type 为 'fingerprint' 时需要 * @param {string} params.fingerprintNumber - 指纹序号,仅当 type 为 'fingerprint' 时需要 * @param {number} params.fingerprintType - 指纹类型,1:永久,2:期限,3:单次,4:循环,仅当 type 为 'fingerprint' 时需要 * @param {number} params.fingerprintUserNo - 指纹UserNo,仅当 type 为 'fingerprint' 时需要 (选填) * @param {number} params.faceName - 人脸名,仅当 type 为 'face' 时需要 * @param {string} params.faceNumber - 指纹序号,仅当 type 为 'face' 时需要 * @param {number} params.faceType - 指纹类型,1:永久,2:期限,4:循环,仅当 type 为 'face' 时需要 * @param {number} params.faceUserNo - 指纹UserNo,仅当 type 为 'face' 时需要 (选填) * @param {number} params.palmVeinName - 掌静脉名,仅当 type 为 'palmVein' 时需要 * @param {string} params.palmVeinNumber - 掌静脉序号,仅当 type 为 'palmVein' 时需要 * @param {number} params.palmVeinType - 掌静脉类型,1:永久,2:期限,4:循环,仅当 type 为 'palmVein' 时需要 * @param {number} params.palmVeinUserNo - 掌静脉UserNo,仅当 type 为 'palmVein' 时需要 (选填) * @param {number} params.remoteName - 遥控名,仅当 type 为 'remote' 时需要 * @param {string} params.remoteNumber - 遥控序号,仅当 type 为 'remote' 时需要 * @param {number} params.remoteType - 遥控类型,1:永久,2:期限,4:循环,仅当 type 为 'remote' 时需要 * @param {number} params.remoteUserNo - 遥控UserNo,仅当 type 为 'remote' 时需要 (选填) * @returns {Promise} - 返回注册结果的 Promise 对象 */ export async function registerExtendedProducts(params) { // 确认产品类型存在 if (!params.type) { return new Result(Result.NotMoreData, null, '注册扩展产品类型type不能为空'); } // 如果是卡片的话需要增加的参数 if (params.type === 'card') { // 注册卡片时的参数校验 if (params.operate === 0) { const cardRequiredFields = ['cardName', 'cardType', 'cardNo']; const missingField = _checkRequiredFields(params, cardRequiredFields); if (missingField) { return new Result(Result.NotMoreData, null, `卡片信息不完整: ${missingField}`); } // 检查卡昵称是否重复 const checkRepeatCardNameResult = await checkRepeatCardName({ lockId: this.lockInfo.lockId, cardName: params.cardName }) if (checkRepeatCardNameResult.code !== Result.Success.code) { return checkRepeatCardNameResult } } // 修改卡片时的参数校验 if (params.operate === 1 || params.operate === 2) { let cardRequiredFields = ['cardId']; if (params.operate === 1) { cardRequiredFields.push('cardType') } if (params.operate === 2) { cardRequiredFields.push('cardNo') } const missingField = _checkRequiredFields(params, cardRequiredFields); if (missingField) { return new Result(Result.NotMoreData, null, `卡片信息不完整: ${missingField}`); } } } // 如果是指纹的话需要增加的参数 if (params.type === 'fingerprint') { if (params.operate === 0) { const cardRequiredFields = ['fingerprintName', 'fingerprintNumber', 'fingerprintType']; const missingField = _checkRequiredFields(params, cardRequiredFields); if (missingField) { return new Result(Result.NotMoreData, null, `指纹信息不完整: ${missingField}`); } // 检查卡昵称是否重复 const checkRepeatFingerprintNameResult = await checkRepeatFingerprintName({ lockId: this.lockInfo.lockId, fingerprintName: params.fingerprintName }) if (checkRepeatFingerprintNameResult.code !== Result.Success.code) { return checkRepeatFingerprintNameResult } } // 修改指纹时的参数校验 if (params.operate === 1 || params.operate === 2) { let cardRequiredFields = ['fingerprintId']; if (params.operate === 1) { cardRequiredFields.push('fingerprintType') } if (params.operate === 2) { cardRequiredFields.push('fingerprintNumber') } const missingField = _checkRequiredFields(params, cardRequiredFields); if (missingField) { return new Result(Result.NotMoreData, null, `指纹信息不完整: ${missingField}`); } } } // 如果是人脸的话需要增加的参数 if (params.type === 'face') { if (params.operate === 0) { const cardRequiredFields = ['faceName', 'faceNumber', 'faceType']; const missingField = _checkRequiredFields(params, cardRequiredFields); if (missingField) { return new Result(Result.NotMoreData, null, `人脸信息不完整: ${missingField}`); } // 检查卡昵称是否重复 const checkRepeatFaceNameResult = await checkRepeatFaceName({ lockId: this.lockInfo.lockId, faceName: params.faceName }) if (checkRepeatFaceNameResult.code !== Result.Success.code) { return checkRepeatFaceNameResult } } // 修改指纹时的参数校验 if (params.operate === 1 || params.operate === 2) { let cardRequiredFields = ['faceId']; if (params.operate === 1) { cardRequiredFields.push('faceType') } if (params.operate === 2) { cardRequiredFields.push('faceNumber') } const missingField = _checkRequiredFields(params, cardRequiredFields); if (missingField) { return new Result(Result.NotMoreData, null, `人脸信息不完整: ${missingField}`); } } } // 如果是掌静脉的话需要增加的参数 if (params.type === 'palmVein') { if (params.operate === 0) { const cardRequiredFields = ['palmVeinName', 'palmVeinNumber', 'palmVeinType']; const missingField = _checkRequiredFields(params, cardRequiredFields); if (missingField) { return new Result(Result.NotMoreData, null, `掌静脉信息不完整: ${missingField}`); } // 检查卡昵称是否重复 const checkRepeatFaceNameResult = await checkRepeatPalmVeinName({ lockId: this.lockInfo.lockId, palmVeinName: params.palmVeinName }) if (checkRepeatFaceNameResult.code !== Result.Success.code) { return checkRepeatFaceNameResult } } // 修改指纹时的参数校验 if (params.operate === 1 || params.operate === 2) { let cardRequiredFields = ['palmVeinId']; if (params.operate === 1) { cardRequiredFields.push('palmVeinType') } if (params.operate === 2) { cardRequiredFields.push('palmVeinNumber') } const missingField = _checkRequiredFields(params, cardRequiredFields); if (missingField) { return new Result(Result.NotMoreData, null, `掌静脉信息不完整: ${missingField}`); } } } // 如果是遥控的话需要增加的参数 if (params.type === 'remote') { if (params.operate === 0) { const cardRequiredFields = ['remoteName', 'remoteNumber', 'remoteType']; const missingField = _checkRequiredFields(params, cardRequiredFields); if (missingField) { return new Result(Result.NotMoreData, null, `遥控信息不完整: ${missingField}`); } // 检查卡昵称是否重复 const checkRepeatFaceNameResult = await checkRepeatRemoteName({ lockId: this.lockInfo.lockId, remoteName: params.remoteName }) if (checkRepeatFaceNameResult.code !== Result.Success.code) { return checkRepeatFaceNameResult } } // 修改指纹时的参数校验 if (params.operate === 1 || params.operate === 2) { let cardRequiredFields = ['remoteId']; if (params.operate === 1) { cardRequiredFields.push('remoteType') } if (params.operate === 2) { cardRequiredFields.push('remoteNumber') } const missingField = _checkRequiredFields(params, cardRequiredFields); if (missingField) { return new Result(Result.NotMoreData, null, `遥控信息不完整: ${missingField}`); } } } // 添加类型:1蓝牙,2远程,3发卡器 params.addType = 1; // 操作后不断开蓝牙 params.disconnect = false; let { type, keyId, uid, cardNo, operate, isAdmin, userCountLimit, isForce, isRound, weekDays, startDate, endDate, startTime, endTime, } = params // 设置执行账号 const result = await this.login(uid) if (result.code !== Result.Success.code) { return result } // 确认设备连接正常 if (!params.connected) { const searchResult = await searchAndConnectDevice(this.lockInfo.bluetooth.bluetoothDeviceName) if (searchResult.code !== Result.Success.code) { return searchResult } this.updateLockInfo(searchResult.data) } // 检查是否已添加为用户 const checkResult = await this.checkLockUser() if (!checkResult) { return { code: -1 } } this.requestParams = params startDate = Math.floor(startDate / 1000) endDate = Math.floor(endDate / 1000) const length = 2 + 1 + 1 + 40 + 20 + 2 + 2 + 1 + 1 + 1 + 4 + 1 + 1 + 4 + 4 + 4 + 4 + 1 + 16 const headArray = this.createPackageHeader(3, length) const contentArray = new Uint8Array(length) contentArray[0] = cmdIds.expandCmd / 256 contentArray[1] = cmdIds.expandCmd % 256 // 子命令 if (type === 'card') { contentArray[2] = subCmdIds.registerCard } else if (type === 'fingerprint') { contentArray[2] = subCmdIds.registerFingerprint } else if (type === 'face') { contentArray[2] = subCmdIds.registerFace } else if (type === 'remote') { contentArray[2] = subCmdIds.registerRemote } else if (type === 'palmVein') { contentArray[2] = subCmdIds.registerPalmVein } contentArray[3] = length - 3 for (let i = 0; i < keyId.length; i++) { contentArray[i + 4] = keyId.charCodeAt(i) } for (let i = 0; i < uid.length; i++) { contentArray[i + 44] = uid.charCodeAt(i) } contentArray[64] = (cardNo || 0) / 256 contentArray[65] = (cardNo || 0) % 256 contentArray[66] = (userCountLimit || 0xffff) / 256 contentArray[67] = (userCountLimit || 0xffff) % 256 contentArray[68] = operate contentArray[69] = isAdmin || 0 contentArray[70] = isForce || 0 contentArray.set(this.lockInfo.token || new Uint8Array([0, 0, 0, 0]), 71) contentArray[75] = isRound contentArray[76] = convertWeekdaysToNumber(weekDays) contentArray.set(timestampToArray(startDate), 77) contentArray.set(timestampToArray(endDate), 81) if (isRound) { contentArray.set(parseTimeToList(startTime), 85) contentArray.set(parseTimeToList(endTime), 89) } else { contentArray.set(new Uint8Array([0, 0, 0, 0]), 85) contentArray.set(new Uint8Array([0, 0, 0, 0]), 89) } contentArray[93] = 16 const md5Array = md5Encrypt( keyId + uid, this.lockInfo.token || new Uint8Array([0, 0, 0, 0]), this.lockInfo.bluetooth.signKey ) contentArray.set(md5Array, 94) const cebArray = sm4.encrypt(contentArray, this.lockInfo.bluetooth.privateKey, { mode: 'ecb', output: 'array' }) const packageArray = createPackageEnd(headArray, cebArray) const writeResult = await writeBLECharacteristicValue(this.lockInfo.deviceId, this.lockInfo.serviceId, this.lockInfo.writeCharacteristicId, packageArray) if (writeResult.code !== Result.Success.code) { return writeResult } return this.getWriteResult(this.registerExtendedProducts, params) } /** * 取消注册扩展产品 * * @param {Object} params - 所需参数 * @param {string} params.Type - 产品类型,['card','fingerprint','face','remote','palmVein'] * @param {string} params.KeyID - 钥匙 ID * @param {string} params.uid - 用户 ID */ export async function registerExtendedProductsCancel(params) { const {type, keyId, uid} = params // 设置执行账号 const result = await this.login(uid) if (result.code !== Result.Success.code) { return result } // 确认设备连接正常 if (!params.connected) { const searchResult = await searchAndConnectDevice(this.lockInfo.bluetooth.bluetoothDeviceName) if (searchResult.code !== Result.Success.code) { return searchResult } this.updateLockInfo(searchResult.data) } // 检查是否已添加为用户 const checkResult = await this.checkLockUser() if (!checkResult) { return { code: -1 } } this.requestParams = params const length = 2 + 1 + 1 + 40 + 20 + 4 + 1 + 16 const headArray = this.createPackageHeader(3, length) const contentArray = new Uint8Array(length) contentArray[0] = cmdIds.expandCmd / 256 contentArray[1] = cmdIds.expandCmd % 256 // 子命令 if (type === 'card') { contentArray[2] = subCmdIds.registerCardCancel } else if (type === 'fingerprint') { contentArray[2] = subCmdIds.registerFingerprintCancel } else if (type === 'face') { contentArray[2] = subCmdIds.registerFaceCancel } else if (type === 'remote') { contentArray[2] = subCmdIds.registerRemoteCancel } else if (type === 'palmVein') { contentArray[2] = subCmdIds.registerPalmVeinCancel } contentArray[3] = length - 3 for (let i = 0; i < keyId.length; i++) { contentArray[i + 4] = keyId.charCodeAt(i) } for (let i = 0; i < uid.length; i++) { contentArray[i + 44] = uid.charCodeAt(i) } contentArray.set(this.lockInfo.token || new Uint8Array([0, 0, 0, 0]), 64) contentArray[68] = 16 const md5Array = md5Encrypt( keyId + uid, this.lockInfo.token || new Uint8Array([0, 0, 0, 0]), this.lockInfo.bluetooth.signKey ) contentArray.set(md5Array, 69) const cebArray = sm4.encrypt(contentArray, this.lockInfo.bluetooth.privateKey, { mode: 'ecb', output: 'array' }) const packageArray = createPackageEnd(headArray, cebArray) await writeBLECharacteristicValue(this.lockInfo.deviceId, this.lockInfo.serviceId, this.lockInfo.writeCharacteristicId, packageArray) } /** * 获取Ic卡列表 * @param params.lockId 锁id (必填) * @param params.pageNo 页码(选填) * @param params.pageSize 每页显示数(选填) * @returns {Promise} */ export async function getIcCardList(params) { return await getIcCardListRequest(params) } /** * 获取指纹列表 * @param params.lockId 锁id (必填) * @param params.pageNo 页码(选填) * @param params.pageSize 每页显示数(选填) * @returns {Promise} */ export async function getFingerprintList(params) { return await getFingerprintListRequest(params) }