添加锁数据上传功能,修改TAPD功能
This commit is contained in:
parent
086495fdf1
commit
30dfff4170
@ -11,7 +11,7 @@ import 'package:crypto/crypto.dart' as crypto;
|
||||
|
||||
//TODO:开门
|
||||
class OpenLockCommand extends SenderProtocol {
|
||||
String? keyID;
|
||||
String? lockID;
|
||||
String? userID;
|
||||
int? openMode;
|
||||
int? openTime;
|
||||
@ -21,7 +21,7 @@ class OpenLockCommand extends SenderProtocol {
|
||||
List<int>? signKey;
|
||||
List<int>? privateKey;
|
||||
OpenLockCommand({
|
||||
this.keyID,
|
||||
this.lockID,
|
||||
this.userID,
|
||||
this.openMode,
|
||||
this.openTime,
|
||||
@ -35,7 +35,7 @@ class OpenLockCommand extends SenderProtocol {
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'OpenLockCommand{keyID: $keyID, userID: $userID, '
|
||||
return 'OpenLockCommand{lockID: $lockID, userID: $userID, '
|
||||
'openMode: $openMode, openTime: ${DateTool().dateIntToYMDHNString(openTime)}, '
|
||||
'onlineToken: $onlineToken, token: $token, '
|
||||
'needAuthor: $needAuthor, signKey: $signKey, privateKey: $privateKey}';
|
||||
@ -55,8 +55,8 @@ class OpenLockCommand extends SenderProtocol {
|
||||
data.add(type2);
|
||||
|
||||
//KeyID 40
|
||||
int keyIDLength = utf8.encode(keyID!).length;
|
||||
data.addAll(utf8.encode(keyID!));
|
||||
int keyIDLength = utf8.encode(lockID!).length;
|
||||
data.addAll(utf8.encode(lockID!));
|
||||
data = getFixedLengthList(data, 40 - keyIDLength);
|
||||
|
||||
//userID 要接受钥匙的用户的useid 20
|
||||
@ -85,7 +85,7 @@ class OpenLockCommand extends SenderProtocol {
|
||||
} else {
|
||||
List<int> authCodeData = [];
|
||||
//KeyID
|
||||
authCodeData.addAll(utf8.encode(keyID!));
|
||||
authCodeData.addAll(utf8.encode(lockID!));
|
||||
|
||||
//UserID
|
||||
authCodeData.addAll(utf8.encode(userID!));
|
||||
|
||||
119
lib/blue/io_protocol/io_updataLockCardList.dart
Normal file
119
lib/blue/io_protocol/io_updataLockCardList.dart
Normal file
@ -0,0 +1,119 @@
|
||||
|
||||
import 'dart:convert';
|
||||
|
||||
import '../io_reply.dart';
|
||||
import '../io_sender.dart';
|
||||
import '../io_tool/io_tool.dart';
|
||||
import '../io_type.dart';
|
||||
import 'package:crypto/crypto.dart' as crypto;
|
||||
|
||||
import '../sm4Encipher/sm4.dart';
|
||||
|
||||
class UpdataLockCardListCommand extends SenderProtocol {
|
||||
|
||||
String? lockID;
|
||||
String? keyID;
|
||||
String? userID;
|
||||
int? page;
|
||||
int? countReq;
|
||||
List<int>? token;
|
||||
int? needAuthor;
|
||||
List<int>? signKey;
|
||||
List<int>? privateKey;
|
||||
UpdataLockCardListCommand({
|
||||
this.lockID,
|
||||
this.keyID,
|
||||
this.userID,
|
||||
this.page,
|
||||
this.countReq,
|
||||
this.token,
|
||||
this.needAuthor,
|
||||
this.signKey,
|
||||
this.privateKey
|
||||
}) : super(CommandType.updataLockCardList);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'UpdataLockCardListCommand{lockID: $lockID, keyID:$keyID userID: $userID, '
|
||||
'page:$page countReq: $countReq, token: $token, '
|
||||
'signKey: $signKey, privateKey: $privateKey}';
|
||||
}
|
||||
|
||||
@override
|
||||
List<int> messageDetail() {
|
||||
List<int> data = [];
|
||||
List<int> ebcData = [];
|
||||
|
||||
// 指令类型
|
||||
int type = commandType!.typeValue;
|
||||
double typeDouble = type / 256;
|
||||
int type1 = typeDouble.toInt();
|
||||
int type2 = type % 256;
|
||||
data.add(type1);
|
||||
data.add(type2);
|
||||
|
||||
// 锁id 40
|
||||
int lockIDLength = utf8.encode(lockID!).length;
|
||||
data.addAll(utf8.encode(lockID!));
|
||||
data = getFixedLengthList(data, 40 - lockIDLength);
|
||||
|
||||
//userID 要接受钥匙的用户的useid 20
|
||||
int userIDLength = utf8.encode(userID!).length;
|
||||
data.addAll(utf8.encode(userID!));
|
||||
data = getFixedLengthList(data, 20 - userIDLength);
|
||||
|
||||
// page
|
||||
data.add(page!);
|
||||
|
||||
// countReq
|
||||
data.add(countReq!);
|
||||
|
||||
// token 长度4 首次请求 Token 填 0,如果锁需要鉴权 操作者身份,则会分配动态口令并在应答消息中返回,二次请求时带上。 当token失效或者第一次发送的时候token为0
|
||||
data.addAll(token!);
|
||||
|
||||
if(needAuthor == 0){
|
||||
//AuthCodeLen 1
|
||||
data.add(0);
|
||||
} else {
|
||||
List<int> authCodeData = [];
|
||||
//KeyID
|
||||
authCodeData.addAll(utf8.encode(lockID!));
|
||||
|
||||
//UserID
|
||||
authCodeData.addAll(utf8.encode(userID!));
|
||||
|
||||
//token 4 首次请求 Token 填 0,如果锁需要鉴权操作者身份,则会分配动态口令并在应答消息中返回,二次请求时带上。
|
||||
authCodeData.addAll(token!);
|
||||
|
||||
authCodeData.addAll(signKey!);
|
||||
|
||||
// 把KeyID、authUserID、时间戳、公钥通过md5加密之后就是authCode
|
||||
var authCode = crypto.md5.convert(authCodeData);
|
||||
|
||||
data.add(authCode.bytes.length);
|
||||
data.addAll(authCode.bytes);
|
||||
}
|
||||
|
||||
if ((data.length % 16) != 0) {
|
||||
int add = (16 - data.length % 16);
|
||||
for (int i = 0; i < add; i++) {
|
||||
data.add(0);
|
||||
}
|
||||
}
|
||||
|
||||
printLog(data);
|
||||
// 拿到数据之后通过LockId进行SM4 ECB加密 key:544d485f633335373034383064613864
|
||||
ebcData = SM4.encrypt(data, key: privateKey, mode: SM4CryptoMode.ECB);
|
||||
return ebcData;
|
||||
}
|
||||
}
|
||||
|
||||
class UpdataLockCardListReply extends Reply {
|
||||
UpdataLockCardListReply.parseData(CommandType commandType, List<int> dataDetail)
|
||||
: super.parseData(commandType, dataDetail) {
|
||||
data = dataDetail;
|
||||
|
||||
int status = data[2];
|
||||
errorWithStstus(status);
|
||||
}
|
||||
}
|
||||
119
lib/blue/io_protocol/io_updataLockFaceList.dart
Normal file
119
lib/blue/io_protocol/io_updataLockFaceList.dart
Normal file
@ -0,0 +1,119 @@
|
||||
|
||||
import 'dart:convert';
|
||||
|
||||
import '../io_reply.dart';
|
||||
import '../io_sender.dart';
|
||||
import '../io_tool/io_tool.dart';
|
||||
import '../io_type.dart';
|
||||
import 'package:crypto/crypto.dart' as crypto;
|
||||
|
||||
import '../sm4Encipher/sm4.dart';
|
||||
|
||||
class UpdataLockFaceListCommand extends SenderProtocol {
|
||||
|
||||
String? lockID;
|
||||
String? keyID;
|
||||
String? userID;
|
||||
int? page;
|
||||
int? countReq;
|
||||
List<int>? token;
|
||||
int? needAuthor;
|
||||
List<int>? signKey;
|
||||
List<int>? privateKey;
|
||||
UpdataLockFaceListCommand({
|
||||
this.lockID,
|
||||
this.keyID,
|
||||
this.userID,
|
||||
this.page,
|
||||
this.countReq,
|
||||
this.token,
|
||||
this.needAuthor,
|
||||
this.signKey,
|
||||
this.privateKey
|
||||
}) : super(CommandType.updataLockFaceList);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'UpdataLockPasswordListCommand{lockID: $lockID, keyID:$keyID userID: $userID, '
|
||||
'page:$page countReq: $countReq, token: $token, '
|
||||
'signKey: $signKey, privateKey: $privateKey}';
|
||||
}
|
||||
|
||||
@override
|
||||
List<int> messageDetail() {
|
||||
List<int> data = [];
|
||||
List<int> ebcData = [];
|
||||
|
||||
// 指令类型
|
||||
int type = commandType!.typeValue;
|
||||
double typeDouble = type / 256;
|
||||
int type1 = typeDouble.toInt();
|
||||
int type2 = type % 256;
|
||||
data.add(type1);
|
||||
data.add(type2);
|
||||
|
||||
// 锁id 40
|
||||
int lockIDLength = utf8.encode(lockID!).length;
|
||||
data.addAll(utf8.encode(lockID!));
|
||||
data = getFixedLengthList(data, 40 - lockIDLength);
|
||||
|
||||
//userID 要接受钥匙的用户的useid 20
|
||||
int userIDLength = utf8.encode(userID!).length;
|
||||
data.addAll(utf8.encode(userID!));
|
||||
data = getFixedLengthList(data, 20 - userIDLength);
|
||||
|
||||
// page
|
||||
data.add(page!);
|
||||
|
||||
// countReq
|
||||
data.add(countReq!);
|
||||
|
||||
// token 长度4 首次请求 Token 填 0,如果锁需要鉴权 操作者身份,则会分配动态口令并在应答消息中返回,二次请求时带上。 当token失效或者第一次发送的时候token为0
|
||||
data.addAll(token!);
|
||||
|
||||
if(needAuthor == 0){
|
||||
//AuthCodeLen 1
|
||||
data.add(0);
|
||||
} else {
|
||||
List<int> authCodeData = [];
|
||||
//KeyID
|
||||
authCodeData.addAll(utf8.encode(lockID!));
|
||||
|
||||
//UserID
|
||||
authCodeData.addAll(utf8.encode(userID!));
|
||||
|
||||
//token 4 首次请求 Token 填 0,如果锁需要鉴权操作者身份,则会分配动态口令并在应答消息中返回,二次请求时带上。
|
||||
authCodeData.addAll(token!);
|
||||
|
||||
authCodeData.addAll(signKey!);
|
||||
|
||||
// 把KeyID、authUserID、时间戳、公钥通过md5加密之后就是authCode
|
||||
var authCode = crypto.md5.convert(authCodeData);
|
||||
|
||||
data.add(authCode.bytes.length);
|
||||
data.addAll(authCode.bytes);
|
||||
}
|
||||
|
||||
if ((data.length % 16) != 0) {
|
||||
int add = (16 - data.length % 16);
|
||||
for (int i = 0; i < add; i++) {
|
||||
data.add(0);
|
||||
}
|
||||
}
|
||||
|
||||
printLog(data);
|
||||
// 拿到数据之后通过LockId进行SM4 ECB加密 key:544d485f633335373034383064613864
|
||||
ebcData = SM4.encrypt(data, key: privateKey, mode: SM4CryptoMode.ECB);
|
||||
return ebcData;
|
||||
}
|
||||
}
|
||||
|
||||
class UpdataLockFaceListReply extends Reply {
|
||||
UpdataLockFaceListReply.parseData(CommandType commandType, List<int> dataDetail)
|
||||
: super.parseData(commandType, dataDetail) {
|
||||
data = dataDetail;
|
||||
|
||||
int status = data[2];
|
||||
errorWithStstus(status);
|
||||
}
|
||||
}
|
||||
119
lib/blue/io_protocol/io_updataLockFingerprintList.dart
Normal file
119
lib/blue/io_protocol/io_updataLockFingerprintList.dart
Normal file
@ -0,0 +1,119 @@
|
||||
|
||||
import 'dart:convert';
|
||||
|
||||
import '../io_reply.dart';
|
||||
import '../io_sender.dart';
|
||||
import '../io_tool/io_tool.dart';
|
||||
import '../io_type.dart';
|
||||
import 'package:crypto/crypto.dart' as crypto;
|
||||
|
||||
import '../sm4Encipher/sm4.dart';
|
||||
|
||||
class UpdataLockFingerprintListCommand extends SenderProtocol {
|
||||
|
||||
String? lockID;
|
||||
String? keyID;
|
||||
String? userID;
|
||||
int? page;
|
||||
int? countReq;
|
||||
List<int>? token;
|
||||
int? needAuthor;
|
||||
List<int>? signKey;
|
||||
List<int>? privateKey;
|
||||
UpdataLockFingerprintListCommand({
|
||||
this.lockID,
|
||||
this.keyID,
|
||||
this.userID,
|
||||
this.page,
|
||||
this.countReq,
|
||||
this.token,
|
||||
this.needAuthor,
|
||||
this.signKey,
|
||||
this.privateKey
|
||||
}) : super(CommandType.updataLockFingerprintList);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'UpdataLockPasswordListCommand{lockID: $lockID, keyID:$keyID userID: $userID, '
|
||||
'page:$page countReq: $countReq, token: $token, '
|
||||
'signKey: $signKey, privateKey: $privateKey}';
|
||||
}
|
||||
|
||||
@override
|
||||
List<int> messageDetail() {
|
||||
List<int> data = [];
|
||||
List<int> ebcData = [];
|
||||
|
||||
// 指令类型
|
||||
int type = commandType!.typeValue;
|
||||
double typeDouble = type / 256;
|
||||
int type1 = typeDouble.toInt();
|
||||
int type2 = type % 256;
|
||||
data.add(type1);
|
||||
data.add(type2);
|
||||
|
||||
// 锁id 40
|
||||
int lockIDLength = utf8.encode(lockID!).length;
|
||||
data.addAll(utf8.encode(lockID!));
|
||||
data = getFixedLengthList(data, 40 - lockIDLength);
|
||||
|
||||
//userID 要接受钥匙的用户的useid 20
|
||||
int userIDLength = utf8.encode(userID!).length;
|
||||
data.addAll(utf8.encode(userID!));
|
||||
data = getFixedLengthList(data, 20 - userIDLength);
|
||||
|
||||
// page
|
||||
data.add(page!);
|
||||
|
||||
// countReq
|
||||
data.add(countReq!);
|
||||
|
||||
// token 长度4 首次请求 Token 填 0,如果锁需要鉴权 操作者身份,则会分配动态口令并在应答消息中返回,二次请求时带上。 当token失效或者第一次发送的时候token为0
|
||||
data.addAll(token!);
|
||||
|
||||
if(needAuthor == 0){
|
||||
//AuthCodeLen 1
|
||||
data.add(0);
|
||||
} else {
|
||||
List<int> authCodeData = [];
|
||||
//KeyID
|
||||
authCodeData.addAll(utf8.encode(lockID!));
|
||||
|
||||
//UserID
|
||||
authCodeData.addAll(utf8.encode(userID!));
|
||||
|
||||
//token 4 首次请求 Token 填 0,如果锁需要鉴权操作者身份,则会分配动态口令并在应答消息中返回,二次请求时带上。
|
||||
authCodeData.addAll(token!);
|
||||
|
||||
authCodeData.addAll(signKey!);
|
||||
|
||||
// 把KeyID、authUserID、时间戳、公钥通过md5加密之后就是authCode
|
||||
var authCode = crypto.md5.convert(authCodeData);
|
||||
|
||||
data.add(authCode.bytes.length);
|
||||
data.addAll(authCode.bytes);
|
||||
}
|
||||
|
||||
if ((data.length % 16) != 0) {
|
||||
int add = (16 - data.length % 16);
|
||||
for (int i = 0; i < add; i++) {
|
||||
data.add(0);
|
||||
}
|
||||
}
|
||||
|
||||
printLog(data);
|
||||
// 拿到数据之后通过LockId进行SM4 ECB加密 key:544d485f633335373034383064613864
|
||||
ebcData = SM4.encrypt(data, key: privateKey, mode: SM4CryptoMode.ECB);
|
||||
return ebcData;
|
||||
}
|
||||
}
|
||||
|
||||
class UpdataLockFingerprintListReply extends Reply {
|
||||
UpdataLockFingerprintListReply.parseData(CommandType commandType, List<int> dataDetail)
|
||||
: super.parseData(commandType, dataDetail) {
|
||||
data = dataDetail;
|
||||
|
||||
int status = data[2];
|
||||
errorWithStstus(status);
|
||||
}
|
||||
}
|
||||
117
lib/blue/io_protocol/io_updataLockPalmVeinList.dart
Normal file
117
lib/blue/io_protocol/io_updataLockPalmVeinList.dart
Normal file
@ -0,0 +1,117 @@
|
||||
|
||||
import 'dart:convert';
|
||||
|
||||
import '../io_reply.dart';
|
||||
import '../io_sender.dart';
|
||||
import '../io_tool/io_tool.dart';
|
||||
import '../io_type.dart';
|
||||
import 'package:crypto/crypto.dart' as crypto;
|
||||
|
||||
import '../sm4Encipher/sm4.dart';
|
||||
|
||||
class UpdataLockPalmVeinListCommand extends SenderProtocol {
|
||||
|
||||
String? lockID;
|
||||
String? userID;
|
||||
int? page;
|
||||
int? countReq;
|
||||
List<int>? token;
|
||||
int? needAuthor;
|
||||
List<int>? signKey;
|
||||
List<int>? privateKey;
|
||||
UpdataLockPalmVeinListCommand({
|
||||
this.lockID,
|
||||
this.userID,
|
||||
this.page,
|
||||
this.countReq,
|
||||
this.token,
|
||||
this.needAuthor,
|
||||
this.signKey,
|
||||
this.privateKey
|
||||
}) : super(CommandType.updataLockPalmVeinList);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'UpdataLockPasswordListCommand{lockID: $lockID, userID: $userID, '
|
||||
'page:$page countReq: $countReq, token: $token, '
|
||||
'signKey: $signKey, privateKey: $privateKey}';
|
||||
}
|
||||
|
||||
@override
|
||||
List<int> messageDetail() {
|
||||
List<int> data = [];
|
||||
List<int> ebcData = [];
|
||||
|
||||
// 指令类型
|
||||
int type = commandType!.typeValue;
|
||||
double typeDouble = type / 256;
|
||||
int type1 = typeDouble.toInt();
|
||||
int type2 = type % 256;
|
||||
data.add(type1);
|
||||
data.add(type2);
|
||||
|
||||
// 锁id 40
|
||||
int lockIDLength = utf8.encode(lockID!).length;
|
||||
data.addAll(utf8.encode(lockID!));
|
||||
data = getFixedLengthList(data, 40 - lockIDLength);
|
||||
|
||||
//userID 要接受钥匙的用户的useid 20
|
||||
int userIDLength = utf8.encode(userID!).length;
|
||||
data.addAll(utf8.encode(userID!));
|
||||
data = getFixedLengthList(data, 20 - userIDLength);
|
||||
|
||||
// page
|
||||
data.add(page!);
|
||||
|
||||
// countReq
|
||||
data.add(countReq!);
|
||||
|
||||
// token 长度4 首次请求 Token 填 0,如果锁需要鉴权 操作者身份,则会分配动态口令并在应答消息中返回,二次请求时带上。 当token失效或者第一次发送的时候token为0
|
||||
data.addAll(token!);
|
||||
|
||||
if(needAuthor == 0){
|
||||
//AuthCodeLen 1
|
||||
data.add(0);
|
||||
} else {
|
||||
List<int> authCodeData = [];
|
||||
//KeyID
|
||||
authCodeData.addAll(utf8.encode(lockID!));
|
||||
|
||||
//UserID
|
||||
authCodeData.addAll(utf8.encode(userID!));
|
||||
|
||||
//token 4 首次请求 Token 填 0,如果锁需要鉴权操作者身份,则会分配动态口令并在应答消息中返回,二次请求时带上。
|
||||
authCodeData.addAll(token!);
|
||||
|
||||
authCodeData.addAll(signKey!);
|
||||
|
||||
// 把KeyID、authUserID、时间戳、公钥通过md5加密之后就是authCode
|
||||
var authCode = crypto.md5.convert(authCodeData);
|
||||
|
||||
data.add(authCode.bytes.length);
|
||||
data.addAll(authCode.bytes);
|
||||
}
|
||||
|
||||
if ((data.length % 16) != 0) {
|
||||
int add = (16 - data.length % 16);
|
||||
for (int i = 0; i < add; i++) {
|
||||
data.add(0);
|
||||
}
|
||||
}
|
||||
|
||||
printLog(data);
|
||||
// 拿到数据之后通过LockId进行SM4 ECB加密 key:544d485f633335373034383064613864
|
||||
ebcData = SM4.encrypt(data, key: privateKey, mode: SM4CryptoMode.ECB);
|
||||
return ebcData;
|
||||
}
|
||||
}
|
||||
|
||||
class UpdataLockPalmVeinListReply extends Reply {
|
||||
UpdataLockPalmVeinListReply.parseData(CommandType commandType, List<int> dataDetail)
|
||||
: super.parseData(commandType, dataDetail) {
|
||||
data = dataDetail;
|
||||
|
||||
int status = data[2];
|
||||
errorWithStstus(status);
|
||||
}
|
||||
}
|
||||
119
lib/blue/io_protocol/io_updataLockPasswordList.dart
Normal file
119
lib/blue/io_protocol/io_updataLockPasswordList.dart
Normal file
@ -0,0 +1,119 @@
|
||||
|
||||
import 'dart:convert';
|
||||
|
||||
import '../io_reply.dart';
|
||||
import '../io_sender.dart';
|
||||
import '../io_tool/io_tool.dart';
|
||||
import '../io_type.dart';
|
||||
import 'package:crypto/crypto.dart' as crypto;
|
||||
|
||||
import '../sm4Encipher/sm4.dart';
|
||||
|
||||
class UpdataLockPasswordListCommand extends SenderProtocol {
|
||||
|
||||
String? lockID;
|
||||
String? keyID;
|
||||
String? userID;
|
||||
int? page;
|
||||
int? countReq;
|
||||
List<int>? token;
|
||||
int? needAuthor;
|
||||
List<int>? signKey;
|
||||
List<int>? privateKey;
|
||||
UpdataLockPasswordListCommand({
|
||||
this.lockID,
|
||||
this.keyID,
|
||||
this.userID,
|
||||
this.page,
|
||||
this.countReq,
|
||||
this.token,
|
||||
this.needAuthor,
|
||||
this.signKey,
|
||||
this.privateKey
|
||||
}) : super(CommandType.updataLockPasswordList);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'UpdataLockPasswordListCommand{lockID: $lockID, keyID:$keyID userID: $userID, '
|
||||
'page:$page countReq: $countReq, token: $token, '
|
||||
'signKey: $signKey, privateKey: $privateKey}';
|
||||
}
|
||||
|
||||
@override
|
||||
List<int> messageDetail() {
|
||||
List<int> data = [];
|
||||
List<int> ebcData = [];
|
||||
|
||||
// 指令类型
|
||||
int type = commandType!.typeValue;
|
||||
double typeDouble = type / 256;
|
||||
int type1 = typeDouble.toInt();
|
||||
int type2 = type % 256;
|
||||
data.add(type1);
|
||||
data.add(type2);
|
||||
|
||||
// 锁id 40
|
||||
int lockIDLength = utf8.encode(lockID!).length;
|
||||
data.addAll(utf8.encode(lockID!));
|
||||
data = getFixedLengthList(data, 40 - lockIDLength);
|
||||
|
||||
//userID 要接受钥匙的用户的useid 20
|
||||
int userIDLength = utf8.encode(userID!).length;
|
||||
data.addAll(utf8.encode(userID!));
|
||||
data = getFixedLengthList(data, 20 - userIDLength);
|
||||
|
||||
// page
|
||||
data.add(page!);
|
||||
|
||||
// countReq
|
||||
data.add(countReq!);
|
||||
|
||||
// token 长度4 首次请求 Token 填 0,如果锁需要鉴权 操作者身份,则会分配动态口令并在应答消息中返回,二次请求时带上。 当token失效或者第一次发送的时候token为0
|
||||
data.addAll(token!);
|
||||
|
||||
if(needAuthor == 0){
|
||||
//AuthCodeLen 1
|
||||
data.add(0);
|
||||
} else {
|
||||
List<int> authCodeData = [];
|
||||
//KeyID
|
||||
authCodeData.addAll(utf8.encode(lockID!));
|
||||
|
||||
//UserID
|
||||
authCodeData.addAll(utf8.encode(userID!));
|
||||
|
||||
//token 4 首次请求 Token 填 0,如果锁需要鉴权操作者身份,则会分配动态口令并在应答消息中返回,二次请求时带上。
|
||||
authCodeData.addAll(token!);
|
||||
|
||||
authCodeData.addAll(signKey!);
|
||||
|
||||
// 把KeyID、authUserID、时间戳、公钥通过md5加密之后就是authCode
|
||||
var authCode = crypto.md5.convert(authCodeData);
|
||||
|
||||
data.add(authCode.bytes.length);
|
||||
data.addAll(authCode.bytes);
|
||||
}
|
||||
|
||||
if ((data.length % 16) != 0) {
|
||||
int add = (16 - data.length % 16);
|
||||
for (int i = 0; i < add; i++) {
|
||||
data.add(0);
|
||||
}
|
||||
}
|
||||
|
||||
printLog(data);
|
||||
// 拿到数据之后通过LockId进行SM4 ECB加密 key:544d485f633335373034383064613864
|
||||
ebcData = SM4.encrypt(data, key: privateKey, mode: SM4CryptoMode.ECB);
|
||||
return ebcData;
|
||||
}
|
||||
}
|
||||
|
||||
class UpdataLockPasswordListReply extends Reply {
|
||||
UpdataLockPasswordListReply.parseData(CommandType commandType, List<int> dataDetail)
|
||||
: super.parseData(commandType, dataDetail) {
|
||||
data = dataDetail;
|
||||
|
||||
int status = data[2];
|
||||
errorWithStstus(status);
|
||||
}
|
||||
}
|
||||
@ -9,6 +9,11 @@ enum CommandType {
|
||||
transferPermissions, //转移权限 = 0x300B
|
||||
cleanUpUsers, //转移权限 = 0x300C
|
||||
reportDoorOpenRecord, //开门记录上报 = 0x3020
|
||||
updataLockPasswordList, //上传数据-获取锁密码列表 0x3021
|
||||
updataLockCardList, //上传数据-获取锁卡片列表 0x3022
|
||||
updataLockFingerprintList, //上传数据-获取锁指纹列表 0x3023
|
||||
updataLockFaceList, //上传数据-获取锁指纹列表 0x3024
|
||||
updataLockPalmVeinList, //上传数据-获取锁指纹列表 0x3025
|
||||
getLockPublicKey, // 获取锁公钥 = 0x3090
|
||||
getLockPrivateKey, // 获取锁私钥 = 0x3091
|
||||
calibrationTime, // 校时 = 0x30f0
|
||||
@ -93,6 +98,31 @@ extension ExtensionCommandType on CommandType {
|
||||
type = CommandType.reportDoorOpenRecord;
|
||||
}
|
||||
break;
|
||||
case 0x3021:
|
||||
{
|
||||
type = CommandType.updataLockPasswordList;
|
||||
}
|
||||
break;
|
||||
case 0x3022:
|
||||
{
|
||||
type = CommandType.updataLockCardList;
|
||||
}
|
||||
break;
|
||||
case 0x3023:
|
||||
{
|
||||
type = CommandType.updataLockFingerprintList;
|
||||
}
|
||||
break;
|
||||
case 0x3024:
|
||||
{
|
||||
type = CommandType.updataLockFaceList;
|
||||
}
|
||||
break;
|
||||
case 0x3025:
|
||||
{
|
||||
type = CommandType.updataLockPalmVeinList;
|
||||
}
|
||||
break;
|
||||
case 0x3030:
|
||||
{
|
||||
type = CommandType.generalExtendedCommond;
|
||||
@ -172,6 +202,21 @@ extension ExtensionCommandType on CommandType {
|
||||
case CommandType.reportDoorOpenRecord:
|
||||
type = 0x3020;
|
||||
break;
|
||||
case CommandType.updataLockPasswordList:
|
||||
type = 0x3021;
|
||||
break;
|
||||
case CommandType.updataLockCardList:
|
||||
type = 0x3022;
|
||||
break;
|
||||
case CommandType.updataLockFingerprintList:
|
||||
type = 0x3023;
|
||||
break;
|
||||
case CommandType.updataLockFaceList:
|
||||
type = 0x3024;
|
||||
break;
|
||||
case CommandType.updataLockPalmVeinList:
|
||||
type = 0x3025;
|
||||
break;
|
||||
case CommandType.generalExtendedCommond:
|
||||
type = 0x3030;
|
||||
break;
|
||||
@ -254,6 +299,21 @@ extension ExtensionCommandType on CommandType {
|
||||
case 0x3020:
|
||||
t = '开门记录上报';
|
||||
break;
|
||||
case 0x3021:
|
||||
t = '上传数据获取锁密码列表';
|
||||
break;
|
||||
case 0x3022:
|
||||
t = '上传数据获取锁卡列表';
|
||||
break;
|
||||
case 0x3023:
|
||||
t = '上传数据获取锁指纹列表';
|
||||
break;
|
||||
case 0x3024:
|
||||
t = '上传数据获取锁人脸列表';
|
||||
break;
|
||||
case 0x3025:
|
||||
t = '上传数据获取锁掌静脉列表';
|
||||
break;
|
||||
case 0x3030:
|
||||
t = '通用扩展指令';
|
||||
break;
|
||||
|
||||
@ -38,6 +38,11 @@ import 'io_protocol/io_openLock.dart';
|
||||
import 'io_protocol/io_queryingFingerprintStatus.dart';
|
||||
import 'io_protocol/io_referEventRecordNumber.dart';
|
||||
import 'io_protocol/io_senderResetPasswords.dart';
|
||||
import 'io_protocol/io_updataLockCardList.dart';
|
||||
import 'io_protocol/io_updataLockFaceList.dart';
|
||||
import 'io_protocol/io_updataLockFingerprintList.dart';
|
||||
import 'io_protocol/io_updataLockPalmVeinList.dart';
|
||||
import 'io_protocol/io_updataLockPasswordList.dart';
|
||||
import 'io_reply.dart';
|
||||
import 'io_protocol/io_senderCustomPasswords.dart';
|
||||
import 'io_type.dart';
|
||||
@ -201,6 +206,31 @@ class CommandReciverManager {
|
||||
reply = CleanUpUsersReply.parseData(commandType, data);
|
||||
}
|
||||
break;
|
||||
case CommandType.updataLockPasswordList:
|
||||
{
|
||||
reply = UpdataLockPasswordListReply.parseData(commandType, data);
|
||||
}
|
||||
break;
|
||||
case CommandType.updataLockCardList:
|
||||
{
|
||||
reply = UpdataLockCardListReply.parseData(commandType, data);
|
||||
}
|
||||
break;
|
||||
case CommandType.updataLockFingerprintList:
|
||||
{
|
||||
reply = UpdataLockFingerprintListReply.parseData(commandType, data);
|
||||
}
|
||||
break;
|
||||
case CommandType.updataLockFaceList:
|
||||
{
|
||||
reply = UpdataLockFaceListReply.parseData(commandType, data);
|
||||
}
|
||||
break;
|
||||
case CommandType.updataLockPalmVeinList:
|
||||
{
|
||||
reply = UpdataLockPalmVeinListReply.parseData(commandType, data);
|
||||
}
|
||||
break;
|
||||
case CommandType.generalExtendedCommond:
|
||||
{
|
||||
// 子命令类型
|
||||
|
||||
@ -36,6 +36,11 @@ import 'io_protocol/io_setSupportFunctionsNoParameters.dart';
|
||||
import 'io_protocol/io_setSupportFunctionsWithParameters.dart';
|
||||
import 'io_protocol/io_timing.dart';
|
||||
import 'io_protocol/io_transferPermissions.dart';
|
||||
import 'io_protocol/io_updataLockCardList.dart';
|
||||
import 'io_protocol/io_updataLockFaceList.dart';
|
||||
import 'io_protocol/io_updataLockFingerprintList.dart';
|
||||
import 'io_protocol/io_updataLockPalmVeinList.dart';
|
||||
import 'io_protocol/io_updataLockPasswordList.dart';
|
||||
import 'sender_data.dart';
|
||||
|
||||
class IoSenderManage {
|
||||
@ -185,7 +190,7 @@ class IoSenderManage {
|
||||
|
||||
//todo:开锁
|
||||
static void senderOpenLock(
|
||||
{String? keyID,
|
||||
{String? lockID,
|
||||
String? userID,
|
||||
int? openMode,
|
||||
int? openTime,
|
||||
@ -197,7 +202,7 @@ class IoSenderManage {
|
||||
CommandSendCallBack? callBack}) {
|
||||
CommandSenderManager().managerSendData(
|
||||
command: OpenLockCommand(
|
||||
keyID: keyID,
|
||||
lockID: lockID,
|
||||
userID: userID,
|
||||
openMode: openMode,
|
||||
openTime: openTime,
|
||||
@ -1186,4 +1191,130 @@ class IoSenderManage {
|
||||
),
|
||||
callBack: callBack);
|
||||
}
|
||||
|
||||
// 上传数据获取锁密码列表
|
||||
static void updataLockPasswordListCommand(
|
||||
{required String? lockID,
|
||||
required String? userID,
|
||||
required int? page,
|
||||
required int? countReq,
|
||||
required List<int>? token,
|
||||
required int? needAuthor,
|
||||
required List<int>? signKey,
|
||||
required List<int>? privateKey,
|
||||
CommandSendCallBack? callBack}) {
|
||||
CommandSenderManager().managerSendData(
|
||||
command: UpdataLockPasswordListCommand(
|
||||
lockID: lockID,
|
||||
userID: userID,
|
||||
page:page,
|
||||
countReq:countReq,
|
||||
token: token,
|
||||
needAuthor: needAuthor,
|
||||
signKey: signKey,
|
||||
privateKey: privateKey,
|
||||
),
|
||||
callBack: callBack);
|
||||
}
|
||||
|
||||
// 上传数据获取锁密码列表
|
||||
static void updataLockCardListCommand(
|
||||
{required String? lockID,
|
||||
required String? userID,
|
||||
required int? page,
|
||||
required int? countReq,
|
||||
required List<int>? token,
|
||||
required int? needAuthor,
|
||||
required List<int>? signKey,
|
||||
required List<int>? privateKey,
|
||||
CommandSendCallBack? callBack}) {
|
||||
CommandSenderManager().managerSendData(
|
||||
command: UpdataLockCardListCommand(
|
||||
lockID: lockID,
|
||||
userID: userID,
|
||||
page:page,
|
||||
countReq:countReq,
|
||||
token: token,
|
||||
needAuthor: needAuthor,
|
||||
signKey: signKey,
|
||||
privateKey: privateKey,
|
||||
),
|
||||
callBack: callBack);
|
||||
}
|
||||
|
||||
// 上传数据获取锁指纹列表
|
||||
static void updataLockFingerprintListCommand(
|
||||
{required String? lockID,
|
||||
required String? userID,
|
||||
required int? page,
|
||||
required int? countReq,
|
||||
required List<int>? token,
|
||||
required int? needAuthor,
|
||||
required List<int>? signKey,
|
||||
required List<int>? privateKey,
|
||||
CommandSendCallBack? callBack}) {
|
||||
CommandSenderManager().managerSendData(
|
||||
command: UpdataLockFingerprintListCommand(
|
||||
lockID: lockID,
|
||||
userID: userID,
|
||||
page:page,
|
||||
countReq:countReq,
|
||||
token: token,
|
||||
needAuthor: needAuthor,
|
||||
signKey: signKey,
|
||||
privateKey: privateKey,
|
||||
),
|
||||
callBack: callBack);
|
||||
}
|
||||
|
||||
// 上传数据获取锁人脸列表
|
||||
static void updataLockFaceListCommand(
|
||||
{required String? lockID,
|
||||
required String? userID,
|
||||
required int? page,
|
||||
required int? countReq,
|
||||
required List<int>? token,
|
||||
required int? needAuthor,
|
||||
required List<int>? signKey,
|
||||
required List<int>? privateKey,
|
||||
CommandSendCallBack? callBack}) {
|
||||
CommandSenderManager().managerSendData(
|
||||
command: UpdataLockFaceListCommand(
|
||||
lockID: lockID,
|
||||
userID: userID,
|
||||
page:page,
|
||||
countReq:countReq,
|
||||
token: token,
|
||||
needAuthor: needAuthor,
|
||||
signKey: signKey,
|
||||
privateKey: privateKey,
|
||||
),
|
||||
callBack: callBack);
|
||||
}
|
||||
|
||||
// 上传数据获取锁掌静脉列表
|
||||
static void updataLockPalmVeinListCommand(
|
||||
{required String? lockID,
|
||||
required String? userID,
|
||||
required int? page,
|
||||
required int? countReq,
|
||||
required List<int>? token,
|
||||
required int? needAuthor,
|
||||
required List<int>? signKey,
|
||||
required List<int>? privateKey,
|
||||
CommandSendCallBack? callBack}) {
|
||||
CommandSenderManager().managerSendData(
|
||||
command: UpdataLockPalmVeinListCommand(
|
||||
lockID: lockID,
|
||||
userID: userID,
|
||||
page:page,
|
||||
countReq:countReq,
|
||||
token: token,
|
||||
needAuthor: needAuthor,
|
||||
signKey: signKey,
|
||||
privateKey: privateKey,
|
||||
),
|
||||
callBack: callBack);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -96,7 +96,7 @@ class LockDetailLogic extends BaseGetXController {
|
||||
Storage.setStringList(saveBlueToken, saveStrList);
|
||||
|
||||
IoSenderManage.senderOpenLock(
|
||||
keyID: BlueManage().connectDeviceName,
|
||||
lockID: BlueManage().connectDeviceName,
|
||||
userID: await Storage.getUid(),
|
||||
openMode: state.openDoorModel,
|
||||
openTime: getUTCNetTime(),
|
||||
@ -270,7 +270,7 @@ class LockDetailLogic extends BaseGetXController {
|
||||
(BluetoothConnectionState deviceConnectionState) async {
|
||||
if (deviceConnectionState == BluetoothConnectionState.connected) {
|
||||
IoSenderManage.senderOpenLock(
|
||||
keyID: BlueManage().connectDeviceName,
|
||||
lockID: BlueManage().connectDeviceName,
|
||||
userID: await Storage.getUid(),
|
||||
openMode: state.openDoorModel,
|
||||
openTime: getUTCNetTime(),
|
||||
|
||||
594
lib/main/lockDetail/lockSet/uploadData/uploadData_logic.dart
Normal file
594
lib/main/lockDetail/lockSet/uploadData/uploadData_logic.dart
Normal file
@ -0,0 +1,594 @@
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
|
||||
import 'package:star_lock/tools/baseGetXController.dart';
|
||||
import 'package:star_lock/tools/commonDataManage.dart';
|
||||
|
||||
import '../../../../blue/blue_manage.dart';
|
||||
import '../../../../blue/io_protocol/io_updataLockCardList.dart';
|
||||
import '../../../../blue/io_protocol/io_updataLockFaceList.dart';
|
||||
import '../../../../blue/io_protocol/io_updataLockFingerprintList.dart';
|
||||
import '../../../../blue/io_protocol/io_updataLockPalmVeinList.dart';
|
||||
import '../../../../blue/io_protocol/io_updataLockPasswordList.dart';
|
||||
import '../../../../blue/io_reply.dart';
|
||||
import '../../../../blue/io_tool/io_tool.dart';
|
||||
import '../../../../blue/io_tool/manager_event_bus.dart';
|
||||
import '../../../../blue/sender_manage.dart';
|
||||
import '../../../../network/api_repository.dart';
|
||||
import '../../../../tools/storage.dart';
|
||||
import 'uploadData_state.dart';
|
||||
|
||||
class UploadDataLogic extends BaseGetXController{
|
||||
UploadDataState state = UploadDataState();
|
||||
|
||||
// 监听蓝牙协议返回结果
|
||||
late StreamSubscription<Reply> _replySubscription;
|
||||
void _initReplySubscription() {
|
||||
_replySubscription = EventBusManager().eventBus!.on<Reply>().listen((reply) async {
|
||||
// 上传数据获取锁密码列表
|
||||
if (reply is UpdataLockPasswordListReply && (state.ifCurrentScreen.value == true)) {
|
||||
_replyupdataLockPasswordListReply(reply);
|
||||
}
|
||||
|
||||
// 上传数据获取锁卡列表
|
||||
if (reply is UpdataLockCardListReply && (state.ifCurrentScreen.value == true)) {
|
||||
_replyupdataLockCardListReply(reply);
|
||||
}
|
||||
|
||||
// 上传数据获取锁指纹列表
|
||||
if (reply is UpdataLockFingerprintListReply && (state.ifCurrentScreen.value == true)) {
|
||||
_replyupdataLockFingerprintListReply(reply);
|
||||
}
|
||||
|
||||
// 上传数据获取锁人脸列表
|
||||
if (reply is UpdataLockFaceListReply && (state.ifCurrentScreen.value == true)) {
|
||||
_replyupdataLockFaceListReply(reply);
|
||||
}
|
||||
|
||||
// 上传数据获取锁掌静脉列表
|
||||
if (reply is UpdataLockPalmVeinListReply && (state.ifCurrentScreen.value == true)) {
|
||||
_replyupdataLockPalmVeinListReply(reply);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 上传数据获取锁密码列表
|
||||
Future<void> _replyupdataLockPasswordListReply(Reply reply) async {
|
||||
int status = reply.data[2];
|
||||
switch(status){
|
||||
case 0x00:
|
||||
//成功
|
||||
state.indexCount.value = state.indexCount.value + 1;
|
||||
cancelBlueConnetctToastTimer();
|
||||
|
||||
int dataLength = reply.data[8];
|
||||
state.uploadPasswordDataList.addAll(reply.data.sublist(9, reply.data.length));
|
||||
if(dataLength == 10){
|
||||
// 当数据是10的时候继续请求
|
||||
var token = reply.data.sublist(3, 7);
|
||||
updataLockPasswordList(token, state.uploadPasswordPage);
|
||||
}else{
|
||||
dismissEasyLoading();
|
||||
|
||||
// 当数据不是10的时候解析数据上传
|
||||
if(state.uploadPasswordDataList.isEmpty){
|
||||
// 如果是空的直接上传下一个
|
||||
getUpdataLockCardList();
|
||||
}else{
|
||||
// 如果不是空的解析数据上传
|
||||
_lockDataUpload(uploadType:2, recordType:2, records:state.uploadPasswordDataList);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x06:
|
||||
//无权限
|
||||
var token = reply.data.sublist(3, 7);
|
||||
var saveStrList = changeIntListToStringList(token);
|
||||
Storage.setStringList(saveBlueToken, saveStrList);
|
||||
|
||||
updataLockPasswordList(token, state.uploadPasswordPage);
|
||||
break;
|
||||
default:
|
||||
dismissEasyLoading();
|
||||
state.sureBtnState.value = 0;
|
||||
state.indexCount.value = 0;
|
||||
cancelBlueConnetctToastTimer();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 上传数据获取锁卡列表
|
||||
Future<void> _replyupdataLockCardListReply(Reply reply) async {
|
||||
int status = reply.data[2];
|
||||
switch(status){
|
||||
case 0x00:
|
||||
//成功
|
||||
state.indexCount.value = state.indexCount.value + 1;
|
||||
dismissEasyLoading();
|
||||
cancelBlueConnetctToastTimer();
|
||||
|
||||
int dataLength = reply.data[8];
|
||||
state.uploadCardDataList.addAll(reply.data.sublist(9, reply.data.length));
|
||||
if(dataLength == 10){
|
||||
// 当数据是10的时候继续请求
|
||||
var token = reply.data.sublist(3, 7);
|
||||
updataLockCardList(token, state.uploadCardPage);
|
||||
}else{
|
||||
// 当数据不是10的时候解析数据上传
|
||||
if(state.uploadCardDataList.isEmpty){
|
||||
// 如果是空的直接上传下一个
|
||||
getUpdataLockFingerprintList();
|
||||
}else{
|
||||
// 如果不是空的解析数据上传
|
||||
_lockDataUpload(uploadType:2, recordType:3, records:state.uploadCardDataList);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x06:
|
||||
//无权限
|
||||
var token = reply.data.sublist(3, 7);
|
||||
var saveStrList = changeIntListToStringList(token);
|
||||
Storage.setStringList(saveBlueToken, saveStrList);
|
||||
|
||||
updataLockCardList(token, state.uploadCardPage);
|
||||
break;
|
||||
default:
|
||||
dismissEasyLoading();
|
||||
state.sureBtnState.value = 0;
|
||||
state.indexCount.value = 0;
|
||||
cancelBlueConnetctToastTimer();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 上传数据获取锁指纹列表
|
||||
Future<void> _replyupdataLockFingerprintListReply(Reply reply) async {
|
||||
int status = reply.data[2];
|
||||
switch(status){
|
||||
case 0x00:
|
||||
//成功
|
||||
state.indexCount.value = state.indexCount.value + 1;
|
||||
dismissEasyLoading();
|
||||
cancelBlueConnetctToastTimer();
|
||||
|
||||
int dataLength = reply.data[8];
|
||||
state.uploadFingerprintDataList.addAll(reply.data.sublist(9, reply.data.length));
|
||||
if(dataLength == 10){
|
||||
// 当数据是10的时候继续请求
|
||||
var token = reply.data.sublist(3, 7);
|
||||
updataLockFingerprintList(token, state.uploadFingerprintPage);
|
||||
}else{
|
||||
// 当数据不是10的时候解析数据上传
|
||||
if(state.uploadFingerprintDataList.isEmpty){
|
||||
// 如果是空的直接上传下一个
|
||||
getUpdataLockFaceList();
|
||||
}else{
|
||||
// 如果不是空的解析数据上传
|
||||
_lockDataUpload(uploadType:2, recordType:4, records:state.uploadFingerprintDataList);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x06:
|
||||
//无权限
|
||||
var token = reply.data.sublist(3, 7);
|
||||
var saveStrList = changeIntListToStringList(token);
|
||||
Storage.setStringList(saveBlueToken, saveStrList);
|
||||
|
||||
updataLockFingerprintList(token, state.uploadFingerprintPage);
|
||||
break;
|
||||
default:
|
||||
dismissEasyLoading();
|
||||
state.sureBtnState.value = 0;
|
||||
state.indexCount.value = 0;
|
||||
cancelBlueConnetctToastTimer();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 上传数据获取锁人脸列表解析
|
||||
Future<void> _replyupdataLockFaceListReply(Reply reply) async {
|
||||
int status = reply.data[2];
|
||||
switch(status){
|
||||
case 0x00:
|
||||
//成功
|
||||
state.indexCount.value = state.indexCount.value + 1;
|
||||
dismissEasyLoading();
|
||||
cancelBlueConnetctToastTimer();
|
||||
|
||||
int dataLength = reply.data[8];
|
||||
state.uploadFaceDataList.addAll(reply.data.sublist(9, reply.data.length));
|
||||
if(dataLength == 10){
|
||||
// 当数据是10的时候继续请求
|
||||
var token = reply.data.sublist(3, 7);
|
||||
updataLockFaceList(token, state.uploadFacePage);
|
||||
}else{
|
||||
// 当数据不是10的时候解析数据上传
|
||||
if(state.uploadFaceDataList.isEmpty){
|
||||
// 如果是空的直接上传下一个
|
||||
getUpdataLockPalmVeinList();
|
||||
}else{
|
||||
// 如果不是空的解析数据上传
|
||||
_lockDataUpload(uploadType:2, recordType:5, records:state.uploadFaceDataList);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x06:
|
||||
//无权限
|
||||
var token = reply.data.sublist(3, 7);
|
||||
var saveStrList = changeIntListToStringList(token);
|
||||
Storage.setStringList(saveBlueToken, saveStrList);
|
||||
|
||||
updataLockFaceList(token, state.uploadFacePage);
|
||||
break;
|
||||
default:
|
||||
dismissEasyLoading();
|
||||
state.sureBtnState.value = 0;
|
||||
state.indexCount.value = 0;
|
||||
cancelBlueConnetctToastTimer();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 上传数据获取锁掌静脉列表解析
|
||||
Future<void> _replyupdataLockPalmVeinListReply(Reply reply) async {
|
||||
int status = reply.data[2];
|
||||
switch(status){
|
||||
case 0x00:
|
||||
//成功
|
||||
state.indexCount.value = state.indexCount.value + 1;
|
||||
dismissEasyLoading();
|
||||
cancelBlueConnetctToastTimer();
|
||||
|
||||
state.sureBtnState.value = 0;
|
||||
state.indexCount.value = 0;
|
||||
|
||||
int dataLength = reply.data[8];
|
||||
state.uploadPalmVeinDataList.addAll(reply.data.sublist(9, reply.data.length));
|
||||
if(dataLength == 10){
|
||||
// 当数据是10的时候继续请求
|
||||
var token = reply.data.sublist(3, 7);
|
||||
updataLockPalmVeinList(token, state.uploadPalmVeinPage);
|
||||
}else{
|
||||
// 当数据不是10的时候解析数据上传
|
||||
if(state.uploadPalmVeinDataList.isEmpty){
|
||||
// 不需要上传 如果是空的直接上传下一个
|
||||
showToast("上传成功");
|
||||
}else{
|
||||
// 如果不是空的解析数据上传
|
||||
_lockDataUpload(uploadType:2, recordType:6, records:state.uploadPalmVeinDataList);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x06:
|
||||
//无权限
|
||||
var token = reply.data.sublist(3, 7);
|
||||
var saveStrList = changeIntListToStringList(token);
|
||||
Storage.setStringList(saveBlueToken, saveStrList);
|
||||
|
||||
updataLockPalmVeinList(token, state.uploadPalmVeinPage);
|
||||
break;
|
||||
default:
|
||||
dismissEasyLoading();
|
||||
state.sureBtnState.value = 0;
|
||||
state.indexCount.value = 0;
|
||||
cancelBlueConnetctToastTimer();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 上传数据获取锁密码列表
|
||||
Future<void> getUpdataLockPasswordList() async {
|
||||
if(state.sureBtnState.value == 1){
|
||||
return;
|
||||
}
|
||||
state.sureBtnState.value = 1;
|
||||
|
||||
showEasyLoading();
|
||||
showBlueConnetctToastTimer(action: (){
|
||||
dismissEasyLoading();
|
||||
state.sureBtnState.value = 0;
|
||||
});
|
||||
BlueManage().bludSendData(BlueManage().connectDeviceName, (BluetoothConnectionState connectionState) async {
|
||||
if (connectionState == BluetoothConnectionState.connected) {
|
||||
var token = await Storage.getStringList(saveBlueToken);
|
||||
List<int> getTokenList = changeStringListToIntList(token!);
|
||||
|
||||
updataLockPasswordList(getTokenList, state.uploadPasswordPage);
|
||||
} else if (connectionState == BluetoothConnectionState.disconnected) {
|
||||
dismissEasyLoading();
|
||||
cancelBlueConnetctToastTimer();
|
||||
state.sureBtnState.value = 0;
|
||||
if(state.ifCurrentScreen.value == true){
|
||||
showBlueConnetctToast();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 公共的获取密码列表
|
||||
Future<void> updataLockPasswordList(List<int> token, int page) async {
|
||||
var privateKey = await Storage.getStringList(saveBluePrivateKey);
|
||||
List<int> getPrivateKeyList = changeStringListToIntList(privateKey!);
|
||||
|
||||
var signKey = await Storage.getStringList(saveBlueSignKey);
|
||||
List<int> signKeyDataList = changeStringListToIntList(signKey!);
|
||||
|
||||
IoSenderManage.updataLockPasswordListCommand(
|
||||
lockID: BlueManage().connectDeviceName,
|
||||
userID: await Storage.getUid(),
|
||||
page: page,
|
||||
countReq: state.countReq,
|
||||
token: token,
|
||||
needAuthor: 1,
|
||||
signKey: signKeyDataList,
|
||||
privateKey: getPrivateKeyList
|
||||
);
|
||||
}
|
||||
|
||||
// 上传数据获取锁Card列表
|
||||
Future<void> getUpdataLockCardList() async {
|
||||
showEasyLoading();
|
||||
showBlueConnetctToastTimer(action: (){
|
||||
dismissEasyLoading();
|
||||
state.indexCount.value = 0;
|
||||
state.sureBtnState.value = 0;
|
||||
});
|
||||
BlueManage().bludSendData(BlueManage().connectDeviceName, (BluetoothConnectionState connectionState) async {
|
||||
if (connectionState == BluetoothConnectionState.connected) {
|
||||
var token = await Storage.getStringList(saveBlueToken);
|
||||
List<int> getTokenList = changeStringListToIntList(token!);
|
||||
|
||||
updataLockCardList(getTokenList, state.uploadCardPage);
|
||||
} else if (connectionState == BluetoothConnectionState.disconnected) {
|
||||
dismissEasyLoading();
|
||||
cancelBlueConnetctToastTimer();
|
||||
state.sureBtnState.value = 0;
|
||||
state.indexCount.value = 0;
|
||||
if(state.ifCurrentScreen.value == true){
|
||||
showBlueConnetctToast();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 公共的获取Card列表
|
||||
Future<void> updataLockCardList(List<int> token, int page) async {
|
||||
var privateKey = await Storage.getStringList(saveBluePrivateKey);
|
||||
List<int> getPrivateKeyList = changeStringListToIntList(privateKey!);
|
||||
|
||||
var signKey = await Storage.getStringList(saveBlueSignKey);
|
||||
List<int> signKeyDataList = changeStringListToIntList(signKey!);
|
||||
|
||||
IoSenderManage.updataLockCardListCommand(
|
||||
lockID: BlueManage().connectDeviceName,
|
||||
userID: await Storage.getUid(),
|
||||
page: page,
|
||||
countReq: state.countReq,
|
||||
token: token,
|
||||
needAuthor: 1,
|
||||
signKey: signKeyDataList,
|
||||
privateKey: getPrivateKeyList
|
||||
);
|
||||
}
|
||||
|
||||
// 上传数据获取锁指纹列表
|
||||
Future<void> getUpdataLockFingerprintList() async {
|
||||
showEasyLoading();
|
||||
showBlueConnetctToastTimer(action: (){
|
||||
dismissEasyLoading();
|
||||
state.indexCount.value = 0;
|
||||
state.sureBtnState.value = 0;
|
||||
});
|
||||
BlueManage().bludSendData(BlueManage().connectDeviceName, (BluetoothConnectionState connectionState) async {
|
||||
if (connectionState == BluetoothConnectionState.connected) {
|
||||
var token = await Storage.getStringList(saveBlueToken);
|
||||
List<int> getTokenList = changeStringListToIntList(token!);
|
||||
|
||||
updataLockFingerprintList(getTokenList, state.uploadFingerprintPage);
|
||||
} else if (connectionState == BluetoothConnectionState.disconnected) {
|
||||
dismissEasyLoading();
|
||||
cancelBlueConnetctToastTimer();
|
||||
state.sureBtnState.value = 0;
|
||||
state.indexCount.value = 0;
|
||||
if(state.ifCurrentScreen.value == true){
|
||||
showBlueConnetctToast();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 公共的获取指纹列表
|
||||
Future<void> updataLockFingerprintList(List<int> token, int page) async {
|
||||
var privateKey = await Storage.getStringList(saveBluePrivateKey);
|
||||
List<int> getPrivateKeyList = changeStringListToIntList(privateKey!);
|
||||
|
||||
var signKey = await Storage.getStringList(saveBlueSignKey);
|
||||
List<int> signKeyDataList = changeStringListToIntList(signKey!);
|
||||
|
||||
IoSenderManage.updataLockFingerprintListCommand(
|
||||
lockID: BlueManage().connectDeviceName,
|
||||
userID: await Storage.getUid(),
|
||||
page: page,
|
||||
countReq: state.countReq,
|
||||
token: token,
|
||||
needAuthor: 1,
|
||||
signKey: signKeyDataList,
|
||||
privateKey: getPrivateKeyList
|
||||
);
|
||||
}
|
||||
|
||||
// 上传数据获取锁人脸列表
|
||||
Future<void> getUpdataLockFaceList() async {
|
||||
showEasyLoading();
|
||||
showBlueConnetctToastTimer(action: (){
|
||||
dismissEasyLoading();
|
||||
state.indexCount.value = 0;
|
||||
state.sureBtnState.value = 0;
|
||||
});
|
||||
BlueManage().bludSendData(BlueManage().connectDeviceName, (BluetoothConnectionState connectionState) async {
|
||||
if (connectionState == BluetoothConnectionState.connected) {
|
||||
var token = await Storage.getStringList(saveBlueToken);
|
||||
List<int> getTokenList = changeStringListToIntList(token!);
|
||||
|
||||
updataLockFaceList(getTokenList, state.uploadFacePage);
|
||||
} else if (connectionState == BluetoothConnectionState.disconnected) {
|
||||
dismissEasyLoading();
|
||||
cancelBlueConnetctToastTimer();
|
||||
state.sureBtnState.value = 0;
|
||||
state.indexCount.value = 0;
|
||||
if(state.ifCurrentScreen.value == true){
|
||||
showBlueConnetctToast();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 公共的获取人脸列表
|
||||
Future<void> updataLockFaceList(List<int> token, int page) async {
|
||||
var privateKey = await Storage.getStringList(saveBluePrivateKey);
|
||||
List<int> getPrivateKeyList = changeStringListToIntList(privateKey!);
|
||||
|
||||
var signKey = await Storage.getStringList(saveBlueSignKey);
|
||||
List<int> signKeyDataList = changeStringListToIntList(signKey!);
|
||||
|
||||
IoSenderManage.updataLockFaceListCommand(
|
||||
lockID: BlueManage().connectDeviceName,
|
||||
userID: await Storage.getUid(),
|
||||
page: page,
|
||||
countReq: state.countReq,
|
||||
token: token,
|
||||
needAuthor: 1,
|
||||
signKey: signKeyDataList,
|
||||
privateKey: getPrivateKeyList
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// 上传数据获取锁掌静脉列表
|
||||
Future<void> getUpdataLockPalmVeinList() async {
|
||||
showEasyLoading();
|
||||
showBlueConnetctToastTimer(action: (){
|
||||
dismissEasyLoading();
|
||||
state.indexCount.value = 0;
|
||||
state.sureBtnState.value = 0;
|
||||
});
|
||||
BlueManage().bludSendData(BlueManage().connectDeviceName, (BluetoothConnectionState connectionState) async {
|
||||
if (connectionState == BluetoothConnectionState.connected) {
|
||||
var token = await Storage.getStringList(saveBlueToken);
|
||||
List<int> getTokenList = changeStringListToIntList(token!);
|
||||
|
||||
updataLockPalmVeinList(getTokenList, state.uploadPalmVeinPage);
|
||||
} else if (connectionState == BluetoothConnectionState.disconnected) {
|
||||
dismissEasyLoading();
|
||||
cancelBlueConnetctToastTimer();
|
||||
state.sureBtnState.value = 0;
|
||||
state.indexCount.value = 0;
|
||||
if(state.ifCurrentScreen.value == true){
|
||||
showBlueConnetctToast();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 公共的获取掌静脉列表
|
||||
Future<void> updataLockPalmVeinList(List<int> token, int page) async {
|
||||
var privateKey = await Storage.getStringList(saveBluePrivateKey);
|
||||
List<int> getPrivateKeyList = changeStringListToIntList(privateKey!);
|
||||
|
||||
var signKey = await Storage.getStringList(saveBlueSignKey);
|
||||
List<int> signKeyDataList = changeStringListToIntList(signKey!);
|
||||
|
||||
IoSenderManage.updataLockPalmVeinListCommand(
|
||||
lockID: BlueManage().connectDeviceName,
|
||||
userID: await Storage.getUid(),
|
||||
page: page,
|
||||
countReq: state.countReq,
|
||||
token: token,
|
||||
needAuthor: 1,
|
||||
signKey: signKeyDataList,
|
||||
privateKey: getPrivateKeyList
|
||||
);
|
||||
}
|
||||
|
||||
// 锁数据上传服务器
|
||||
Future<void> _lockDataUpload({
|
||||
required int uploadType,
|
||||
required int recordType,
|
||||
required List records
|
||||
}) async{
|
||||
var entity = await ApiRepository.to.lockDataUpload(
|
||||
lockId: CommonDataManage().currentKeyInfo.lockId!,
|
||||
uploadType:uploadType,
|
||||
recordType: recordType,
|
||||
records:records
|
||||
);
|
||||
if(entity.errorCode!.codeIsSuccessful){
|
||||
if(uploadType == 1){
|
||||
// 1设置
|
||||
|
||||
}else{
|
||||
// 2开门方式
|
||||
switch(recordType){
|
||||
// case 1:
|
||||
// // 电子钥匙
|
||||
//
|
||||
// break;
|
||||
case 2:
|
||||
// 密码
|
||||
getUpdataLockCardList();
|
||||
break;
|
||||
case 3:
|
||||
// IC卡
|
||||
getUpdataLockFingerprintList();
|
||||
break;
|
||||
case 4:
|
||||
// 指纹
|
||||
getUpdataLockFaceList();
|
||||
break;
|
||||
case 5:
|
||||
// 人脸
|
||||
getUpdataLockPalmVeinList();
|
||||
break;
|
||||
case 6:
|
||||
// 掌静脉
|
||||
state.indexCount.value = 0;
|
||||
state.sureBtnState.value = 0;
|
||||
showToast("上传成功");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
state.indexCount.value = 0;
|
||||
state.sureBtnState.value = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void onReady() {
|
||||
// TODO: implement onReady
|
||||
super.onReady();
|
||||
|
||||
_initReplySubscription();
|
||||
|
||||
// getUpdataLockPalmVeinList();
|
||||
}
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
// TODO: implement onInit
|
||||
super.onInit();
|
||||
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
// TODO: implement onClose
|
||||
super.onClose();
|
||||
|
||||
_replySubscription.cancel();
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,11 +1,14 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_easyloading/flutter_easyloading.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../../../../app_settings/app_colors.dart';
|
||||
import '../../../../tools/appRouteObserver.dart';
|
||||
import '../../../../tools/submitBtn.dart';
|
||||
import '../../../../tools/titleAppBar.dart';
|
||||
import '../../../../translations/trans_lib.dart';
|
||||
import 'uploadData_logic.dart';
|
||||
|
||||
class UploadDataPage extends StatefulWidget {
|
||||
const UploadDataPage({Key? key}) : super(key: key);
|
||||
@ -14,7 +17,10 @@ class UploadDataPage extends StatefulWidget {
|
||||
State<UploadDataPage> createState() => _UploadDataPageState();
|
||||
}
|
||||
|
||||
class _UploadDataPageState extends State<UploadDataPage> {
|
||||
class _UploadDataPageState extends State<UploadDataPage> with RouteAware{
|
||||
final logic = Get.put(UploadDataLogic());
|
||||
final state = Get.find<UploadDataLogic>().state;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
@ -31,18 +37,89 @@ class _UploadDataPageState extends State<UploadDataPage> {
|
||||
],
|
||||
),
|
||||
SizedBox(height: 30.h,),
|
||||
SubmitBtn(btnName: TranslationLoader.lanKeys!.begin!.tr,
|
||||
Obx(() => SubmitBtn(btnName: state.indexCount.value == 0 ? TranslationLoader.lanKeys!.begin!.tr : "${TranslationLoader.lanKeys!.begin!.tr}(${state.indexCount.value}/5)",
|
||||
borderRadius: 20.w,
|
||||
fontSize: 24.sp,
|
||||
// margin: EdgeInsets.only(left: 03.w, right: 30.w, top: 20.w),
|
||||
padding: EdgeInsets.only(top: 20.w, bottom: 20.w),
|
||||
onClick: () {
|
||||
state.uploadPasswordPage = 0;
|
||||
state.uploadPasswordDataList = [];
|
||||
state.uploadCardPage = 0;
|
||||
state.uploadCardDataList = [];
|
||||
state.uploadFingerprintPage = 0;
|
||||
state.uploadFingerprintDataList = [];
|
||||
state.uploadFacePage = 0;
|
||||
state.uploadFaceDataList = [];
|
||||
state.uploadPalmVeinPage = 0;
|
||||
state.uploadPalmVeinDataList = [];
|
||||
|
||||
logic.getUpdataLockPasswordList();
|
||||
}
|
||||
),
|
||||
)),
|
||||
],
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
// TODO: implement didChangeDependencies
|
||||
super.didChangeDependencies();
|
||||
|
||||
/// 路由订阅
|
||||
AppRouteObserver().routeObserver.subscribe(this, ModalRoute.of(context)!);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
// TODO: implement dispose
|
||||
/// 取消路由订阅
|
||||
AppRouteObserver().routeObserver.unsubscribe(this);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
/// 从上级界面进入 当前界面即将出现
|
||||
@override
|
||||
void didPush() {
|
||||
super.didPush();
|
||||
|
||||
state.ifCurrentScreen.value = true;
|
||||
}
|
||||
|
||||
/// 返回上一个界面 当前界面即将消失
|
||||
@override
|
||||
void didPop() {
|
||||
super.didPop();
|
||||
|
||||
logic.cancelBlueConnetctToastTimer();
|
||||
if (EasyLoading.isShow) EasyLoading.dismiss(animation: true);
|
||||
// if (state.deletWaitScanTimer != null) {
|
||||
// state.deletWaitScanTimer!.cancel();
|
||||
// }
|
||||
// if (state.deletWaitScanCompleter != null &&
|
||||
// !state.deletWaitScanCompleter!.isCompleted) {
|
||||
// state.deletWaitScanCompleter!.complete();
|
||||
// }
|
||||
state.ifCurrentScreen.value = false;
|
||||
}
|
||||
|
||||
/// 从下级返回 当前界面即将出现
|
||||
@override
|
||||
void didPopNext() {
|
||||
super.didPopNext();
|
||||
|
||||
state.ifCurrentScreen.value = true;
|
||||
}
|
||||
|
||||
/// 进入下级界面 当前界面即将消失
|
||||
@override
|
||||
void didPushNext() {
|
||||
super.didPushNext();
|
||||
|
||||
logic.cancelBlueConnetctToastTimer();
|
||||
if (EasyLoading.isShow) EasyLoading.dismiss(animation: true);
|
||||
state.ifCurrentScreen.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
25
lib/main/lockDetail/lockSet/uploadData/uploadData_state.dart
Normal file
25
lib/main/lockDetail/lockSet/uploadData/uploadData_state.dart
Normal file
@ -0,0 +1,25 @@
|
||||
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class UploadDataState{
|
||||
var ifCurrentScreen = true.obs; // 是否是当前界面,用于判断是否需要针对当前界面进行展示
|
||||
var sureBtnState = 0.obs;// 0普通状态(可用) 1连接中(不可用)
|
||||
|
||||
var countReq = 10;// 每次请求的数量
|
||||
var indexCount = 0.obs;// 用来显示按钮的索引 0/5
|
||||
|
||||
var uploadPasswordPage = 0;// 上传密码的页数
|
||||
List<int> uploadPasswordDataList = [];// 上传密码的数据
|
||||
|
||||
var uploadCardPage = 0;// 上传卡片的页数
|
||||
List<int> uploadCardDataList = [];// 上传卡片的数据
|
||||
|
||||
var uploadFingerprintPage = 0;// 上传指纹的页数
|
||||
List<int> uploadFingerprintDataList = [];// 上传指纹的数据
|
||||
|
||||
var uploadFacePage = 0;// 上传人脸的页数
|
||||
List<int> uploadFaceDataList = [];// 上传人脸的数据
|
||||
|
||||
var uploadPalmVeinPage = 0;// 上传掌静脉的页数
|
||||
List<int> uploadPalmVeinDataList = [];// 上传掌静脉的数据
|
||||
}
|
||||
@ -24,7 +24,7 @@ class LockListPage extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _LockListPageState extends State<LockListPage> with RouteAware {
|
||||
final logic = Get.put(LockListLogic());
|
||||
final logic = Get.put(LockListLogic());
|
||||
final state = Get.find<LockListLogic>().state;
|
||||
|
||||
var groupDataList = <GroupList>[];
|
||||
|
||||
@ -221,7 +221,7 @@ class _ExpireLockListPageState extends State<ExpireLockListPage> {
|
||||
);
|
||||
} else {
|
||||
return Container(
|
||||
padding: EdgeInsets.only(left: 5.w, right: 5.w),
|
||||
padding: EdgeInsets.only(left: 5.w, right: 5.w, bottom: 2.h),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.red,
|
||||
borderRadius: BorderRadius.circular(2.0),
|
||||
|
||||
@ -235,4 +235,5 @@ abstract class Api {
|
||||
|
||||
final String getUserNoList = '/key/getUserNoList'; //获取指定锁下所有userNo
|
||||
|
||||
final String lockDataUploadUrl = '/lockRecords/lockDataUpload'; // 锁数据上传
|
||||
}
|
||||
|
||||
@ -2076,6 +2076,21 @@ class ApiProvider extends BaseProvider {
|
||||
// 获取指定锁下所有userNo
|
||||
Future<Response> getLockUserNoList(int lockId) =>
|
||||
post(getUserNoList.toUrl, jsonEncode({'lockId': lockId}));
|
||||
|
||||
// 锁数据上传
|
||||
Future<Response> lockDataUpload(
|
||||
int lockId,
|
||||
int uploadType,
|
||||
int recordType,
|
||||
List records,
|
||||
) => post(
|
||||
lockDataUploadUrl.toUrl,
|
||||
jsonEncode({
|
||||
'lockId': lockId,
|
||||
'uploadType': uploadType,
|
||||
'recordType': recordType,
|
||||
'records': records
|
||||
}));
|
||||
}
|
||||
|
||||
extension ExtensionString on String {
|
||||
|
||||
@ -2107,4 +2107,15 @@ class ApiRepository {
|
||||
final res = await apiProvider.getLockUserNoList(lockId);
|
||||
return LockUserNoListEntity.fromJson(res.body);
|
||||
}
|
||||
|
||||
// 锁数据上传
|
||||
Future<LoginEntity> lockDataUpload({
|
||||
required int lockId,
|
||||
required int uploadType,
|
||||
required int recordType,
|
||||
required List records,
|
||||
}) async {
|
||||
final res = await apiProvider.lockDataUpload(lockId, uploadType, recordType, records);
|
||||
return LoginEntity.fromJson(res.body);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user